aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes3
-rw-r--r--.gitlab-ci.d/base.yml2
-rw-r--r--.gitlab-ci.d/buildtest-template.yml29
-rw-r--r--.gitlab-ci.d/buildtest.yml111
-rwxr-xr-x.gitlab-ci.d/check-dco.py5
-rwxr-xr-x.gitlab-ci.d/check-patch.py5
-rw-r--r--.gitlab-ci.d/cirrus.yml20
-rw-r--r--.gitlab-ci.d/cirrus/build.yml2
-rw-r--r--.gitlab-ci.d/cirrus/freebsd-13.vars16
-rw-r--r--.gitlab-ci.d/cirrus/freebsd-14.vars16
-rw-r--r--.gitlab-ci.d/cirrus/macos-14.vars2
-rw-r--r--.gitlab-ci.d/cirrus/macos-15.vars (renamed from .gitlab-ci.d/cirrus/macos-13.vars)4
-rw-r--r--.gitlab-ci.d/container-cross.yml11
-rw-r--r--.gitlab-ci.d/containers.yml6
-rw-r--r--.gitlab-ci.d/crossbuild-template.yml54
-rw-r--r--.gitlab-ci.d/crossbuilds.yml15
-rw-r--r--.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml2
-rw-r--r--.gitlab-ci.d/custom-runners/ubuntu-22.04-s390x.yml2
-rw-r--r--.gitlab-ci.d/windows.yml29
-rw-r--r--.travis.yml2
-rw-r--r--Kconfig1
-rw-r--r--Kconfig.host3
-rw-r--r--MAINTAINERS308
-rw-r--r--Makefile3
-rw-r--r--VERSION2
-rw-r--r--accel/accel-blocker.c1
-rw-r--r--accel/hvf/hvf-accel-ops.c16
-rw-r--r--accel/kvm/kvm-all.c522
-rw-r--r--accel/kvm/kvm-cpus.h1
-rw-r--r--accel/kvm/trace-events14
-rw-r--r--accel/stubs/tcg-stub.c14
-rw-r--r--accel/tcg/atomic_common.c.inc13
-rw-r--r--accel/tcg/atomic_template.h66
-rw-r--r--accel/tcg/cpu-exec.c3
-rw-r--r--accel/tcg/cputlb.c160
-rw-r--r--accel/tcg/ldst_atomicity.c.inc9
-rw-r--r--accel/tcg/ldst_common.c.inc38
-rw-r--r--accel/tcg/plugin-gen.c8
-rw-r--r--accel/tcg/tcg-accel-ops-rr.c6
-rw-r--r--accel/tcg/trace-events12
-rw-r--r--accel/tcg/translator.c1
-rw-r--r--accel/tcg/user-exec.c12
-rw-r--r--accel/tcg/user-retaddr.h28
-rw-r--r--audio/dbusaudio.c2
-rw-r--r--audio/pwaudio.c8
-rw-r--r--audio/trace-events2
-rw-r--r--backends/Kconfig4
-rw-r--r--backends/cryptodev-builtin.c52
-rw-r--r--backends/cryptodev-lkcf.c36
-rw-r--r--backends/cryptodev-vhost-user.c6
-rw-r--r--backends/cryptodev.c12
-rw-r--r--backends/hostmem.c2
-rw-r--r--backends/iommufd.c89
-rw-r--r--backends/meson.build2
-rw-r--r--backends/spdm-socket.c216
-rw-r--r--backends/tpm/tpm_emulator.c74
-rw-r--r--backends/tpm/tpm_ioctl.h13
-rw-r--r--backends/tpm/trace-events2
-rw-r--r--backends/trace-events3
-rw-r--r--block.c6
-rw-r--r--block/aio_task.c5
-rw-r--r--block/backup.c2
-rw-r--r--block/blkio.c6
-rw-r--r--block/block-backend.c94
-rw-r--r--block/block-copy.c42
-rw-r--r--block/copy-before-write.c17
-rw-r--r--block/copy-before-write.h1
-rw-r--r--block/crypto.c10
-rw-r--r--block/export/vduse-blk.c7
-rw-r--r--block/export/vhost-user-blk-server.c6
-rw-r--r--block/file-posix.c2
-rw-r--r--block/gluster.c9
-rw-r--r--block/mirror.c8
-rw-r--r--block/monitor/block-hmp-cmds.c3
-rw-r--r--block/parallels-ext.c2
-rw-r--r--block/qcow.c2
-rw-r--r--block/qcow2.c12
-rw-r--r--block/quorum.c4
-rw-r--r--block/raw-format.c4
-rw-r--r--block/rbd.c4
-rw-r--r--block/reqlist.c2
-rw-r--r--block/ssh.c13
-rw-r--r--block/stream.c6
-rw-r--r--block/vdi.c8
-rw-r--r--block/vvfat.c27
-rw-r--r--blockdev-nbd.c59
-rw-r--r--blockdev.c3
-rw-r--r--bsd-user/aarch64/signal.c137
-rw-r--r--bsd-user/aarch64/target.h20
-rw-r--r--bsd-user/aarch64/target_arch.h29
-rw-r--r--bsd-user/aarch64/target_arch_cpu.c31
-rw-r--r--bsd-user/aarch64/target_arch_cpu.h189
-rw-r--r--bsd-user/aarch64/target_arch_elf.h163
-rw-r--r--bsd-user/aarch64/target_arch_reg.h56
-rw-r--r--bsd-user/aarch64/target_arch_signal.h82
-rw-r--r--bsd-user/aarch64/target_arch_sigtramp.h48
-rw-r--r--bsd-user/aarch64/target_arch_sysarch.h42
-rw-r--r--bsd-user/aarch64/target_arch_thread.h61
-rw-r--r--bsd-user/aarch64/target_arch_vmparam.h74
-rw-r--r--bsd-user/aarch64/target_syscall.h51
-rw-r--r--bsd-user/arm/target_arch_signal.h2
-rw-r--r--bsd-user/freebsd/os-proc.c118
-rw-r--r--bsd-user/i386/target_arch_signal.h2
-rw-r--r--bsd-user/main.c44
-rw-r--r--bsd-user/mmap.c38
-rw-r--r--bsd-user/qemu.h3
-rw-r--r--bsd-user/riscv/signal.c170
-rw-r--r--bsd-user/riscv/target.h20
-rw-r--r--bsd-user/riscv/target_arch.h27
-rw-r--r--bsd-user/riscv/target_arch_cpu.c29
-rw-r--r--bsd-user/riscv/target_arch_cpu.h148
-rw-r--r--bsd-user/riscv/target_arch_elf.h42
-rw-r--r--bsd-user/riscv/target_arch_reg.h88
-rw-r--r--bsd-user/riscv/target_arch_signal.h75
-rw-r--r--bsd-user/riscv/target_arch_sigtramp.h41
-rw-r--r--bsd-user/riscv/target_arch_sysarch.h41
-rw-r--r--bsd-user/riscv/target_arch_thread.h47
-rw-r--r--bsd-user/riscv/target_arch_vmparam.h53
-rw-r--r--bsd-user/riscv/target_syscall.h38
-rw-r--r--bsd-user/signal.c9
-rw-r--r--bsd-user/x86_64/target_arch_signal.h2
-rw-r--r--chardev/char-fe.c13
-rw-r--r--chardev/char-mux.c90
-rw-r--r--chardev/char-pty.c33
-rw-r--r--chardev/char-socket.c70
-rw-r--r--chardev/char-win-stdio.c5
-rw-r--r--chardev/char.c81
-rw-r--r--chardev/chardev-internal.h16
-rw-r--r--chardev/msmouse.c2
-rw-r--r--chardev/trace-events10
-rw-r--r--configs/devices/arm-softmmu/default.mak7
-rw-r--r--configs/devices/cris-softmmu/default.mak4
-rw-r--r--configs/devices/sh4-softmmu/default.mak3
-rw-r--r--configs/devices/sh4eb-softmmu/default.mak3
-rw-r--r--configs/targets/aarch64-bsd-user.mak3
-rw-r--r--configs/targets/aarch64-linux-user.mak2
-rw-r--r--configs/targets/aarch64_be-linux-user.mak4
-rw-r--r--configs/targets/cris-linux-user.mak1
-rw-r--r--configs/targets/cris-softmmu.mak1
-rw-r--r--configs/targets/hexagon-linux-user.mak2
-rw-r--r--configs/targets/i386-linux-user.mak2
-rw-r--r--configs/targets/loongarch64-linux-user.mak4
-rw-r--r--configs/targets/loongarch64-softmmu.mak2
-rw-r--r--configs/targets/or1k-linux-user.mak2
-rw-r--r--configs/targets/riscv32-linux-user.mak3
-rw-r--r--configs/targets/riscv64-bsd-user.mak4
-rw-r--r--configs/targets/riscv64-linux-user.mak3
-rw-r--r--configs/targets/sh4eb-softmmu.mak2
-rw-r--r--configs/targets/x86_64-linux-user.mak2
-rwxr-xr-xconfigure227
-rw-r--r--contrib/plugins/Makefile30
-rw-r--r--contrib/plugins/bbv.c158
-rw-r--r--contrib/plugins/cache.c2
-rw-r--r--contrib/plugins/cflow.c388
-rw-r--r--contrib/plugins/execlog.c6
-rw-r--r--contrib/plugins/ips.c6
-rw-r--r--contrib/plugins/lockstep.c25
-rw-r--r--contrib/plugins/stoptrigger.c151
-rw-r--r--contrib/systemd/qemu-vmsr-helper.service15
-rw-r--r--contrib/systemd/qemu-vmsr-helper.socket9
-rw-r--r--contrib/vhost-user-blk/vhost-user-blk.c2
-rw-r--r--cpu-common.c7
-rw-r--r--crypto/afalg.c8
-rw-r--r--crypto/afalgpriv.h14
-rw-r--r--crypto/afsplit.c6
-rw-r--r--crypto/akcipher-gcrypt.c.inc44
-rw-r--r--crypto/akcipher-nettle.c.inc56
-rw-r--r--crypto/akcipher.c2
-rw-r--r--crypto/akcipherpriv.h2
-rw-r--r--crypto/block-luks.c131
-rw-r--r--crypto/block-qcow.c6
-rw-r--r--crypto/block.c8
-rw-r--r--crypto/blockpriv.h6
-rw-r--r--crypto/cipher-afalg.c36
-rw-r--r--crypto/cipher-builtin.c.inc18
-rw-r--r--crypto/cipher-gcrypt.c.inc56
-rw-r--r--crypto/cipher-gnutls.c.inc38
-rw-r--r--crypto/cipher-nettle.c.inc83
-rw-r--r--crypto/cipher.c72
-rw-r--r--crypto/cipherpriv.h2
-rw-r--r--crypto/der.c13
-rw-r--r--crypto/der.h22
-rw-r--r--crypto/hash-afalg.c199
-rw-r--r--crypto/hash-gcrypt.c135
-rw-r--r--crypto/hash-glib.c113
-rw-r--r--crypto/hash-gnutls.c125
-rw-r--r--crypto/hash-nettle.c110
-rw-r--r--crypto/hash.c191
-rw-r--r--crypto/hashpriv.h13
-rw-r--r--crypto/hmac-gcrypt.c22
-rw-r--r--crypto/hmac-glib.c22
-rw-r--r--crypto/hmac-gnutls.c22
-rw-r--r--crypto/hmac-nettle.c22
-rw-r--r--crypto/hmac.c2
-rw-r--r--crypto/hmacpriv.h4
-rw-r--r--crypto/init.c15
-rw-r--r--crypto/ivgen.c18
-rw-r--r--crypto/ivgenpriv.h6
-rw-r--r--crypto/meson.build4
-rw-r--r--crypto/pbkdf-gcrypt.c38
-rw-r--r--crypto/pbkdf-gnutls.c38
-rw-r--r--crypto/pbkdf-nettle.c32
-rw-r--r--crypto/pbkdf-stub.c4
-rw-r--r--crypto/pbkdf.c53
-rw-r--r--crypto/rsakey-builtin.c.inc4
-rw-r--r--crypto/rsakey-nettle.c.inc4
-rw-r--r--crypto/secret_common.c2
-rw-r--r--crypto/tlscredspsk.c1
-rw-r--r--crypto/tlssession.c124
-rw-r--r--crypto/x509-utils.c76
-rw-r--r--disas/cris.c2863
-rw-r--r--disas/meson.build1
-rw-r--r--disas/riscv.c189
-rw-r--r--disas/riscv.h2
-rw-r--r--docs/COLO-FT.txt4
-rw-r--r--docs/about/deprecated.rst125
-rw-r--r--docs/about/emulation.rst650
-rw-r--r--docs/about/removed-features.rst71
-rw-r--r--docs/conf.py3
-rw-r--r--docs/devel/atomics.rst6
-rw-r--r--docs/devel/blkdebug.txt162
-rw-r--r--docs/devel/build-system.rst6
-rw-r--r--docs/devel/clocks.rst6
-rw-r--r--docs/devel/crypto.rst10
-rw-r--r--docs/devel/index-api.rst1
-rw-r--r--docs/devel/index-build.rst14
-rw-r--r--docs/devel/index-internals.rst3
-rw-r--r--docs/devel/index.rst1
-rw-r--r--docs/devel/loads-stores.rst2
-rw-r--r--docs/devel/lockcnt.rst (renamed from docs/devel/lockcnt.txt)89
-rw-r--r--docs/devel/luks-detached-header.rst182
-rw-r--r--docs/devel/maintainers.rst4
-rw-r--r--docs/devel/migration/features.rst1
-rw-r--r--docs/devel/migration/main.rst6
-rw-r--r--docs/devel/migration/mapped-ram.rst4
-rw-r--r--docs/devel/migration/qatzip-compression.rst165
-rw-r--r--docs/devel/migration/uadk-compression.rst4
-rw-r--r--docs/devel/multiple-iothreads.rst139
-rw-r--r--docs/devel/multiple-iothreads.txt130
-rw-r--r--docs/devel/nested-papr.txt119
-rw-r--r--docs/devel/rcu.rst (renamed from docs/devel/rcu.txt)172
-rw-r--r--docs/devel/replay.rst3
-rw-r--r--docs/devel/reset.rst20
-rw-r--r--docs/devel/tcg-plugins.rst496
-rw-r--r--docs/devel/testing/acpi-bits.rst (renamed from docs/devel/acpi-bits.rst)86
-rw-r--r--docs/devel/testing/avocado.rst581
-rw-r--r--docs/devel/testing/blkdebug.rst177
-rw-r--r--docs/devel/testing/blkverify.rst (renamed from docs/devel/blkverify.txt)30
-rw-r--r--docs/devel/testing/ci-definitions.rst.inc (renamed from docs/devel/ci-definitions.rst.inc)0
-rw-r--r--docs/devel/testing/ci-jobs.rst.inc (renamed from docs/devel/ci-jobs.rst.inc)0
-rw-r--r--docs/devel/testing/ci-runners.rst.inc (renamed from docs/devel/ci-runners.rst.inc)0
-rw-r--r--docs/devel/testing/ci.rst (renamed from docs/devel/ci.rst)0
-rw-r--r--docs/devel/testing/functional.rst338
-rw-r--r--docs/devel/testing/fuzzing.rst (renamed from docs/devel/fuzzing.rst)9
-rw-r--r--docs/devel/testing/index.rst18
-rw-r--r--docs/devel/testing/main.rst (renamed from docs/devel/testing.rst)643
-rw-r--r--docs/devel/testing/qgraph.rst (renamed from docs/devel/qgraph.rst)0
-rw-r--r--docs/devel/testing/qtest.rst (renamed from docs/devel/qtest.rst)0
-rw-r--r--docs/interop/firmware.json47
-rw-r--r--docs/interop/index.rst3
-rw-r--r--docs/interop/live-block-operations.rst4
-rw-r--r--docs/interop/nbd.rst89
-rw-r--r--docs/interop/nbd.txt72
-rw-r--r--docs/interop/parallels.rst (renamed from docs/interop/parallels.txt)108
-rw-r--r--docs/interop/prl-xml.rst192
-rw-r--r--docs/interop/prl-xml.txt158
-rw-r--r--docs/interop/qemu-ga.rst20
-rw-r--r--docs/meson.build6
-rw-r--r--docs/pcie_sriov.txt8
-rw-r--r--docs/specs/acpi_hw_reduced_hotplug.rst3
-rw-r--r--docs/specs/fw_cfg.rst4
-rw-r--r--docs/specs/index.rst3
-rw-r--r--docs/specs/pci-ids.rst8
-rw-r--r--docs/specs/rapl-msr.rst154
-rw-r--r--docs/specs/rocker.rst (renamed from docs/specs/rocker.txt)181
-rw-r--r--docs/specs/spdm.rst134
-rw-r--r--docs/sphinx/depfile.py2
-rw-r--r--docs/sphinx/qapidoc.py5
-rw-r--r--docs/system/arm/aspeed.rst2
-rw-r--r--docs/system/arm/cubieboard.rst1
-rw-r--r--docs/system/arm/emulation.rst1
-rw-r--r--docs/system/arm/gumstix.rst21
-rw-r--r--docs/system/arm/mainstone.rst25
-rw-r--r--docs/system/arm/nseries.rst33
-rw-r--r--docs/system/arm/palm.rst23
-rw-r--r--docs/system/arm/stm32.rst3
-rw-r--r--docs/system/arm/xscale.rst35
-rw-r--r--docs/system/bootindex.rst7
-rw-r--r--docs/system/devices/virtio-gpu.rst11
-rw-r--r--docs/system/i386/hyperv.rst43
-rw-r--r--docs/system/i386/xenpvh.rst49
-rw-r--r--docs/system/loongarch/virt.rst2
-rw-r--r--docs/system/ppc/powermac.rst4
-rw-r--r--docs/system/ppc/powernv.rst2
-rw-r--r--docs/system/s390x/bootdevices.rst29
-rw-r--r--docs/system/target-arm.rst5
-rw-r--r--docs/system/target-i386.rst1
-rw-r--r--docs/tools/index.rst2
-rw-r--r--docs/tools/qemu-vmsr-helper.rst89
-rw-r--r--docs/tools/virtfs-proxy-helper.rst75
-rw-r--r--docs/user/main.rst4
-rw-r--r--dump/dump.c12
-rw-r--r--ebpf/ebpf_rss-stub.c8
-rw-r--r--ebpf/ebpf_rss.c120
-rw-r--r--ebpf/ebpf_rss.h10
-rw-r--r--ebpf/trace-events8
-rw-r--r--fpu/softfloat-parts.c.inc2
-rw-r--r--fpu/softfloat-specialize.c.inc4
-rw-r--r--fsdev/9p-iov-marshal.c15
-rw-r--r--fsdev/meson.build8
-rw-r--r--fsdev/qemu-fsdev.c19
-rw-r--r--fsdev/qemu-fsdev.h1
-rw-r--r--fsdev/virtfs-proxy-helper.c1193
-rw-r--r--gdb-xml/hexagon-core.xml6
-rw-r--r--gdb-xml/i386-32bit-linux.xml11
-rw-r--r--gdb-xml/i386-64bit-linux.xml11
-rw-r--r--gdb-xml/loongarch-lasx.xml60
-rw-r--r--gdb-xml/loongarch-lsx.xml59
-rw-r--r--gdbstub/gdbstub.c156
-rw-r--r--gdbstub/syscalls.c2
-rw-r--r--gdbstub/system.c2
-rw-r--r--gdbstub/user-target.c2
-rw-r--r--gdbstub/user.c2
-rw-r--r--host/include/riscv/host/cpuinfo.h2
-rw-r--r--hw/9pfs/9p-proxy.c1279
-rw-r--r--hw/9pfs/9p-proxy.h101
-rw-r--r--hw/9pfs/meson.build1
-rw-r--r--hw/Kconfig2
-rw-r--r--hw/acpi/acpi-cpu-hotplug-stub.c6
-rw-r--r--hw/acpi/aml-build.c3
-rw-r--r--hw/acpi/cpu.c18
-rw-r--r--hw/acpi/erst.c2
-rw-r--r--hw/acpi/generic_event_device.c56
-rw-r--r--hw/acpi/ich9.c23
-rw-r--r--hw/acpi/ich9_timer.c93
-rw-r--r--hw/acpi/meson.build2
-rw-r--r--hw/acpi/piix4.c2
-rw-r--r--hw/adc/Kconfig3
-rw-r--r--hw/adc/aspeed_adc.c18
-rw-r--r--hw/adc/max111x.c236
-rw-r--r--hw/adc/meson.build1
-rw-r--r--hw/adc/stm32f2xx_adc.c2
-rw-r--r--hw/adc/zynq-xadc.c2
-rw-r--r--hw/arm/Kconfig140
-rw-r--r--hw/arm/allwinner-a10.c16
-rw-r--r--hw/arm/allwinner-h3.c7
-rw-r--r--hw/arm/allwinner-r40.c7
-rw-r--r--hw/arm/armsse.c2
-rw-r--r--hw/arm/aspeed.c101
-rw-r--r--hw/arm/aspeed_ast2400.c2
-rw-r--r--hw/arm/aspeed_ast2600.c8
-rw-r--r--hw/arm/aspeed_ast27x0.c75
-rw-r--r--hw/arm/aspeed_soc_common.c9
-rw-r--r--hw/arm/boot.c10
-rw-r--r--hw/arm/gumstix.c141
-rw-r--r--hw/arm/highbank.c4
-rw-r--r--hw/arm/kzm.c2
-rw-r--r--hw/arm/mainstone.c175
-rw-r--r--hw/arm/meson.build14
-rw-r--r--hw/arm/mps2-tz.c10
-rw-r--r--hw/arm/msf2-soc.c2
-rw-r--r--hw/arm/musicpal.c8
-rw-r--r--hw/arm/npcm7xx.c2
-rw-r--r--hw/arm/nseries.c1473
-rw-r--r--hw/arm/omap1.c29
-rw-r--r--hw/arm/omap2.c2715
-rw-r--r--hw/arm/palm.c324
-rw-r--r--hw/arm/pxa2xx.c2393
-rw-r--r--hw/arm/pxa2xx_gpio.c365
-rw-r--r--hw/arm/pxa2xx_pic.c359
-rw-r--r--hw/arm/sbsa-ref.c16
-rw-r--r--hw/arm/smmu-common.c2
-rw-r--r--hw/arm/smmuv3-internal.h3
-rw-r--r--hw/arm/smmuv3.c1
-rw-r--r--hw/arm/spitz.c1284
-rw-r--r--hw/arm/stm32f405_soc.c12
-rw-r--r--hw/arm/stm32l4x5_soc.c2
-rw-r--r--hw/arm/strongarm.c4
-rw-r--r--hw/arm/tosa.c327
-rw-r--r--hw/arm/trace-events5
-rw-r--r--hw/arm/virt-acpi-build.c6
-rw-r--r--hw/arm/virt.c63
-rw-r--r--hw/arm/xen-pvh.c106
-rw-r--r--hw/arm/xen-stubs.c32
-rw-r--r--hw/arm/xen_arm.c267
-rw-r--r--hw/arm/xilinx_zynq.c78
-rw-r--r--hw/arm/xlnx-versal-virt.c4
-rw-r--r--hw/arm/xlnx-versal.c12
-rw-r--r--hw/arm/xlnx-zynqmp.c11
-rw-r--r--hw/arm/z2.c355
-rw-r--r--hw/audio/ac97.c2
-rw-r--r--hw/audio/cs4231.c2
-rw-r--r--hw/audio/cs4231a.c2
-rw-r--r--hw/audio/es1370.c2
-rw-r--r--hw/audio/hda-codec.c35
-rw-r--r--hw/audio/intel-hda.c2
-rw-r--r--hw/audio/marvell_88w8618.c2
-rw-r--r--hw/audio/pl041.c2
-rw-r--r--hw/audio/soundhw.c3
-rw-r--r--hw/audio/trace-events1
-rw-r--r--hw/audio/via-ac97.c2
-rw-r--r--hw/audio/virtio-snd.c38
-rw-r--r--hw/block/Kconfig9
-rw-r--r--hw/block/ecc.c91
-rw-r--r--hw/block/fdc-isa.c4
-rw-r--r--hw/block/fdc-sysbus.c2
-rw-r--r--hw/block/m25p80.c71
-rw-r--r--hw/block/m25p80_sfdp.c73
-rw-r--r--hw/block/m25p80_sfdp.h3
-rw-r--r--hw/block/meson.build3
-rw-r--r--hw/block/nand.c2
-rw-r--r--hw/block/onenand.c872
-rw-r--r--hw/block/pflash_cfi01.c3
-rw-r--r--hw/block/pflash_cfi02.c2
-rw-r--r--hw/block/swim.c2
-rw-r--r--hw/block/tc58128.c211
-rw-r--r--hw/block/vhost-user-blk.c1
-rw-r--r--hw/block/virtio-blk.c4
-rw-r--r--hw/char/Kconfig4
-rw-r--r--hw/char/avr_usart.c4
-rw-r--r--hw/char/bcm2835_aux.c2
-rw-r--r--hw/char/cmsdk-apb-uart.c2
-rw-r--r--hw/char/digic-uart.c2
-rw-r--r--hw/char/escc.c90
-rw-r--r--hw/char/etraxfs_ser.c267
-rw-r--r--hw/char/exynos4210_uart.c2
-rw-r--r--hw/char/goldfish_tty.c14
-rw-r--r--hw/char/grlib_apbuart.c2
-rw-r--r--hw/char/ibex_uart.c2
-rw-r--r--hw/char/imx_serial.c2
-rw-r--r--hw/char/mcf_uart.c2
-rw-r--r--hw/char/mchp_pfsoc_mmuart.c2
-rw-r--r--hw/char/meson.build2
-rw-r--r--hw/char/nrf51_uart.c2
-rw-r--r--hw/char/omap_uart.c115
-rw-r--r--hw/char/pl011.c215
-rw-r--r--hw/char/renesas_sci.c2
-rw-r--r--hw/char/riscv_htif.c1
-rw-r--r--hw/char/sclpconsole-lm.c2
-rw-r--r--hw/char/sclpconsole.c2
-rw-r--r--hw/char/serial-isa.c1
-rw-r--r--hw/char/serial-mm.c157
-rw-r--r--hw/char/serial.c133
-rw-r--r--hw/char/sh_serial.c2
-rw-r--r--hw/char/shakti_uart.c2
-rw-r--r--hw/char/stm32f2xx_usart.c2
-rw-r--r--hw/char/stm32l4x5_usart.c16
-rw-r--r--hw/char/trace-events4
-rw-r--r--hw/char/xilinx_uartlite.c2
-rw-r--r--hw/core/clock.c16
-rw-r--r--hw/core/cpu-common.c6
-rw-r--r--hw/core/irq.c34
-rw-r--r--hw/core/machine.c12
-rw-r--r--hw/core/numa.c6
-rw-r--r--hw/core/or-irq.c2
-rw-r--r--hw/core/platform-bus.c5
-rw-r--r--hw/core/ptimer.c4
-rw-r--r--hw/core/qdev-properties-system.c14
-rw-r--r--hw/core/qdev.c97
-rw-r--r--hw/core/reset.c5
-rw-r--r--hw/core/resettable.c24
-rw-r--r--hw/core/sysbus.c10
-rw-r--r--hw/core/uboot_image.h2
-rw-r--r--hw/cris/Kconfig11
-rw-r--r--hw/cris/axis_dev88.c351
-rw-r--r--hw/cris/boot.c102
-rw-r--r--hw/cris/boot.h16
-rw-r--r--hw/cris/meson.build5
-rw-r--r--hw/cxl/cxl-events.c13
-rw-r--r--hw/cxl/cxl-host.c3
-rw-r--r--hw/cxl/cxl-mailbox-utils.c974
-rw-r--r--hw/cxl/switch-mailbox-cci.c2
-rw-r--r--hw/display/Kconfig5
-rw-r--r--hw/display/artist.c2
-rw-r--r--hw/display/ati.c2
-rw-r--r--hw/display/bcm2835_fb.c2
-rw-r--r--hw/display/blizzard.c1026
-rw-r--r--hw/display/cg3.c2
-rw-r--r--hw/display/dm163.c2
-rw-r--r--hw/display/dpcd.c2
-rw-r--r--hw/display/exynos4210_fimd.c2
-rw-r--r--hw/display/g364fb.c2
-rw-r--r--hw/display/i2c-ddc.c2
-rw-r--r--hw/display/jazz_led.c2
-rw-r--r--hw/display/macfb.c4
-rw-r--r--hw/display/meson.build4
-rw-r--r--hw/display/omap_dss.c1093
-rw-r--r--hw/display/pxa2xx_lcd.c1451
-rw-r--r--hw/display/qxl.c6
-rw-r--r--hw/display/sii9022.c2
-rw-r--r--hw/display/sm501.c6
-rw-r--r--hw/display/tc6393xb.c568
-rw-r--r--hw/display/tcx.c2
-rw-r--r--hw/display/trace-events3
-rw-r--r--hw/display/vga-isa.c2
-rw-r--r--hw/display/vga-mmio.c2
-rw-r--r--hw/display/vga-pci.c2
-rw-r--r--hw/display/vhost-user-gpu.c4
-rw-r--r--hw/display/virtio-gpu-gl.c71
-rw-r--r--hw/display/virtio-gpu-virgl.c585
-rw-r--r--hw/display/virtio-gpu.c113
-rw-r--r--hw/display/vmware_vga.c2
-rw-r--r--hw/display/xlnx_dp.c2
-rw-r--r--hw/dma/bcm2835_dma.c2
-rw-r--r--hw/dma/etraxfs_dma.c781
-rw-r--r--hw/dma/i8257.c2
-rw-r--r--hw/dma/meson.build2
-rw-r--r--hw/dma/omap_dma.c451
-rw-r--r--hw/dma/pl080.c2
-rw-r--r--hw/dma/pl330.c2
-rw-r--r--hw/dma/pxa2xx_dma.c591
-rw-r--r--hw/dma/rc4030.c2
-rw-r--r--hw/dma/sparc32_dma.c2
-rw-r--r--hw/dma/xilinx_axidma.c4
-rw-r--r--hw/dma/xlnx-zdma.c2
-rw-r--r--hw/dma/xlnx-zynq-devcfg.c2
-rw-r--r--hw/dma/xlnx_csu_dma.c2
-rw-r--r--hw/dma/xlnx_dpdma.c2
-rw-r--r--hw/fsi/aspeed_apb2opb.c2
-rw-r--r--hw/fsi/fsi-master.c2
-rw-r--r--hw/fsi/fsi.c2
-rw-r--r--hw/fsi/lbus.c2
-rw-r--r--hw/gpio/Kconfig7
-rw-r--r--hw/gpio/aspeed_gpio.c431
-rw-r--r--hw/gpio/bcm2835_gpio.c2
-rw-r--r--hw/gpio/bcm2838_gpio.c2
-rw-r--r--hw/gpio/gpio_key.c2
-rw-r--r--hw/gpio/imx_gpio.c2
-rw-r--r--hw/gpio/max7310.c217
-rw-r--r--hw/gpio/meson.build3
-rw-r--r--hw/gpio/mpc8xxx.c2
-rw-r--r--hw/gpio/nrf51_gpio.c3
-rw-r--r--hw/gpio/omap_gpio.c559
-rw-r--r--hw/gpio/pca9552.c2
-rw-r--r--hw/gpio/pca9554.c2
-rw-r--r--hw/gpio/pcf8574.c2
-rw-r--r--hw/gpio/sifive_gpio.c2
-rw-r--r--hw/hppa/Kconfig2
-rw-r--r--hw/hppa/machine.c6
-rw-r--r--hw/hyperv/hyperv.c2
-rw-r--r--hw/hyperv/hyperv_testdev.c7
-rw-r--r--hw/hyperv/vmbus.c17
-rw-r--r--hw/i2c/aspeed_i2c.c345
-rw-r--r--hw/i2c/bcm2835_i2c.c2
-rw-r--r--hw/i2c/exynos4210_i2c.c2
-rw-r--r--hw/i2c/imx_i2c.c2
-rw-r--r--hw/i2c/microbit_i2c.c2
-rw-r--r--hw/i2c/mpc_i2c.c10
-rw-r--r--hw/i2c/omap_i2c.c2
-rw-r--r--hw/i2c/ppc4xx_i2c.c2
-rw-r--r--hw/i2c/smbus_eeprom.c2
-rw-r--r--hw/i386/acpi-build.c123
-rw-r--r--hw/i386/amd_iommu.c10
-rw-r--r--hw/i386/intel_iommu.c89
-rw-r--r--hw/i386/intel_iommu_internal.h17
-rw-r--r--hw/i386/kvm/i8254.c2
-rw-r--r--hw/i386/kvm/i8259.c2
-rw-r--r--hw/i386/kvm/ioapic.c2
-rw-r--r--hw/i386/kvm/xen_overlay.c2
-rw-r--r--hw/i386/microvm-dt.c2
-rw-r--r--hw/i386/microvm.c6
-rw-r--r--hw/i386/multiboot.c39
-rw-r--r--hw/i386/pc.c30
-rw-r--r--hw/i386/pc_piix.c21
-rw-r--r--hw/i386/pc_q35.c19
-rw-r--r--hw/i386/port92.c2
-rw-r--r--hw/i386/sgx-stub.c5
-rw-r--r--hw/i386/sgx.c14
-rw-r--r--hw/i386/vapic.c2
-rw-r--r--hw/i386/vmmouse.c2
-rw-r--r--hw/i386/x86-common.c31
-rw-r--r--hw/i386/xen/meson.build1
-rw-r--r--hw/i386/xen/xen-hvm.c4
-rw-r--r--hw/i386/xen/xen-pvh.c124
-rw-r--r--hw/i386/xen/xen_platform.c2
-rw-r--r--hw/ide/Kconfig6
-rw-r--r--hw/ide/ahci.c5
-rw-r--r--hw/ide/atapi.c2
-rw-r--r--hw/ide/cmd646.c2
-rw-r--r--hw/ide/ich.c2
-rw-r--r--hw/ide/isa.c2
-rw-r--r--hw/ide/macio.c8
-rw-r--r--hw/ide/meson.build1
-rw-r--r--hw/ide/microdrive.c644
-rw-r--r--hw/ide/mmio.c2
-rw-r--r--hw/ide/pci.c7
-rw-r--r--hw/ide/piix.c4
-rw-r--r--hw/ide/sii3112.c2
-rw-r--r--hw/ide/via.c2
-rw-r--r--hw/input/Kconfig13
-rw-r--r--hw/input/adb-kbd.c2
-rw-r--r--hw/input/adb-mouse.c63
-rw-r--r--hw/input/ads7846.c186
-rw-r--r--hw/input/lm832x.c528
-rw-r--r--hw/input/meson.build5
-rw-r--r--hw/input/pckbd.c4
-rw-r--r--hw/input/pxa2xx_keypad.c331
-rw-r--r--hw/input/trace-events3
-rw-r--r--hw/input/tsc2005.c571
-rw-r--r--hw/input/tsc210x.c1241
-rw-r--r--hw/intc/Kconfig8
-rw-r--r--hw/intc/allwinner-a10-pic.c2
-rw-r--r--hw/intc/apic_common.c2
-rw-r--r--hw/intc/arm_gic.c11
-rw-r--r--hw/intc/arm_gicv3_cpuif.c6
-rw-r--r--hw/intc/armv7m_nvic.c2
-rw-r--r--hw/intc/aspeed_intc.c2
-rw-r--r--hw/intc/aspeed_vic.c2
-rw-r--r--hw/intc/bcm2835_ic.c2
-rw-r--r--hw/intc/bcm2836_control.c2
-rw-r--r--hw/intc/etraxfs_pic.c172
-rw-r--r--hw/intc/exynos4210_combiner.c2
-rw-r--r--hw/intc/goldfish_pic.c2
-rw-r--r--hw/intc/grlib_irqmp.c2
-rw-r--r--hw/intc/heathrow_pic.c2
-rw-r--r--hw/intc/i8259.c2
-rw-r--r--hw/intc/imx_avic.c2
-rw-r--r--hw/intc/imx_gpcv2.c2
-rw-r--r--hw/intc/ioapic.c2
-rw-r--r--hw/intc/loongarch_extioi.c2
-rw-r--r--hw/intc/loongarch_ipi.c68
-rw-r--r--hw/intc/loongarch_pch_pic.c2
-rw-r--r--hw/intc/loongson_ipi.c367
-rw-r--r--hw/intc/loongson_ipi_common.c347
-rw-r--r--hw/intc/m68k_irqc.c2
-rw-r--r--hw/intc/meson.build3
-rw-r--r--hw/intc/omap_intc.c289
-rw-r--r--hw/intc/openpic.c7
-rw-r--r--hw/intc/openpic_kvm.c2
-rw-r--r--hw/intc/pl190.c2
-rw-r--r--hw/intc/pnv_xive2.c566
-rw-r--r--hw/intc/pnv_xive2_regs.h108
-rw-r--r--hw/intc/ppc-uic.c2
-rw-r--r--hw/intc/riscv_imsic.c50
-rw-r--r--hw/intc/s390_flic.c2
-rw-r--r--hw/intc/s390_flic_kvm.c2
-rw-r--r--hw/intc/sifive_plic.c2
-rw-r--r--hw/intc/slavio_intctl.c2
-rw-r--r--hw/intc/xive.c12
-rw-r--r--hw/intc/xive2.c33
-rw-r--r--hw/intc/xlnx-pmu-iomod-intc.c2
-rw-r--r--hw/intc/xlnx-zynqmp-ipi.c2
-rw-r--r--hw/isa/isa-superio.c2
-rw-r--r--hw/isa/lpc_ich9.c16
-rw-r--r--hw/isa/pc87312.c2
-rw-r--r--hw/isa/piix.c2
-rw-r--r--hw/isa/vt82c686.c19
-rw-r--r--hw/loongarch/Kconfig5
-rw-r--r--hw/loongarch/acpi-build.c65
-rw-r--r--hw/loongarch/meson.build2
-rw-r--r--hw/loongarch/virt.c79
-rw-r--r--hw/m68k/bootinfo.h30
-rw-r--r--hw/m68k/mcf5206.c2
-rw-r--r--hw/m68k/mcf5208.c12
-rw-r--r--hw/m68k/mcf_intc.c2
-rw-r--r--hw/m68k/next-cube.c4
-rw-r--r--hw/m68k/next-kbd.c2
-rw-r--r--hw/m68k/q800.c4
-rw-r--r--hw/m68k/virt.c9
-rw-r--r--hw/mem/cxl_type3.c66
-rw-r--r--hw/meson.build2
-rw-r--r--hw/microblaze/Kconfig2
-rw-r--r--hw/microblaze/petalogix_ml605_mmu.c2
-rw-r--r--hw/mips/Kconfig10
-rw-r--r--hw/mips/boston.c2
-rw-r--r--hw/mips/cps.c4
-rw-r--r--hw/mips/fuloong2e.c2
-rw-r--r--hw/mips/jazz.c7
-rw-r--r--hw/mips/loongson3_virt.c13
-rw-r--r--hw/mips/malta.c7
-rw-r--r--hw/mips/meson.build2
-rw-r--r--hw/mips/mipssim.c5
-rw-r--r--hw/misc/Kconfig4
-rw-r--r--hw/misc/a9scu.c2
-rw-r--r--hw/misc/allwinner-cpucfg.c2
-rw-r--r--hw/misc/allwinner-h3-ccu.c2
-rw-r--r--hw/misc/allwinner-h3-dramc.c2
-rw-r--r--hw/misc/allwinner-h3-sysctrl.c2
-rw-r--r--hw/misc/allwinner-r40-ccu.c2
-rw-r--r--hw/misc/allwinner-r40-dramc.c2
-rw-r--r--hw/misc/allwinner-sid.c2
-rw-r--r--hw/misc/allwinner-sramc.c2
-rw-r--r--hw/misc/applesmc.c2
-rw-r--r--hw/misc/arm_l2x0.c2
-rw-r--r--hw/misc/arm_sysctl.c2
-rw-r--r--hw/misc/armsse-cpu-pwrctrl.c2
-rw-r--r--hw/misc/armsse-mhu.c2
-rw-r--r--hw/misc/aspeed_hace.c122
-rw-r--r--hw/misc/aspeed_i3c.c4
-rw-r--r--hw/misc/aspeed_lpc.c2
-rw-r--r--hw/misc/aspeed_peci.c2
-rw-r--r--hw/misc/aspeed_sbc.c2
-rw-r--r--hw/misc/aspeed_scu.c10
-rw-r--r--hw/misc/aspeed_sdmc.c4
-rw-r--r--hw/misc/aspeed_xdma.c2
-rw-r--r--hw/misc/avr_power.c2
-rw-r--r--hw/misc/bcm2835_cprman.c8
-rw-r--r--hw/misc/bcm2835_mbox.c2
-rw-r--r--hw/misc/bcm2835_mphi.c2
-rw-r--r--hw/misc/bcm2835_powermgt.c2
-rw-r--r--hw/misc/bcm2835_property.c91
-rw-r--r--hw/misc/bcm2835_rng.c2
-rw-r--r--hw/misc/bcm2835_thermal.c2
-rw-r--r--hw/misc/cbus.c619
-rw-r--r--hw/misc/eccmemctl.c2
-rw-r--r--hw/misc/exynos4210_clk.c2
-rw-r--r--hw/misc/exynos4210_pmu.c2
-rw-r--r--hw/misc/exynos4210_rng.c2
-rw-r--r--hw/misc/imx25_ccm.c2
-rw-r--r--hw/misc/imx31_ccm.c2
-rw-r--r--hw/misc/imx6_ccm.c3
-rw-r--r--hw/misc/imx6_src.c2
-rw-r--r--hw/misc/imx6ul_ccm.c2
-rw-r--r--hw/misc/imx7_ccm.c4
-rw-r--r--hw/misc/imx7_snvs.c2
-rw-r--r--hw/misc/imx7_src.c2
-rw-r--r--hw/misc/imx_rngc.c2
-rw-r--r--hw/misc/iotkit-secctl.c2
-rw-r--r--hw/misc/iotkit-sysctl.c2
-rw-r--r--hw/misc/ivshmem.c2
-rw-r--r--hw/misc/lasi.c2
-rw-r--r--hw/misc/led.c2
-rw-r--r--hw/misc/mac_via.c2
-rw-r--r--hw/misc/macio/cuda.c2
-rw-r--r--hw/misc/macio/gpio.c2
-rw-r--r--hw/misc/macio/mac_dbdma.c2
-rw-r--r--hw/misc/macio/pmu.c2
-rw-r--r--hw/misc/meson.build7
-rw-r--r--hw/misc/mips_cmgcr.c2
-rw-r--r--hw/misc/mips_cpc.c2
-rw-r--r--hw/misc/mips_itu.c2
-rw-r--r--hw/misc/mps2-fpgaio.c2
-rw-r--r--hw/misc/mps2-scc.c2
-rw-r--r--hw/misc/msf2-sysreg.c2
-rw-r--r--hw/misc/mst_fpga.c269
-rw-r--r--hw/misc/nrf51_rng.c2
-rw-r--r--hw/misc/omap_clk.c527
-rw-r--r--hw/misc/omap_gpmc.c898
-rw-r--r--hw/misc/omap_l4.c162
-rw-r--r--hw/misc/omap_sdrc.c167
-rw-r--r--hw/misc/omap_tap.c117
-rw-r--r--hw/misc/pci-testdev.c2
-rw-r--r--hw/misc/sifive_e_aon.c2
-rw-r--r--hw/misc/sifive_u_prci.c2
-rw-r--r--hw/misc/slavio_misc.c2
-rw-r--r--hw/misc/stm32_rcc.c162
-rw-r--r--hw/misc/stm32f2xx_syscfg.c2
-rw-r--r--hw/misc/stm32f4xx_exti.c2
-rw-r--r--hw/misc/stm32f4xx_syscfg.c2
-rw-r--r--hw/misc/stm32l4x5_rcc.c28
-rw-r--r--hw/misc/stm32l4x5_syscfg.c19
-rw-r--r--hw/misc/trace-events6
-rw-r--r--hw/misc/tz-mpc.c2
-rw-r--r--hw/misc/tz-msc.c2
-rw-r--r--hw/misc/tz-ppc.c2
-rw-r--r--hw/misc/virt_ctrl.c2
-rw-r--r--hw/misc/xlnx-versal-cfu.c10
-rw-r--r--hw/misc/xlnx-versal-trng.c12
-rw-r--r--hw/net/allwinner-sun8i-emac.c2
-rw-r--r--hw/net/allwinner_emac.c4
-rw-r--r--hw/net/cadence_gem.c4
-rw-r--r--hw/net/can/can_kvaser_pci.c2
-rw-r--r--hw/net/can/can_mioe3680_pci.c2
-rw-r--r--hw/net/can/can_pcm3680_pci.c2
-rw-r--r--hw/net/can/ctucan_pci.c2
-rw-r--r--hw/net/can/xlnx-versal-canfd.c175
-rw-r--r--hw/net/dp8393x.c4
-rw-r--r--hw/net/e1000e_core.c4
-rw-r--r--hw/net/eepro100.c4
-rw-r--r--hw/net/etraxfs_eth.c688
-rw-r--r--hw/net/fsl_etsec/etsec.c2
-rw-r--r--hw/net/ftgmac100.c7
-rw-r--r--hw/net/i82596.c4
-rw-r--r--hw/net/igb.c13
-rw-r--r--hw/net/igb_core.c4
-rw-r--r--hw/net/igb_regs.h2
-rw-r--r--hw/net/imx_fec.c5
-rw-r--r--hw/net/lan9118.c5
-rw-r--r--hw/net/lance.c2
-rw-r--r--hw/net/lasi_i82596.c2
-rw-r--r--hw/net/mcf_fec.c5
-rw-r--r--hw/net/meson.build1
-rw-r--r--hw/net/mipsnet.c2
-rw-r--r--hw/net/msf2-emac.c2
-rw-r--r--hw/net/net_rx_pkt.c16
-rw-r--r--hw/net/net_rx_pkt.h17
-rw-r--r--hw/net/npcm7xx_emc.c5
-rw-r--r--hw/net/npcm_gmac.c2
-rw-r--r--hw/net/opencores_eth.c2
-rw-r--r--hw/net/pcnet-pci.c2
-rw-r--r--hw/net/rocker/rocker.c7
-rw-r--r--hw/net/rocker/rocker.h1
-rw-r--r--hw/net/rtl8139.c12
-rw-r--r--hw/net/smc91c111.c5
-rw-r--r--hw/net/stellaris_enet.c4
-rw-r--r--hw/net/sungem.c2
-rw-r--r--hw/net/sunhme.c2
-rw-r--r--hw/net/trace-events13
-rw-r--r--hw/net/tulip.c2
-rw-r--r--hw/net/vhost_net.c159
-rw-r--r--hw/net/virtio-net.c142
-rw-r--r--hw/net/vmxnet3.c3
-rw-r--r--hw/net/xilinx_axienet.c2
-rw-r--r--hw/net/xilinx_ethlite.c2
-rw-r--r--hw/nubus/nubus-device.c7
-rw-r--r--hw/nubus/nubus-virtio-mmio.c2
-rw-r--r--hw/nvme/ctrl.c682
-rw-r--r--hw/nvme/nvme.h16
-rw-r--r--hw/nvram/eeprom_at24c.c2
-rw-r--r--hw/nvram/fw_cfg-acpi.c2
-rw-r--r--hw/nvram/fw_cfg.c7
-rw-r--r--hw/nvram/mac_nvram.c4
-rw-r--r--hw/nvram/nrf51_nvm.c2
-rw-r--r--hw/nvram/xlnx-bbram.c13
-rw-r--r--hw/nvram/xlnx-versal-efuse-ctrl.c6
-rw-r--r--hw/nvram/xlnx-zynqmp-efuse.c13
-rw-r--r--hw/openrisc/Kconfig4
-rw-r--r--hw/openrisc/openrisc_sim.c2
-rw-r--r--hw/openrisc/virt.c2
-rw-r--r--hw/pci-bridge/Kconfig5
-rw-r--r--hw/pci-bridge/cxl_downstream.c2
-rw-r--r--hw/pci-bridge/cxl_upstream.c6
-rw-r--r--hw/pci-bridge/i82801b11.c2
-rw-r--r--hw/pci-bridge/meson.build2
-rw-r--r--hw/pci-bridge/pci_bridge_dev.c2
-rw-r--r--hw/pci-bridge/pci_expander_bridge.c2
-rw-r--r--hw/pci-bridge/pcie_pci_bridge.c2
-rw-r--r--hw/pci-bridge/simba.c2
-rw-r--r--hw/pci-bridge/xio3130_downstream.c2
-rw-r--r--hw/pci-bridge/xio3130_upstream.c2
-rw-r--r--hw/pci-host/astro.c4
-rw-r--r--hw/pci-host/designware.c46
-rw-r--r--hw/pci-host/dino.c2
-rw-r--r--hw/pci-host/gpex-acpi.c13
-rw-r--r--hw/pci-host/gt64120.c27
-rw-r--r--hw/pci-host/mv64361.c2
-rw-r--r--hw/pci-host/ppc440_pcix.c2
-rw-r--r--hw/pci-host/q35.c12
-rw-r--r--hw/pci-host/sabre.c2
-rw-r--r--hw/pci-host/versatile.c2
-rw-r--r--hw/pci-host/xilinx-pcie.c2
-rw-r--r--hw/pci/pci-hmp-cmds.c26
-rw-r--r--hw/pci/pci-stub.c6
-rw-r--r--hw/pci/pci.c46
-rw-r--r--hw/pci/pci_host.c4
-rw-r--r--hw/pci/pcie_port.c10
-rw-r--r--hw/pci/pcie_sriov.c149
-rw-r--r--hw/pci/trace-events2
-rw-r--r--hw/pcmcia/Kconfig2
-rw-r--r--hw/pcmcia/meson.build2
-rw-r--r--hw/pcmcia/pcmcia.c24
-rw-r--r--hw/pcmcia/pxa2xx.c248
-rw-r--r--hw/ppc/Kconfig14
-rw-r--r--hw/ppc/e500.c2
-rw-r--r--hw/ppc/mac_newworld.c2
-rw-r--r--hw/ppc/mac_oldworld.c2
-rw-r--r--hw/ppc/meson.build1
-rw-r--r--hw/ppc/pegasos2.c4
-rw-r--r--hw/ppc/pnv.c395
-rw-r--r--hw/ppc/pnv_adu.c206
-rw-r--r--hw/ppc/pnv_chiptod.c7
-rw-r--r--hw/ppc/pnv_core.c127
-rw-r--r--hw/ppc/pnv_lpc.c162
-rw-r--r--hw/ppc/pnv_psi.c4
-rw-r--r--hw/ppc/pnv_xscom.c9
-rw-r--r--hw/ppc/ppc.c1
-rw-r--r--hw/ppc/ppc405_boards.c2
-rw-r--r--hw/ppc/ppc405_uc.c14
-rw-r--r--hw/ppc/ppc440_bamboo.c2
-rw-r--r--hw/ppc/ppc4xx_devs.c6
-rw-r--r--hw/ppc/ppc4xx_sdram.c4
-rw-r--r--hw/ppc/ppce500_spin.c2
-rw-r--r--hw/ppc/prep.c1
-rw-r--r--hw/ppc/rs6000_mc.c4
-rw-r--r--hw/ppc/sam460ex.c2
-rw-r--r--hw/ppc/spapr.c22
-rw-r--r--hw/ppc/spapr_caps.c1
-rw-r--r--hw/ppc/spapr_cpu_core.c18
-rw-r--r--hw/ppc/spapr_events.c3
-rw-r--r--hw/ppc/spapr_iommu.c2
-rw-r--r--hw/ppc/spapr_pci.c10
-rw-r--r--hw/ppc/spapr_vhyp_mmu.c21
-rw-r--r--hw/ppc/spapr_vio.c2
-rw-r--r--hw/ppc/spapr_vof.c2
-rw-r--r--hw/ppc/trace-events4
-rw-r--r--hw/ppc/virtex_ml507.c2
-rw-r--r--hw/ppc/vof.c2
-rw-r--r--hw/remote/iohub.c13
-rw-r--r--hw/remote/message.c5
-rw-r--r--hw/remote/proxy.c2
-rw-r--r--hw/riscv/Kconfig2
-rw-r--r--hw/riscv/boot.c11
-rw-r--r--hw/riscv/microchip_pfsoc.c2
-rw-r--r--hw/riscv/opentitan.c3
-rw-r--r--hw/riscv/shakti_c.c13
-rw-r--r--hw/riscv/sifive_e.c1
-rw-r--r--hw/riscv/sifive_u.c5
-rw-r--r--hw/riscv/spike.c5
-rw-r--r--hw/riscv/virt-acpi-build.c34
-rw-r--r--hw/riscv/virt.c16
-rw-r--r--hw/rtc/Kconfig4
-rw-r--r--hw/rtc/allwinner-rtc.c2
-rw-r--r--hw/rtc/aspeed_rtc.c2
-rw-r--r--hw/rtc/ds1338.c2
-rw-r--r--hw/rtc/exynos4210_rtc.c2
-rw-r--r--hw/rtc/goldfish_rtc.c2
-rw-r--r--hw/rtc/ls7a_rtc.c4
-rw-r--r--hw/rtc/m48t59-isa.c2
-rw-r--r--hw/rtc/m48t59.c2
-rw-r--r--hw/rtc/meson.build1
-rw-r--r--hw/rtc/twl92230.c882
-rw-r--r--hw/rtc/xlnx-zynqmp-rtc.c2
-rw-r--r--hw/s390x/ccw-device.c53
-rw-r--r--hw/s390x/ccw-device.h2
-rw-r--r--hw/s390x/cpu-topology.c6
-rw-r--r--hw/s390x/event-facility.c2
-rw-r--r--hw/s390x/ipl.c288
-rw-r--r--hw/s390x/ipl.h123
-rw-r--r--hw/s390x/s390-pci-bus.c4
-rw-r--r--hw/s390x/s390-pci-inst.c166
-rw-r--r--hw/s390x/s390-virtio-ccw.c46
-rw-r--r--hw/s390x/sclp.c9
-rw-r--r--hw/s390x/sclpquiesce.c2
-rw-r--r--hw/s390x/virtio-ccw.c13
-rw-r--r--hw/s390x/virtio-ccw.h2
-rw-r--r--hw/scsi/esp-pci.c2
-rw-r--r--hw/scsi/esp.c40
-rw-r--r--hw/scsi/lsi53c895a.c2
-rw-r--r--hw/scsi/megasas.c2
-rw-r--r--hw/scsi/mptsas.c2
-rw-r--r--hw/scsi/scsi-disk.c75
-rw-r--r--hw/scsi/scsi-generic.c2
-rw-r--r--hw/scsi/vhost-scsi.c3
-rw-r--r--hw/scsi/vhost-user-scsi.c1
-rw-r--r--hw/scsi/virtio-scsi.c1
-rw-r--r--hw/scsi/vmw_pvscsi.c2
-rw-r--r--hw/sd/allwinner-sdhost.c2
-rw-r--r--hw/sd/aspeed_sdhci.c2
-rw-r--r--hw/sd/bcm2835_sdhost.c2
-rw-r--r--hw/sd/cadence_sdhci.c2
-rw-r--r--hw/sd/meson.build1
-rw-r--r--hw/sd/npcm7xx_sdhci.c2
-rw-r--r--hw/sd/omap_mmc.c63
-rw-r--r--hw/sd/pl181.c2
-rw-r--r--hw/sd/pxa2xx_mmci.c594
-rw-r--r--hw/sd/sd.c25
-rw-r--r--hw/sd/sdhci.c5
-rw-r--r--hw/sd/ssi-sd.c2
-rw-r--r--hw/sd/trace-events4
-rw-r--r--hw/sensor/dps310.c2
-rw-r--r--hw/sensor/emc141x.c2
-rw-r--r--hw/sensor/lsm303dlhc_mag.c2
-rw-r--r--hw/sensor/tmp105.c66
-rw-r--r--hw/sh4/Kconfig7
-rw-r--r--hw/sh4/meson.build1
-rw-r--r--hw/sh4/r2d.c2
-rw-r--r--hw/sh4/sh7750.c57
-rw-r--r--hw/sh4/shix.c86
-rw-r--r--hw/smbios/smbios.c11
-rw-r--r--hw/sparc/sun4m_iommu.c2
-rw-r--r--hw/sparc64/Kconfig1
-rw-r--r--hw/sparc64/niagara.c2
-rw-r--r--hw/sparc64/sun4u.c3
-rw-r--r--hw/sparc64/sun4u_iommu.c2
-rw-r--r--hw/ssi/Kconfig8
-rw-r--r--hw/ssi/allwinner-a10-spi.c561
-rw-r--r--hw/ssi/aspeed_smc.c45
-rw-r--r--hw/ssi/bcm2835_spi.c2
-rw-r--r--hw/ssi/ibex_spi_host.c2
-rw-r--r--hw/ssi/imx_spi.c2
-rw-r--r--hw/ssi/meson.build3
-rw-r--r--hw/ssi/mss-spi.c2
-rw-r--r--hw/ssi/omap_spi.c380
-rw-r--r--hw/ssi/pl022.c2
-rw-r--r--hw/ssi/pnv_spi.c1268
-rw-r--r--hw/ssi/sifive_spi.c2
-rw-r--r--hw/ssi/stm32f2xx_spi.c2
-rw-r--r--hw/ssi/trace-events31
-rw-r--r--hw/ssi/xilinx_spi.c2
-rw-r--r--hw/ssi/xilinx_spips.c8
-rw-r--r--hw/ssi/xlnx-versal-ospi.c2
-rw-r--r--hw/timer/Kconfig3
-rw-r--r--hw/timer/a9gtimer.c2
-rw-r--r--hw/timer/allwinner-a10-pit.c2
-rw-r--r--hw/timer/arm_mptimer.c2
-rw-r--r--hw/timer/armv7m_systick.c2
-rw-r--r--hw/timer/aspeed_timer.c2
-rw-r--r--hw/timer/avr_timer16.c2
-rw-r--r--hw/timer/bcm2835_systmr.c2
-rw-r--r--hw/timer/cmsdk-apb-dualtimer.c2
-rw-r--r--hw/timer/cmsdk-apb-timer.c2
-rw-r--r--hw/timer/digic-timer.c2
-rw-r--r--hw/timer/etraxfs_timer.c407
-rw-r--r--hw/timer/exynos4210_mct.c2
-rw-r--r--hw/timer/exynos4210_pwm.c2
-rw-r--r--hw/timer/grlib_gptimer.c2
-rw-r--r--hw/timer/hpet.c325
-rw-r--r--hw/timer/i8254.c2
-rw-r--r--hw/timer/ibex_timer.c2
-rw-r--r--hw/timer/imx_epit.c2
-rw-r--r--hw/timer/imx_gpt.c2
-rw-r--r--hw/timer/meson.build5
-rw-r--r--hw/timer/nrf51_timer.c2
-rw-r--r--hw/timer/omap_gptimer.c512
-rw-r--r--hw/timer/omap_synctimer.c110
-rw-r--r--hw/timer/pxa2xx_timer.c25
-rw-r--r--hw/timer/renesas_cmt.c2
-rw-r--r--hw/timer/renesas_tmr.c2
-rw-r--r--hw/timer/sifive_pwm.c2
-rw-r--r--hw/timer/slavio_timer.c2
-rw-r--r--hw/timer/sse-counter.c2
-rw-r--r--hw/timer/sse-timer.c2
-rw-r--r--hw/timer/stm32f2xx_timer.c2
-rw-r--r--hw/timer/trace-events4
-rw-r--r--hw/tpm/tpm_spapr.c1
-rw-r--r--hw/tpm/tpm_tis_i2c.c2
-rw-r--r--hw/tpm/tpm_tis_isa.c2
-rw-r--r--hw/tpm/tpm_tis_sysbus.c2
-rw-r--r--hw/tricore/tricore_testdevice.c2
-rw-r--r--hw/ufs/ufs.c32
-rw-r--r--hw/ufs/ufs.h1
-rw-r--r--hw/usb/Kconfig8
-rw-r--r--hw/usb/hcd-dwc3.c2
-rw-r--r--hw/usb/hcd-ehci-pci.c2
-rw-r--r--hw/usb/hcd-ehci-sysbus.c2
-rw-r--r--hw/usb/hcd-musb.c1553
-rw-r--r--hw/usb/hcd-ohci-pci.c2
-rw-r--r--hw/usb/hcd-ohci-sysbus.c2
-rw-r--r--hw/usb/hcd-uhci.c2
-rw-r--r--hw/usb/hcd-xhci-pci.c2
-rw-r--r--hw/usb/hcd-xhci-sysbus.c2
-rw-r--r--hw/usb/hcd-xhci.c2
-rw-r--r--hw/usb/imx-usb-phy.c2
-rw-r--r--hw/usb/meson.build2
-rw-r--r--hw/usb/tusb6010.c850
-rw-r--r--hw/vfio/ap.c5
-rw-r--r--hw/vfio/ccw.c5
-rw-r--r--hw/vfio/common.c20
-rw-r--r--hw/vfio/container.c10
-rw-r--r--hw/vfio/helpers.c91
-rw-r--r--hw/vfio/igd.c185
-rw-r--r--hw/vfio/iommufd.c196
-rw-r--r--hw/vfio/migration.c17
-rw-r--r--hw/vfio/pci-quirks.c1
-rw-r--r--hw/vfio/pci.c38
-rw-r--r--hw/vfio/pci.h1
-rw-r--r--hw/vfio/trace-events15
-rw-r--r--hw/virtio/Kconfig13
-rw-r--r--hw/virtio/trace-events1
-rw-r--r--hw/virtio/vhost-shadow-virtqueue.c6
-rw-r--r--hw/virtio/vhost-user-fs.c1
-rw-r--r--hw/virtio/vhost-user-vsock.c1
-rw-r--r--hw/virtio/vhost.c62
-rw-r--r--hw/virtio/virtio-acpi.c2
-rw-r--r--hw/virtio/virtio-crypto.c44
-rw-r--r--hw/virtio/virtio-iommu.c88
-rw-r--r--hw/virtio/virtio-mem.c55
-rw-r--r--hw/virtio/virtio-mmio.c2
-rw-r--r--hw/virtio/virtio-pci.c11
-rw-r--r--hw/virtio/virtio-qmp.c3
-rw-r--r--hw/virtio/virtio-rng.c5
-rw-r--r--hw/virtio/virtio.c207
-rw-r--r--hw/watchdog/cmsdk-apb-watchdog.c2
-rw-r--r--hw/watchdog/sbsa_gwdt.c2
-rw-r--r--hw/watchdog/watchdog.c2
-rw-r--r--hw/watchdog/wdt_aspeed.c2
-rw-r--r--hw/watchdog/wdt_diag288.c2
-rw-r--r--hw/watchdog/wdt_i6300esb.c2
-rw-r--r--hw/watchdog/wdt_ib700.c2
-rw-r--r--hw/watchdog/wdt_imx2.c2
-rw-r--r--hw/xen/meson.build1
-rw-r--r--hw/xen/trace-events4
-rw-r--r--hw/xen/xen-hvm-common.c107
-rw-r--r--hw/xen/xen-legacy-backend.c18
-rw-r--r--hw/xen/xen-pvh-common.c400
-rw-r--r--hw/xen/xen_devconfig.c8
-rw-r--r--hw/xtensa/Kconfig2
-rw-r--r--hw/xtensa/xtfpga.c14
-rw-r--r--include/block/aio.h1
-rw-r--r--include/block/aio_task.h2
-rw-r--r--include/block/block-copy.h1
-rw-r--r--include/block/graph-lock.h21
-rw-r--r--include/block/nbd.h18
-rw-r--r--include/block/nvme.h40
-rw-r--r--include/block/ufs.h6
-rw-r--r--include/chardev/char-fe.h5
-rw-r--r--include/chardev/char-socket.h2
-rw-r--r--include/crypto/afsplit.h8
-rw-r--r--include/crypto/block.h2
-rw-r--r--include/crypto/cipher.h18
-rw-r--r--include/crypto/hash.h188
-rw-r--r--include/crypto/hmac.h40
-rw-r--r--include/crypto/ivgen.h30
-rw-r--r--include/crypto/pbkdf.h14
-rw-r--r--include/crypto/tlssession.h33
-rw-r--r--include/crypto/x509-utils.h22
-rw-r--r--include/disas/dis-asm.h6
-rw-r--r--include/exec/cpu-all.h13
-rw-r--r--include/exec/cpu-common.h23
-rw-r--r--include/exec/cpu_ldst.h34
-rw-r--r--include/exec/exec-all.h38
-rw-r--r--include/exec/gdbstub.h6
-rw-r--r--include/exec/memop.h47
-rw-r--r--include/exec/memory.h16
-rw-r--r--include/exec/poison.h2
-rw-r--r--include/exec/ramlist.h1
-rw-r--r--include/exec/translator.h2
-rw-r--r--include/exec/tswap.h2
-rw-r--r--include/gdbstub/commands.h19
-rw-r--r--include/gdbstub/helpers.h4
-rw-r--r--include/gdbstub/syscalls.h2
-rw-r--r--include/gdbstub/user.h2
-rw-r--r--include/hw/acpi/cpu.h7
-rw-r--r--include/hw/acpi/generic_event_device.h12
-rw-r--r--include/hw/acpi/ich9.h6
-rw-r--r--include/hw/acpi/ich9_timer.h23
-rw-r--r--include/hw/adc/aspeed_adc.h1
-rw-r--r--include/hw/adc/max111x.h56
-rw-r--r--include/hw/arm/allwinner-a10.h2
-rw-r--r--include/hw/arm/aspeed_soc.h3
-rw-r--r--include/hw/arm/omap.h348
-rw-r--r--include/hw/arm/pxa.h197
-rw-r--r--include/hw/arm/stm32f405_soc.h2
-rw-r--r--include/hw/arm/virt.h4
-rw-r--r--include/hw/arm/xlnx-versal.h1
-rw-r--r--include/hw/arm/xlnx-zynqmp.h1
-rw-r--r--include/hw/block/flash.h14
-rw-r--r--include/hw/boards.h15
-rw-r--r--include/hw/char/escc.h3
-rw-r--r--include/hw/char/mchp_pfsoc_mmuart.h2
-rw-r--r--include/hw/char/pl011.h1
-rw-r--r--include/hw/char/serial-isa.h38
-rw-r--r--include/hw/char/serial-mm.h52
-rw-r--r--include/hw/char/serial.h30
-rw-r--r--include/hw/core/cpu.h10
-rw-r--r--include/hw/core/tcg-cpu-ops.h26
-rw-r--r--include/hw/cris/etraxfs_dma.h36
-rw-r--r--include/hw/cxl/cxl_device.h88
-rw-r--r--include/hw/cxl/cxl_mailbox.h18
-rw-r--r--include/hw/display/blizzard.h21
-rw-r--r--include/hw/display/tc6393xb.h21
-rw-r--r--include/hw/gpio/aspeed_gpio.h4
-rw-r--r--include/hw/i2c/aspeed_i2c.h34
-rw-r--r--include/hw/i386/pc.h3
-rw-r--r--include/hw/i386/sgx-epc.h1
-rw-r--r--include/hw/input/lm832x.h28
-rw-r--r--include/hw/input/tsc2xxx.h41
-rw-r--r--include/hw/intc/loongarch_extioi.h1
-rw-r--r--include/hw/intc/loongarch_ipi.h25
-rw-r--r--include/hw/intc/loongson_ipi.h51
-rw-r--r--include/hw/intc/loongson_ipi_common.h74
-rw-r--r--include/hw/irq.h18
-rw-r--r--include/hw/loongarch/virt.h4
-rw-r--r--include/hw/mips/cps.h1
-rw-r--r--include/hw/misc/aspeed_hace.h4
-rw-r--r--include/hw/misc/aspeed_scu.h4
-rw-r--r--include/hw/misc/cbus.h31
-rw-r--r--include/hw/misc/stm32_rcc.h91
-rw-r--r--include/hw/misc/stm32l4x5_syscfg.h1
-rw-r--r--include/hw/misc/xlnx-versal-trng.h1
-rw-r--r--include/hw/nvram/fw_cfg.h1
-rw-r--r--include/hw/nvram/fw_cfg_acpi.h2
-rw-r--r--include/hw/nvram/xlnx-bbram.h1
-rw-r--r--include/hw/nvram/xlnx-versal-efuse.h1
-rw-r--r--include/hw/nvram/xlnx-zynqmp-efuse.h1
-rw-r--r--include/hw/pci-host/designware.h2
-rw-r--r--include/hw/pci-host/ls7a.h9
-rw-r--r--include/hw/pci-host/q35.h2
-rw-r--r--include/hw/pci/pci.h2
-rw-r--r--include/hw/pci/pci_device.h27
-rw-r--r--include/hw/pci/pcie_doe.h5
-rw-r--r--include/hw/pci/pcie_port.h1
-rw-r--r--include/hw/pci/pcie_sriov.h9
-rw-r--r--include/hw/pcmcia.h66
-rw-r--r--include/hw/ppc/mac_dbdma.h4
-rw-r--r--include/hw/ppc/pnv.h8
-rw-r--r--include/hw/ppc/pnv_adu.h32
-rw-r--r--include/hw/ppc/pnv_chip.h13
-rw-r--r--include/hw/ppc/pnv_core.h31
-rw-r--r--include/hw/ppc/pnv_lpc.h22
-rw-r--r--include/hw/ppc/pnv_xscom.h11
-rw-r--r--include/hw/ppc/spapr.h1
-rw-r--r--include/hw/ppc/xive2_regs.h9
-rw-r--r--include/hw/qdev-core.h33
-rw-r--r--include/hw/qdev-properties-system.h2
-rw-r--r--include/hw/remote/iohub.h1
-rw-r--r--include/hw/resettable.h17
-rw-r--r--include/hw/riscv/boot.h4
-rw-r--r--include/hw/s390x/cpu-topology.h4
-rw-r--r--include/hw/s390x/ipl/qipl.h127
-rw-r--r--include/hw/sh4/sh.h19
-rw-r--r--include/hw/southbridge/ich9.h4
-rw-r--r--include/hw/ssi/allwinner-a10-spi.h57
-rw-r--r--include/hw/ssi/aspeed_smc.h1
-rw-r--r--include/hw/ssi/pnv_spi.h67
-rw-r--r--include/hw/ssi/pnv_spi_regs.h133
-rw-r--r--include/hw/sysbus.h1
-rw-r--r--include/hw/usb/dwc2-regs.h2
-rw-r--r--include/hw/usb/hcd-musb.h49
-rw-r--r--include/hw/vfio/vfio-common.h15
-rw-r--r--include/hw/virtio/vhost.h6
-rw-r--r--include/hw/virtio/virtio-acpi.h2
-rw-r--r--include/hw/virtio/virtio-gpu.h36
-rw-r--r--include/hw/virtio/virtio-iommu.h1
-rw-r--r--include/hw/virtio/virtio-mem.h4
-rw-r--r--include/hw/virtio/virtio.h26
-rw-r--r--include/hw/xen/xen-hvm-common.h3
-rw-r--r--include/hw/xen/xen-legacy-backend.h5
-rw-r--r--include/hw/xen/xen-pvh-common.h91
-rw-r--r--include/hw/xen/xen_native.h3
-rw-r--r--include/io/channel.h21
-rw-r--r--include/net/net.h4
-rw-r--r--include/net/queue.h4
-rw-r--r--include/qapi/qmp/qerror.h6
-rw-r--r--include/qapi/qmp/qobject.h2
-rw-r--r--include/qemu/atomic.h2
-rw-r--r--include/qemu/bswap.h2
-rw-r--r--include/qemu/co-shared-resource.h7
-rw-r--r--include/qemu/compiler.h2
-rw-r--r--include/qemu/crc-ccitt.h2
-rw-r--r--include/qemu/cutils.h5
-rw-r--r--include/qemu/envlist.h2
-rw-r--r--include/qemu/fifo8.h82
-rw-r--r--include/qemu/iov.h27
-rw-r--r--include/qemu/iova-tree.h25
-rw-r--r--include/qemu/lockcnt.h130
-rw-r--r--include/qemu/osdep.h20
-rw-r--r--include/qemu/plugin.h4
-rw-r--r--include/qemu/pmem.h1
-rw-r--r--include/qemu/qemu-plugin.h64
-rw-r--r--include/qemu/range.h4
-rw-r--r--include/qemu/sockets.h16
-rw-r--r--include/qemu/thread.h111
-rw-r--r--include/qemu/timed-average.h4
-rw-r--r--include/qemu/timer.h21
-rw-r--r--include/qemu/typedefs.h1
-rw-r--r--include/qemu/userfaultfd.h1
-rw-r--r--include/qom/object.h12
-rw-r--r--include/semihosting/syscalls.h2
-rw-r--r--include/sysemu/arch_init.h1
-rw-r--r--include/sysemu/block-backend-global-state.h8
-rw-r--r--include/sysemu/cryptodev.h2
-rw-r--r--include/sysemu/dma.h11
-rw-r--r--include/sysemu/host_iommu_device.h5
-rw-r--r--include/sysemu/hvf_int.h1
-rw-r--r--include/sysemu/iommufd.h13
-rw-r--r--include/sysemu/kvm.h45
-rw-r--r--include/sysemu/kvm_int.h56
-rw-r--r--include/sysemu/replay.h7
-rw-r--r--include/sysemu/reset.h5
-rw-r--r--include/sysemu/runstate.h1
-rw-r--r--include/sysemu/spdm-socket.h74
-rw-r--r--include/sysemu/sysemu.h1
-rw-r--r--include/tcg/tcg.h29
-rw-r--r--include/ui/console.h1
-rw-r--r--include/ui/qemu-pixman.h24
-rw-r--r--include/ui/sdl2.h2
-rw-r--r--include/ui/surface.h14
-rw-r--r--include/user/abitypes.h7
-rw-r--r--io/channel-socket.c28
-rw-r--r--io/channel-tls.c66
-rw-r--r--io/channel-websock.c2
-rw-r--r--io/channel.c13
-rw-r--r--linux-headers/asm-powerpc/kvm.h3
-rw-r--r--linux-user/aarch64/meson.build6
-rw-r--r--linux-user/aarch64/syscall_64.tbl405
-rw-r--r--linux-user/aarch64/syscall_nr.h314
-rw-r--r--linux-user/aarch64/syscallhdr.sh28
-rw-r--r--linux-user/alpha/syscall.tbl30
-rw-r--r--linux-user/alpha/syscallhdr.sh2
-rw-r--r--linux-user/arm/syscall.tbl25
-rw-r--r--linux-user/arm/syscallhdr.sh2
-rw-r--r--linux-user/cris/cpu_loop.c95
-rw-r--r--linux-user/cris/signal.c194
-rw-r--r--linux-user/cris/sockbits.h1
-rw-r--r--linux-user/cris/syscall_nr.h367
-rw-r--r--linux-user/cris/target_cpu.h45
-rw-r--r--linux-user/cris/target_elf.h14
-rw-r--r--linux-user/cris/target_errno_defs.h7
-rw-r--r--linux-user/cris/target_fcntl.h11
-rw-r--r--linux-user/cris/target_mman.h13
-rw-r--r--linux-user/cris/target_prctl.h1
-rw-r--r--linux-user/cris/target_proc.h1
-rw-r--r--linux-user/cris/target_resource.h1
-rw-r--r--linux-user/cris/target_signal.h9
-rw-r--r--linux-user/cris/target_structs.h1
-rw-r--r--linux-user/cris/target_syscall.h46
-rw-r--r--linux-user/cris/termbits.h225
-rw-r--r--linux-user/elfload.c41
-rw-r--r--linux-user/flatload.c3
-rw-r--r--linux-user/hexagon/meson.build6
-rw-r--r--linux-user/hexagon/syscall.tbl405
-rw-r--r--linux-user/hexagon/syscall_nr.h332
-rw-r--r--linux-user/hexagon/syscallhdr.sh28
-rw-r--r--linux-user/hppa/cpu_loop.c2
-rw-r--r--linux-user/hppa/syscall.tbl43
-rw-r--r--linux-user/hppa/syscallhdr.sh2
-rw-r--r--linux-user/i386/cpu_loop.c3
-rw-r--r--linux-user/i386/signal.c4
-rw-r--r--linux-user/i386/syscall_32.tbl35
-rw-r--r--linux-user/i386/syscallhdr.sh2
-rw-r--r--linux-user/loongarch64/meson.build7
-rw-r--r--linux-user/loongarch64/syscall.tbl405
-rw-r--r--linux-user/loongarch64/syscall_nr.h312
-rw-r--r--linux-user/loongarch64/syscallhdr.sh28
-rw-r--r--linux-user/m68k/syscall.tbl24
-rw-r--r--linux-user/m68k/syscallhdr.sh2
-rw-r--r--linux-user/main.c3
-rw-r--r--linux-user/meson.build2
-rw-r--r--linux-user/microblaze/syscall.tbl24
-rw-r--r--linux-user/microblaze/syscallhdr.sh2
-rw-r--r--linux-user/mips/syscall-args-o32.c.inc20
-rw-r--r--linux-user/mips/syscall_o32.tbl38
-rw-r--r--linux-user/mips/syscallhdr.sh2
-rw-r--r--linux-user/mips/target_elf.h3
-rw-r--r--linux-user/mips64/syscall_n32.tbl34
-rw-r--r--linux-user/mips64/syscall_n64.tbl22
-rw-r--r--linux-user/mips64/syscallhdr.sh2
-rw-r--r--linux-user/mips64/target_elf.h24
-rw-r--r--linux-user/mmap.c62
-rw-r--r--linux-user/openrisc/meson.build5
-rw-r--r--linux-user/openrisc/syscall.tbl405
-rw-r--r--linux-user/openrisc/syscall_nr.h334
-rw-r--r--linux-user/openrisc/syscallhdr.sh28
-rw-r--r--linux-user/ppc/signal.c2
-rw-r--r--linux-user/ppc/syscall.tbl73
-rw-r--r--linux-user/ppc/syscallhdr.sh2
-rw-r--r--linux-user/qemu.h13
-rw-r--r--linux-user/riscv/cpu_loop.c2
-rw-r--r--linux-user/riscv/meson.build6
-rw-r--r--linux-user/riscv/syscall.tbl405
-rw-r--r--linux-user/riscv/syscall32_nr.h308
-rw-r--r--linux-user/riscv/syscall64_nr.h314
-rw-r--r--linux-user/riscv/syscall_nr.h15
-rw-r--r--linux-user/riscv/syscallhdr.sh28
-rw-r--r--linux-user/s390x/syscall.tbl36
-rwxr-xr-xlinux-user/s390x/syscallhdr.sh2
-rw-r--r--linux-user/sh4/syscall.tbl27
-rw-r--r--linux-user/sh4/syscallhdr.sh2
-rw-r--r--linux-user/sparc/syscall.tbl42
-rw-r--r--linux-user/sparc/syscallhdr.sh2
-rw-r--r--linux-user/strace.c247
-rw-r--r--linux-user/strace.list16
-rw-r--r--linux-user/syscall.c204
-rw-r--r--linux-user/syscall_defs.h32
-rw-r--r--linux-user/user-internals.h1
-rw-r--r--linux-user/vm86.c201
-rw-r--r--linux-user/x86_64/syscall_64.tbl30
-rw-r--r--linux-user/x86_64/syscallhdr.sh2
-rw-r--r--linux-user/xtensa/syscall.tbl24
-rw-r--r--linux-user/xtensa/syscallhdr.sh2
-rw-r--r--meson.build290
-rw-r--r--meson_options.txt13
-rw-r--r--migration/dirtyrate.c7
-rw-r--r--migration/file.c5
-rw-r--r--migration/file.h2
-rw-r--r--migration/meson.build2
-rw-r--r--migration/migration-hmp-cmds.c6
-rw-r--r--migration/migration.c7
-rw-r--r--migration/multifd-nocomp.c391
-rw-r--r--migration/multifd-qatzip.c394
-rw-r--r--migration/multifd-qpl.c89
-rw-r--r--migration/multifd-uadk.c104
-rw-r--r--migration/multifd-zero-page.c13
-rw-r--r--migration/multifd-zlib.c99
-rw-r--r--migration/multifd-zstd.c106
-rw-r--r--migration/multifd.c581
-rw-r--r--migration/multifd.h157
-rw-r--r--migration/options.c65
-rw-r--r--migration/options.h3
-rw-r--r--migration/postcopy-ram.c69
-rw-r--r--migration/ram.c20
-rw-r--r--migration/savevm.c21
-rw-r--r--migration/socket.c18
-rw-r--r--migration/socket.h1
-rw-r--r--migration/trace-events9
-rw-r--r--monitor/monitor.c7
-rw-r--r--nbd/client-connection.c2
-rw-r--r--nbd/server.c48
-rw-r--r--nbd/trace-events1
-rw-r--r--net/colo-compare.c3
-rw-r--r--net/hub.c25
-rw-r--r--net/meson.build2
-rw-r--r--net/net.c39
-rw-r--r--net/queue.c11
-rw-r--r--net/stream.c34
-rw-r--r--net/tap-win32.c15
-rw-r--r--net/tap.c34
-rw-r--r--net/vhost-vdpa.c2
-rw-r--r--pc-bios/descriptors/60-edk2-loongarch64.json31
-rw-r--r--pc-bios/descriptors/meson.build3
-rw-r--r--pc-bios/edk2-aarch64-code.fd.bz2bin1588976 -> 1565763 bytes
-rw-r--r--pc-bios/edk2-arm-code.fd.bz2bin1571639 -> 1570311 bytes
-rw-r--r--pc-bios/edk2-i386-code.fd.bz2bin1775230 -> 1780004 bytes
-rw-r--r--pc-bios/edk2-i386-secure-code.fd.bz2bin1877268 -> 1858666 bytes
-rw-r--r--pc-bios/edk2-loongarch64-code.fd.bz2bin0 -> 1148383 bytes
-rw-r--r--pc-bios/edk2-loongarch64-vars.fd.bz2bin0 -> 233 bytes
-rw-r--r--pc-bios/edk2-riscv-code.fd.bz2bin1289337 -> 1296526 bytes
-rw-r--r--pc-bios/edk2-x86_64-code.fd.bz2bin1892766 -> 1907255 bytes
-rw-r--r--pc-bios/edk2-x86_64-microvm.fd.bz2bin1785290 -> 1787244 bytes
-rw-r--r--pc-bios/edk2-x86_64-secure-code.fd.bz2bin1969096 -> 1962992 bytes
-rw-r--r--pc-bios/meson.build3
-rw-r--r--pc-bios/openbios-ppcbin677196 -> 677200 bytes
-rw-r--r--pc-bios/openbios-sparc32bin382080 -> 382080 bytes
-rw-r--r--pc-bios/openbios-sparc64bin1593408 -> 1593408 bytes
-rw-r--r--pc-bios/opensbi-riscv32-generic-fw_dynamic.binbin267416 -> 268312 bytes
-rw-r--r--pc-bios/opensbi-riscv64-generic-fw_dynamic.binbin270808 -> 272504 bytes
-rw-r--r--pc-bios/s390-ccw.imgbin42608 -> 79608 bytes
-rw-r--r--pc-bios/s390-ccw/Makefile72
-rw-r--r--pc-bios/s390-ccw/bootmap.c455
-rw-r--r--pc-bios/s390-ccw/bootmap.h20
-rw-r--r--pc-bios/s390-ccw/cio.c81
-rw-r--r--pc-bios/s390-ccw/cio.h2
-rw-r--r--pc-bios/s390-ccw/dasd-ipl.c71
-rw-r--r--pc-bios/s390-ccw/dasd-ipl.h2
-rw-r--r--pc-bios/s390-ccw/iplb.h108
-rw-r--r--pc-bios/s390-ccw/jump2ipl.c22
-rw-r--r--pc-bios/s390-ccw/libc.c88
-rw-r--r--pc-bios/s390-ccw/libc.h89
-rw-r--r--pc-bios/s390-ccw/main.c97
-rw-r--r--pc-bios/s390-ccw/menu.c51
-rw-r--r--pc-bios/s390-ccw/netboot.mak62
-rw-r--r--pc-bios/s390-ccw/netmain.c38
-rw-r--r--pc-bios/s390-ccw/s390-ccw.h36
-rw-r--r--pc-bios/s390-ccw/sclp.c7
-rw-r--r--pc-bios/s390-ccw/start.S11
-rw-r--r--pc-bios/s390-ccw/virtio-blkdev.c12
-rw-r--r--pc-bios/s390-ccw/virtio-net.c7
-rw-r--r--pc-bios/s390-ccw/virtio-scsi.c160
-rw-r--r--pc-bios/s390-ccw/virtio.c67
-rw-r--r--pc-bios/s390-ccw/virtio.h3
-rw-r--r--pc-bios/s390-netboot.imgbin67232 -> 0 bytes
-rw-r--r--plugins/api.c53
-rw-r--r--plugins/core.c49
-rw-r--r--plugins/loader.c8
-rw-r--r--plugins/meson.build50
-rw-r--r--plugins/qemu-plugins.symbols2
-rw-r--r--po/it.po2
-rwxr-xr-xpython/scripts/vendor.py4
-rw-r--r--python/wheels/meson-1.2.3-py3-none-any.whlbin964928 -> 0 bytes
-rw-r--r--python/wheels/meson-1.5.0-py3-none-any.whlbin0 -> 959846 bytes
-rw-r--r--python/wheels/pycotap-1.3.1-py3-none-any.whlbin0 -> 5119 bytes
-rw-r--r--pythondeps.toml5
-rw-r--r--qapi/block-core.json122
-rw-r--r--qapi/block-export.json12
-rw-r--r--qapi/block.json12
-rw-r--r--qapi/char.json96
-rw-r--r--qapi/common.json14
-rw-r--r--qapi/control.json14
-rw-r--r--qapi/crypto.json76
-rw-r--r--qapi/cryptodev.json17
-rw-r--r--qapi/cxl.json45
-rw-r--r--qapi/dump.json2
-rw-r--r--qapi/ebpf.json2
-rw-r--r--qapi/introspect.json20
-rw-r--r--qapi/job.json8
-rw-r--r--qapi/machine-common.json5
-rw-r--r--qapi/machine-target.json71
-rw-r--r--qapi/machine.json48
-rw-r--r--qapi/migration.json95
-rw-r--r--qapi/misc.json31
-rw-r--r--qapi/net.json40
-rw-r--r--qapi/pci.json3
-rw-r--r--qapi/pragma.json17
-rw-r--r--qapi/qdev.json20
-rw-r--r--qapi/qom.json59
-rw-r--r--qapi/rocker.json12
-rw-r--r--qapi/run-state.json12
-rw-r--r--qapi/sockets.json5
-rw-r--r--qapi/stats.json6
-rw-r--r--qapi/transaction.json4
-rw-r--r--qapi/ui.json28
-rw-r--r--qapi/vfio.json17
-rw-r--r--qapi/virtio.json6
-rw-r--r--qemu-keymap.c9
-rw-r--r--qemu-nbd.c7
-rw-r--r--qemu-options.hx314
-rw-r--r--qemu.nsi4
-rw-r--r--qga/commands-bsd.c25
-rw-r--r--qga/commands-common.h9
-rw-r--r--qga/commands-linux.c1937
-rw-r--r--qga/commands-posix.c2028
-rw-r--r--qga/commands-win32.c80
-rw-r--r--qga/main.c224
-rw-r--r--qga/qapi-schema.json235
-rw-r--r--qobject/qlit.c2
-rw-r--r--qobject/qnum.c12
-rw-r--r--qom/object.c16
-rw-r--r--replay/replay-events.c9
-rw-r--r--replay/replay.c23
m---------roms/edk20
-rw-r--r--roms/edk2-build.config13
-rw-r--r--roms/edk2-version4
m---------roms/openbios0
m---------roms/opensbi0
-rw-r--r--rust/.gitignore3
-rw-r--r--rust/Kconfig1
-rw-r--r--rust/hw/Kconfig2
-rw-r--r--rust/hw/char/Kconfig3
-rw-r--r--rust/hw/char/meson.build1
-rw-r--r--rust/hw/char/pl011/.gitignore2
-rw-r--r--rust/hw/char/pl011/Cargo.lock134
-rw-r--r--rust/hw/char/pl011/Cargo.toml26
-rw-r--r--rust/hw/char/pl011/README.md31
-rw-r--r--rust/hw/char/pl011/meson.build26
-rw-r--r--rust/hw/char/pl011/src/device.rs599
-rw-r--r--rust/hw/char/pl011/src/device_class.rs70
-rw-r--r--rust/hw/char/pl011/src/lib.rs586
-rw-r--r--rust/hw/char/pl011/src/memory_ops.rs59
-rw-r--r--rust/hw/meson.build1
-rw-r--r--rust/meson.build4
-rw-r--r--rust/qemu-api-macros/Cargo.lock47
-rw-r--r--rust/qemu-api-macros/Cargo.toml25
-rw-r--r--rust/qemu-api-macros/README.md1
-rw-r--r--rust/qemu-api-macros/meson.build23
-rw-r--r--rust/qemu-api-macros/src/lib.rs43
-rw-r--r--rust/qemu-api/.gitignore2
-rw-r--r--rust/qemu-api/Cargo.lock7
-rw-r--r--rust/qemu-api/Cargo.toml26
-rw-r--r--rust/qemu-api/README.md17
-rw-r--r--rust/qemu-api/build.rs14
-rw-r--r--rust/qemu-api/meson.build24
-rw-r--r--rust/qemu-api/src/definitions.rs97
-rw-r--r--rust/qemu-api/src/device_class.rs128
-rw-r--r--rust/qemu-api/src/lib.rs166
-rw-r--r--rust/qemu-api/src/tests.rs49
-rw-r--r--rust/rustfmt.toml7
-rw-r--r--rust/wrapper.h (renamed from include/hw/cris/etraxfs.h)51
-rwxr-xr-xscripts/archive-source.sh29
-rwxr-xr-xscripts/checkpatch.pl28
-rw-r--r--scripts/ci/gitlab-ci-section29
-rw-r--r--scripts/ci/setup/gitlab-runner.yml39
-rw-r--r--scripts/ci/setup/ubuntu/build-environment.yml2
-rw-r--r--scripts/ci/setup/ubuntu/ubuntu-2204-aarch64.yaml1
-rw-r--r--scripts/ci/setup/ubuntu/ubuntu-2204-s390x.yaml1
-rw-r--r--scripts/coccinelle/device-reset.cocci30
-rw-r--r--scripts/coverity-scan/COMPONENTS.md3
-rwxr-xr-xscripts/gensyscalls.sh103
-rwxr-xr-xscripts/kernel-doc2
-rwxr-xr-xscripts/make-release6
-rw-r--r--scripts/meson-buildoptions.0
-rw-r--r--scripts/meson-buildoptions.sh19
-rw-r--r--scripts/minikconf.py2
-rw-r--r--scripts/probe-gdb-support.py76
-rw-r--r--scripts/qapi/common.py44
-rw-r--r--scripts/qapi/schema.py2
-rwxr-xr-xscripts/replay-dump.py167
-rwxr-xr-xscripts/rust/rust_root_crate.sh13
-rw-r--r--scripts/rust/rustc_args.py84
-rwxr-xr-xscripts/update-syscalltbl.sh5
-rw-r--r--semihosting/Kconfig1
-rw-r--r--subprojects/.gitignore11
-rw-r--r--subprojects/arbitrary-int-1-rs.wrap7
-rw-r--r--subprojects/bilge-0.2-rs.wrap7
-rw-r--r--subprojects/bilge-impl-0.2-rs.wrap7
-rw-r--r--subprojects/either-1-rs.wrap7
-rw-r--r--subprojects/itertools-0.11-rs.wrap7
-rw-r--r--subprojects/packagefiles/arbitrary-int-1-rs/meson.build19
-rw-r--r--subprojects/packagefiles/bilge-0.2-rs/meson.build29
-rw-r--r--subprojects/packagefiles/bilge-impl-0.2-rs/meson.build45
-rw-r--r--subprojects/packagefiles/either-1-rs/meson.build24
-rw-r--r--subprojects/packagefiles/itertools-0.11-rs/meson.build30
-rw-r--r--subprojects/packagefiles/proc-macro-error-1-rs/meson.build40
-rw-r--r--subprojects/packagefiles/proc-macro-error-attr-1-rs/meson.build32
-rw-r--r--subprojects/packagefiles/proc-macro2-1-rs/meson.build31
-rw-r--r--subprojects/packagefiles/quote-1-rs/meson.build29
-rw-r--r--subprojects/packagefiles/syn-2-rs/meson.build40
-rw-r--r--subprojects/packagefiles/unicode-ident-1-rs/meson.build20
-rw-r--r--subprojects/proc-macro-error-1-rs.wrap7
-rw-r--r--subprojects/proc-macro-error-attr-1-rs.wrap7
-rw-r--r--subprojects/proc-macro2-1-rs.wrap7
-rw-r--r--subprojects/quote-1-rs.wrap7
-rw-r--r--subprojects/syn-2-rs.wrap7
-rw-r--r--subprojects/unicode-ident-1-rs.wrap7
-rw-r--r--subprojects/unicode-ident-1-rs/meson.build20
-rw-r--r--system/async-teardown.c37
-rw-r--r--system/cpu-throttle.c3
-rw-r--r--system/cpus.c12
-rw-r--r--system/globals.c1
-rw-r--r--system/memory.c88
-rw-r--r--system/memory_mapping.c4
-rw-r--r--system/physmem.c166
-rw-r--r--system/qdev-monitor.c18
-rw-r--r--system/qemu-seccomp.c4
-rw-r--r--system/rtc.c2
-rw-r--r--system/runstate.c44
-rw-r--r--system/trace-events3
-rw-r--r--system/vl.c25
-rw-r--r--target/Kconfig1
-rw-r--r--target/alpha/cpu-param.h2
-rw-r--r--target/alpha/cpu.h2
-rw-r--r--target/alpha/gdbstub.c2
-rw-r--r--target/arm/cpu-features.h55
-rw-r--r--target/arm/cpu-param.h6
-rw-r--r--target/arm/cpu.c2
-rw-r--r--target/arm/cpu.h51
-rw-r--r--target/arm/cpu64.c19
-rw-r--r--target/arm/gdbstub.c16
-rw-r--r--target/arm/gdbstub64.c38
-rw-r--r--target/arm/helper.c47
-rw-r--r--target/arm/helper.h46
-rw-r--r--target/arm/hvf/hvf.c367
-rw-r--r--target/arm/hvf_arm.h19
-rw-r--r--target/arm/hyp_gdbstub.c1
-rw-r--r--target/arm/internals.h66
-rw-r--r--target/arm/kvm.c11
-rw-r--r--target/arm/ptw.c178
-rw-r--r--target/arm/tcg/a64.decode257
-rw-r--r--target/arm/tcg/cpu-v7m.c2
-rw-r--r--target/arm/tcg/cpu64.c114
-rw-r--r--target/arm/tcg/gengvec.c121
-rw-r--r--target/arm/tcg/helper-a64.c55
-rw-r--r--target/arm/tcg/helper-a64.h3
-rw-r--r--target/arm/tcg/helper-sme.h6
-rw-r--r--target/arm/tcg/hflags.c4
-rw-r--r--target/arm/tcg/m_helper.c8
-rw-r--r--target/arm/tcg/neon-dp.decode6
-rw-r--r--target/arm/tcg/neon_helper.c76
-rw-r--r--target/arm/tcg/sme_helper.c141
-rw-r--r--target/arm/tcg/sve_helper.c42
-rw-r--r--target/arm/tcg/tlb_helper.c47
-rw-r--r--target/arm/tcg/translate-a64.c2188
-rw-r--r--target/arm/tcg/translate-neon.c222
-rw-r--r--target/arm/tcg/translate-sme.c38
-rw-r--r--target/arm/tcg/translate-sve.c171
-rw-r--r--target/arm/tcg/translate-vfp.c8
-rw-r--r--target/arm/tcg/translate.c9
-rw-r--r--target/arm/tcg/translate.h18
-rw-r--r--target/arm/tcg/vec_helper.c208
-rw-r--r--target/arm/tcg/vec_internal.h37
-rw-r--r--target/arm/tcg/vfp.decode12
-rw-r--r--target/arm/vfp_helper.c8
-rw-r--r--target/avr/gdbstub.c4
-rw-r--r--target/cris/Kconfig2
-rw-r--r--target/cris/cpu-param.h16
-rw-r--r--target/cris/cpu-qom.h32
-rw-r--r--target/cris/cpu.c323
-rw-r--r--target/cris/cpu.h286
-rw-r--r--target/cris/crisv10-decode.h112
-rw-r--r--target/cris/crisv32-decode.h133
-rw-r--r--target/cris/gdbstub.c127
-rw-r--r--target/cris/helper.c287
-rw-r--r--target/cris/helper.h23
-rw-r--r--target/cris/machine.c93
-rw-r--r--target/cris/meson.build17
-rw-r--r--target/cris/mmu.c356
-rw-r--r--target/cris/mmu.h22
-rw-r--r--target/cris/op_helper.c580
-rw-r--r--target/cris/opcode-cris.h355
-rw-r--r--target/cris/translate.c3252
-rw-r--r--target/cris/translate_v10.c.inc1262
-rw-r--r--target/hexagon/cpu-qom.h1
-rw-r--r--target/hexagon/cpu.c20
-rw-r--r--target/hexagon/gdbstub.c27
-rw-r--r--target/hexagon/gen_idef_parser_funcs.py2
-rw-r--r--target/hexagon/idef-parser/README.rst4
-rw-r--r--target/hexagon/idef-parser/idef-parser.y1
-rw-r--r--target/hexagon/idef-parser/macros.h.inc (renamed from target/hexagon/idef-parser/macros.inc)0
-rw-r--r--target/hexagon/meson.build4
-rw-r--r--target/hexagon/op_helper.c18
-rw-r--r--target/hppa/cpu-param.h2
-rw-r--r--target/hppa/cpu.c2
-rw-r--r--target/hppa/cpu.h14
-rw-r--r--target/hppa/helper.c2
-rw-r--r--target/hppa/int_helper.c2
-rw-r--r--target/hppa/mem_helper.c55
-rw-r--r--target/hppa/op_helper.c2
-rw-r--r--target/i386/cpu-param.h2
-rw-r--r--target/i386/cpu.c141
-rw-r--r--target/i386/cpu.h30
-rw-r--r--target/i386/gdbstub.c102
-rw-r--r--target/i386/hvf/hvf.c5
-rw-r--r--target/i386/kvm/hyperv.c1
-rw-r--r--target/i386/kvm/kvm.c782
-rw-r--r--target/i386/kvm/kvm_i386.h11
-rw-r--r--target/i386/kvm/meson.build1
-rw-r--r--target/i386/kvm/vmsr_energy.c346
-rw-r--r--target/i386/kvm/vmsr_energy.h99
-rw-r--r--target/i386/machine.c20
-rw-r--r--target/i386/sev.c8
-rw-r--r--target/i386/tcg/access.c27
-rw-r--r--target/i386/tcg/cc_helper.c18
-rw-r--r--target/i386/tcg/cc_helper_template.h.inc18
-rw-r--r--target/i386/tcg/decode-new.c.inc161
-rw-r--r--target/i386/tcg/decode-new.h19
-rw-r--r--target/i386/tcg/emit.c.inc257
-rw-r--r--target/i386/tcg/seg_helper.c27
-rw-r--r--target/i386/tcg/sysemu/excp_helper.c45
-rw-r--r--target/i386/tcg/translate.c473
-rw-r--r--target/loongarch/arch_dump.c163
-rw-r--r--target/loongarch/cpu.c17
-rw-r--r--target/loongarch/gdbstub.c107
-rw-r--r--target/loongarch/internals.h2
-rw-r--r--target/loongarch/kvm/kvm.c9
-rw-r--r--target/loongarch/kvm/kvm_loongarch.h2
-rw-r--r--target/loongarch/meson.build1
-rw-r--r--target/loongarch/tcg/op_helper.c2
-rw-r--r--target/loongarch/tcg/tlb_helper.c1
-rw-r--r--target/m68k/Kconfig2
-rw-r--r--target/m68k/cpu-param.h2
-rw-r--r--target/m68k/gdbstub.c2
-rw-r--r--target/m68k/helper.c17
-rw-r--r--target/m68k/meson.build5
-rw-r--r--target/m68k/semihosting-stub.c15
-rw-r--r--target/m68k/translate.c13
-rw-r--r--target/meson.build1
-rw-r--r--target/microblaze/cpu-param.h2
-rw-r--r--target/mips/Kconfig2
-rw-r--r--target/mips/cpu-param.h2
-rw-r--r--target/mips/cpu.c17
-rw-r--r--target/mips/cpu.h7
-rw-r--r--target/mips/internal.h10
-rw-r--r--target/mips/kvm.c4
-rw-r--r--target/mips/tcg/ldst_helper.c15
-rw-r--r--target/mips/tcg/micromips_translate.c.inc34
-rw-r--r--target/mips/tcg/mips16e_translate.c.inc118
-rw-r--r--target/mips/tcg/msa_helper.c8
-rw-r--r--target/mips/tcg/mxu_translate.c18
-rw-r--r--target/mips/tcg/nanomips_translate.c.inc162
-rw-r--r--target/mips/tcg/sysemu/meson.build6
-rw-r--r--target/mips/tcg/sysemu/semihosting-stub.c15
-rw-r--r--target/mips/tcg/sysemu/tlb_helper.c69
-rw-r--r--target/mips/tcg/translate.c198
-rw-r--r--target/mips/tcg/translate.h13
-rw-r--r--target/mips/tcg/tx79_translate.c8
-rw-r--r--target/openrisc/cpu-param.h2
-rw-r--r--target/ppc/arch_dump.c24
-rw-r--r--target/ppc/cpu-param.h2
-rw-r--r--target/ppc/cpu.h45
-rw-r--r--target/ppc/cpu_init.c38
-rw-r--r--target/ppc/dfp_helper.c8
-rw-r--r--target/ppc/excp_helper.c69
-rw-r--r--target/ppc/fpu_helper.c60
-rw-r--r--target/ppc/helper.h98
-rw-r--r--target/ppc/insn32.decode98
-rw-r--r--target/ppc/int_helper.c22
-rw-r--r--target/ppc/kvm.c50
-rw-r--r--target/ppc/machine.c2
-rw-r--r--target/ppc/mem_helper.c60
-rw-r--r--target/ppc/misc_helper.c111
-rw-r--r--target/ppc/mmu-book3s-v3.c1
-rw-r--r--target/ppc/mmu-book3s-v3.h43
-rw-r--r--target/ppc/mmu-hash32.c69
-rw-r--r--target/ppc/mmu-hash32.h56
-rw-r--r--target/ppc/mmu-hash64.c50
-rw-r--r--target/ppc/mmu-hash64.h1
-rw-r--r--target/ppc/mmu-radix64.c50
-rw-r--r--target/ppc/mmu-radix64.h53
-rw-r--r--target/ppc/mmu_common.c333
-rw-r--r--target/ppc/mmu_helper.c2
-rw-r--r--target/ppc/timebase_helper.c89
-rw-r--r--target/ppc/translate.c64
-rw-r--r--target/ppc/translate/vmx-impl.c.inc290
-rw-r--r--target/ppc/translate/vmx-ops.c.inc19
-rw-r--r--target/ppc/translate/vsx-impl.c.inc594
-rw-r--r--target/ppc/translate/vsx-ops.c.inc82
-rw-r--r--target/riscv/Kconfig4
-rw-r--r--target/riscv/cpu-param.h2
-rw-r--r--target/riscv/cpu-qom.h1
-rw-r--r--target/riscv/cpu.c54
-rw-r--r--target/riscv/cpu.h24
-rw-r--r--target/riscv/cpu_bits.h51
-rw-r--r--target/riscv/cpu_cfg.h7
-rw-r--r--target/riscv/cpu_helper.c74
-rw-r--r--target/riscv/csr.c501
-rw-r--r--target/riscv/debug.c114
-rw-r--r--target/riscv/debug.h3
-rw-r--r--target/riscv/insn16.decode1
-rw-r--r--target/riscv/insn32.decode33
-rw-r--r--target/riscv/insn_trans/trans_rva.c.inc51
-rw-r--r--target/riscv/insn_trans/trans_rvd.c.inc28
-rw-r--r--target/riscv/insn_trans/trans_rvf.c.inc14
-rw-r--r--target/riscv/insn_trans/trans_rvi.c.inc6
-rw-r--r--target/riscv/insn_trans/trans_rvv.c.inc2
-rw-r--r--target/riscv/insn_trans/trans_rvzabha.c.inc145
-rw-r--r--target/riscv/insn_trans/trans_rvzacas.c.inc13
-rw-r--r--target/riscv/insn_trans/trans_rvzcmop.c.inc29
-rw-r--r--target/riscv/insn_trans/trans_rvzimop.c.inc37
-rw-r--r--target/riscv/kvm/kvm-cpu.c10
-rw-r--r--target/riscv/machine.c5
-rw-r--r--target/riscv/monitor.c1
-rw-r--r--target/riscv/op_helper.c23
-rw-r--r--target/riscv/pmu.c185
-rw-r--r--target/riscv/pmu.h4
-rw-r--r--target/riscv/tcg/tcg-cpu.c18
-rw-r--r--target/riscv/time_helper.c1
-rw-r--r--target/riscv/translate.c38
-rw-r--r--target/riscv/vector_helper.c33
-rw-r--r--target/rx/translate.c3
-rw-r--r--target/s390x/cpu-param.h2
-rw-r--r--target/s390x/cpu.c38
-rw-r--r--target/s390x/cpu.h23
-rw-r--r--target/s390x/cpu_models_sysemu.c25
-rw-r--r--target/s390x/diag.c9
-rw-r--r--target/s390x/gdbstub.c34
-rw-r--r--target/s390x/ioinst.c2
-rw-r--r--target/s390x/kvm/kvm.c4
-rw-r--r--target/s390x/sigp.c8
-rw-r--r--target/s390x/tcg/mem_helper.c105
-rw-r--r--target/s390x/tcg/translate.c1
-rw-r--r--target/sh4/cpu-param.h2
-rw-r--r--target/sh4/helper.c2
-rw-r--r--target/sparc/cpu-param.h2
-rw-r--r--target/sparc/cpu.h30
-rw-r--r--target/sparc/fop_helper.c4
-rw-r--r--target/sparc/insns.decode6
-rw-r--r--target/sparc/int32_helper.c40
-rw-r--r--target/sparc/ldst_helper.c5
-rw-r--r--target/sparc/machine.c25
-rw-r--r--target/sparc/translate.c130
-rw-r--r--target/tricore/gdbstub.c2
-rw-r--r--target/tricore/op_helper.c4
-rw-r--r--target/tricore/translate.c3
-rw-r--r--target/xtensa/Kconfig2
-rw-r--r--target/xtensa/exc_helper.c2
-rw-r--r--target/xtensa/mmu_helper.c4
-rw-r--r--target/xtensa/translate.c2
-rw-r--r--tcg/arm/tcg-target.c.inc4
-rw-r--r--tcg/i386/tcg-target-con-set.h1
-rw-r--r--tcg/i386/tcg-target-con-str.h1
-rw-r--r--tcg/i386/tcg-target.c.inc486
-rw-r--r--tcg/i386/tcg-target.h4
-rw-r--r--tcg/i386/tcg-target.opc.h1
-rw-r--r--tcg/loongarch64/tcg-target.c.inc1
-rw-r--r--tcg/optimize.c99
-rw-r--r--tcg/ppc/tcg-target-con-set.h1
-rw-r--r--tcg/ppc/tcg-target.c.inc287
-rw-r--r--tcg/ppc/tcg-target.h2
-rw-r--r--tcg/riscv/tcg-target-con-set.h9
-rw-r--r--tcg/riscv/tcg-target-con-str.h3
-rw-r--r--tcg/riscv/tcg-target.c.inc994
-rw-r--r--tcg/riscv/tcg-target.h78
-rw-r--r--tcg/riscv/tcg-target.opc.h12
-rw-r--r--tcg/s390x/tcg-target-con-set.h2
-rw-r--r--tcg/s390x/tcg-target-con-str.h1
-rw-r--r--tcg/s390x/tcg-target.c.inc219
-rw-r--r--tcg/s390x/tcg-target.h2
-rw-r--r--tcg/sparc64/tcg-target.c.inc2
-rw-r--r--tcg/tcg-internal.h14
-rw-r--r--tcg/tcg-op-gvec.c2
-rw-r--r--tcg/tcg-op-ldst.c72
-rw-r--r--tcg/tcg-op-vec.c4
-rw-r--r--tcg/tcg-op.c86
-rw-r--r--tcg/tcg.c4
-rw-r--r--tests/Makefile.include46
-rw-r--r--tests/avocado/avocado_qemu/__init__.py273
-rw-r--r--tests/avocado/avocado_qemu/linuxtest.py253
-rw-r--r--tests/avocado/boot_linux.py3
-rw-r--r--tests/avocado/boot_linux_console.py646
-rw-r--r--tests/avocado/boot_xen.py47
-rw-r--r--tests/avocado/hotplug_blk.py2
-rw-r--r--tests/avocado/hotplug_cpu.py2
-rw-r--r--tests/avocado/intel_iommu.py3
-rw-r--r--tests/avocado/load_bflt.py54
-rw-r--r--tests/avocado/machine_aarch64_sbsaref.py236
-rw-r--r--tests/avocado/machine_arm_n8x0.py49
-rw-r--r--tests/avocado/machine_aspeed.py269
-rw-r--r--tests/avocado/machine_microblaze.py61
-rw-r--r--tests/avocado/machine_mips_fuloong2e.py42
-rw-r--r--tests/avocado/machine_mips_loongson3v.py39
-rw-r--r--tests/avocado/machine_mips_malta.py164
-rw-r--r--tests/avocado/machine_sparc64_sun4u.py36
-rw-r--r--tests/avocado/machine_sparc_leon3.py37
-rw-r--r--tests/avocado/multiprocess.py102
-rw-r--r--tests/avocado/ppc_amiga.py38
-rw-r--r--tests/avocado/replay_kernel.py31
-rw-r--r--tests/avocado/replay_linux.py12
-rw-r--r--tests/avocado/reverse_debugging.py4
-rw-r--r--tests/avocado/smmu.py4
-rw-r--r--tests/avocado/tcg_plugins.py37
-rw-r--r--tests/avocado/tesseract_utils.py46
-rw-r--r--tests/avocado/tuxrun_baselines.py396
-rw-r--r--tests/avocado/virtiofs_submounts.py.data/cleanup.sh46
-rw-r--r--tests/avocado/virtiofs_submounts.py.data/guest-cleanup.sh30
-rw-r--r--tests/avocado/virtiofs_submounts.py.data/guest.sh138
-rw-r--r--tests/avocado/virtiofs_submounts.py.data/host.sh127
-rw-r--r--tests/bench/benchmark-crypto-akcipher.c30
-rw-r--r--tests/bench/benchmark-crypto-cipher.c22
-rw-r--r--tests/bench/benchmark-crypto-hash.c10
-rw-r--r--tests/bench/benchmark-crypto-hmac.c6
-rw-r--r--tests/bench/test_akcipher_keys.c.inc (renamed from tests/bench/test_akcipher_keys.inc)0
-rw-r--r--tests/data/acpi/aarch64/virt/DSDTbin5196 -> 5196 bytes
-rw-r--r--tests/data/acpi/aarch64/virt/DSDT.acpihmatvirtbin5282 -> 5282 bytes
-rw-r--r--tests/data/acpi/aarch64/virt/DSDT.memhpbin6557 -> 6557 bytes
-rw-r--r--tests/data/acpi/aarch64/virt/DSDT.pxbbin7679 -> 7679 bytes
-rw-r--r--tests/data/acpi/aarch64/virt/DSDT.topologybin5398 -> 5398 bytes
-rw-r--r--tests/data/acpi/aarch64/virt/SSDT.memhpbin1817 -> 1817 bytes
-rw-r--r--tests/data/acpi/riscv64/virt/APICbin0 -> 116 bytes
-rw-r--r--tests/data/acpi/riscv64/virt/DSDTbin0 -> 3576 bytes
-rw-r--r--tests/data/acpi/riscv64/virt/FACPbin0 -> 276 bytes
-rw-r--r--tests/data/acpi/riscv64/virt/MCFGbin0 -> 60 bytes
-rw-r--r--tests/data/acpi/riscv64/virt/RHCTbin0 -> 332 bytes
-rw-r--r--tests/data/acpi/riscv64/virt/SPCRbin0 -> 80 bytes
-rw-r--r--tests/data/acpi/riscv64/virt/SRAT.numamembin0 -> 108 bytes
-rw-r--r--tests/data/acpi/x86/microvm/DSDT.pciebin3023 -> 3023 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDTbin6830 -> 8527 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.acpierstbin6741 -> 8438 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.acpihmatbin8155 -> 9852 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.bridgebin13701 -> 15398 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.cphpbin7294 -> 8991 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.dimmpxmbin8484 -> 10181 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.hpbridgebin6781 -> 8478 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.hpbrrootbin3337 -> 5034 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.ipmikcsbin6902 -> 8599 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.memhpbin8189 -> 9886 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.nohpetbin6688 -> 8385 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.numamembin6836 -> 8533 bytes
-rw-r--r--tests/data/acpi/x86/pc/DSDT.roothpbin10623 -> 12320 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.cxlbin9714 -> 13148 bytes
-rw-r--r--tests/data/acpi/x86/q35/DSDT.viotbin9464 -> 14615 bytes
-rw-r--r--tests/data/qobject/qdict.txt6
-rw-r--r--tests/docker/Makefile.include6
-rw-r--r--tests/docker/dockerfiles/alpine.docker1
-rw-r--r--tests/docker/dockerfiles/debian-all-test-cross.docker3
-rw-r--r--tests/docker/dockerfiles/debian-amd64-cross.docker1
-rw-r--r--tests/docker/dockerfiles/debian-arm64-cross.docker1
-rw-r--r--tests/docker/dockerfiles/debian-armel-cross.docker178
-rw-r--r--tests/docker/dockerfiles/debian-armhf-cross.docker1
-rw-r--r--tests/docker/dockerfiles/debian-hexagon-cross.docker3
-rw-r--r--tests/docker/dockerfiles/debian-i686-cross.docker11
-rw-r--r--tests/docker/dockerfiles/debian-legacy-test-cross.docker3
-rw-r--r--tests/docker/dockerfiles/debian-loongarch-cross.docker7
-rwxr-xr-xtests/docker/dockerfiles/debian-microblaze-cross.d/build-toolchain.sh8
-rw-r--r--tests/docker/dockerfiles/debian-mips64el-cross.docker19
-rw-r--r--tests/docker/dockerfiles/debian-mipsel-cross.docker11
-rw-r--r--tests/docker/dockerfiles/debian-ppc64el-cross.docker1
-rw-r--r--tests/docker/dockerfiles/debian-s390x-cross.docker1
-rw-r--r--tests/docker/dockerfiles/debian-toolchain.docker7
-rw-r--r--tests/docker/dockerfiles/debian-tricore-cross.docker3
-rw-r--r--tests/docker/dockerfiles/debian-xtensa-cross.docker3
-rw-r--r--tests/docker/dockerfiles/debian.docker1
-rw-r--r--tests/docker/dockerfiles/fedora-cris-cross.docker14
-rw-r--r--tests/docker/dockerfiles/fedora-rust-nightly.docker173
-rw-r--r--tests/docker/dockerfiles/fedora-win64-cross.docker1
-rw-r--r--tests/docker/dockerfiles/fedora.docker1
-rw-r--r--tests/docker/dockerfiles/opensuse-leap.docker6
-rw-r--r--tests/docker/dockerfiles/ubuntu2204.docker1
-rwxr-xr-xtests/docker/test-debug4
-rw-r--r--tests/fp/meson.build16
-rw-r--r--tests/functional/acpi-bits/bits-config/bits-cfg.txt (renamed from tests/avocado/acpi-bits/bits-config/bits-cfg.txt)0
-rw-r--r--tests/functional/acpi-bits/bits-tests/smbios.py2 (renamed from tests/avocado/acpi-bits/bits-tests/smbios.py2)0
-rw-r--r--tests/functional/acpi-bits/bits-tests/smilatency.py2 (renamed from tests/avocado/acpi-bits/bits-tests/smilatency.py2)0
-rw-r--r--tests/functional/acpi-bits/bits-tests/testacpi.py2 (renamed from tests/avocado/acpi-bits/bits-tests/testacpi.py2)0
-rw-r--r--tests/functional/acpi-bits/bits-tests/testcpuid.py2 (renamed from tests/avocado/acpi-bits/bits-tests/testcpuid.py2)0
-rw-r--r--tests/functional/meson.build272
-rw-r--r--tests/functional/qemu_test/__init__.py15
-rw-r--r--tests/functional/qemu_test/asset.py177
-rw-r--r--tests/functional/qemu_test/cmd.py193
-rw-r--r--tests/functional/qemu_test/config.py36
-rw-r--r--tests/functional/qemu_test/linuxkernel.py53
-rw-r--r--tests/functional/qemu_test/tesseract.py36
-rw-r--r--tests/functional/qemu_test/testcase.py202
-rw-r--r--tests/functional/qemu_test/tuxruntest.py158
-rw-r--r--tests/functional/qemu_test/utils.py56
-rwxr-xr-xtests/functional/test_aarch64_raspi3.py41
-rwxr-xr-xtests/functional/test_aarch64_raspi4.py99
-rwxr-xr-xtests/functional/test_aarch64_sbsaref.py190
-rwxr-xr-x[-rw-r--r--]tests/functional/test_aarch64_virt.py (renamed from tests/avocado/machine_aarch64_virt.py)71
-rwxr-xr-x[-rw-r--r--]tests/functional/test_acpi_bits.py (renamed from tests/avocado/acpi-bits.py)83
-rwxr-xr-xtests/functional/test_alpha_clipper.py38
-rw-r--r--tests/functional/test_arm_aspeed.py282
-rwxr-xr-xtests/functional/test_arm_bflt.py44
-rwxr-xr-x[-rw-r--r--]tests/functional/test_arm_canona1100.py (renamed from tests/avocado/machine_arm_canona1100.py)30
-rwxr-xr-x[-rw-r--r--]tests/functional/test_arm_integratorcp.py (renamed from tests/avocado/machine_arm_integratorcp.py)56
-rwxr-xr-xtests/functional/test_arm_raspi2.py95
-rwxr-xr-xtests/functional/test_arm_tuxrun.py70
-rwxr-xr-xtests/functional/test_arm_vexpress.py26
-rwxr-xr-x[-rw-r--r--]tests/functional/test_avr_mega2560.py (renamed from tests/avocado/machine_avr6.py)22
-rwxr-xr-x[-rw-r--r--]tests/functional/test_cpu_queries.py (renamed from tests/avocado/cpu_queries.py)12
-rwxr-xr-x[-rw-r--r--]tests/functional/test_empty_cpu_model.py (renamed from tests/avocado/empty_cpu_model.py)7
-rwxr-xr-xtests/functional/test_i386_tuxrun.py35
-rwxr-xr-x[-rw-r--r--]tests/functional/test_info_usernet.py (renamed from tests/avocado/info_usernet.py)11
-rwxr-xr-x[-rw-r--r--]tests/functional/test_linux_initrd.py (renamed from tests/avocado/linux_initrd.py)38
-rwxr-xr-x[-rw-r--r--]tests/functional/test_loongarch64_virt.py (renamed from tests/avocado/machine_loongarch.py)46
-rwxr-xr-xtests/functional/test_m68k_mcf5208evb.py29
-rwxr-xr-x[-rw-r--r--]tests/functional/test_m68k_nextcube.py (renamed from tests/avocado/machine_m68k_nextcube.py)29
-rwxr-xr-xtests/functional/test_m68k_q800.py37
-rwxr-xr-x[-rw-r--r--]tests/functional/test_mem_addr_space.py (renamed from tests/avocado/mem-addr-space-check.py)53
-rwxr-xr-xtests/functional/test_microblaze_s3adsp1800.py40
-rwxr-xr-xtests/functional/test_microblazeel_s3adsp1800.py42
-rwxr-xr-xtests/functional/test_mips64_tuxrun.py35
-rwxr-xr-xtests/functional/test_mips64el_fuloong2e.py64
-rwxr-xr-xtests/functional/test_mips64el_loongson3v.py39
-rwxr-xr-xtests/functional/test_mips64el_malta.py186
-rwxr-xr-xtests/functional/test_mips64el_tuxrun.py35
-rwxr-xr-xtests/functional/test_mips_malta.py81
-rwxr-xr-xtests/functional/test_mips_tuxrun.py36
-rwxr-xr-xtests/functional/test_mipsel_malta.py96
-rwxr-xr-xtests/functional/test_mipsel_tuxrun.py36
-rwxr-xr-xtests/functional/test_multiprocess.py100
-rwxr-xr-x[-rw-r--r--]tests/functional/test_netdev_ethtool.py (renamed from tests/avocado/netdev-ethtool.py)53
-rwxr-xr-xtests/functional/test_or1k_sim.py29
-rwxr-xr-x[-rw-r--r--]tests/functional/test_pc_cpu_hotplug_props.py (renamed from tests/avocado/pc_cpu_hotplug_props.py)11
-rwxr-xr-xtests/functional/test_ppc64_e500.py25
-rwxr-xr-x[-rw-r--r--]tests/functional/test_ppc64_hv.py (renamed from tests/avocado/ppc_hv_tests.py)53
-rwxr-xr-x[-rw-r--r--]tests/functional/test_ppc64_powernv.py (renamed from tests/avocado/ppc_powernv.py)94
-rwxr-xr-x[-rw-r--r--]tests/functional/test_ppc64_pseries.py (renamed from tests/avocado/ppc_pseries.py)56
-rwxr-xr-xtests/functional/test_ppc64_tuxrun.py110
-rwxr-xr-x[-rw-r--r--]tests/functional/test_ppc_405.py (renamed from tests/avocado/ppc_405.py)29
-rwxr-xr-x[-rw-r--r--]tests/functional/test_ppc_40p.py (renamed from tests/avocado/ppc_prep_40p.py)65
-rwxr-xr-x[-rw-r--r--]tests/functional/test_ppc_74xx.py (renamed from tests/avocado/ppc_74xx.py)74
-rwxr-xr-xtests/functional/test_ppc_amiga.py43
-rwxr-xr-x[-rw-r--r--]tests/functional/test_ppc_bamboo.py (renamed from tests/avocado/ppc_bamboo.py)33
-rwxr-xr-xtests/functional/test_ppc_mac.py38
-rwxr-xr-x[-rw-r--r--]tests/functional/test_ppc_mpc8544ds.py (renamed from tests/avocado/ppc_mpc8544ds.py)29
-rwxr-xr-xtests/functional/test_ppc_tuxrun.py35
-rwxr-xr-x[-rw-r--r--]tests/functional/test_ppc_virtex_ml507.py (renamed from tests/avocado/ppc_virtex_ml507.py)29
-rwxr-xr-xtests/functional/test_riscv32_tuxrun.py38
-rwxr-xr-xtests/functional/test_riscv64_tuxrun.py38
-rwxr-xr-x[-rw-r--r--]tests/functional/test_rx_gdbsim.py (renamed from tests/avocado/machine_rx_gdbsim.py)55
-rwxr-xr-x[-rw-r--r--]tests/functional/test_s390x_ccw_virtio.py (renamed from tests/avocado/machine_s390_ccw_virtio.py)81
-rwxr-xr-x[-rw-r--r--]tests/functional/test_s390x_topology.py (renamed from tests/avocado/s390_topology.py)86
-rwxr-xr-xtests/functional/test_s390x_tuxrun.py34
-rwxr-xr-xtests/functional/test_sh4_r2d.py31
-rwxr-xr-xtests/functional/test_sh4_tuxrun.py57
-rwxr-xr-xtests/functional/test_sparc64_sun4u.py41
-rwxr-xr-xtests/functional/test_sparc64_tuxrun.py34
-rwxr-xr-xtests/functional/test_sparc_sun4m.py25
-rwxr-xr-x[-rw-r--r--]tests/functional/test_version.py (renamed from tests/avocado/version.py)13
-rwxr-xr-x[-rw-r--r--]tests/functional/test_virtio_gpu.py (renamed from tests/avocado/virtio-gpu.py)64
-rwxr-xr-x[-rw-r--r--]tests/functional/test_virtio_version.py (renamed from tests/avocado/virtio_version.py)8
-rwxr-xr-xtests/functional/test_x86_64_tuxrun.py36
-rwxr-xr-x[-rw-r--r--]tests/functional/test_x86_cpu_model_versions.py (renamed from tests/avocado/x86_cpu_model_versions.py)65
-rwxr-xr-xtests/functional/test_xtensa_lx60.py26
-rwxr-xr-xtests/guest-debug/run-test.py6
-rw-r--r--tests/guest-debug/test_gdbstub.py5
m---------tests/lcitool/libvirt-ci0
-rw-r--r--tests/lcitool/mappings.yml28
-rw-r--r--tests/lcitool/projects/qemu.yml1
-rwxr-xr-xtests/lcitool/refresh44
-rw-r--r--tests/meson.build3
-rw-r--r--tests/plugin/mem.c139
-rw-r--r--tests/qapi-schema/alternate-array.out1
-rw-r--r--tests/qapi-schema/comments.out1
-rw-r--r--tests/qapi-schema/doc-good.out1
-rw-r--r--tests/qapi-schema/empty.out1
-rw-r--r--tests/qapi-schema/include-repetition.out1
-rw-r--r--tests/qapi-schema/include-simple.out1
-rw-r--r--tests/qapi-schema/indented-expr.out1
-rw-r--r--tests/qapi-schema/qapi-schema-test.out1
-rwxr-xr-xtests/qemu-iotests/0242
-rw-r--r--tests/qemu-iotests/024.out1
-rw-r--r--tests/qemu-iotests/211.out6
-rw-r--r--tests/qemu-iotests/233.out12
-rwxr-xr-xtests/qemu-iotests/check2
-rw-r--r--tests/qemu-iotests/fat16.py690
-rw-r--r--tests/qemu-iotests/testenv.py4
-rwxr-xr-xtests/qemu-iotests/tests/backup-discard-source39
-rwxr-xr-xtests/qemu-iotests/tests/vvfat485
-rwxr-xr-xtests/qemu-iotests/tests/vvfat.out5
-rw-r--r--tests/qtest/acpi-utils.c1
-rw-r--r--tests/qtest/aspeed_smc-test.c6
-rw-r--r--tests/qtest/ast2700-gpio-test.c95
-rw-r--r--tests/qtest/bcm2835-i2c-test.c2
-rw-r--r--tests/qtest/bios-tables-test.c68
-rw-r--r--tests/qtest/boot-order-test.c4
-rw-r--r--tests/qtest/cdrom-test.c101
-rw-r--r--tests/qtest/dbus-display-test.c72
-rw-r--r--tests/qtest/dm163-test.c2
-rw-r--r--tests/qtest/endianness-test.c1
-rw-r--r--tests/qtest/fdc-test.c2
-rw-r--r--tests/qtest/fuzz/generic_fuzz.c3
-rw-r--r--tests/qtest/hd-geo-test.c71
-rw-r--r--tests/qtest/ipmi-bt-test.c4
-rw-r--r--tests/qtest/ipmi-kcs-test.c4
-rw-r--r--tests/qtest/libqos/arm-n800-machine.c92
-rw-r--r--tests/qtest/libqos/meson.build1
-rw-r--r--tests/qtest/libqtest.c17
-rw-r--r--tests/qtest/libqtest.h2
-rw-r--r--tests/qtest/machine-none-test.c2
-rw-r--r--tests/qtest/meson.build44
-rw-r--r--tests/qtest/migration-helpers.c21
-rw-r--r--tests/qtest/migration-test.c169
-rw-r--r--tests/qtest/netdev-socket.c2
-rw-r--r--tests/qtest/numa-test.c10
-rw-r--r--tests/qtest/pnv-spi-seeprom-test.c110
-rw-r--r--tests/qtest/pnv-xscom.h2
-rw-r--r--tests/qtest/rtl8139-test.c2
-rw-r--r--tests/qtest/stm32l4x5.h42
-rw-r--r--tests/qtest/stm32l4x5_gpio-test.c23
-rw-r--r--tests/qtest/stm32l4x5_syscfg-test.c20
-rw-r--r--tests/qtest/stm32l4x5_usart-test.c66
-rw-r--r--tests/qtest/tmp105-test.c4
-rw-r--r--tests/qtest/tpm-tests.c2
-rw-r--r--tests/qtest/ufs-test.c384
-rw-r--r--tests/qtest/vhost-user-test.c2
-rw-r--r--tests/tcg/Makefile.target25
-rw-r--r--tests/tcg/README23
-rw-r--r--tests/tcg/aarch64/Makefile.softmmu-target51
-rw-r--r--tests/tcg/aarch64/Makefile.target3
-rw-r--r--tests/tcg/aarch64/gdbstub/test-mte.py75
-rw-r--r--tests/tcg/aarch64/system/boot.S11
-rw-r--r--tests/tcg/aarch64/system/kernel.ld33
-rw-r--r--tests/tcg/aarch64/system/mte.S109
-rw-r--r--tests/tcg/aarch64_be/Makefile.target17
-rw-r--r--tests/tcg/aarch64_be/hello.c35
-rw-r--r--tests/tcg/alpha/Makefile.softmmu-target4
-rw-r--r--tests/tcg/alpha/Makefile.target3
-rw-r--r--tests/tcg/arm/Makefile.softmmu-target2
-rw-r--r--tests/tcg/arm/Makefile.target2
-rw-r--r--tests/tcg/cris/.gdbinit11
-rw-r--r--tests/tcg/cris/Makefile.target62
-rw-r--r--tests/tcg/cris/README1
-rw-r--r--tests/tcg/cris/bare/check_addcv17.s65
-rw-r--r--tests/tcg/cris/bare/check_addi.s57
-rw-r--r--tests/tcg/cris/bare/check_addiv32.s62
-rw-r--r--tests/tcg/cris/bare/check_addm.s96
-rw-r--r--tests/tcg/cris/bare/check_addq.s47
-rw-r--r--tests/tcg/cris/bare/check_addr.s96
-rw-r--r--tests/tcg/cris/bare/check_addxc.s91
-rw-r--r--tests/tcg/cris/bare/check_addxm.s106
-rw-r--r--tests/tcg/cris/bare/check_addxr.s96
-rw-r--r--tests/tcg/cris/bare/check_andc.s80
-rw-r--r--tests/tcg/cris/bare/check_andm.s90
-rw-r--r--tests/tcg/cris/bare/check_andq.s46
-rw-r--r--tests/tcg/cris/bare/check_andr.s95
-rw-r--r--tests/tcg/cris/bare/check_asr.s230
-rw-r--r--tests/tcg/cris/bare/check_ba.s93
-rw-r--r--tests/tcg/cris/bare/check_bas.s102
-rw-r--r--tests/tcg/cris/bare/check_bcc.s197
-rw-r--r--tests/tcg/cris/bare/check_boundc.s101
-rw-r--r--tests/tcg/cris/bare/check_boundr.s125
-rw-r--r--tests/tcg/cris/bare/check_btst.s96
-rw-r--r--tests/tcg/cris/bare/check_clearfv32.s19
-rw-r--r--tests/tcg/cris/bare/check_clrjmp1.s36
-rw-r--r--tests/tcg/cris/bare/check_cmp-2.s15
-rw-r--r--tests/tcg/cris/bare/check_cmpc.s86
-rw-r--r--tests/tcg/cris/bare/check_cmpm.s96
-rw-r--r--tests/tcg/cris/bare/check_cmpq.s75
-rw-r--r--tests/tcg/cris/bare/check_cmpr.s102
-rw-r--r--tests/tcg/cris/bare/check_cmpxc.s92
-rw-r--r--tests/tcg/cris/bare/check_cmpxm.s106
-rw-r--r--tests/tcg/cris/bare/check_dstep.s42
-rw-r--r--tests/tcg/cris/bare/check_jsr.s85
-rw-r--r--tests/tcg/cris/bare/check_lapc.s78
-rw-r--r--tests/tcg/cris/bare/check_lsl.s217
-rw-r--r--tests/tcg/cris/bare/check_lsr.s218
-rw-r--r--tests/tcg/cris/bare/check_mcp.s49
-rw-r--r--tests/tcg/cris/bare/check_movdelsr1.s33
-rw-r--r--tests/tcg/cris/bare/check_movecr.s37
-rw-r--r--tests/tcg/cris/bare/check_movei.s50
-rw-r--r--tests/tcg/cris/bare/check_movemr.s78
-rw-r--r--tests/tcg/cris/bare/check_movemrv32.s96
-rw-r--r--tests/tcg/cris/bare/check_mover.s28
-rw-r--r--tests/tcg/cris/bare/check_moverm.s45
-rw-r--r--tests/tcg/cris/bare/check_movmp.s131
-rw-r--r--tests/tcg/cris/bare/check_movpmv32.s35
-rw-r--r--tests/tcg/cris/bare/check_movpr.s28
-rw-r--r--tests/tcg/cris/bare/check_movprv32.s21
-rw-r--r--tests/tcg/cris/bare/check_movscr.s29
-rw-r--r--tests/tcg/cris/bare/check_movsm.s44
-rw-r--r--tests/tcg/cris/bare/check_movsr.s46
-rw-r--r--tests/tcg/cris/bare/check_movucr.s33
-rw-r--r--tests/tcg/cris/bare/check_movum.s40
-rw-r--r--tests/tcg/cris/bare/check_movur.s45
-rw-r--r--tests/tcg/cris/bare/check_mulv32.s51
-rw-r--r--tests/tcg/cris/bare/check_mulx.s257
-rw-r--r--tests/tcg/cris/bare/check_neg.s104
-rw-r--r--tests/tcg/cris/bare/check_not.s31
-rw-r--r--tests/tcg/cris/bare/check_orc.s71
-rw-r--r--tests/tcg/cris/bare/check_orm.s75
-rw-r--r--tests/tcg/cris/bare/check_orq.s41
-rw-r--r--tests/tcg/cris/bare/check_orr.s84
-rw-r--r--tests/tcg/cris/bare/check_ret.s25
-rw-r--r--tests/tcg/cris/bare/check_scc.s95
-rw-r--r--tests/tcg/cris/bare/check_subc.s87
-rw-r--r--tests/tcg/cris/bare/check_subm.s96
-rw-r--r--tests/tcg/cris/bare/check_subq.s52
-rw-r--r--tests/tcg/cris/bare/check_subr.s102
-rw-r--r--tests/tcg/cris/bare/check_xarith.s72
-rw-r--r--tests/tcg/cris/bare/crt.s13
-rw-r--r--tests/tcg/cris/bare/sys.c63
-rw-r--r--tests/tcg/cris/bare/testutils.inc117
-rw-r--r--tests/tcg/cris/libc/check_abs.c40
-rw-r--r--tests/tcg/cris/libc/check_addc.c58
-rw-r--r--tests/tcg/cris/libc/check_addcm.c85
-rw-r--r--tests/tcg/cris/libc/check_addo.c125
-rw-r--r--tests/tcg/cris/libc/check_addoq.c44
-rw-r--r--tests/tcg/cris/libc/check_bound.c142
-rw-r--r--tests/tcg/cris/libc/check_ftag.c37
-rw-r--r--tests/tcg/cris/libc/check_gcctorture_pr28634-1.c15
-rw-r--r--tests/tcg/cris/libc/check_gcctorture_pr28634.c15
-rw-r--r--tests/tcg/cris/libc/check_glibc_kernelversion.c116
-rw-r--r--tests/tcg/cris/libc/check_hello.c7
-rw-r--r--tests/tcg/cris/libc/check_int64.c47
-rw-r--r--tests/tcg/cris/libc/check_lz.c49
-rw-r--r--tests/tcg/cris/libc/check_mapbrk.c39
-rw-r--r--tests/tcg/cris/libc/check_mmap1.c48
-rw-r--r--tests/tcg/cris/libc/check_mmap2.c48
-rw-r--r--tests/tcg/cris/libc/check_mmap3.c33
-rw-r--r--tests/tcg/cris/libc/check_moveq.c51
-rw-r--r--tests/tcg/cris/libc/check_openpf1.c38
-rw-r--r--tests/tcg/cris/libc/check_openpf2.c16
-rw-r--r--tests/tcg/cris/libc/check_openpf3.c49
-rw-r--r--tests/tcg/cris/libc/check_openpf5.c56
-rw-r--r--tests/tcg/cris/libc/check_settls1.c45
-rw-r--r--tests/tcg/cris/libc/check_sigalrm.c26
-rw-r--r--tests/tcg/cris/libc/check_stat1.c16
-rw-r--r--tests/tcg/cris/libc/check_stat2.c20
-rw-r--r--tests/tcg/cris/libc/check_stat3.c25
-rw-r--r--tests/tcg/cris/libc/check_stat4.c27
-rw-r--r--tests/tcg/cris/libc/check_swap.c76
-rw-r--r--tests/tcg/cris/libc/check_time2.c18
-rw-r--r--tests/tcg/cris/libc/crisutils.h76
-rw-r--r--tests/tcg/cris/libc/sys.h18
-rw-r--r--tests/tcg/hexagon/usr.c12
-rw-r--r--tests/tcg/i386/Makefile.softmmu-target2
-rw-r--r--tests/tcg/loongarch64/Makefile.softmmu-target4
-rw-r--r--tests/tcg/loongarch64/system/regdef.h2
-rw-r--r--tests/tcg/multiarch/Makefile.target11
-rwxr-xr-xtests/tcg/multiarch/check-plugin-output.sh36
-rw-r--r--tests/tcg/multiarch/gdbstub/test-proc-mappings.py17
-rw-r--r--tests/tcg/multiarch/system/Makefile.softmmu-target6
-rw-r--r--tests/tcg/multiarch/system/memory.c123
-rwxr-xr-xtests/tcg/multiarch/system/validate-memory-counts.py130
-rw-r--r--tests/tcg/multiarch/test-plugin-mem-access.c177
-rw-r--r--tests/tcg/plugins/bb.c (renamed from tests/plugin/bb.c)0
-rw-r--r--tests/tcg/plugins/empty.c (renamed from tests/plugin/empty.c)0
-rw-r--r--tests/tcg/plugins/inline.c (renamed from tests/plugin/inline.c)58
-rw-r--r--tests/tcg/plugins/insn.c (renamed from tests/plugin/insn.c)0
-rw-r--r--tests/tcg/plugins/mem.c405
-rw-r--r--tests/tcg/plugins/meson.build (renamed from tests/plugin/meson.build)6
-rw-r--r--tests/tcg/plugins/syscall.c (renamed from tests/plugin/syscall.c)116
-rw-r--r--tests/tcg/ppc64/Makefile.target17
-rw-r--r--tests/tcg/riscv64/Makefile.softmmu-target2
-rw-r--r--tests/tcg/s390x/Makefile.softmmu-target12
-rw-r--r--tests/tcg/s390x/Makefile.target1
-rw-r--r--tests/tcg/s390x/console.c3
-rw-r--r--tests/tcg/s390x/ex-smc.c57
-rw-r--r--tests/tcg/x86_64/Makefile.softmmu-target2
-rw-r--r--tests/tcg/x86_64/Makefile.target5
-rw-r--r--tests/tcg/x86_64/cross-modifying-code.c80
-rw-r--r--tests/tcg/x86_64/test-2175.c24
-rw-r--r--tests/unit/crypto-tls-psk-helpers.c1
-rw-r--r--tests/unit/crypto-tls-x509-helpers.c19
-rw-r--r--tests/unit/crypto-tls-x509-helpers.h9
-rw-r--r--tests/unit/meson.build13
-rw-r--r--tests/unit/pkix_asn1_tab.c.inc (renamed from tests/unit/pkix_asn1_tab.c)5
-rw-r--r--tests/unit/ptimer-test.c33
-rw-r--r--tests/unit/test-bdrv-drain.c2
-rw-r--r--tests/unit/test-block-iothread.c2
-rw-r--r--tests/unit/test-char.c32
-rw-r--r--tests/unit/test-crypto-afsplit.c10
-rw-r--r--tests/unit/test-crypto-akcipher.c54
-rw-r--r--tests/unit/test-crypto-block.c58
-rw-r--r--tests/unit/test-crypto-cipher.c66
-rw-r--r--tests/unit/test-crypto-hash.c95
-rw-r--r--tests/unit/test-crypto-hmac.c22
-rw-r--r--tests/unit/test-crypto-ivgen.c38
-rw-r--r--tests/unit/test-crypto-pbkdf.c57
-rw-r--r--tests/unit/test-crypto-tlssession.c30
-rw-r--r--tests/unit/test-fifo.c449
-rw-r--r--tests/unit/test-io-channel-socket.c6
-rw-r--r--tests/unit/test-qobject-input-visitor.c4
-rw-r--r--tests/unit/test-qobject-output-visitor.c4
-rw-r--r--tests/unit/test-xs-node.c4
-rwxr-xr-xtests/vm/freebsd6
-rw-r--r--tests/vm/generated/freebsd.json15
-rwxr-xr-xtests/vm/openbsd5
-rw-r--r--tools/i386/qemu-vmsr-helper.c540
-rw-r--r--tools/i386/rapl-msr-index.h28
-rw-r--r--ui/clipboard.c2
-rw-r--r--ui/console-vc.c6
-rw-r--r--ui/console.c83
-rw-r--r--ui/curses.c2
-rw-r--r--ui/cursor.c26
-rw-r--r--ui/dbus-clipboard.c4
-rw-r--r--ui/dbus-console.c23
-rw-r--r--ui/dbus-display1.xml49
-rw-r--r--ui/dbus-listener.c159
-rw-r--r--ui/dbus.c8
-rw-r--r--ui/egl-context.c2
-rw-r--r--ui/egl-headless.c2
-rw-r--r--ui/egl-helpers.c12
-rw-r--r--ui/gtk.c6
-rw-r--r--ui/input.c36
-rw-r--r--ui/qemu-pixman.c72
-rw-r--r--ui/sdl2-gl.c8
-rw-r--r--ui/sdl2-input.c5
-rw-r--r--ui/sdl2.c21
-rw-r--r--ui/spice-core.c2
-rw-r--r--ui/trace-events6
-rw-r--r--ui/vdagent.c11
-rw-r--r--ui/vnc-auth-sasl.c75
-rw-r--r--ui/vnc.c11
-rw-r--r--ui/vnc.h5
-rw-r--r--util/aio-posix.c1
-rw-r--r--util/aio-win32.c1
-rw-r--r--util/async.c3
-rw-r--r--util/block-helpers.c28
-rw-r--r--util/block-helpers.h3
-rw-r--r--util/cpuinfo-aarch64.c9
-rw-r--r--util/cpuinfo-ppc.c5
-rw-r--r--util/cpuinfo-riscv.c35
-rw-r--r--util/cutils.c5
-rw-r--r--util/envlist.c69
-rw-r--r--util/fdmon-epoll.c1
-rw-r--r--util/fifo8.c84
-rw-r--r--util/getauxval.c9
-rw-r--r--util/hbitmap.c2
-rw-r--r--util/iov.c25
-rw-r--r--util/iova-tree.c23
-rw-r--r--util/lockcnt.c1
-rw-r--r--util/memfd.c9
-rw-r--r--util/module.c2
-rw-r--r--util/oslib-posix.c124
-rw-r--r--util/qemu-co-shared-resource.c6
-rw-r--r--util/qemu-coroutine.c2
-rw-r--r--util/qemu-sockets.c36
-rw-r--r--util/qemu-timer.c30
-rw-r--r--util/timed-average.c4
-rw-r--r--util/userfaultfd.c49
2312 files changed, 57924 insertions, 81944 deletions
diff --git a/.gitattributes b/.gitattributes
index a217cb7..6dc6383 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -2,3 +2,6 @@
*.h.inc diff=c
*.m diff=objc
*.py diff=python
+*.rs diff=rust
+*.rs.inc diff=rust
+Cargo.lock diff=toml merge=binary
diff --git a/.gitlab-ci.d/base.yml b/.gitlab-ci.d/base.yml
index bf3d8ef..25b88aa 100644
--- a/.gitlab-ci.d/base.yml
+++ b/.gitlab-ci.d/base.yml
@@ -128,7 +128,7 @@ variables:
when: manual
# Jobs can run if any jobs they depend on were successful
- - if: '$QEMU_JOB_SKIPPED && $CI_PROJECT_NAMESPACE == $QEMU_CI_UPSTREAM && $CI_COMMIT_BRANCH =~ /staging-[[:digit:]]+\.[[:digit:]]/'
+ - if: '$CI_PROJECT_NAMESPACE == $QEMU_CI_UPSTREAM && $CI_COMMIT_BRANCH =~ /staging-[[:digit:]]+\.[[:digit:]]/'
when: on_success
variables:
QEMU_CI_CONTAINER_TAG: $CI_COMMIT_REF_SLUG
diff --git a/.gitlab-ci.d/buildtest-template.yml b/.gitlab-ci.d/buildtest-template.yml
index 8f7ebfa..8c69c60 100644
--- a/.gitlab-ci.d/buildtest-template.yml
+++ b/.gitlab-ci.d/buildtest-template.yml
@@ -8,7 +8,11 @@
key: "$CI_JOB_NAME"
when: always
before_script:
+ - source scripts/ci/gitlab-ci-section
+ - section_start setup "Pre-script setup"
- JOBS=$(expr $(nproc) + 1)
+ - cat /packages.txt
+ - section_end setup
script:
- export CCACHE_BASEDIR="$(pwd)"
- export CCACHE_DIR="$CCACHE_BASEDIR/ccache"
@@ -18,6 +22,7 @@
- mkdir build
- cd build
- ccache --zero-stats
+ - section_start configure "Running configure"
- ../configure --enable-werror --disable-docs --enable-fdt=system
${TARGETS:+--target-list="$TARGETS"}
$CONFIGURE_ARGS ||
@@ -26,11 +31,16 @@
then
pyvenv/bin/meson configure . -Dbackend_max_links="$LD_JOBS" ;
fi || exit 1;
+ - section_end configure
+ - section_start build "Building QEMU"
- $MAKE -j"$JOBS"
+ - section_end build
+ - section_start test "Running tests"
- if test -n "$MAKE_CHECK_ARGS";
then
$MAKE -j"$JOBS" $MAKE_CHECK_ARGS ;
fi
+ - section_end test
- ccache --show-stats
# We jump some hoops in common_test_job_template to avoid
@@ -53,12 +63,21 @@
stage: test
image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:$QEMU_CI_CONTAINER_TAG
script:
+ - source scripts/ci/gitlab-ci-section
+ - section_start buildenv "Setting up to run tests"
- scripts/git-submodule.sh update roms/SLOF
- meson subprojects download $(cd build/subprojects && echo *)
- cd build
- find . -type f -exec touch {} +
# Avoid recompiling by hiding ninja with NINJA=":"
+ # We also have to pre-cache the functional tests manually in this case
+ - if [ "x${QEMU_TEST_CACHE_DIR}" != "x" ]; then
+ $MAKE precache-functional ;
+ fi
+ - section_end buildenv
+ - section_start test "Running tests"
- $MAKE NINJA=":" $MAKE_CHECK_ARGS
+ - section_end test
.native_test_job_template:
extends: .common_test_job_template
@@ -71,12 +90,13 @@
reports:
junit: build/meson-logs/testlog.junit.xml
-.avocado_test_job_template:
+.functional_test_job_template:
extends: .common_test_job_template
cache:
key: "${CI_JOB_NAME}-cache"
paths:
- ${CI_PROJECT_DIR}/avocado-cache
+ - ${CI_PROJECT_DIR}/functional-cache
policy: pull-push
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
@@ -85,6 +105,7 @@
paths:
- build/tests/results/latest/results.xml
- build/tests/results/latest/test-results
+ - build/tests/functional/*/*/*.log
reports:
junit: build/tests/results/latest/results.xml
before_script:
@@ -95,11 +116,13 @@
- echo -e '[job.output.testlogs]\nstatuses = ["FAIL", "INTERRUPT"]'
>> ~/.config/avocado/avocado.conf
- if [ -d ${CI_PROJECT_DIR}/avocado-cache ]; then
- du -chs ${CI_PROJECT_DIR}/avocado-cache ;
+ du -chs ${CI_PROJECT_DIR}/*-cache ;
fi
- export AVOCADO_ALLOW_UNTRUSTED_CODE=1
+ - export QEMU_TEST_ALLOW_UNTRUSTED_CODE=1
+ - export QEMU_TEST_CACHE_DIR=${CI_PROJECT_DIR}/functional-cache
after_script:
- cd build
- - du -chs ${CI_PROJECT_DIR}/avocado-cache
+ - du -chs ${CI_PROJECT_DIR}/*-cache
variables:
QEMU_JOB_AVOCADO: 1
diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml
index e3a0758..f0cbdf1 100644
--- a/.gitlab-ci.d/buildtest.yml
+++ b/.gitlab-ci.d/buildtest.yml
@@ -22,14 +22,14 @@ check-system-alpine:
IMAGE: alpine
MAKE_CHECK_ARGS: check-unit check-qtest
-avocado-system-alpine:
- extends: .avocado_test_job_template
+functional-system-alpine:
+ extends: .functional_test_job_template
needs:
- job: build-system-alpine
artifacts: true
variables:
IMAGE: alpine
- MAKE_CHECK_ARGS: check-avocado
+ MAKE_CHECK_ARGS: check-avocado check-functional
AVOCADO_TAGS: arch:avr arch:loongarch64 arch:mips64 arch:mipsel
build-system-ubuntu:
@@ -53,14 +53,14 @@ check-system-ubuntu:
IMAGE: ubuntu2204
MAKE_CHECK_ARGS: check
-avocado-system-ubuntu:
- extends: .avocado_test_job_template
+functional-system-ubuntu:
+ extends: .functional_test_job_template
needs:
- job: build-system-ubuntu
artifacts: true
variables:
IMAGE: ubuntu2204
- MAKE_CHECK_ARGS: check-avocado
+ MAKE_CHECK_ARGS: check-avocado check-functional
AVOCADO_TAGS: arch:alpha arch:microblazeel arch:mips64el
build-system-debian:
@@ -72,7 +72,7 @@ build-system-debian:
variables:
IMAGE: debian
CONFIGURE_ARGS: --with-coroutine=sigaltstack
- TARGETS: arm-softmmu i386-softmmu riscv64-softmmu sh4eb-softmmu
+ TARGETS: arm-softmmu i386-softmmu riscv64-softmmu sh4-softmmu
sparc-softmmu xtensa-softmmu
MAKE_CHECK_ARGS: check-build
@@ -85,14 +85,14 @@ check-system-debian:
IMAGE: debian
MAKE_CHECK_ARGS: check
-avocado-system-debian:
- extends: .avocado_test_job_template
+functional-system-debian:
+ extends: .functional_test_job_template
needs:
- job: build-system-debian
artifacts: true
variables:
IMAGE: debian
- MAKE_CHECK_ARGS: check-avocado
+ MAKE_CHECK_ARGS: check-avocado check-functional
AVOCADO_TAGS: arch:arm arch:i386 arch:riscv64 arch:sh4 arch:sparc arch:xtensa
crash-test-debian:
@@ -115,11 +115,24 @@ build-system-fedora:
job: amd64-fedora-container
variables:
IMAGE: fedora
- CONFIGURE_ARGS: --disable-gcrypt --enable-nettle --enable-docs
+ CONFIGURE_ARGS: --disable-gcrypt --enable-nettle --enable-docs --enable-crypto-afalg
TARGETS: microblaze-softmmu mips-softmmu
xtensa-softmmu m68k-softmmu riscv32-softmmu ppc-softmmu sparc64-softmmu
MAKE_CHECK_ARGS: check-build
+build-system-fedora-rust-nightly:
+ extends:
+ - .native_build_job_template
+ - .native_build_artifact_template
+ needs:
+ job: amd64-fedora-rust-nightly-container
+ variables:
+ IMAGE: fedora-rust-nightly
+ CONFIGURE_ARGS: --disable-docs --enable-rust
+ TARGETS: aarch64-softmmu
+ MAKE_CHECK_ARGS: check-build
+ allow_failure: true
+
check-system-fedora:
extends: .native_test_job_template
needs:
@@ -129,14 +142,14 @@ check-system-fedora:
IMAGE: fedora
MAKE_CHECK_ARGS: check
-avocado-system-fedora:
- extends: .avocado_test_job_template
+functional-system-fedora:
+ extends: .functional_test_job_template
needs:
- job: build-system-fedora
artifacts: true
variables:
IMAGE: fedora
- MAKE_CHECK_ARGS: check-avocado
+ MAKE_CHECK_ARGS: check-avocado check-functional
AVOCADO_TAGS: arch:microblaze arch:mips arch:xtensa arch:m68k
arch:riscv32 arch:ppc arch:sparc64
@@ -188,6 +201,7 @@ build-previous-qemu:
# Override the default flags as we need more to grab the old version
GIT_FETCH_EXTRA_FLAGS: --prune --quiet
before_script:
+ - source scripts/ci/gitlab-ci-section
- export QEMU_PREV_VERSION="$(sed 's/\([0-9.]*\)\.[0-9]*/v\1.0/' VERSION)"
- git remote add upstream https://gitlab.com/qemu-project/qemu
- git fetch upstream refs/tags/$QEMU_PREV_VERSION:refs/tags/$QEMU_PREV_VERSION
@@ -212,6 +226,14 @@ build-previous-qemu:
# testing an old QEMU against new features/tests that it is not
# compatible with.
- cd build-previous
+ # Don't allow python-based tests to run. The
+ # vmstate-checker-script test has a race that causes it to fail
+ # sometimes. It cannot be fixed it because this job runs the test
+ # from the old QEMU version. The test will be removed on master,
+ # but this job will only see the change in the next release.
+ #
+ # TODO: remove this line after 9.2 release
+ - unset PYTHON
# old to new
- QTEST_QEMU_BINARY_SRC=./qemu-system-${TARGET}
QTEST_QEMU_BINARY=../build/qemu-system-${TARGET} ./tests/qtest/migration-test
@@ -243,14 +265,14 @@ check-system-centos:
IMAGE: centos9
MAKE_CHECK_ARGS: check
-avocado-system-centos:
- extends: .avocado_test_job_template
+functional-system-centos:
+ extends: .functional_test_job_template
needs:
- job: build-system-centos
artifacts: true
variables:
IMAGE: centos9
- MAKE_CHECK_ARGS: check-avocado
+ MAKE_CHECK_ARGS: check-avocado check-functional
AVOCADO_TAGS: arch:ppc64 arch:or1k arch:s390x arch:x86_64 arch:rx
arch:sh4
@@ -274,14 +296,14 @@ check-system-opensuse:
IMAGE: opensuse-leap
MAKE_CHECK_ARGS: check
-avocado-system-opensuse:
- extends: .avocado_test_job_template
+functional-system-opensuse:
+ extends: .functional_test_job_template
needs:
- job: build-system-opensuse
artifacts: true
variables:
IMAGE: opensuse-leap
- MAKE_CHECK_ARGS: check-avocado
+ MAKE_CHECK_ARGS: check-avocado check-functional
AVOCADO_TAGS: arch:s390x arch:x86_64 arch:aarch64
#
@@ -302,15 +324,15 @@ build-system-flaky:
ppc64-softmmu rx-softmmu s390x-softmmu sh4-softmmu x86_64-softmmu
MAKE_CHECK_ARGS: check-build
-avocado-system-flaky:
- extends: .avocado_test_job_template
+functional-system-flaky:
+ extends: .functional_test_job_template
needs:
- job: build-system-flaky
artifacts: true
allow_failure: true
variables:
IMAGE: debian
- MAKE_CHECK_ARGS: check-avocado
+ MAKE_CHECK_ARGS: check-avocado check-functional
QEMU_JOB_OPTIONAL: 1
QEMU_TEST_FLAKY_TESTS: 1
AVOCADO_TAGS: flaky
@@ -345,6 +367,8 @@ build-tcg-disabled:
124 132 139 142 144 145 151 152 155 157 165 194 196 200 202
208 209 216 218 227 234 246 247 248 250 254 255 257 258
260 261 262 263 264 270 272 273 277 279 image-fleecing
+ - cd ../..
+ - make distclean
build-user:
extends: .native_build_job_template
@@ -428,9 +452,8 @@ clang-system:
job: amd64-fedora-container
variables:
IMAGE: fedora
- CONFIGURE_ARGS: --cc=clang --cxx=clang++
- --extra-cflags=-fsanitize=undefined --extra-cflags=-fno-sanitize-recover=undefined
- --extra-cflags=-fno-sanitize=function
+ CONFIGURE_ARGS: --cc=clang --cxx=clang++ --enable-ubsan
+ --extra-cflags=-fno-sanitize-recover=undefined
TARGETS: alpha-softmmu arm-softmmu m68k-softmmu mips64-softmmu s390x-softmmu
MAKE_CHECK_ARGS: check-qtest check-tcg
@@ -441,9 +464,9 @@ clang-user:
timeout: 70m
variables:
IMAGE: debian-all-test-cross
- CONFIGURE_ARGS: --cc=clang --cxx=clang++ --disable-system
+ CONFIGURE_ARGS: --cc=clang --cxx=clang++ --disable-system --enable-ubsan
--target-list-exclude=alpha-linux-user,microblazeel-linux-user,aarch64_be-linux-user,i386-linux-user,m68k-linux-user,mipsn32el-linux-user,xtensaeb-linux-user
- --extra-cflags=-fsanitize=undefined --extra-cflags=-fno-sanitize-recover=undefined
+ --extra-cflags=-fno-sanitize-recover=undefined
MAKE_CHECK_ARGS: check-unit check-tcg
# Set LD_JOBS=1 because this requires LTO and ld consumes a large amount of memory.
@@ -484,14 +507,14 @@ check-cfi-aarch64:
IMAGE: fedora
MAKE_CHECK_ARGS: check
-avocado-cfi-aarch64:
- extends: .avocado_test_job_template
+functional-cfi-aarch64:
+ extends: .functional_test_job_template
needs:
- job: build-cfi-aarch64
artifacts: true
variables:
IMAGE: fedora
- MAKE_CHECK_ARGS: check-avocado
+ MAKE_CHECK_ARGS: check-avocado check-functional
build-cfi-ppc64-s390x:
extends:
@@ -522,14 +545,14 @@ check-cfi-ppc64-s390x:
IMAGE: fedora
MAKE_CHECK_ARGS: check
-avocado-cfi-ppc64-s390x:
- extends: .avocado_test_job_template
+functional-cfi-ppc64-s390x:
+ extends: .functional_test_job_template
needs:
- job: build-cfi-ppc64-s390x
artifacts: true
variables:
IMAGE: fedora
- MAKE_CHECK_ARGS: check-avocado
+ MAKE_CHECK_ARGS: check-avocado check-functional
build-cfi-x86_64:
extends:
@@ -556,14 +579,14 @@ check-cfi-x86_64:
IMAGE: fedora
MAKE_CHECK_ARGS: check
-avocado-cfi-x86_64:
- extends: .avocado_test_job_template
+functional-cfi-x86_64:
+ extends: .functional_test_job_template
needs:
- job: build-cfi-x86_64
artifacts: true
variables:
IMAGE: fedora
- MAKE_CHECK_ARGS: check-avocado
+ MAKE_CHECK_ARGS: check-avocado check-functional
tsan-build:
extends: .native_build_job_template
@@ -618,12 +641,15 @@ build-oss-fuzz:
- CC="clang" CXX="clang++" CFLAGS="-fsanitize=address"
./scripts/oss-fuzz/build.sh
- export ASAN_OPTIONS="fast_unwind_on_malloc=0"
+ - failures=0
- for fuzzer in $(find ./build-oss-fuzz/DEST_DIR/ -executable -type f
| grep -v slirp); do
grep "LLVMFuzzerTestOneInput" ${fuzzer} > /dev/null 2>&1 || continue ;
echo Testing ${fuzzer} ... ;
- "${fuzzer}" -runs=1 -seed=1 || exit 1 ;
+ "${fuzzer}" -runs=1 -seed=1 || { echo "FAILED:"" ${fuzzer} exit code is $?"; failures=$(($failures+1)); };
done
+ - echo "Number of failures:"" $failures"
+ - test $failures = 0
build-tci:
extends: .native_build_job_template
@@ -650,9 +676,6 @@ build-tci:
- make check-tcg
# Check our reduced build configurations
-# requires libfdt: aarch64, arm, loongarch64, microblaze, microblazeel,
-# or1k, ppc64, riscv32, riscv64, rx
-# fails qtest without boards: i386, x86_64
build-without-defaults:
extends: .native_build_job_template
needs:
@@ -666,11 +689,7 @@ build-without-defaults:
--disable-pie
--disable-qom-cast-debug
--disable-strip
- TARGETS: alpha-softmmu avr-softmmu cris-softmmu hppa-softmmu m68k-softmmu
- mips-softmmu mips64-softmmu mipsel-softmmu mips64el-softmmu
- ppc-softmmu s390x-softmmu sh4-softmmu sh4eb-softmmu sparc-softmmu
- sparc64-softmmu tricore-softmmu xtensa-softmmu xtensaeb-softmmu
- hexagon-linux-user i386-linux-user s390x-linux-user
+ --target-list-exclude=aarch64-softmmu,microblaze-softmmu,mips64-softmmu,mipsel-softmmu,ppc64-softmmu,sh4el-softmmu,xtensa-softmmu,x86_64-softmmu
MAKE_CHECK_ARGS: check
build-libvhost-user:
diff --git a/.gitlab-ci.d/check-dco.py b/.gitlab-ci.d/check-dco.py
index 632c8bc..d221b16 100755
--- a/.gitlab-ci.d/check-dco.py
+++ b/.gitlab-ci.d/check-dco.py
@@ -19,10 +19,9 @@ cwd = os.getcwd()
reponame = os.path.basename(cwd)
repourl = "https://gitlab.com/%s/%s.git" % (namespace, reponame)
+print(f"adding upstream git repo @ {repourl}")
subprocess.check_call(["git", "remote", "add", "check-dco", repourl])
-subprocess.check_call(["git", "fetch", "check-dco", "master"],
- stdout=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL)
+subprocess.check_call(["git", "fetch", "check-dco", "master"])
ancestor = subprocess.check_output(["git", "merge-base",
"check-dco/master", "HEAD"],
diff --git a/.gitlab-ci.d/check-patch.py b/.gitlab-ci.d/check-patch.py
index 39e2b40..68c549a 100755
--- a/.gitlab-ci.d/check-patch.py
+++ b/.gitlab-ci.d/check-patch.py
@@ -19,13 +19,12 @@ cwd = os.getcwd()
reponame = os.path.basename(cwd)
repourl = "https://gitlab.com/%s/%s.git" % (namespace, reponame)
+print(f"adding upstream git repo @ {repourl}")
# GitLab CI environment does not give us any direct info about the
# base for the user's branch. We thus need to figure out a common
# ancestor between the user's branch and current git master.
subprocess.check_call(["git", "remote", "add", "check-patch", repourl])
-subprocess.check_call(["git", "fetch", "check-patch", "master"],
- stdout=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL)
+subprocess.check_call(["git", "fetch", "check-patch", "master"])
ancestor = subprocess.check_output(["git", "merge-base",
"check-patch/master", "HEAD"],
diff --git a/.gitlab-ci.d/cirrus.yml b/.gitlab-ci.d/cirrus.yml
index 75df127..5708c2b 100644
--- a/.gitlab-ci.d/cirrus.yml
+++ b/.gitlab-ci.d/cirrus.yml
@@ -46,27 +46,27 @@
variables:
QEMU_JOB_CIRRUS: 1
-x64-freebsd-13-build:
+x64-freebsd-14-build:
extends: .cirrus_build_job
variables:
- NAME: freebsd-13
+ NAME: freebsd-14
CIRRUS_VM_INSTANCE_TYPE: freebsd_instance
CIRRUS_VM_IMAGE_SELECTOR: image_family
- CIRRUS_VM_IMAGE_NAME: freebsd-13-3
+ CIRRUS_VM_IMAGE_NAME: freebsd-14-1
CIRRUS_VM_CPUS: 8
CIRRUS_VM_RAM: 8G
UPDATE_COMMAND: pkg update; pkg upgrade -y
INSTALL_COMMAND: pkg install -y
- CONFIGURE_ARGS: --target-list-exclude=arm-softmmu,i386-softmmu,microblaze-softmmu,mips64el-softmmu,mipsel-softmmu,mips-softmmu,ppc-softmmu,sh4eb-softmmu,xtensa-softmmu
+ CONFIGURE_ARGS: --target-list-exclude=arm-softmmu,i386-softmmu,microblaze-softmmu,mips64el-softmmu,mipsel-softmmu,mips-softmmu,ppc-softmmu,xtensa-softmmu
TEST_TARGETS: check
-aarch64-macos-13-base-build:
+aarch64-macos-14-base-build:
extends: .cirrus_build_job
variables:
- NAME: macos-13
+ NAME: macos-14
CIRRUS_VM_INSTANCE_TYPE: macos_instance
CIRRUS_VM_IMAGE_SELECTOR: image
- CIRRUS_VM_IMAGE_NAME: ghcr.io/cirruslabs/macos-ventura-base:latest
+ CIRRUS_VM_IMAGE_NAME: ghcr.io/cirruslabs/macos-sonoma-base:latest
CIRRUS_VM_CPUS: 12
CIRRUS_VM_RAM: 24G
UPDATE_COMMAND: brew update
@@ -76,13 +76,13 @@ aarch64-macos-13-base-build:
CONFIGURE_ARGS: --target-list-exclude=arm-softmmu,i386-softmmu,microblazeel-softmmu,mips64-softmmu,mipsel-softmmu,mips-softmmu,ppc-softmmu,sh4-softmmu,xtensaeb-softmmu
TEST_TARGETS: check-unit check-block check-qapi-schema check-softfloat check-qtest-x86_64
-aarch64-macos-14-base-build:
+aarch64-macos-15-base-build:
extends: .cirrus_build_job
variables:
- NAME: macos-14
+ NAME: macos-15
CIRRUS_VM_INSTANCE_TYPE: macos_instance
CIRRUS_VM_IMAGE_SELECTOR: image
- CIRRUS_VM_IMAGE_NAME: ghcr.io/cirruslabs/macos-sonoma-base:latest
+ CIRRUS_VM_IMAGE_NAME: ghcr.io/cirruslabs/macos-sequoia-base:latest
CIRRUS_VM_CPUS: 12
CIRRUS_VM_RAM: 24G
UPDATE_COMMAND: brew update
diff --git a/.gitlab-ci.d/cirrus/build.yml b/.gitlab-ci.d/cirrus/build.yml
index 43dd52d..102cdbd 100644
--- a/.gitlab-ci.d/cirrus/build.yml
+++ b/.gitlab-ci.d/cirrus/build.yml
@@ -26,7 +26,7 @@ build_task:
- git clone --depth 100 "$CI_REPOSITORY_URL" .
- git fetch origin "$CI_COMMIT_REF_NAME"
- git reset --hard "$CI_COMMIT_SHA"
- build_script:
+ step_script:
- mkdir build
- cd build
- ../configure --enable-werror $CONFIGURE_ARGS
diff --git a/.gitlab-ci.d/cirrus/freebsd-13.vars b/.gitlab-ci.d/cirrus/freebsd-13.vars
deleted file mode 100644
index 3785afc..0000000
--- a/.gitlab-ci.d/cirrus/freebsd-13.vars
+++ /dev/null
@@ -1,16 +0,0 @@
-# THIS FILE WAS AUTO-GENERATED
-#
-# $ lcitool variables freebsd-13 qemu
-#
-# https://gitlab.com/libvirt/libvirt-ci
-
-CCACHE='/usr/local/bin/ccache'
-CPAN_PKGS=''
-CROSS_PKGS=''
-MAKE='/usr/local/bin/gmake'
-NINJA='/usr/local/bin/ninja'
-PACKAGING_COMMAND='pkg'
-PIP3='/usr/local/bin/pip-3.8'
-PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson mtools ncurses nettle ninja opencv pixman pkgconf png py39-numpy py39-pillow py39-pip py39-sphinx py39-sphinx_rtd_theme py39-tomli py39-yaml python3 rpm2cpio sdl2 sdl2_image snappy sndio socat spice-protocol tesseract usbredir virglrenderer vte3 xorriso zstd'
-PYPI_PKGS=''
-PYTHON='/usr/local/bin/python3'
diff --git a/.gitlab-ci.d/cirrus/freebsd-14.vars b/.gitlab-ci.d/cirrus/freebsd-14.vars
new file mode 100644
index 0000000..c0655b2
--- /dev/null
+++ b/.gitlab-ci.d/cirrus/freebsd-14.vars
@@ -0,0 +1,16 @@
+# THIS FILE WAS AUTO-GENERATED
+#
+# $ lcitool variables freebsd-14 qemu
+#
+# https://gitlab.com/libvirt/libvirt-ci
+
+CCACHE='/usr/local/bin/ccache'
+CPAN_PKGS=''
+CROSS_PKGS=''
+MAKE='/usr/local/bin/gmake'
+NINJA='/usr/local/bin/ninja'
+PACKAGING_COMMAND='pkg'
+PIP3='/usr/local/bin/pip-3.8'
+PKGS='alsa-lib bash bison bzip2 ca_root_nss capstone4 ccache cmocka ctags curl cyrus-sasl dbus diffutils dtc flex fusefs-libs3 gettext git glib gmake gnutls gsed gtk-vnc gtk3 json-c libepoxy libffi libgcrypt libjpeg-turbo libnfs libslirp libspice-server libssh libtasn1 llvm lzo2 meson mtools ncurses nettle ninja opencv pixman pkgconf png py311-numpy py311-pillow py311-pip py311-pyyaml py311-sphinx py311-sphinx_rtd_theme py311-tomli python3 rpm2cpio sdl2 sdl2_image snappy sndio socat spice-protocol tesseract usbredir virglrenderer vte3 xorriso zstd'
+PYPI_PKGS=''
+PYTHON='/usr/local/bin/python3'
diff --git a/.gitlab-ci.d/cirrus/macos-14.vars b/.gitlab-ci.d/cirrus/macos-14.vars
index 43070f4..24cfec3 100644
--- a/.gitlab-ci.d/cirrus/macos-14.vars
+++ b/.gitlab-ci.d/cirrus/macos-14.vars
@@ -11,6 +11,6 @@ MAKE='/opt/homebrew/bin/gmake'
NINJA='/opt/homebrew/bin/ninja'
PACKAGING_COMMAND='brew'
PIP3='/opt/homebrew/bin/pip3'
-PKGS='bash bc bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo json-c libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson mtools ncurses nettle ninja pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy socat sparse spice-protocol swtpm tesseract usbredir vde vte3 xorriso zlib zstd'
+PKGS='bash bc bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 gtk-vnc jemalloc jpeg-turbo json-c libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson mtools ncurses nettle ninja pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy socat sparse spice-protocol swtpm tesseract usbredir vde vte3 xorriso zlib zstd'
PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme tomli'
PYTHON='/opt/homebrew/bin/python3'
diff --git a/.gitlab-ci.d/cirrus/macos-13.vars b/.gitlab-ci.d/cirrus/macos-15.vars
index 534f029..23b2c1d 100644
--- a/.gitlab-ci.d/cirrus/macos-13.vars
+++ b/.gitlab-ci.d/cirrus/macos-15.vars
@@ -1,6 +1,6 @@
# THIS FILE WAS AUTO-GENERATED
#
-# $ lcitool variables macos-13 qemu
+# $ lcitool variables macos-15 qemu
#
# https://gitlab.com/libvirt/libvirt-ci
@@ -11,6 +11,6 @@ MAKE='/opt/homebrew/bin/gmake'
NINJA='/opt/homebrew/bin/ninja'
PACKAGING_COMMAND='brew'
PIP3='/opt/homebrew/bin/pip3'
-PKGS='bash bc bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo json-c libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson mtools ncurses nettle ninja pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy socat sparse spice-protocol swtpm tesseract usbredir vde vte3 xorriso zlib zstd'
+PKGS='bash bc bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 gtk-vnc jemalloc jpeg-turbo json-c libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson mtools ncurses nettle ninja pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy socat sparse spice-protocol swtpm tesseract usbredir vde vte3 xorriso zlib zstd'
PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme tomli'
PYTHON='/opt/homebrew/bin/python3'
diff --git a/.gitlab-ci.d/container-cross.yml b/.gitlab-ci.d/container-cross.yml
index e310394..34c0e72 100644
--- a/.gitlab-ci.d/container-cross.yml
+++ b/.gitlab-ci.d/container-cross.yml
@@ -22,12 +22,6 @@ arm64-debian-cross-container:
variables:
NAME: debian-arm64-cross
-armel-debian-cross-container:
- extends: .container_job_template
- stage: containers
- variables:
- NAME: debian-armel-cross
-
armhf-debian-cross-container:
extends: .container_job_template
stage: containers
@@ -96,11 +90,6 @@ xtensa-debian-cross-container:
variables:
NAME: debian-xtensa-cross
-cris-fedora-cross-container:
- extends: .container_job_template
- variables:
- NAME: fedora-cris-cross
-
win64-fedora-cross-container:
extends: .container_job_template
variables:
diff --git a/.gitlab-ci.d/containers.yml b/.gitlab-ci.d/containers.yml
index ae79d4c..db9b4d5 100644
--- a/.gitlab-ci.d/containers.yml
+++ b/.gitlab-ci.d/containers.yml
@@ -27,3 +27,9 @@ python-container:
extends: .container_job_template
variables:
NAME: python
+
+amd64-fedora-rust-nightly-container:
+ extends: .container_job_template
+ variables:
+ NAME: fedora-rust-nightly
+ allow_failure: true
diff --git a/.gitlab-ci.d/crossbuild-template.yml b/.gitlab-ci.d/crossbuild-template.yml
index d9f81b7..45a9810 100644
--- a/.gitlab-ci.d/crossbuild-template.yml
+++ b/.gitlab-ci.d/crossbuild-template.yml
@@ -8,6 +8,12 @@
key: "$CI_JOB_NAME"
when: always
timeout: 80m
+ before_script:
+ - source scripts/ci/gitlab-ci-section
+ - section_start setup "Pre-script setup"
+ - JOBS=$(expr $(nproc) + 1)
+ - cat /packages.txt
+ - section_end setup
script:
- export CCACHE_BASEDIR="$(pwd)"
- export CCACHE_DIR="$CCACHE_BASEDIR/ccache"
@@ -16,18 +22,30 @@
- mkdir build
- cd build
- ccache --zero-stats
+ - section_start configure "Running configure"
- ../configure --enable-werror --disable-docs --enable-fdt=system
--disable-user $QEMU_CONFIGURE_OPTS $EXTRA_CONFIGURE_OPTS
- --target-list-exclude="arm-softmmu cris-softmmu
+ --target-list-exclude="arm-softmmu
i386-softmmu microblaze-softmmu mips-softmmu mipsel-softmmu
mips64-softmmu ppc-softmmu riscv32-softmmu sh4-softmmu
sparc-softmmu xtensa-softmmu $CROSS_SKIP_TARGETS"
- - make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS
+ - section_end configure
+ - section_start build "Building QEMU"
+ - make -j"$JOBS" all check-build
+ - section_end build
+ - section_start test "Running tests"
+ - if test -n "$MAKE_CHECK_ARGS";
+ then
+ $MAKE -j"$JOBS" $MAKE_CHECK_ARGS ;
+ fi
+ - section_end test
+ - section_start installer "Building the installer"
- if grep -q "EXESUF=.exe" config-host.mak;
then make installer;
version="$(git describe --match v[0-9]* 2>/dev/null || git rev-parse --short HEAD)";
mv -v qemu-setup*.exe qemu-setup-${version}.exe;
fi
+ - section_end installer
- ccache --show-stats
# Job to cross-build specific accelerators.
@@ -44,6 +62,9 @@
paths:
- ccache/
key: "$CI_JOB_NAME"
+ before_script:
+ - source scripts/ci/gitlab-ci-section
+ - JOBS=$(expr $(nproc) + 1)
script:
- export CCACHE_BASEDIR="$(pwd)"
- export CCACHE_DIR="$CCACHE_BASEDIR/ccache"
@@ -51,9 +72,19 @@
- export PATH="$CCACHE_WRAPPERSDIR:$PATH"
- mkdir build
- cd build
+ - section_start configure "Running configure"
- ../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS
--disable-tools --enable-${ACCEL:-kvm} $EXTRA_CONFIGURE_OPTS
- - make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS
+ - section_end configure
+ - section_start build "Building QEMU"
+ - make -j"$JOBS" all check-build
+ - section_end build
+ - section_start test "Running tests"
+ - if test -n "$MAKE_CHECK_ARGS";
+ then
+ $MAKE -j"$JOBS" $MAKE_CHECK_ARGS ;
+ fi
+ - section_end test
.cross_user_build_job:
extends: .base_job_template
@@ -63,18 +94,31 @@
paths:
- ccache/
key: "$CI_JOB_NAME"
+ before_script:
+ - source scripts/ci/gitlab-ci-section
+ - JOBS=$(expr $(nproc) + 1)
script:
- export CCACHE_BASEDIR="$(pwd)"
- export CCACHE_DIR="$CCACHE_BASEDIR/ccache"
- export CCACHE_MAXSIZE="500M"
- mkdir build
- cd build
+ - section_start configure "Running configure"
- ../configure --enable-werror --disable-docs $QEMU_CONFIGURE_OPTS
--disable-system --target-list-exclude="aarch64_be-linux-user
- alpha-linux-user cris-linux-user m68k-linux-user microblazeel-linux-user
+ alpha-linux-user m68k-linux-user microblazeel-linux-user
or1k-linux-user ppc-linux-user sparc-linux-user
xtensa-linux-user $CROSS_SKIP_TARGETS"
- - make -j$(expr $(nproc) + 1) all check-build $MAKE_CHECK_ARGS
+ - section_end configure
+ - section_start build "Building QEMU"
+ - make -j"$JOBS" all check-build
+ - section_end build
+ - section_start test "Running tests"
+ - if test -n "$MAKE_CHECK_ARGS";
+ then
+ $MAKE -j"$JOBS" $MAKE_CHECK_ARGS ;
+ fi
+ - section_end test
# We can still run some tests on some of our cross build jobs. They can add this
# template to their extends to save the build logs and test results
diff --git a/.gitlab-ci.d/crossbuilds.yml b/.gitlab-ci.d/crossbuilds.yml
index cb499e4..178f628 100644
--- a/.gitlab-ci.d/crossbuilds.yml
+++ b/.gitlab-ci.d/crossbuilds.yml
@@ -1,13 +1,6 @@
include:
- local: '/.gitlab-ci.d/crossbuild-template.yml'
-cross-armel-user:
- extends: .cross_user_build_job
- needs:
- job: armel-debian-cross-container
- variables:
- IMAGE: debian-armel-cross
-
cross-armhf-user:
extends: .cross_user_build_job
needs:
@@ -69,7 +62,11 @@ cross-i686-tci:
IMAGE: debian-i686-cross
ACCEL: tcg-interpreter
EXTRA_CONFIGURE_OPTS: --target-list=i386-softmmu,i386-linux-user,aarch64-softmmu,aarch64-linux-user,ppc-softmmu,ppc-linux-user --disable-plugins --disable-kvm
- MAKE_CHECK_ARGS: check check-tcg
+ # Force tests to run with reduced parallelism, to see whether this
+ # reduces the flakiness of this CI job. The CI
+ # environment by default shows us 8 CPUs and so we
+ # would otherwise be using a parallelism of 9.
+ MAKE_CHECK_ARGS: check check-tcg -j2
cross-mipsel-system:
extends: .cross_system_build_job
@@ -179,7 +176,7 @@ cross-win64-system:
EXTRA_CONFIGURE_OPTS: --enable-fdt=internal --disable-plugins
CROSS_SKIP_TARGETS: alpha-softmmu avr-softmmu hppa-softmmu
m68k-softmmu microblazeel-softmmu
- or1k-softmmu rx-softmmu sh4eb-softmmu sparc64-softmmu
+ or1k-softmmu rx-softmmu sh4-softmmu sparc64-softmmu
tricore-softmmu xtensaeb-softmmu
artifacts:
when: on_success
diff --git a/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml b/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml
index 263a3c2..ca2f140 100644
--- a/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml
+++ b/.gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml
@@ -103,7 +103,7 @@ ubuntu-22.04-aarch64-clang:
script:
- mkdir build
- cd build
- - ../configure --disable-libssh --cc=clang --cxx=clang++ --enable-sanitizers
+ - ../configure --disable-libssh --cc=clang --cxx=clang++ --enable-ubsan
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
- make --output-sync -j`nproc --ignore=40`
- make --output-sync -j`nproc --ignore=40` check
diff --git a/.gitlab-ci.d/custom-runners/ubuntu-22.04-s390x.yml b/.gitlab-ci.d/custom-runners/ubuntu-22.04-s390x.yml
index 69ddd3e..ca374ac 100644
--- a/.gitlab-ci.d/custom-runners/ubuntu-22.04-s390x.yml
+++ b/.gitlab-ci.d/custom-runners/ubuntu-22.04-s390x.yml
@@ -80,7 +80,7 @@ ubuntu-22.04-s390x-clang:
script:
- mkdir build
- cd build
- - ../configure --cc=clang --cxx=clang++ --enable-sanitizers
+ - ../configure --cc=clang --cxx=clang++ --enable-ubsan
|| { cat config.log meson-logs/meson-log.txt; exit 1; }
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check
diff --git a/.gitlab-ci.d/windows.yml b/.gitlab-ci.d/windows.yml
index a83f23a..45ed0c9 100644
--- a/.gitlab-ci.d/windows.yml
+++ b/.gitlab-ci.d/windows.yml
@@ -17,12 +17,7 @@ msys2-64bit:
# This feature doesn't (currently) work with PowerShell, it stops
# the echo'ing of commands being run and doesn't show any timing
FF_SCRIPT_SECTIONS: 0
- # do not remove "--without-default-devices"!
- # commit 9f8e6cad65a6 ("gitlab-ci: Speed up the msys2-64bit job by using --without-default-devices"
- # changed to compile QEMU with the --without-default-devices switch
- # for this job, because otherwise the build could not complete within
- # the project timeout.
- CONFIGURE_ARGS: --target-list=sparc-softmmu --without-default-devices -Ddebug=false -Doptimization=0
+ CONFIGURE_ARGS: --disable-system --enable-tools -Ddebug=false -Doptimization=0
# The Windows git is a bit older so override the default
GIT_FETCH_EXTRA_FLAGS: --no-tags --prune --quiet
artifacts:
@@ -81,35 +76,19 @@ msys2-64bit:
bison diffutils flex
git grep make sed
mingw-w64-x86_64-binutils
- mingw-w64-x86_64-capstone
mingw-w64-x86_64-ccache
mingw-w64-x86_64-curl
- mingw-w64-x86_64-cyrus-sasl
- mingw-w64-x86_64-dtc
mingw-w64-x86_64-gcc
mingw-w64-x86_64-glib2
- mingw-w64-x86_64-gnutls
- mingw-w64-x86_64-gtk3
- mingw-w64-x86_64-libgcrypt
- mingw-w64-x86_64-libjpeg-turbo
mingw-w64-x86_64-libnfs
- mingw-w64-x86_64-libpng
mingw-w64-x86_64-libssh
- mingw-w64-x86_64-libtasn1
- mingw-w64-x86_64-libusb
- mingw-w64-x86_64-lzo2
- mingw-w64-x86_64-nettle
mingw-w64-x86_64-ninja
mingw-w64-x86_64-pixman
mingw-w64-x86_64-pkgconf
mingw-w64-x86_64-python
- mingw-w64-x86_64-SDL2
- mingw-w64-x86_64-SDL2_image
- mingw-w64-x86_64-snappy
- mingw-w64-x86_64-spice
- mingw-w64-x86_64-usbredir
mingw-w64-x86_64-zstd"
- Write-Output "Running build at $(Get-Date -Format u)"
+ - $env:JOBS = $(.\msys64\usr\bin\bash -lc nproc)
- $env:CHERE_INVOKING = 'yes' # Preserve the current working directory
- $env:MSYS = 'winsymlinks:native' # Enable native Windows symlink
- $env:CCACHE_BASEDIR = "$env:CI_PROJECT_DIR"
@@ -120,8 +99,8 @@ msys2-64bit:
- mkdir build
- cd build
- ..\msys64\usr\bin\bash -lc "ccache --zero-stats"
- - ..\msys64\usr\bin\bash -lc "../configure --enable-fdt=system $CONFIGURE_ARGS"
- - ..\msys64\usr\bin\bash -lc "make"
+ - ..\msys64\usr\bin\bash -lc "../configure $CONFIGURE_ARGS"
+ - ..\msys64\usr\bin\bash -lc "make -j$env:JOBS"
- ..\msys64\usr\bin\bash -lc "make check MTESTARGS='$TEST_ARGS' || { cat meson-logs/testlog.txt; exit 1; } ;"
- ..\msys64\usr\bin\bash -lc "ccache --show-stats"
- Write-Output "Finished build at $(Get-Date -Format u)"
diff --git a/.travis.yml b/.travis.yml
index 8fc1ae0..ad81bc5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -223,7 +223,7 @@ jobs:
- genisoimage
env:
- CONFIG="--disable-containers --audio-drv-list=sdl --disable-user
- --target-list=arm-softmmu,avr-softmmu,microblaze-softmmu,sh4eb-softmmu,sparc64-softmmu,xtensaeb-softmmu"
+ --target-list=arm-softmmu,avr-softmmu,microblaze-softmmu,sh4-softmmu,sparc64-softmmu,xtensaeb-softmmu"
- name: "[s390x] GCC (user)"
arch: s390x
diff --git a/Kconfig b/Kconfig
index fb6a24a..63ca7f4 100644
--- a/Kconfig
+++ b/Kconfig
@@ -4,3 +4,4 @@ source accel/Kconfig
source target/Kconfig
source hw/Kconfig
source semihosting/Kconfig
+source rust/Kconfig
diff --git a/Kconfig.host b/Kconfig.host
index 17f4050..4ade789 100644
--- a/Kconfig.host
+++ b/Kconfig.host
@@ -52,3 +52,6 @@ config VFIO_USER_SERVER_ALLOWED
config HV_BALLOON_POSSIBLE
bool
+
+config HAVE_RUST
+ bool
diff --git a/MAINTAINERS b/MAINTAINERS
index 7d98114..f48d914 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -140,6 +140,7 @@ F: docs/system/target-i386*
F: target/i386/*.[ch]
F: target/i386/Kconfig
F: target/i386/meson.build
+F: tools/i386/
Guest CPU cores (TCG)
---------------------
@@ -221,16 +222,7 @@ S: Maintained
F: docs/system/target-avr.rst
F: gdb-xml/avr-cpu.xml
F: target/avr/
-F: tests/avocado/machine_avr6.py
-
-CRIS TCG CPUs
-M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
-S: Maintained
-F: target/cris/
-F: hw/cris/
-F: include/hw/cris/
-F: tests/tcg/cris/
-F: disas/cris.c
+F: tests/functional/test_avr_mega2560.py
Hexagon TCG CPUs
M: Brian Cain <bcain@quicinc.com>
@@ -244,6 +236,7 @@ F: disas/hexagon.c
F: configs/targets/hexagon-linux-user/default.mak
F: docker/dockerfiles/debian-hexagon-cross.docker
F: gdb-xml/hexagon*.xml
+T: git https://github.com/quic/qemu.git hex-next
Hexagon idef-parser
M: Alessandro Di Federico <ale@rev.ng>
@@ -264,7 +257,7 @@ M: Song Gao <gaosong@loongson.cn>
S: Maintained
F: target/loongarch/
F: tests/tcg/loongarch64/
-F: tests/avocado/machine_loongarch.py
+F: tests/functional/test_loongarch64_virt.py
M68K TCG CPUs
M: Laurent Vivier <laurent@vivier.eu>
@@ -316,6 +309,7 @@ F: configs/devices/ppc*
F: docs/system/ppc/embedded.rst
F: docs/system/target-ppc.rst
F: tests/tcg/ppc*/*
+F: tests/functional/test_ppc_74xx.py
RISC-V TCG CPUs
M: Palmer Dabbelt <palmer@dabbelt.com>
@@ -557,6 +551,8 @@ F: include/hw/xen/
F: include/sysemu/xen.h
F: include/sysemu/xen-mapcache.h
F: stubs/xen-hw-stub.c
+F: docs/system/arm/xenpvh.rst
+F: docs/system/i386/xenpvh.rst
Guest CPU Cores (NVMM)
----------------------
@@ -705,6 +701,14 @@ F: include/hw/timer/armv7m_systick.h
F: include/hw/misc/armv7m_ras.h
F: tests/qtest/test-arm-mptimer.c
+B-L475E-IOT01A IoT Node
+M: Samuel Tardieu <sam@rfc1149.net>
+L: qemu-arm@nongnu.org
+S: Maintained
+F: hw/arm/b-l475e-iot01a.c
+F: hw/display/dm163.c
+F: tests/qtest/dm163-test.c
+
Exynos
M: Igor Mitsyanko <i.mitsyanko@gmail.com>
M: Peter Maydell <peter.maydell@linaro.org>
@@ -730,7 +734,7 @@ S: Odd Fixes
F: include/hw/arm/digic.h
F: hw/*/digic*
F: include/hw/*/digic*
-F: tests/avocado/machine_arm_canona1100.py
+F: tests/functional/test_arm_canona1100.py
F: docs/system/arm/digic.rst
Goldfish RTC
@@ -741,14 +745,6 @@ S: Maintained
F: hw/rtc/goldfish_rtc.c
F: include/hw/rtc/goldfish_rtc.h
-Gumstix
-M: Peter Maydell <peter.maydell@linaro.org>
-R: Philippe Mathieu-DaudƩ <philmd@linaro.org>
-L: qemu-arm@nongnu.org
-S: Odd Fixes
-F: hw/arm/gumstix.c
-F: docs/system/arm/gumstix.rst
-
i.MX25 PDK
M: Peter Maydell <peter.maydell@linaro.org>
R: Jean-Christophe Dubois <jcd@tribudubois.net>
@@ -781,7 +777,7 @@ S: Maintained
F: hw/arm/integratorcp.c
F: hw/misc/arm_integrator_debug.c
F: include/hw/misc/arm_integrator_debug.h
-F: tests/avocado/machine_arm_integratorcp.py
+F: tests/functional/test_arm_integratorcp.py
F: docs/system/arm/integratorcp.rst
MCIMX6UL EVK / i.MX6ul
@@ -869,32 +865,6 @@ F: pc-bios/npcm7xx_bootrom.bin
F: roms/vbootrom
F: docs/system/arm/nuvoton.rst
-nSeries
-M: Peter Maydell <peter.maydell@linaro.org>
-L: qemu-arm@nongnu.org
-S: Odd Fixes
-F: hw/arm/nseries.c
-F: hw/display/blizzard.c
-F: hw/input/lm832x.c
-F: hw/input/tsc2005.c
-F: hw/misc/cbus.c
-F: hw/rtc/twl92230.c
-F: include/hw/display/blizzard.h
-F: include/hw/input/lm832x.h
-F: include/hw/input/tsc2xxx.h
-F: include/hw/misc/cbus.h
-F: tests/avocado/machine_arm_n8x0.py
-F: docs/system/arm/nseries.rst
-
-Palm
-M: Peter Maydell <peter.maydell@linaro.org>
-L: qemu-arm@nongnu.org
-S: Odd Fixes
-F: hw/arm/palm.c
-F: hw/input/tsc210x.c
-F: include/hw/input/tsc2xxx.h
-F: docs/system/arm/palm.rst
-
Raspberry Pi
M: Peter Maydell <peter.maydell@linaro.org>
R: Philippe Mathieu-DaudƩ <philmd@linaro.org>
@@ -906,6 +876,9 @@ F: hw/*/bcm283*
F: include/hw/arm/rasp*
F: include/hw/*/bcm283*
F: docs/system/arm/raspi.rst
+F: tests/functional/test_arm_raspi2.py
+F: tests/functional/test_aarch64_raspi3.py
+F: tests/functional/test_aarch64_raspi4.py
Real View
M: Peter Maydell <peter.maydell@linaro.org>
@@ -917,28 +890,6 @@ F: hw/intc/realview_gic.c
F: include/hw/intc/realview_gic.h
F: docs/system/arm/realview.rst
-PXA2XX
-M: Peter Maydell <peter.maydell@linaro.org>
-L: qemu-arm@nongnu.org
-S: Odd Fixes
-F: hw/arm/mainstone.c
-F: hw/arm/spitz.c
-F: hw/arm/tosa.c
-F: hw/arm/z2.c
-F: hw/*/pxa2xx*
-F: hw/display/tc6393xb.c
-F: hw/gpio/max7310.c
-F: hw/gpio/zaurus.c
-F: hw/input/ads7846.c
-F: hw/misc/mst_fpga.c
-F: hw/adc/max111x.c
-F: include/hw/adc/max111x.h
-F: include/hw/arm/pxa.h
-F: include/hw/arm/sharpsl.h
-F: include/hw/display/tc6393xb.h
-F: docs/system/arm/xscale.rst
-F: docs/system/arm/mainstone.rst
-
SABRELITE / i.MX6
M: Peter Maydell <peter.maydell@linaro.org>
R: Jean-Christophe Dubois <jcd@tribudubois.net>
@@ -967,7 +918,7 @@ F: hw/misc/sbsa_ec.c
F: hw/watchdog/sbsa_gwdt.c
F: include/hw/watchdog/sbsa_gwdt.h
F: docs/system/arm/sbsa.rst
-F: tests/avocado/machine_aarch64_sbsaref.py
+F: tests/functional/test_aarch64_sbsaref.py
Sharp SL-5500 (Collie) PDA
M: Peter Maydell <peter.maydell@linaro.org>
@@ -975,6 +926,8 @@ L: qemu-arm@nongnu.org
S: Odd Fixes
F: hw/arm/collie.c
F: hw/arm/strongarm*
+F: hw/gpio/zaurus.c
+F: include/hw/arm/sharpsl.h
F: docs/system/arm/collie.rst
Stellaris
@@ -987,6 +940,19 @@ F: include/hw/input/gamepad.h
F: include/hw/timer/stellaris-gptm.h
F: docs/system/arm/stellaris.rst
+STM32L4x5 SoC Family
+M: Samuel Tardieu <sam@rfc1149.net>
+L: qemu-arm@nongnu.org
+S: Maintained
+F: hw/arm/stm32l4x5_soc.c
+F: hw/char/stm32l4x5_usart.c
+F: hw/misc/stm32l4x5_exti.c
+F: hw/misc/stm32l4x5_syscfg.c
+F: hw/misc/stm32l4x5_rcc.c
+F: hw/gpio/stm32l4x5_gpio.c
+F: include/hw/*/stm32l4x5_*.h
+F: tests/qtest/stm32l4x5*
+
STM32VLDISCOVERY
M: Alexandre Iooss <erdnaxe@crans.org>
L: qemu-arm@nongnu.org
@@ -1001,6 +967,7 @@ S: Maintained
F: hw/arm/vexpress.c
F: hw/display/sii9022.c
F: docs/system/arm/vexpress.rst
+F: tests/functional/test_arm_vexpress.py
Versatile PB
M: Peter Maydell <peter.maydell@linaro.org>
@@ -1019,7 +986,8 @@ S: Maintained
F: hw/arm/virt*
F: include/hw/arm/virt.h
F: docs/system/arm/virt.rst
-F: tests/avocado/machine_aarch64_virt.py
+F: tests/functional/test_aarch64_virt.py
+F: tests/functional/test_arm_tuxrun.py
Xilinx Zynq
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
@@ -1050,7 +1018,7 @@ F: include/hw/display/dpcd.h
F: docs/system/arm/xlnx-versal-virt.rst
Xilinx Versal OSPI
-M: Francisco Iglesias <francisco.iglesias@xilinx.com>
+M: Francisco Iglesias <francisco.iglesias@amd.com>
S: Maintained
F: hw/ssi/xlnx-versal-ospi.c
F: include/hw/ssi/xlnx-versal-ospi.h
@@ -1092,6 +1060,8 @@ S: Maintained
F: hw/arm/stm32f405_soc.c
F: hw/misc/stm32f4xx_syscfg.c
F: hw/misc/stm32f4xx_exti.c
+F: hw/misc/stm32_rcc.c
+F: include/hw/misc/stm32_rcc.h
Netduino 2
M: Alistair Francis <alistair@alistair23.me>
@@ -1113,26 +1083,6 @@ L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/olimex-stm32-h405.c
-STM32L4x5 SoC Family
-M: Arnaud Minier <arnaud.minier@telecom-paris.fr>
-M: InĆØs Varhol <ines.varhol@telecom-paris.fr>
-L: qemu-arm@nongnu.org
-S: Maintained
-F: hw/arm/stm32l4x5_soc.c
-F: hw/char/stm32l4x5_usart.c
-F: hw/misc/stm32l4x5_exti.c
-F: hw/misc/stm32l4x5_syscfg.c
-F: hw/misc/stm32l4x5_rcc.c
-F: hw/gpio/stm32l4x5_gpio.c
-F: include/hw/*/stm32l4x5_*.h
-
-B-L475E-IOT01A IoT Node
-M: Arnaud Minier <arnaud.minier@telecom-paris.fr>
-M: InĆØs Varhol <ines.varhol@telecom-paris.fr>
-L: qemu-arm@nongnu.org
-S: Maintained
-F: hw/arm/b-l475e-iot01a.c
-
SmartFusion2
M: Subbaraya Sundeep <sundeep.lkml@gmail.com>
M: Peter Maydell <peter.maydell@linaro.org>
@@ -1173,6 +1123,7 @@ F: hw/net/ftgmac100.c
F: include/hw/net/ftgmac100.h
F: docs/system/arm/aspeed.rst
F: tests/*/*aspeed*
+F: tests/*/*ast2700*
F: hw/arm/fby35.c
NRF51
@@ -1187,6 +1138,11 @@ F: include/hw/*/microbit*.h
F: tests/qtest/microbit-test.c
F: docs/system/arm/nrf.rst
+ARM PL011 Rust device
+M: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+S: Maintained
+F: rust/hw/char/pl011/
+
AVR Machines
-------------
@@ -1207,14 +1163,6 @@ M: Philippe Mathieu-DaudƩ <philmd@linaro.org>
S: Maintained
F: hw/avr/arduino.c
-CRIS Machines
--------------
-Axis Dev88
-M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
-S: Maintained
-F: hw/cris/axis_dev88.c
-F: hw/*/etraxfs_*.c
-
HP-PARISC Machines
------------------
HP B160L, HP C3700
@@ -1249,9 +1197,9 @@ F: configs/devices/loongarch64-softmmu/default.mak
F: hw/loongarch/
F: include/hw/loongarch/virt.h
F: include/hw/intc/loongarch_*.h
-F: include/hw/intc/loongson_ipi.h
+F: include/hw/intc/loongson_ipi_common.h
F: hw/intc/loongarch_*.c
-F: hw/intc/loongson_ipi.c
+F: hw/intc/loongson_ipi_common.c
F: include/hw/pci-host/ls7a.h
F: hw/rtc/ls7a_rtc.c
F: gdb-xml/loongarch*.xml
@@ -1279,6 +1227,7 @@ S: Odd Fixes
F: hw/m68k/next-*.c
F: hw/display/next-fb.c
F: include/hw/m68k/next-cube.h
+F: tests/functional/test_m68k_nextcube.py
q800
M: Laurent Vivier <laurent@vivier.eu>
@@ -1304,6 +1253,7 @@ F: include/hw/m68k/q800-glue.h
F: include/hw/misc/djmemc.h
F: include/hw/misc/iosb.h
F: include/hw/audio/asc.h
+F: tests/functional/test_m68k_q800.py
virt
M: Laurent Vivier <laurent@vivier.eu>
@@ -1326,7 +1276,7 @@ M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
S: Maintained
F: hw/microblaze/petalogix_s3adsp1800_mmu.c
F: include/hw/char/xilinx_uartlite.h
-F: tests/avocado/machine_microblaze.py
+F: tests/functional/test_microblaze*.py
petalogix_ml605
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
@@ -1363,7 +1313,8 @@ F: hw/mips/malta.c
F: hw/pci-host/gt64120.c
F: include/hw/southbridge/piix.h
F: tests/avocado/linux_ssh_mips_malta.py
-F: tests/avocado/machine_mips_malta.py
+F: tests/functional/test_mips*_malta.py
+F: tests/functional/test_mips*_tuxrun.py
Mipssim
R: Aleksandar Rikalo <arikalo@gmail.com>
@@ -1379,20 +1330,22 @@ S: Odd Fixes
F: hw/mips/fuloong2e.c
F: hw/pci-host/bonito.c
F: include/hw/pci-host/bonito.h
-F: tests/avocado/machine_mips_fuloong2e.py
+F: tests/functional/test_mips64el_fuloong2e.py
Loongson-3 virtual platforms
M: Huacai Chen <chenhuacai@kernel.org>
R: Jiaxun Yang <jiaxun.yang@flygoat.com>
S: Maintained
+F: hw/intc/loongson_ipi_common.c
F: hw/intc/loongson_ipi.c
F: hw/intc/loongson_liointc.c
F: hw/mips/loongson3_bootp.c
F: hw/mips/loongson3_bootp.h
F: hw/mips/loongson3_virt.c
+F: include/hw/intc/loongson_ipi_common.h
F: include/hw/intc/loongson_ipi.h
F: include/hw/intc/loongson_liointc.h
-F: tests/avocado/machine_mips_loongson3v.py
+F: tests/functional/test_mips64el_loongson3v.py
Boston
M: Paul Burton <paulburton@kernel.org>
@@ -1418,18 +1371,19 @@ PowerPC Machines
L: qemu-ppc@nongnu.org
S: Orphan
F: hw/ppc/ppc405*
-F: tests/avocado/ppc_405.py
+F: tests/functional/test_ppc_405.py
Bamboo
L: qemu-ppc@nongnu.org
S: Orphan
F: hw/ppc/ppc440_bamboo.c
F: hw/pci-host/ppc4xx_pci.c
-F: tests/avocado/ppc_bamboo.py
+F: tests/functional/test_ppc_bamboo.py
e500
+M: Bernhard Beschow <shentey@gmail.com>
L: qemu-ppc@nongnu.org
-S: Orphan
+S: Odd Fixes
F: hw/ppc/e500*
F: hw/ppc/ppce500_spin.c
F: hw/gpio/mpc8xxx.c
@@ -1442,13 +1396,16 @@ F: pc-bios/u-boot.e500
F: hw/intc/openpic_kvm.c
F: include/hw/ppc/openpic_kvm.h
F: docs/system/ppc/ppce500.rst
+F: tests/functional/test_ppc64_e500.py
+F: tests/functional/test_ppc_tuxrun.py
mpc8544ds
+M: Bernhard Beschow <shentey@gmail.com>
L: qemu-ppc@nongnu.org
-S: Orphan
+S: Odd Fixes
F: hw/ppc/mpc8544ds.c
F: hw/ppc/mpc8544_guts.c
-F: tests/avocado/ppc_mpc8544ds.py
+F: tests/functional/test_ppc_mpc8544ds.py
New World (mac99)
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
@@ -1470,6 +1427,7 @@ F: include/hw/ppc/mac_dbdma.h
F: include/hw/pci-host/uninorth.h
F: include/hw/input/adb*
F: pc-bios/qemu_vga.ndrv
+F: tests/functional/test_ppc_mac.py
Old World (g3beige)
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
@@ -1485,6 +1443,7 @@ F: include/hw/intc/heathrow_pic.h
F: include/hw/input/adb*
F: include/hw/pci-host/grackle.h
F: pc-bios/qemu_vga.ndrv
+F: tests/functional/test_ppc_mac.py
PReP
M: HervƩ Poussineau <hpoussin@reactos.org>
@@ -1501,7 +1460,7 @@ F: hw/dma/i82374.c
F: hw/rtc/m48t59-isa.c
F: include/hw/isa/pc87312.h
F: include/hw/rtc/m48t59.h
-F: tests/avocado/ppc_prep_40p.py
+F: tests/functional/test_ppc_40p.py
sPAPR (pseries)
M: Nicholas Piggin <npiggin@gmail.com>
@@ -1525,8 +1484,9 @@ F: tests/qtest/spapr*
F: tests/qtest/libqos/*spapr*
F: tests/qtest/rtas*
F: tests/qtest/libqos/rtas*
-F: tests/avocado/ppc_pseries.py
-F: tests/avocado/ppc_hv_tests.py
+F: tests/functional/test_ppc64_pseries.py
+F: tests/functional/test_ppc64_hv.py
+F: tests/functional/test_ppc64_tuxrun.py
PowerNV (Non-Virtualized)
M: CĆ©dric Le Goater <clg@kaod.org>
@@ -1543,6 +1503,7 @@ F: include/hw/ppc/pnv*
F: include/hw/pci-host/pnv*
F: pc-bios/skiboot.lid
F: tests/qtest/pnv*
+F: tests/functional/test_ppc64_powernv.py
pca955x
M: Glenn Miles <milesg@linux.ibm.com>
@@ -1557,7 +1518,7 @@ M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
L: qemu-ppc@nongnu.org
S: Odd Fixes
F: hw/ppc/virtex_ml507.c
-F: tests/avocado/ppc_virtex_ml507.py
+F: tests/functional/test_ppc_virtex_ml507.py
sam460ex
M: BALATON Zoltan <balaton@eik.bme.hu>
@@ -1590,6 +1551,7 @@ S: Maintained
F: hw/ppc/amigaone.c
F: hw/pci-host/articia.c
F: include/hw/pci-host/articia.h
+F: tests/functional/test_ppc_amiga.py
Virtual Open Firmware (VOF)
M: Alexey Kardashevskiy <aik@ozlabs.ru>
@@ -1656,7 +1618,7 @@ R: Yoshinori Sato <ysato@users.sourceforge.jp>
S: Orphan
F: docs/system/target-rx.rst
F: hw/rx/rx-gdbsim.c
-F: tests/avocado/machine_rx_gdbsim.py
+F: tests/functional/test_rx_gdbsim.py
SH4 Machines
------------
@@ -1671,17 +1633,8 @@ F: hw/pci-host/sh_pci.c
F: hw/timer/sh_timer.c
F: include/hw/sh4/sh_intc.h
F: include/hw/timer/tmu012.h
-
-Shix
-R: Yoshinori Sato <ysato@users.sourceforge.jp>
-R: Magnus Damm <magnus.damm@gmail.com>
-S: Odd Fixes
-F: hw/block/tc58128.c
-F: hw/char/sh_serial.c
-F: hw/sh4/shix.c
-F: hw/intc/sh_intc.c
-F: hw/timer/sh_timer.c
-F: include/hw/sh4/sh_intc.h
+F: tests/functional/test_sh4_r2d.py
+F: tests/functional/test_sh4_tuxrun.py
SPARC Machines
--------------
@@ -1699,6 +1652,7 @@ F: include/hw/nvram/sun_nvram.h
F: include/hw/sparc/sparc32_dma.h
F: include/hw/sparc/sun4m_iommu.h
F: pc-bios/openbios-sparc32
+F: tests/functional/test_sparc_sun4m.py
Sun4u
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
@@ -1711,7 +1665,8 @@ F: include/hw/pci-host/sabre.h
F: hw/pci-bridge/simba.c
F: include/hw/pci-bridge/simba.h
F: pc-bios/openbios-sparc64
-F: tests/avocado/machine_sparc64_sun4u.py
+F: tests/functional/test_sparc64_sun4u.py
+F: tests/functional/test_sparc64_tuxrun.py
Sun4v
M: Artyom Tarasenko <atar4qemu@gmail.com>
@@ -1727,7 +1682,6 @@ S: Maintained
F: hw/sparc/leon3.c
F: hw/*/grlib*
F: include/hw/*/grlib*
-F: tests/avocado/machine_sparc_leon3.py
S390 Machines
-------------
@@ -1739,7 +1693,7 @@ S: Supported
F: hw/s390x/
F: include/hw/s390x/
F: configs/devices/s390x-softmmu/default.mak
-F: tests/avocado/machine_s390_ccw_virtio.py
+F: tests/functional/test_s390x_*
T: git https://github.com/borntraeger/qemu.git s390-next
L: qemu-s390x@nongnu.org
@@ -1802,7 +1756,7 @@ F: hw/s390x/cpu-topology.c
F: target/s390x/kvm/stsi-topology.c
F: docs/devel/s390-cpu-topology.rst
F: docs/system/s390x/cpu-topology.rst
-F: tests/avocado/s390_topology.py
+F: tests/functional/test_s390x_topology.py
X86 Machines
------------
@@ -1830,6 +1784,11 @@ F: hw/isa/apm.c
F: include/hw/isa/apm.h
F: tests/unit/test-x86-topo.c
F: tests/qtest/test-x86-cpuid-compat.c
+F: tests/functional/test_i386_tuxrun.py
+F: tests/functional/test_mem_addr_space.py
+F: tests/functional/test_pc_cpu_hotplug_props.py
+F: tests/functional/test_x86_64_tuxrun.py
+F: tests/functional/test_x86_cpu_model_versions.py
PC Chipset
M: Michael S. Tsirkin <mst@redhat.com>
@@ -1879,6 +1838,7 @@ M: Eduardo Habkost <eduardo@habkost.net>
M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
R: Philippe Mathieu-DaudƩ <philmd@linaro.org>
R: Yanan Wang <wangyanan55@huawei.com>
+R: Zhao Liu <zhao1.liu@intel.com>
S: Supported
F: hw/core/cpu-common.c
F: hw/core/cpu-sysemu.c
@@ -1895,6 +1855,8 @@ F: include/hw/boards.h
F: include/hw/core/cpu.h
F: include/hw/cpu/cluster.h
F: include/sysemu/numa.h
+F: tests/functional/test_cpu_queries.py
+F: tests/functional/test_empty_cpu_model.py
F: tests/unit/test-smp-parse.c
T: git https://gitlab.com/ehabkost/qemu.git machine-next
@@ -1916,6 +1878,7 @@ S: Maintained
F: hw/xtensa/xtfpga.c
F: hw/net/opencores_eth.c
F: include/hw/xtensa/mx_pic.h
+F: tests/functional/test_xtensa_lx60.py
Devices
-------
@@ -1930,7 +1893,6 @@ F: tests/qtest/intel-hda-test.c
F: tests/qtest/fuzz-sb16-test.c
Xilinx CAN
-M: Vikram Garhwal <vikram.garhwal@amd.com>
M: Francisco Iglesias <francisco.iglesias@amd.com>
S: Maintained
F: hw/net/can/xlnx-*
@@ -2061,8 +2023,8 @@ ACPI/AVOCADO/BIOSBITS
M: Ani Sinha <anisinha@redhat.com>
M: Michael S. Tsirkin <mst@redhat.com>
S: Supported
-F: tests/avocado/acpi-bits/*
-F: tests/avocado/acpi-bits.py
+F: tests/functional/acpi-bits/*
+F: tests/functional/test_acpi_bits.py
F: docs/devel/acpi-bits.rst
ACPI/HEST/GHES
@@ -2099,6 +2061,7 @@ S: Odd Fixes
F: hw/net/
F: include/hw/net/
F: tests/qtest/virtio-net-test.c
+F: tests/functional/test_info_usernet.py
F: docs/virtio-net-failover.rst
T: git https://github.com/jasowang/qemu.git net
@@ -2209,6 +2172,7 @@ F: docs/devel/vfio-iommufd.rst
vhost
M: Michael S. Tsirkin <mst@redhat.com>
+R: Stefano Garzarella <sgarzare@redhat.com>
S: Supported
F: hw/*/*vhost*
F: docs/interop/vhost-user.json
@@ -2233,6 +2197,7 @@ F: net/vhost-user.c
F: include/hw/virtio/
F: docs/devel/virtio*
F: docs/devel/migration/virtio.rst
+F: tests/functional/test_virtio_version.py
virtio-balloon
M: Michael S. Tsirkin <mst@redhat.com>
@@ -2251,20 +2216,12 @@ S: Maintained
W: https://wiki.qemu.org/Documentation/9p
F: hw/9pfs/
X: hw/9pfs/xen-9p*
-X: hw/9pfs/9p-proxy*
F: fsdev/
-X: fsdev/virtfs-proxy-helper.c
F: tests/qtest/virtio-9p-test.c
F: tests/qtest/libqos/virtio-9p*
T: git https://gitlab.com/gkurz/qemu.git 9p-next
T: git https://github.com/cschoenebeck/qemu.git 9p.next
-virtio-9p-proxy
-F: hw/9pfs/9p-proxy*
-F: fsdev/virtfs-proxy-helper.c
-F: docs/tools/virtfs-proxy-helper.rst
-S: Obsolete
-
virtio-blk
M: Stefan Hajnoczi <stefanha@redhat.com>
L: qemu-block@nongnu.org
@@ -2460,7 +2417,7 @@ S: Maintained
F: hw/net/rocker/
F: qapi/rocker.json
F: tests/rocker/
-F: docs/specs/rocker.txt
+F: docs/specs/rocker.rst
e1000x
M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
@@ -2483,7 +2440,7 @@ R: Sriram Yagnaraman <sriram.yagnaraman@ericsson.com>
S: Maintained
F: docs/system/devices/igb.rst
F: hw/net/igb*
-F: tests/avocado/netdev-ethtool.py
+F: tests/functional/test_netdev_ethtool.py
F: tests/qtest/igb-test.c
F: tests/qtest/libqos/igb.c
@@ -2684,7 +2641,7 @@ F: include/hw/rx/
CAN bus subsystem and hardware
M: Pavel Pisa <pisa@cmp.felk.cvut.cz>
-M: Vikram Garhwal <fnu.vikram@xilinx.com>
+M: Francisco Iglesias <francisco.iglesias@amd.com>
S: Maintained
W: https://canbus.pages.fel.cvut.cz/
F: net/can/*
@@ -2966,6 +2923,7 @@ S: Supported
F: include/qemu/option.h
F: tests/unit/test-keyval.c
F: tests/unit/test-qemu-opts.c
+F: tests/functional/test_version.py
F: util/keyval.c
F: util/qemu-option.c
@@ -3027,6 +2985,7 @@ F: gdb-xml/
F: tests/tcg/multiarch/gdbstub/*
F: scripts/feature_to_c.py
F: scripts/probe-gdb-support.py
+T: git https://gitlab.com/stsquad/qemu gdbstub/next
Memory API
M: Paolo Bonzini <pbonzini@redhat.com>
@@ -3107,11 +3066,13 @@ F: qapi/run-state.json
Read, Copy, Update (RCU)
M: Paolo Bonzini <pbonzini@redhat.com>
S: Maintained
-F: docs/devel/lockcnt.txt
-F: docs/devel/rcu.txt
+F: docs/devel/lockcnt.rst
+F: docs/devel/rcu.rst
F: include/qemu/rcu*.h
+F: include/qemu/lockcnt.h
F: tests/unit/rcutorture.c
F: tests/unit/test-rcu-*.c
+F: util/lockcnt.c
F: util/rcu.c
Human Monitor (HMP)
@@ -3169,7 +3130,6 @@ F: qapi/cryptodev.json
Python library
M: John Snow <jsnow@redhat.com>
M: Cleber Rosa <crosa@redhat.com>
-R: Beraldo Leal <bleal@redhat.com>
S: Maintained
F: python/
T: git https://gitlab.com/jsnow/qemu.git python
@@ -3219,6 +3179,7 @@ M: Eric Blake <eblake@redhat.com>
M: Markus Armbruster <armbru@redhat.com>
S: Supported
F: qapi/*.json
+F: qga/qapi-schema.json
T: git https://repo.or.cz/qemu/armbru.git qapi-next
QObject
@@ -3306,7 +3267,7 @@ F: tests/qtest/qmp-cmd-test.c
T: git https://repo.or.cz/qemu/armbru.git qapi-next
qtest
-M: Thomas Huth <thuth@redhat.com>
+M: Fabiano Rosas <farosas@suse.de>
M: Laurent Vivier <lvivier@redhat.com>
R: Paolo Bonzini <pbonzini@redhat.com>
S: Maintained
@@ -3324,7 +3285,7 @@ M: Alexander Bulekov <alxndr@bu.edu>
R: Paolo Bonzini <pbonzini@redhat.com>
R: Bandan Das <bsd@redhat.com>
R: Stefan Hajnoczi <stefanha@redhat.com>
-R: Thomas Huth <thuth@redhat.com>
+R: Fabiano Rosas <farosas@suse.de>
R: Darren Kenny <darren.kenny@oracle.com>
R: Qiuhao Li <Qiuhao.Li@outlook.com>
S: Maintained
@@ -3342,6 +3303,13 @@ F: hw/core/register.c
F: include/hw/register.h
F: include/hw/registerfields.h
+Rust
+M: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+S: Maintained
+F: rust/qemu-api
+F: rust/qemu-api-macros
+F: rust/rustfmt.toml
+
SLIRP
M: Samuel Thibault <samuel.thibault@ens-lyon.org>
S: Maintained
@@ -3399,6 +3367,12 @@ F: tests/qtest/*tpm*
F: docs/specs/tpm.rst
T: git https://github.com/stefanberger/qemu-tpm.git tpm-next
+SPDM
+M: Alistair Francis <alistair.francis@wdc.com>
+S: Maintained
+F: backends/spdm-socket.c
+F: include/sysemu/spdm-socket.h
+
Checkpatch
S: Odd Fixes
F: scripts/checkpatch.pl
@@ -3441,6 +3415,7 @@ Detached LUKS header
M: Hyman Huang <yong.huang@smartx.com>
S: Maintained
F: tests/qemu-iotests/tests/luks-detached-header
+F: docs/devel/luks-detached-header.rst
D-Bus
M: Marc-AndrƩ Lureau <marcandre.lureau@redhat.com>
@@ -3474,7 +3449,7 @@ F: qapi/crypto.json
F: tests/unit/test-crypto-*
F: tests/bench/benchmark-crypto-*
F: tests/unit/crypto-tls-*
-F: tests/unit/pkix_asn1_tab.c
+F: tests/unit/pkix_asn1_tab.c.inc
F: qemu.sasl
Coroutines
@@ -3658,6 +3633,8 @@ F: tests/uefi-test-tools/
VT-d Emulation
M: Michael S. Tsirkin <mst@redhat.com>
R: Jason Wang <jasowang@redhat.com>
+R: Yi Liu <yi.l.liu@intel.com>
+R: ClƩment Mathieu--Drif <clement.mathieu--drif@eviden.com>
S: Supported
F: hw/i386/intel_iommu.c
F: hw/i386/intel_iommu_internal.h
@@ -3721,7 +3698,6 @@ F: configs/targets/*linux-user.mak
F: scripts/qemu-binfmt-conf.sh
F: scripts/update-syscalltbl.sh
F: scripts/update-mips-syscall-args.sh
-F: scripts/gensyscalls.sh
Tiny Code Generator (TCG)
-------------------------
@@ -3733,13 +3709,14 @@ F: include/tcg/
TCG Plugins
M: Alex BennƩe <alex.bennee@linaro.org>
+T: git https://gitlab.com/stsquad/qemu plugins/next
R: Alexandre Iooss <erdnaxe@crans.org>
R: Mahmoud Mandour <ma.mandourr@gmail.com>
R: Pierrick Bouvier <pierrick.bouvier@linaro.org>
S: Maintained
F: docs/devel/tcg-plugins.rst
F: plugins/
-F: tests/plugin/
+F: tests/tcg/plugins/
F: tests/avocado/tcg_plugins.py
F: contrib/plugins/
@@ -3857,7 +3834,7 @@ F: nbd/
F: include/block/nbd*
F: qemu-nbd.*
F: blockdev-nbd.c
-F: docs/interop/nbd.txt
+F: docs/interop/nbd.rst
F: docs/tools/qemu-nbd.rst
F: tests/qemu-iotests/tests/*nbd*
T: git https://repo.or.cz/qemu/ericb.git nbd
@@ -3924,6 +3901,7 @@ M: Stefan Hajnoczi <stefanha@redhat.com>
L: qemu-block@nongnu.org
S: Supported
F: block/blkverify.c
+F: docs/devel/blkverify.rst
bochs
M: Stefan Hajnoczi <stefanha@redhat.com>
@@ -3950,7 +3928,8 @@ L: qemu-block@nongnu.org
S: Supported
F: block/parallels.c
F: block/parallels-ext.c
-F: docs/interop/parallels.txt
+F: docs/interop/parallels.rst
+F: docs/interop/prl-xml.rst
T: git https://src.openvz.org/scm/~den/qemu.git parallels
qed
@@ -4000,6 +3979,7 @@ M: Hanna Reitz <hreitz@redhat.com>
L: qemu-block@nongnu.org
S: Supported
F: block/blkdebug.c
+F: docs/devel/blkdebug.rst
vpc
M: Kevin Wolf <kwolf@redhat.com>
@@ -4103,10 +4083,10 @@ Build and test automation
-------------------------
Build and test automation, general continuous integration
M: Alex BennƩe <alex.bennee@linaro.org>
+T: git https://gitlab.com/stsquad/qemu testing/next
M: Philippe Mathieu-DaudƩ <philmd@linaro.org>
M: Thomas Huth <thuth@redhat.com>
R: Wainer dos Santos Moschetta <wainersm@redhat.com>
-R: Beraldo Leal <bleal@redhat.com>
S: Maintained
F: .github/workflows/lockdown.yml
F: .gitlab-ci.yml
@@ -4131,6 +4111,11 @@ F: .gitlab-ci.d/cirrus/freebsd*
F: tests/vm/freebsd
W: https://cirrus-ci.com/github/qemu/qemu
+Functional testing framework
+M: Thomas Huth <thuth@redhat.com>
+R: Philippe Mathieu-DaudƩ <philmd@linaro.org>
+F: tests/functional/qemu_test/
+
Windows Hosted Continuous Integration
M: Yonggang Luo <luoyonggang@gmail.com>
S: Maintained
@@ -4147,7 +4132,6 @@ W: https://trello.com/b/6Qi1pxVn/avocado-qemu
R: Cleber Rosa <crosa@redhat.com>
R: Philippe Mathieu-DaudƩ <philmd@linaro.org>
R: Wainer dos Santos Moschetta <wainersm@redhat.com>
-R: Beraldo Leal <bleal@redhat.com>
S: Odd Fixes
F: tests/avocado/
@@ -4181,7 +4165,6 @@ Meson
M: Paolo Bonzini <pbonzini@redhat.com>
R: Marc-AndrƩ Lureau <marcandre.lureau@redhat.com>
R: Daniel P. Berrange <berrange@redhat.com>
-R: Thomas Huth <thuth@redhat.com>
R: Philippe Mathieu-DaudƩ <philmd@linaro.org>
S: Maintained
F: meson.build
@@ -4228,6 +4211,15 @@ F: docs/sphinx/
F: docs/_templates/
F: docs/devel/docs.rst
+Rust build system integration
+M: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+S: Maintained
+F: scripts/rust/
+F: rust/.gitignore
+F: rust/Kconfig
+F: rust/meson.build
+F: rust/wrapper.h
+
Miscellaneous
-------------
Performance Tools and Tests
diff --git a/Makefile b/Makefile
index 02a2575..917c9a3 100644
--- a/Makefile
+++ b/Makefile
@@ -78,7 +78,8 @@ x := $(shell rm -rf meson-private meson-info meson-logs)
endif
# 1. ensure config-host.mak is up-to-date
-config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/scripts/meson-buildoptions.sh $(SRC_PATH)/VERSION
+config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/scripts/meson-buildoptions.sh \
+ $(SRC_PATH)/pythondeps.toml $(SRC_PATH)/VERSION
@echo config-host.mak is out-of-date, running configure
@if test -f meson-private/coredata.dat; then \
./config.status --skip-meson; \
diff --git a/VERSION b/VERSION
index bc66ba6..33ea410 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-9.0.50
+9.1.50
diff --git a/accel/accel-blocker.c b/accel/accel-blocker.c
index e083f24..75daaa2 100644
--- a/accel/accel-blocker.c
+++ b/accel/accel-blocker.c
@@ -25,6 +25,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/lockcnt.h"
#include "qemu/thread.h"
#include "qemu/main-loop.h"
#include "hw/core/cpu.h"
diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c
index ac08cfb..d60874d 100644
--- a/accel/hvf/hvf-accel-ops.c
+++ b/accel/hvf/hvf-accel-ops.c
@@ -53,6 +53,7 @@
#include "exec/address-spaces.h"
#include "exec/exec-all.h"
#include "gdbstub/enums.h"
+#include "hw/boards.h"
#include "sysemu/cpus.h"
#include "sysemu/hvf.h"
#include "sysemu/hvf_int.h"
@@ -61,10 +62,6 @@
HVFState *hvf_state;
-#ifdef __aarch64__
-#define HV_VM_DEFAULT NULL
-#endif
-
/* Memory slots */
hvf_slot *hvf_find_overlap_slot(uint64_t start, uint64_t size)
@@ -323,8 +320,17 @@ static int hvf_accel_init(MachineState *ms)
int x;
hv_return_t ret;
HVFState *s;
+ int pa_range = 36;
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+
+ if (mc->hvf_get_physical_address_range) {
+ pa_range = mc->hvf_get_physical_address_range(ms);
+ if (pa_range < 0) {
+ return -EINVAL;
+ }
+ }
- ret = hv_vm_create(HV_VM_DEFAULT);
+ ret = hvf_arch_vm_create(ms, (uint32_t)pa_range);
assert_hvf_ok(ret);
s = g_new0(HVFState, 1);
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 64bf47a..801cff1 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -69,6 +69,11 @@
#define KVM_GUESTDBG_BLOCKIRQ 0
#endif
+/* Default num of memslots to be allocated when VM starts */
+#define KVM_MEMSLOTS_NR_ALLOC_DEFAULT 16
+/* Default max allowed memslots if kernel reported nothing */
+#define KVM_MEMSLOTS_NR_MAX_DEFAULT 32
+
struct KVMParkedVcpu {
unsigned long vcpu_id;
int kvm_fd;
@@ -165,11 +170,62 @@ void kvm_resample_fd_notify(int gsi)
}
}
+/**
+ * kvm_slots_grow(): Grow the slots[] array in the KVMMemoryListener
+ *
+ * @kml: The KVMMemoryListener* to grow the slots[] array
+ * @nr_slots_new: The new size of slots[] array
+ *
+ * Returns: True if the array grows larger, false otherwise.
+ */
+static bool kvm_slots_grow(KVMMemoryListener *kml, unsigned int nr_slots_new)
+{
+ unsigned int i, cur = kml->nr_slots_allocated;
+ KVMSlot *slots;
+
+ if (nr_slots_new > kvm_state->nr_slots_max) {
+ nr_slots_new = kvm_state->nr_slots_max;
+ }
+
+ if (cur >= nr_slots_new) {
+ /* Big enough, no need to grow, or we reached max */
+ return false;
+ }
+
+ if (cur == 0) {
+ slots = g_new0(KVMSlot, nr_slots_new);
+ } else {
+ assert(kml->slots);
+ slots = g_renew(KVMSlot, kml->slots, nr_slots_new);
+ /*
+ * g_renew() doesn't initialize extended buffers, however kvm
+ * memslots require fields to be zero-initialized. E.g. pointers,
+ * memory_size field, etc.
+ */
+ memset(&slots[cur], 0x0, sizeof(slots[0]) * (nr_slots_new - cur));
+ }
+
+ for (i = cur; i < nr_slots_new; i++) {
+ slots[i].slot = i;
+ }
+
+ kml->slots = slots;
+ kml->nr_slots_allocated = nr_slots_new;
+ trace_kvm_slots_grow(cur, nr_slots_new);
+
+ return true;
+}
+
+static bool kvm_slots_double(KVMMemoryListener *kml)
+{
+ return kvm_slots_grow(kml, kml->nr_slots_allocated * 2);
+}
+
unsigned int kvm_get_max_memslots(void)
{
KVMState *s = KVM_STATE(current_accel());
- return s->nr_slots;
+ return s->nr_slots_max;
}
unsigned int kvm_get_free_memslots(void)
@@ -183,25 +239,36 @@ unsigned int kvm_get_free_memslots(void)
if (!s->as[i].ml) {
continue;
}
- used_slots = MAX(used_slots, s->as[i].ml->nr_used_slots);
+ used_slots = MAX(used_slots, s->as[i].ml->nr_slots_used);
}
kvm_slots_unlock();
- return s->nr_slots - used_slots;
+ return s->nr_slots_max - used_slots;
}
/* Called with KVMMemoryListener.slots_lock held */
static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml)
{
- KVMState *s = kvm_state;
+ unsigned int n;
int i;
- for (i = 0; i < s->nr_slots; i++) {
+ for (i = 0; i < kml->nr_slots_allocated; i++) {
if (kml->slots[i].memory_size == 0) {
return &kml->slots[i];
}
}
+ /*
+ * If no free slots, try to grow first by doubling. Cache the old size
+ * here to avoid another round of search: if the grow succeeded, it
+ * means slots[] now must have the existing "n" slots occupied,
+ * followed by one or more free slots starting from slots[n].
+ */
+ n = kml->nr_slots_allocated;
+ if (kvm_slots_double(kml)) {
+ return &kml->slots[n];
+ }
+
return NULL;
}
@@ -222,10 +289,9 @@ static KVMSlot *kvm_lookup_matching_slot(KVMMemoryListener *kml,
hwaddr start_addr,
hwaddr size)
{
- KVMState *s = kvm_state;
int i;
- for (i = 0; i < s->nr_slots; i++) {
+ for (i = 0; i < kml->nr_slots_allocated; i++) {
KVMSlot *mem = &kml->slots[i];
if (start_addr == mem->start_addr && size == mem->memory_size) {
@@ -267,7 +333,7 @@ int kvm_physical_memory_addr_from_host(KVMState *s, void *ram,
int i, ret = 0;
kvm_slots_lock();
- for (i = 0; i < s->nr_slots; i++) {
+ for (i = 0; i < kml->nr_slots_allocated; i++) {
KVMSlot *mem = &kml->slots[i];
if (ram >= mem->ram && ram < mem->ram + mem->memory_size) {
@@ -340,14 +406,84 @@ err:
return ret;
}
+void kvm_park_vcpu(CPUState *cpu)
+{
+ struct KVMParkedVcpu *vcpu;
+
+ trace_kvm_park_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu));
+
+ vcpu = g_malloc0(sizeof(*vcpu));
+ vcpu->vcpu_id = kvm_arch_vcpu_id(cpu);
+ vcpu->kvm_fd = cpu->kvm_fd;
+ QLIST_INSERT_HEAD(&kvm_state->kvm_parked_vcpus, vcpu, node);
+}
+
+int kvm_unpark_vcpu(KVMState *s, unsigned long vcpu_id)
+{
+ struct KVMParkedVcpu *cpu;
+ int kvm_fd = -ENOENT;
+
+ QLIST_FOREACH(cpu, &s->kvm_parked_vcpus, node) {
+ if (cpu->vcpu_id == vcpu_id) {
+ QLIST_REMOVE(cpu, node);
+ kvm_fd = cpu->kvm_fd;
+ g_free(cpu);
+ break;
+ }
+ }
+
+ trace_kvm_unpark_vcpu(vcpu_id, kvm_fd > 0 ? "unparked" : "!found parked");
+
+ return kvm_fd;
+}
+
+int kvm_create_vcpu(CPUState *cpu)
+{
+ unsigned long vcpu_id = kvm_arch_vcpu_id(cpu);
+ KVMState *s = kvm_state;
+ int kvm_fd;
+
+ /* check if the KVM vCPU already exist but is parked */
+ kvm_fd = kvm_unpark_vcpu(s, vcpu_id);
+ if (kvm_fd < 0) {
+ /* vCPU not parked: create a new KVM vCPU */
+ kvm_fd = kvm_vm_ioctl(s, KVM_CREATE_VCPU, vcpu_id);
+ if (kvm_fd < 0) {
+ error_report("KVM_CREATE_VCPU IOCTL failed for vCPU %lu", vcpu_id);
+ return kvm_fd;
+ }
+ }
+
+ cpu->kvm_fd = kvm_fd;
+ cpu->kvm_state = s;
+ cpu->vcpu_dirty = true;
+ cpu->dirty_pages = 0;
+ cpu->throttle_us_per_full = 0;
+
+ trace_kvm_create_vcpu(cpu->cpu_index, vcpu_id, kvm_fd);
+
+ return 0;
+}
+
+int kvm_create_and_park_vcpu(CPUState *cpu)
+{
+ int ret = 0;
+
+ ret = kvm_create_vcpu(cpu);
+ if (!ret) {
+ kvm_park_vcpu(cpu);
+ }
+
+ return ret;
+}
+
static int do_kvm_destroy_vcpu(CPUState *cpu)
{
KVMState *s = kvm_state;
- long mmap_size;
- struct KVMParkedVcpu *vcpu = NULL;
+ int mmap_size;
int ret = 0;
- trace_kvm_destroy_vcpu();
+ trace_kvm_destroy_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu));
ret = kvm_arch_destroy_vcpu(cpu);
if (ret < 0) {
@@ -373,10 +509,7 @@ static int do_kvm_destroy_vcpu(CPUState *cpu)
}
}
- vcpu = g_malloc0(sizeof(*vcpu));
- vcpu->vcpu_id = kvm_arch_vcpu_id(cpu);
- vcpu->kvm_fd = cpu->kvm_fd;
- QLIST_INSERT_HEAD(&kvm_state->kvm_parked_vcpus, vcpu, node);
+ kvm_park_vcpu(cpu);
err:
return ret;
}
@@ -389,45 +522,22 @@ void kvm_destroy_vcpu(CPUState *cpu)
}
}
-static int kvm_get_vcpu(KVMState *s, unsigned long vcpu_id)
-{
- struct KVMParkedVcpu *cpu;
-
- QLIST_FOREACH(cpu, &s->kvm_parked_vcpus, node) {
- if (cpu->vcpu_id == vcpu_id) {
- int kvm_fd;
-
- QLIST_REMOVE(cpu, node);
- kvm_fd = cpu->kvm_fd;
- g_free(cpu);
- return kvm_fd;
- }
- }
-
- return kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)vcpu_id);
-}
-
int kvm_init_vcpu(CPUState *cpu, Error **errp)
{
KVMState *s = kvm_state;
- long mmap_size;
+ int mmap_size;
int ret;
trace_kvm_init_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu));
- ret = kvm_get_vcpu(s, kvm_arch_vcpu_id(cpu));
+ ret = kvm_create_vcpu(cpu);
if (ret < 0) {
- error_setg_errno(errp, -ret, "kvm_init_vcpu: kvm_get_vcpu failed (%lu)",
+ error_setg_errno(errp, -ret,
+ "kvm_init_vcpu: kvm_create_vcpu failed (%lu)",
kvm_arch_vcpu_id(cpu));
goto err;
}
- cpu->kvm_fd = ret;
- cpu->kvm_state = s;
- cpu->vcpu_dirty = true;
- cpu->dirty_pages = 0;
- cpu->throttle_us_per_full = 0;
-
mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0);
if (mmap_size < 0) {
ret = mmap_size;
@@ -1027,7 +1137,7 @@ static int kvm_physical_log_clear(KVMMemoryListener *kml,
kvm_slots_lock();
- for (i = 0; i < s->nr_slots; i++) {
+ for (i = 0; i < kml->nr_slots_allocated; i++) {
mem = &kml->slots[i];
/* Discard slots that are empty or do not overlap the section */
if (!mem->memory_size ||
@@ -1406,7 +1516,7 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
}
start_addr += slot_size;
size -= slot_size;
- kml->nr_used_slots--;
+ kml->nr_slots_used--;
} while (size);
return;
}
@@ -1445,7 +1555,7 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
ram_start_offset += slot_size;
ram += slot_size;
size -= slot_size;
- kml->nr_used_slots++;
+ kml->nr_slots_used++;
} while (size);
}
@@ -1481,11 +1591,7 @@ static void *kvm_dirty_ring_reaper_thread(void *data)
r->reaper_iteration++;
}
- trace_kvm_dirty_ring_reaper("exit");
-
- rcu_unregister_thread();
-
- return NULL;
+ g_assert_not_reached();
}
static void kvm_dirty_ring_reaper_init(KVMState *s)
@@ -1675,12 +1781,8 @@ static void kvm_log_sync_global(MemoryListener *l, bool last_stage)
/* Flush all kernel dirty addresses into KVMSlot dirty bitmap */
kvm_dirty_ring_flush();
- /*
- * TODO: make this faster when nr_slots is big while there are
- * only a few used slots (small VMs).
- */
kvm_slots_lock();
- for (i = 0; i < s->nr_slots; i++) {
+ for (i = 0; i < kml->nr_slots_allocated; i++) {
mem = &kml->slots[i];
if (mem->memory_size && mem->flags & KVM_MEM_LOG_DIRTY_PAGES) {
kvm_slot_sync_dirty_pages(mem);
@@ -1795,12 +1897,9 @@ void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml,
{
int i;
- kml->slots = g_new0(KVMSlot, s->nr_slots);
kml->as_id = as_id;
- for (i = 0; i < s->nr_slots; i++) {
- kml->slots[i].slot = i;
- }
+ kvm_slots_grow(kml, KVM_MEMSLOTS_NR_ALLOC_DEFAULT);
QSIMPLEQ_INIT(&kml->transaction_add);
QSIMPLEQ_INIT(&kml->transaction_del);
@@ -2341,6 +2440,109 @@ uint32_t kvm_dirty_ring_size(void)
return kvm_state->kvm_dirty_ring_size;
}
+static int do_kvm_create_vm(MachineState *ms, int type)
+{
+ KVMState *s;
+ int ret;
+
+ s = KVM_STATE(ms->accelerator);
+
+ do {
+ ret = kvm_ioctl(s, KVM_CREATE_VM, type);
+ } while (ret == -EINTR);
+
+ if (ret < 0) {
+ error_report("ioctl(KVM_CREATE_VM) failed: %s", strerror(-ret));
+
+#ifdef TARGET_S390X
+ if (ret == -EINVAL) {
+ error_printf("Host kernel setup problem detected."
+ " Please verify:\n");
+ error_printf("- for kernels supporting the"
+ " switch_amode or user_mode parameters, whether");
+ error_printf(" user space is running in primary address space\n");
+ error_printf("- for kernels supporting the vm.allocate_pgste"
+ " sysctl, whether it is enabled\n");
+ }
+#elif defined(TARGET_PPC)
+ if (ret == -EINVAL) {
+ error_printf("PPC KVM module is not loaded. Try modprobe kvm_%s.\n",
+ (type == 2) ? "pr" : "hv");
+ }
+#endif
+ }
+
+ return ret;
+}
+
+static int find_kvm_machine_type(MachineState *ms)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ int type;
+
+ if (object_property_find(OBJECT(current_machine), "kvm-type")) {
+ g_autofree char *kvm_type;
+ kvm_type = object_property_get_str(OBJECT(current_machine),
+ "kvm-type",
+ &error_abort);
+ type = mc->kvm_type(ms, kvm_type);
+ } else if (mc->kvm_type) {
+ type = mc->kvm_type(ms, NULL);
+ } else {
+ type = kvm_arch_get_default_type(ms);
+ }
+ return type;
+}
+
+static int kvm_setup_dirty_ring(KVMState *s)
+{
+ uint64_t dirty_log_manual_caps;
+ int ret;
+
+ /*
+ * Enable KVM dirty ring if supported, otherwise fall back to
+ * dirty logging mode
+ */
+ ret = kvm_dirty_ring_init(s);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /*
+ * KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 is not needed when dirty ring is
+ * enabled. More importantly, KVM_DIRTY_LOG_INITIALLY_SET will assume no
+ * page is wr-protected initially, which is against how kvm dirty ring is
+ * usage - kvm dirty ring requires all pages are wr-protected at the very
+ * beginning. Enabling this feature for dirty ring causes data corruption.
+ *
+ * TODO: Without KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 and kvm clear dirty log,
+ * we may expect a higher stall time when starting the migration. In the
+ * future we can enable KVM_CLEAR_DIRTY_LOG to work with dirty ring too:
+ * instead of clearing dirty bit, it can be a way to explicitly wr-protect
+ * guest pages.
+ */
+ if (!s->kvm_dirty_ring_size) {
+ dirty_log_manual_caps =
+ kvm_check_extension(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2);
+ dirty_log_manual_caps &= (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE |
+ KVM_DIRTY_LOG_INITIALLY_SET);
+ s->manual_dirty_log_protect = dirty_log_manual_caps;
+ if (dirty_log_manual_caps) {
+ ret = kvm_vm_enable_cap(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2, 0,
+ dirty_log_manual_caps);
+ if (ret) {
+ warn_report("Trying to enable capability %"PRIu64" of "
+ "KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 but failed. "
+ "Falling back to the legacy mode. ",
+ dirty_log_manual_caps);
+ s->manual_dirty_log_protect = 0;
+ }
+ }
+ }
+
+ return 0;
+}
+
static int kvm_init(MachineState *ms)
{
MachineClass *mc = MACHINE_GET_CLASS(ms);
@@ -2360,7 +2562,6 @@ static int kvm_init(MachineState *ms)
const KVMCapabilityInfo *missing_cap;
int ret;
int type;
- uint64_t dirty_log_manual_caps;
qemu_mutex_init(&kml_slots_lock);
@@ -2383,7 +2584,7 @@ static int kvm_init(MachineState *ms)
QLIST_INIT(&s->kvm_parked_vcpus);
s->fd = qemu_open_old(s->device ?: "/dev/kvm", O_RDWR);
if (s->fd == -1) {
- fprintf(stderr, "Could not access KVM kernel module: %m\n");
+ error_report("Could not access KVM kernel module: %m");
ret = -errno;
goto err;
}
@@ -2393,84 +2594,43 @@ static int kvm_init(MachineState *ms)
if (ret >= 0) {
ret = -EINVAL;
}
- fprintf(stderr, "kvm version too old\n");
+ error_report("kvm version too old");
goto err;
}
if (ret > KVM_API_VERSION) {
ret = -EINVAL;
- fprintf(stderr, "kvm version not supported\n");
+ error_report("kvm version not supported");
goto err;
}
- kvm_supported_memory_attributes = kvm_check_extension(s, KVM_CAP_MEMORY_ATTRIBUTES);
- kvm_guest_memfd_supported =
- kvm_check_extension(s, KVM_CAP_GUEST_MEMFD) &&
- kvm_check_extension(s, KVM_CAP_USER_MEMORY2) &&
- (kvm_supported_memory_attributes & KVM_MEMORY_ATTRIBUTE_PRIVATE);
-
kvm_immediate_exit = kvm_check_extension(s, KVM_CAP_IMMEDIATE_EXIT);
- s->nr_slots = kvm_check_extension(s, KVM_CAP_NR_MEMSLOTS);
+ s->nr_slots_max = kvm_check_extension(s, KVM_CAP_NR_MEMSLOTS);
/* If unspecified, use the default value */
- if (!s->nr_slots) {
- s->nr_slots = 32;
- }
-
- s->nr_as = kvm_check_extension(s, KVM_CAP_MULTI_ADDRESS_SPACE);
- if (s->nr_as <= 1) {
- s->nr_as = 1;
- }
- s->as = g_new0(struct KVMAs, s->nr_as);
-
- if (object_property_find(OBJECT(current_machine), "kvm-type")) {
- g_autofree char *kvm_type = object_property_get_str(OBJECT(current_machine),
- "kvm-type",
- &error_abort);
- type = mc->kvm_type(ms, kvm_type);
- } else if (mc->kvm_type) {
- type = mc->kvm_type(ms, NULL);
- } else {
- type = kvm_arch_get_default_type(ms);
+ if (!s->nr_slots_max) {
+ s->nr_slots_max = KVM_MEMSLOTS_NR_MAX_DEFAULT;
}
+ type = find_kvm_machine_type(ms);
if (type < 0) {
ret = -EINVAL;
goto err;
}
- do {
- ret = kvm_ioctl(s, KVM_CREATE_VM, type);
- } while (ret == -EINTR);
-
+ ret = do_kvm_create_vm(ms, type);
if (ret < 0) {
- fprintf(stderr, "ioctl(KVM_CREATE_VM) failed: %d %s\n", -ret,
- strerror(-ret));
-
-#ifdef TARGET_S390X
- if (ret == -EINVAL) {
- fprintf(stderr,
- "Host kernel setup problem detected. Please verify:\n");
- fprintf(stderr, "- for kernels supporting the switch_amode or"
- " user_mode parameters, whether\n");
- fprintf(stderr,
- " user space is running in primary address space\n");
- fprintf(stderr,
- "- for kernels supporting the vm.allocate_pgste sysctl, "
- "whether it is enabled\n");
- }
-#elif defined(TARGET_PPC)
- if (ret == -EINVAL) {
- fprintf(stderr,
- "PPC KVM module is not loaded. Try modprobe kvm_%s.\n",
- (type == 2) ? "pr" : "hv");
- }
-#endif
goto err;
}
s->vmfd = ret;
+ s->nr_as = kvm_vm_check_extension(s, KVM_CAP_MULTI_ADDRESS_SPACE);
+ if (s->nr_as <= 1) {
+ s->nr_as = 1;
+ }
+ s->as = g_new0(struct KVMAs, s->nr_as);
+
/* check the vcpu limits */
soft_vcpus_limit = kvm_recommended_vcpus(s);
hard_vcpus_limit = kvm_max_vcpus(s);
@@ -2482,9 +2642,9 @@ static int kvm_init(MachineState *ms)
nc->name, nc->num, soft_vcpus_limit);
if (nc->num > hard_vcpus_limit) {
- fprintf(stderr, "Number of %s cpus requested (%d) exceeds "
- "the maximum cpus supported by KVM (%d)\n",
- nc->name, nc->num, hard_vcpus_limit);
+ error_report("Number of %s cpus requested (%d) exceeds "
+ "the maximum cpus supported by KVM (%d)",
+ nc->name, nc->num, hard_vcpus_limit);
exit(1);
}
}
@@ -2498,8 +2658,8 @@ static int kvm_init(MachineState *ms)
}
if (missing_cap) {
ret = -EINVAL;
- fprintf(stderr, "kvm does not support %s\n%s",
- missing_cap->name, upgrade_note);
+ error_report("kvm does not support %s", missing_cap->name);
+ error_printf("%s", upgrade_note);
goto err;
}
@@ -2507,47 +2667,11 @@ static int kvm_init(MachineState *ms)
s->coalesced_pio = s->coalesced_mmio &&
kvm_check_extension(s, KVM_CAP_COALESCED_PIO);
- /*
- * Enable KVM dirty ring if supported, otherwise fall back to
- * dirty logging mode
- */
- ret = kvm_dirty_ring_init(s);
+ ret = kvm_setup_dirty_ring(s);
if (ret < 0) {
goto err;
}
- /*
- * KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 is not needed when dirty ring is
- * enabled. More importantly, KVM_DIRTY_LOG_INITIALLY_SET will assume no
- * page is wr-protected initially, which is against how kvm dirty ring is
- * usage - kvm dirty ring requires all pages are wr-protected at the very
- * beginning. Enabling this feature for dirty ring causes data corruption.
- *
- * TODO: Without KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 and kvm clear dirty log,
- * we may expect a higher stall time when starting the migration. In the
- * future we can enable KVM_CLEAR_DIRTY_LOG to work with dirty ring too:
- * instead of clearing dirty bit, it can be a way to explicitly wr-protect
- * guest pages.
- */
- if (!s->kvm_dirty_ring_size) {
- dirty_log_manual_caps =
- kvm_check_extension(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2);
- dirty_log_manual_caps &= (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE |
- KVM_DIRTY_LOG_INITIALLY_SET);
- s->manual_dirty_log_protect = dirty_log_manual_caps;
- if (dirty_log_manual_caps) {
- ret = kvm_vm_enable_cap(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2, 0,
- dirty_log_manual_caps);
- if (ret) {
- warn_report("Trying to enable capability %"PRIu64" of "
- "KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 but failed. "
- "Falling back to the legacy mode. ",
- dirty_log_manual_caps);
- s->manual_dirty_log_protect = 0;
- }
- }
- }
-
#ifdef KVM_CAP_VCPU_EVENTS
s->vcpu_events = kvm_check_extension(s, KVM_CAP_VCPU_EVENTS);
#endif
@@ -2559,7 +2683,7 @@ static int kvm_init(MachineState *ms)
}
kvm_readonly_mem_allowed =
- (kvm_check_extension(s, KVM_CAP_READONLY_MEM) > 0);
+ (kvm_vm_check_extension(s, KVM_CAP_READONLY_MEM) > 0);
kvm_resamplefds_allowed =
(kvm_check_extension(s, KVM_CAP_IRQFD_RESAMPLE) > 0);
@@ -2593,6 +2717,12 @@ static int kvm_init(MachineState *ms)
goto err;
}
+ kvm_supported_memory_attributes = kvm_vm_check_extension(s, KVM_CAP_MEMORY_ATTRIBUTES);
+ kvm_guest_memfd_supported =
+ kvm_check_extension(s, KVM_CAP_GUEST_MEMFD) &&
+ kvm_check_extension(s, KVM_CAP_USER_MEMORY2) &&
+ (kvm_supported_memory_attributes & KVM_MEMORY_ATTRIBUTE_PRIVATE);
+
if (s->kernel_irqchip_split == ON_OFF_AUTO_AUTO) {
s->kernel_irqchip_split = mc->default_kernel_irqchip_split ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
}
@@ -2722,9 +2852,15 @@ void kvm_flush_coalesced_mmio_buffer(void)
static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
{
if (!cpu->vcpu_dirty && !kvm_state->guest_state_protected) {
- int ret = kvm_arch_get_registers(cpu);
+ Error *err = NULL;
+ int ret = kvm_arch_get_registers(cpu, &err);
if (ret) {
- error_report("Failed to get registers: %s", strerror(-ret));
+ if (err) {
+ error_reportf_err(err, "Failed to synchronize CPU state: ");
+ } else {
+ error_report("Failed to get registers: %s", strerror(-ret));
+ }
+
cpu_dump_state(cpu, stderr, CPU_DUMP_CODE);
vm_stop(RUN_STATE_INTERNAL_ERROR);
}
@@ -2742,9 +2878,15 @@ void kvm_cpu_synchronize_state(CPUState *cpu)
static void do_kvm_cpu_synchronize_post_reset(CPUState *cpu, run_on_cpu_data arg)
{
- int ret = kvm_arch_put_registers(cpu, KVM_PUT_RESET_STATE);
+ Error *err = NULL;
+ int ret = kvm_arch_put_registers(cpu, KVM_PUT_RESET_STATE, &err);
if (ret) {
- error_report("Failed to put registers after reset: %s", strerror(-ret));
+ if (err) {
+ error_reportf_err(err, "Restoring resisters after reset: ");
+ } else {
+ error_report("Failed to put registers after reset: %s",
+ strerror(-ret));
+ }
cpu_dump_state(cpu, stderr, CPU_DUMP_CODE);
vm_stop(RUN_STATE_INTERNAL_ERROR);
}
@@ -2759,9 +2901,15 @@ void kvm_cpu_synchronize_post_reset(CPUState *cpu)
static void do_kvm_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg)
{
- int ret = kvm_arch_put_registers(cpu, KVM_PUT_FULL_STATE);
+ Error *err = NULL;
+ int ret = kvm_arch_put_registers(cpu, KVM_PUT_FULL_STATE, &err);
if (ret) {
- error_report("Failed to put registers after init: %s", strerror(-ret));
+ if (err) {
+ error_reportf_err(err, "Putting registers after init: ");
+ } else {
+ error_report("Failed to put registers after init: %s",
+ strerror(-ret));
+ }
exit(1);
}
@@ -2951,10 +3099,15 @@ int kvm_cpu_exec(CPUState *cpu)
MemTxAttrs attrs;
if (cpu->vcpu_dirty) {
- ret = kvm_arch_put_registers(cpu, KVM_PUT_RUNTIME_STATE);
+ Error *err = NULL;
+ ret = kvm_arch_put_registers(cpu, KVM_PUT_RUNTIME_STATE, &err);
if (ret) {
- error_report("Failed to put registers after init: %s",
- strerror(-ret));
+ if (err) {
+ error_reportf_err(err, "Putting registers after init: ");
+ } else {
+ error_report("Failed to put registers after init: %s",
+ strerror(-ret));
+ }
ret = -1;
break;
}
@@ -3126,7 +3279,7 @@ int kvm_cpu_exec(CPUState *cpu)
return ret;
}
-int kvm_ioctl(KVMState *s, int type, ...)
+int kvm_ioctl(KVMState *s, unsigned long type, ...)
{
int ret;
void *arg;
@@ -3144,7 +3297,7 @@ int kvm_ioctl(KVMState *s, int type, ...)
return ret;
}
-int kvm_vm_ioctl(KVMState *s, int type, ...)
+int kvm_vm_ioctl(KVMState *s, unsigned long type, ...)
{
int ret;
void *arg;
@@ -3164,7 +3317,7 @@ int kvm_vm_ioctl(KVMState *s, int type, ...)
return ret;
}
-int kvm_vcpu_ioctl(CPUState *cpu, int type, ...)
+int kvm_vcpu_ioctl(CPUState *cpu, unsigned long type, ...)
{
int ret;
void *arg;
@@ -3184,7 +3337,7 @@ int kvm_vcpu_ioctl(CPUState *cpu, int type, ...)
return ret;
}
-int kvm_device_ioctl(int fd, int type, ...)
+int kvm_device_ioctl(int fd, unsigned long type, ...)
{
int ret;
void *arg;
@@ -3745,6 +3898,21 @@ static void kvm_set_device(Object *obj,
s->device = g_strdup(value);
}
+static void kvm_set_kvm_rapl(Object *obj, bool value, Error **errp)
+{
+ KVMState *s = KVM_STATE(obj);
+ s->msr_energy.enable = value;
+}
+
+static void kvm_set_kvm_rapl_socket_path(Object *obj,
+ const char *str,
+ Error **errp)
+{
+ KVMState *s = KVM_STATE(obj);
+ g_free(s->msr_energy.socket_path);
+ s->msr_energy.socket_path = g_strdup(str);
+}
+
static void kvm_accel_instance_init(Object *obj)
{
KVMState *s = KVM_STATE(obj);
@@ -3764,6 +3932,7 @@ static void kvm_accel_instance_init(Object *obj)
s->xen_gnttab_max_frames = 64;
s->xen_evtchn_max_pirq = 256;
s->device = NULL;
+ s->msr_energy.enable = false;
}
/**
@@ -3808,6 +3977,17 @@ static void kvm_accel_class_init(ObjectClass *oc, void *data)
object_class_property_set_description(oc, "device",
"Path to the device node to use (default: /dev/kvm)");
+ object_class_property_add_bool(oc, "rapl",
+ NULL,
+ kvm_set_kvm_rapl);
+ object_class_property_set_description(oc, "rapl",
+ "Allow energy related MSRs for RAPL interface in Guest");
+
+ object_class_property_add_str(oc, "rapl-helper-socket", NULL,
+ kvm_set_kvm_rapl_socket_path);
+ object_class_property_set_description(oc, "rapl-helper-socket",
+ "Socket Path for comminucating with the Virtual MSR helper daemon");
+
kvm_arch_accel_class_init(oc);
}
diff --git a/accel/kvm/kvm-cpus.h b/accel/kvm/kvm-cpus.h
index ca40add..171b22fd 100644
--- a/accel/kvm/kvm-cpus.h
+++ b/accel/kvm/kvm-cpus.h
@@ -22,5 +22,4 @@ bool kvm_supports_guest_debug(void);
int kvm_insert_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len);
int kvm_remove_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len);
void kvm_remove_all_breakpoints(CPUState *cpu);
-
#endif /* KVM_CPUS_H */
diff --git a/accel/kvm/trace-events b/accel/kvm/trace-events
index 681ccb6..e43d18a 100644
--- a/accel/kvm/trace-events
+++ b/accel/kvm/trace-events
@@ -1,14 +1,18 @@
# See docs/devel/tracing.rst for syntax documentation.
# kvm-all.c
-kvm_ioctl(int type, void *arg) "type 0x%x, arg %p"
-kvm_vm_ioctl(int type, void *arg) "type 0x%x, arg %p"
-kvm_vcpu_ioctl(int cpu_index, int type, void *arg) "cpu_index %d, type 0x%x, arg %p"
+kvm_ioctl(unsigned long type, void *arg) "type 0x%lx, arg %p"
+kvm_vm_ioctl(unsigned long type, void *arg) "type 0x%lx, arg %p"
+kvm_vcpu_ioctl(int cpu_index, unsigned long type, void *arg) "cpu_index %d, type 0x%lx, arg %p"
kvm_run_exit(int cpu_index, uint32_t reason) "cpu_index %d, reason %d"
-kvm_device_ioctl(int fd, int type, void *arg) "dev fd %d, type 0x%x, arg %p"
+kvm_device_ioctl(int fd, unsigned long type, void *arg) "dev fd %d, type 0x%lx, arg %p"
kvm_failed_reg_get(uint64_t id, const char *msg) "Warning: Unable to retrieve ONEREG %" PRIu64 " from KVM: %s"
kvm_failed_reg_set(uint64_t id, const char *msg) "Warning: Unable to set ONEREG %" PRIu64 " to KVM: %s"
kvm_init_vcpu(int cpu_index, unsigned long arch_cpu_id) "index: %d id: %lu"
+kvm_create_vcpu(int cpu_index, unsigned long arch_cpu_id, int kvm_fd) "index: %d, id: %lu, kvm fd: %d"
+kvm_destroy_vcpu(int cpu_index, unsigned long arch_cpu_id) "index: %d id: %lu"
+kvm_park_vcpu(int cpu_index, unsigned long arch_cpu_id) "index: %d id: %lu"
+kvm_unpark_vcpu(unsigned long arch_cpu_id, const char *msg) "id: %lu %s"
kvm_irqchip_commit_routes(void) ""
kvm_irqchip_add_msi_route(char *name, int vector, int virq) "dev %s vector %d virq %d"
kvm_irqchip_update_msi_route(int virq) "Updating MSI route virq=%d"
@@ -25,7 +29,6 @@ kvm_dirty_ring_reaper(const char *s) "%s"
kvm_dirty_ring_reap(uint64_t count, int64_t t) "reaped %"PRIu64" pages (took %"PRIi64" us)"
kvm_dirty_ring_reaper_kick(const char *reason) "%s"
kvm_dirty_ring_flush(int finished) "%d"
-kvm_destroy_vcpu(void) ""
kvm_failed_get_vcpu_mmap_size(void) ""
kvm_cpu_exec(void) ""
kvm_interrupt_exit_request(void) ""
@@ -33,3 +36,4 @@ kvm_io_window_exit(void) ""
kvm_run_exit_system_event(int cpu_index, uint32_t event_type) "cpu_index %d, system_even_type %"PRIu32
kvm_convert_memory(uint64_t start, uint64_t size, const char *msg) "start 0x%" PRIx64 " size 0x%" PRIx64 " %s"
kvm_memory_fault(uint64_t start, uint64_t size, uint64_t flags) "start 0x%" PRIx64 " size 0x%" PRIx64 " flags 0x%" PRIx64
+kvm_slots_grow(unsigned int old, unsigned int new) "%u -> %u"
diff --git a/accel/stubs/tcg-stub.c b/accel/stubs/tcg-stub.c
index dd890d6..7f4208f 100644
--- a/accel/stubs/tcg-stub.c
+++ b/accel/stubs/tcg-stub.c
@@ -18,20 +18,6 @@ void tb_flush(CPUState *cpu)
{
}
-int probe_access_flags(CPUArchState *env, vaddr addr, int size,
- MMUAccessType access_type, int mmu_idx,
- bool nonfault, void **phost, uintptr_t retaddr)
-{
- g_assert_not_reached();
-}
-
-void *probe_access(CPUArchState *env, vaddr addr, int size,
- MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
-{
- /* Handled by hardware accelerator. */
- g_assert_not_reached();
-}
-
G_NORETURN void cpu_loop_exit(CPUState *cpu)
{
g_assert_not_reached();
diff --git a/accel/tcg/atomic_common.c.inc b/accel/tcg/atomic_common.c.inc
index 95a5c5f..6056598 100644
--- a/accel/tcg/atomic_common.c.inc
+++ b/accel/tcg/atomic_common.c.inc
@@ -14,9 +14,20 @@
*/
static void atomic_trace_rmw_post(CPUArchState *env, uint64_t addr,
+ uint64_t read_value_low,
+ uint64_t read_value_high,
+ uint64_t write_value_low,
+ uint64_t write_value_high,
MemOpIdx oi)
{
- qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_RW);
+ if (cpu_plugin_mem_cbs_enabled(env_cpu(env))) {
+ qemu_plugin_vcpu_mem_cb(env_cpu(env), addr,
+ read_value_low, read_value_high,
+ oi, QEMU_PLUGIN_MEM_R);
+ qemu_plugin_vcpu_mem_cb(env_cpu(env), addr,
+ write_value_low, write_value_high,
+ oi, QEMU_PLUGIN_MEM_W);
+ }
}
/*
diff --git a/accel/tcg/atomic_template.h b/accel/tcg/atomic_template.h
index 1dc2151..89593b2 100644
--- a/accel/tcg/atomic_template.h
+++ b/accel/tcg/atomic_template.h
@@ -53,6 +53,14 @@
# error unsupported data size
#endif
+#if DATA_SIZE == 16
+# define VALUE_LOW(val) int128_getlo(val)
+# define VALUE_HIGH(val) int128_gethi(val)
+#else
+# define VALUE_LOW(val) val
+# define VALUE_HIGH(val) 0
+#endif
+
#if DATA_SIZE >= 4
# define ABI_TYPE DATA_TYPE
#else
@@ -83,7 +91,12 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, abi_ptr addr,
ret = qatomic_cmpxchg__nocheck(haddr, cmpv, newv);
#endif
ATOMIC_MMU_CLEANUP;
- atomic_trace_rmw_post(env, addr, oi);
+ atomic_trace_rmw_post(env, addr,
+ VALUE_LOW(ret),
+ VALUE_HIGH(ret),
+ VALUE_LOW(newv),
+ VALUE_HIGH(newv),
+ oi);
return ret;
}
@@ -97,7 +110,12 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, abi_ptr addr, ABI_TYPE val,
ret = qatomic_xchg__nocheck(haddr, val);
ATOMIC_MMU_CLEANUP;
- atomic_trace_rmw_post(env, addr, oi);
+ atomic_trace_rmw_post(env, addr,
+ VALUE_LOW(ret),
+ VALUE_HIGH(ret),
+ VALUE_LOW(val),
+ VALUE_HIGH(val),
+ oi);
return ret;
}
@@ -109,7 +127,12 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr, \
haddr = atomic_mmu_lookup(env_cpu(env), addr, oi, DATA_SIZE, retaddr); \
ret = qatomic_##X(haddr, val); \
ATOMIC_MMU_CLEANUP; \
- atomic_trace_rmw_post(env, addr, oi); \
+ atomic_trace_rmw_post(env, addr, \
+ VALUE_LOW(ret), \
+ VALUE_HIGH(ret), \
+ VALUE_LOW(val), \
+ VALUE_HIGH(val), \
+ oi); \
return ret; \
}
@@ -145,7 +168,12 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr, \
cmp = qatomic_cmpxchg__nocheck(haddr, old, new); \
} while (cmp != old); \
ATOMIC_MMU_CLEANUP; \
- atomic_trace_rmw_post(env, addr, oi); \
+ atomic_trace_rmw_post(env, addr, \
+ VALUE_LOW(old), \
+ VALUE_HIGH(old), \
+ VALUE_LOW(xval), \
+ VALUE_HIGH(xval), \
+ oi); \
return RET; \
}
@@ -188,7 +216,12 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, abi_ptr addr,
ret = qatomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv));
#endif
ATOMIC_MMU_CLEANUP;
- atomic_trace_rmw_post(env, addr, oi);
+ atomic_trace_rmw_post(env, addr,
+ VALUE_LOW(ret),
+ VALUE_HIGH(ret),
+ VALUE_LOW(newv),
+ VALUE_HIGH(newv),
+ oi);
return BSWAP(ret);
}
@@ -202,7 +235,12 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, abi_ptr addr, ABI_TYPE val,
ret = qatomic_xchg__nocheck(haddr, BSWAP(val));
ATOMIC_MMU_CLEANUP;
- atomic_trace_rmw_post(env, addr, oi);
+ atomic_trace_rmw_post(env, addr,
+ VALUE_LOW(ret),
+ VALUE_HIGH(ret),
+ VALUE_LOW(val),
+ VALUE_HIGH(val),
+ oi);
return BSWAP(ret);
}
@@ -214,7 +252,12 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr, \
haddr = atomic_mmu_lookup(env_cpu(env), addr, oi, DATA_SIZE, retaddr); \
ret = qatomic_##X(haddr, BSWAP(val)); \
ATOMIC_MMU_CLEANUP; \
- atomic_trace_rmw_post(env, addr, oi); \
+ atomic_trace_rmw_post(env, addr, \
+ VALUE_LOW(ret), \
+ VALUE_HIGH(ret), \
+ VALUE_LOW(val), \
+ VALUE_HIGH(val), \
+ oi); \
return BSWAP(ret); \
}
@@ -247,7 +290,12 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr, \
ldn = qatomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new)); \
} while (ldo != ldn); \
ATOMIC_MMU_CLEANUP; \
- atomic_trace_rmw_post(env, addr, oi); \
+ atomic_trace_rmw_post(env, addr, \
+ VALUE_LOW(old), \
+ VALUE_HIGH(old), \
+ VALUE_LOW(xval), \
+ VALUE_HIGH(xval), \
+ oi); \
return RET; \
}
@@ -281,3 +329,5 @@ GEN_ATOMIC_HELPER_FN(add_fetch, ADD, DATA_TYPE, new)
#undef SUFFIX
#undef DATA_SIZE
#undef SHIFT
+#undef VALUE_LOW
+#undef VALUE_HIGH
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index 9010dad..8163295 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -41,9 +41,6 @@
#include "tb-context.h"
#include "internal-common.h"
#include "internal-target.h"
-#if defined(CONFIG_USER_ONLY)
-#include "user-retaddr.h"
-#endif
/* -icount align implementation. */
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index 117b516..b76a4ea 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -1221,22 +1221,35 @@ void tlb_set_page(CPUState *cpu, vaddr addr,
}
/*
- * Note: tlb_fill() can trigger a resize of the TLB. This means that all of the
- * caller's prior references to the TLB table (e.g. CPUTLBEntry pointers) must
- * be discarded and looked up again (e.g. via tlb_entry()).
+ * Note: tlb_fill_align() can trigger a resize of the TLB.
+ * This means that all of the caller's prior references to the TLB table
+ * (e.g. CPUTLBEntry pointers) must be discarded and looked up again
+ * (e.g. via tlb_entry()).
*/
-static void tlb_fill(CPUState *cpu, vaddr addr, int size,
- MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
+static bool tlb_fill_align(CPUState *cpu, vaddr addr, MMUAccessType type,
+ int mmu_idx, MemOp memop, int size,
+ bool probe, uintptr_t ra)
{
- bool ok;
+ const TCGCPUOps *ops = cpu->cc->tcg_ops;
+ CPUTLBEntryFull full;
- /*
- * This is not a probe, so only valid return is success; failure
- * should result in exception + longjmp to the cpu loop.
- */
- ok = cpu->cc->tcg_ops->tlb_fill(cpu, addr, size,
- access_type, mmu_idx, false, retaddr);
- assert(ok);
+ if (ops->tlb_fill_align) {
+ if (ops->tlb_fill_align(cpu, &full, addr, type, mmu_idx,
+ memop, size, probe, ra)) {
+ tlb_set_page_full(cpu, mmu_idx, addr, &full);
+ return true;
+ }
+ } else {
+ /* Legacy behaviour is alignment before paging. */
+ if (addr & ((1u << memop_alignment_bits(memop)) - 1)) {
+ ops->do_unaligned_access(cpu, addr, type, mmu_idx, ra);
+ }
+ if (ops->tlb_fill(cpu, addr, size, type, mmu_idx, probe, ra)) {
+ return true;
+ }
+ }
+ assert(probe);
+ return false;
}
static inline void cpu_unaligned_access(CPUState *cpu, vaddr addr,
@@ -1351,22 +1364,22 @@ static int probe_access_internal(CPUState *cpu, vaddr addr,
if (!tlb_hit_page(tlb_addr, page_addr)) {
if (!victim_tlb_hit(cpu, mmu_idx, index, access_type, page_addr)) {
- if (!cpu->cc->tcg_ops->tlb_fill(cpu, addr, fault_size, access_type,
- mmu_idx, nonfault, retaddr)) {
+ if (!tlb_fill_align(cpu, addr, access_type, mmu_idx,
+ 0, fault_size, nonfault, retaddr)) {
/* Non-faulting page table read failed. */
*phost = NULL;
*pfull = NULL;
return TLB_INVALID_MASK;
}
- /* TLB resize via tlb_fill may have moved the entry. */
+ /* TLB resize via tlb_fill_align may have moved the entry. */
index = tlb_index(cpu, mmu_idx, addr);
entry = tlb_entry(cpu, mmu_idx, addr);
/*
* With PAGE_WRITE_INV, we set TLB_INVALID_MASK immediately,
- * to force the next access through tlb_fill. We've just
- * called tlb_fill, so we know that this entry *is* valid.
+ * to force the next access through tlb_fill_align. We've just
+ * called tlb_fill_align, so we know that this entry *is* valid.
*/
flags &= ~TLB_INVALID_MASK;
}
@@ -1607,16 +1620,17 @@ typedef struct MMULookupLocals {
* mmu_lookup1: translate one page
* @cpu: generic cpu state
* @data: lookup parameters
+ * @memop: memory operation for the access, or 0
* @mmu_idx: virtual address context
* @access_type: load/store/code
* @ra: return address into tcg generated code, or 0
*
* Resolve the translation for the one page at @data.addr, filling in
* the rest of @data with the results. If the translation fails,
- * tlb_fill will longjmp out. Return true if the softmmu tlb for
+ * tlb_fill_align will longjmp out. Return true if the softmmu tlb for
* @mmu_idx may have resized.
*/
-static bool mmu_lookup1(CPUState *cpu, MMULookupPageData *data,
+static bool mmu_lookup1(CPUState *cpu, MMULookupPageData *data, MemOp memop,
int mmu_idx, MMUAccessType access_type, uintptr_t ra)
{
vaddr addr = data->addr;
@@ -1631,7 +1645,8 @@ static bool mmu_lookup1(CPUState *cpu, MMULookupPageData *data,
if (!tlb_hit(tlb_addr, addr)) {
if (!victim_tlb_hit(cpu, mmu_idx, index, access_type,
addr & TARGET_PAGE_MASK)) {
- tlb_fill(cpu, addr, data->size, access_type, mmu_idx, ra);
+ tlb_fill_align(cpu, addr, access_type, mmu_idx,
+ memop, data->size, false, ra);
maybe_resized = true;
index = tlb_index(cpu, mmu_idx, addr);
entry = tlb_entry(cpu, mmu_idx, addr);
@@ -1643,6 +1658,25 @@ static bool mmu_lookup1(CPUState *cpu, MMULookupPageData *data,
flags = tlb_addr & (TLB_FLAGS_MASK & ~TLB_FORCE_SLOW);
flags |= full->slow_flags[access_type];
+ if (likely(!maybe_resized)) {
+ /* Alignment has not been checked by tlb_fill_align. */
+ int a_bits = memop_alignment_bits(memop);
+
+ /*
+ * This alignment check differs from the one above, in that this is
+ * based on the atomicity of the operation. The intended use case is
+ * the ARM memory type field of each PTE, where access to pages with
+ * Device memory type require alignment.
+ */
+ if (unlikely(flags & TLB_CHECK_ALIGNED)) {
+ int at_bits = memop_atomicity_bits(memop);
+ a_bits = MAX(a_bits, at_bits);
+ }
+ if (unlikely(addr & ((1 << a_bits) - 1))) {
+ cpu_unaligned_access(cpu, addr, access_type, mmu_idx, ra);
+ }
+ }
+
data->full = full;
data->flags = flags;
/* Compute haddr speculatively; depending on flags it might be invalid. */
@@ -1699,7 +1733,6 @@ static void mmu_watch_or_dirty(CPUState *cpu, MMULookupPageData *data,
static bool mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
uintptr_t ra, MMUAccessType type, MMULookupLocals *l)
{
- unsigned a_bits;
bool crosspage;
int flags;
@@ -1708,12 +1741,6 @@ static bool mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
tcg_debug_assert(l->mmu_idx < NB_MMU_MODES);
- /* Handle CPU specific unaligned behaviour */
- a_bits = get_alignment_bits(l->memop);
- if (addr & ((1 << a_bits) - 1)) {
- cpu_unaligned_access(cpu, addr, type, l->mmu_idx, ra);
- }
-
l->page[0].addr = addr;
l->page[0].size = memop_size(l->memop);
l->page[1].addr = (addr + l->page[0].size - 1) & TARGET_PAGE_MASK;
@@ -1721,7 +1748,7 @@ static bool mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
crosspage = (addr ^ l->page[1].addr) & TARGET_PAGE_MASK;
if (likely(!crosspage)) {
- mmu_lookup1(cpu, &l->page[0], l->mmu_idx, type, ra);
+ mmu_lookup1(cpu, &l->page[0], l->memop, l->mmu_idx, type, ra);
flags = l->page[0].flags;
if (unlikely(flags & (TLB_WATCHPOINT | TLB_NOTDIRTY))) {
@@ -1740,8 +1767,8 @@ static bool mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
* Lookup both pages, recognizing exceptions from either. If the
* second lookup potentially resized, refresh first CPUTLBEntryFull.
*/
- mmu_lookup1(cpu, &l->page[0], l->mmu_idx, type, ra);
- if (mmu_lookup1(cpu, &l->page[1], l->mmu_idx, type, ra)) {
+ mmu_lookup1(cpu, &l->page[0], l->memop, l->mmu_idx, type, ra);
+ if (mmu_lookup1(cpu, &l->page[1], 0, l->mmu_idx, type, ra)) {
uintptr_t index = tlb_index(cpu, l->mmu_idx, addr);
l->page[0].full = &cpu->neg.tlb.d[l->mmu_idx].fulltlb[index];
}
@@ -1760,31 +1787,6 @@ static bool mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
tcg_debug_assert((flags & TLB_BSWAP) == 0);
}
- /*
- * This alignment check differs from the one above, in that this is
- * based on the atomicity of the operation. The intended use case is
- * the ARM memory type field of each PTE, where access to pages with
- * Device memory type require alignment.
- */
- if (unlikely(flags & TLB_CHECK_ALIGNED)) {
- MemOp size = l->memop & MO_SIZE;
-
- switch (l->memop & MO_ATOM_MASK) {
- case MO_ATOM_NONE:
- size = MO_8;
- break;
- case MO_ATOM_IFALIGN_PAIR:
- case MO_ATOM_WITHIN16_PAIR:
- size = size ? size - 1 : 0;
- break;
- default:
- break;
- }
- if (addr & ((1 << size) - 1)) {
- cpu_unaligned_access(cpu, addr, type, l->mmu_idx, ra);
- }
- }
-
return crosspage;
}
@@ -1797,34 +1799,18 @@ static void *atomic_mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
{
uintptr_t mmu_idx = get_mmuidx(oi);
MemOp mop = get_memop(oi);
- int a_bits = get_alignment_bits(mop);
uintptr_t index;
CPUTLBEntry *tlbe;
vaddr tlb_addr;
void *hostaddr;
CPUTLBEntryFull *full;
+ bool did_tlb_fill = false;
tcg_debug_assert(mmu_idx < NB_MMU_MODES);
/* Adjust the given return address. */
retaddr -= GETPC_ADJ;
- /* Enforce guest required alignment. */
- if (unlikely(a_bits > 0 && (addr & ((1 << a_bits) - 1)))) {
- /* ??? Maybe indicate atomic op to cpu_unaligned_access */
- cpu_unaligned_access(cpu, addr, MMU_DATA_STORE,
- mmu_idx, retaddr);
- }
-
- /* Enforce qemu required alignment. */
- if (unlikely(addr & (size - 1))) {
- /* We get here if guest alignment was not requested,
- or was not enforced by cpu_unaligned_access above.
- We might widen the access and emulate, but for now
- mark an exception and exit the cpu loop. */
- goto stop_the_world;
- }
-
index = tlb_index(cpu, mmu_idx, addr);
tlbe = tlb_entry(cpu, mmu_idx, addr);
@@ -1833,8 +1819,9 @@ static void *atomic_mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
if (!tlb_hit(tlb_addr, addr)) {
if (!victim_tlb_hit(cpu, mmu_idx, index, MMU_DATA_STORE,
addr & TARGET_PAGE_MASK)) {
- tlb_fill(cpu, addr, size,
- MMU_DATA_STORE, mmu_idx, retaddr);
+ tlb_fill_align(cpu, addr, MMU_DATA_STORE, mmu_idx,
+ mop, size, false, retaddr);
+ did_tlb_fill = true;
index = tlb_index(cpu, mmu_idx, addr);
tlbe = tlb_entry(cpu, mmu_idx, addr);
}
@@ -1848,15 +1835,32 @@ static void *atomic_mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
* but addr_read will only be -1 if PAGE_READ was unset.
*/
if (unlikely(tlbe->addr_read == -1)) {
- tlb_fill(cpu, addr, size, MMU_DATA_LOAD, mmu_idx, retaddr);
+ tlb_fill_align(cpu, addr, MMU_DATA_LOAD, mmu_idx,
+ 0, size, false, retaddr);
/*
* Since we don't support reads and writes to different
* addresses, and we do have the proper page loaded for
- * write, this shouldn't ever return. But just in case,
- * handle via stop-the-world.
+ * write, this shouldn't ever return.
+ */
+ g_assert_not_reached();
+ }
+
+ /* Enforce guest required alignment, if not handled by tlb_fill_align. */
+ if (!did_tlb_fill && (addr & ((1 << memop_alignment_bits(mop)) - 1))) {
+ cpu_unaligned_access(cpu, addr, MMU_DATA_STORE, mmu_idx, retaddr);
+ }
+
+ /* Enforce qemu required alignment. */
+ if (unlikely(addr & (size - 1))) {
+ /*
+ * We get here if guest alignment was not requested, or was not
+ * enforced by cpu_unaligned_access or tlb_fill_align above.
+ * We might widen the access and emulate, but for now
+ * mark an exception and exit the cpu loop.
*/
goto stop_the_world;
}
+
/* Collect tlb flags for read. */
tlb_addr |= tlbe->addr_read;
diff --git a/accel/tcg/ldst_atomicity.c.inc b/accel/tcg/ldst_atomicity.c.inc
index 134da3c..c735add 100644
--- a/accel/tcg/ldst_atomicity.c.inc
+++ b/accel/tcg/ldst_atomicity.c.inc
@@ -168,6 +168,7 @@ static uint64_t load_atomic8_or_exit(CPUState *cpu, uintptr_t ra, void *pv)
#endif
/* Ultimate fallback: re-execute in serial context. */
+ trace_load_atom8_or_exit_fallback(ra);
cpu_loop_exit_atomic(cpu, ra);
}
@@ -212,6 +213,7 @@ static Int128 load_atomic16_or_exit(CPUState *cpu, uintptr_t ra, void *pv)
}
/* Ultimate fallback: re-execute in serial context. */
+ trace_load_atom16_or_exit_fallback(ra);
cpu_loop_exit_atomic(cpu, ra);
}
@@ -519,6 +521,7 @@ static uint64_t load_atom_8(CPUState *cpu, uintptr_t ra,
if (HAVE_al8) {
return load_atom_extract_al8x2(pv);
}
+ trace_load_atom8_fallback(memop, ra);
cpu_loop_exit_atomic(cpu, ra);
default:
g_assert_not_reached();
@@ -563,6 +566,7 @@ static Int128 load_atom_16(CPUState *cpu, uintptr_t ra,
break;
case MO_64:
if (!HAVE_al8) {
+ trace_load_atom16_fallback(memop, ra);
cpu_loop_exit_atomic(cpu, ra);
}
a = load_atomic8(pv);
@@ -570,6 +574,7 @@ static Int128 load_atom_16(CPUState *cpu, uintptr_t ra,
break;
case -MO_64:
if (!HAVE_al8) {
+ trace_load_atom16_fallback(memop, ra);
cpu_loop_exit_atomic(cpu, ra);
}
a = load_atom_extract_al8x2(pv);
@@ -897,6 +902,7 @@ static void store_atom_2(CPUState *cpu, uintptr_t ra,
g_assert_not_reached();
}
+ trace_store_atom2_fallback(memop, ra);
cpu_loop_exit_atomic(cpu, ra);
}
@@ -961,6 +967,7 @@ static void store_atom_4(CPUState *cpu, uintptr_t ra,
return;
}
}
+ trace_store_atom4_fallback(memop, ra);
cpu_loop_exit_atomic(cpu, ra);
default:
g_assert_not_reached();
@@ -1029,6 +1036,7 @@ static void store_atom_8(CPUState *cpu, uintptr_t ra,
default:
g_assert_not_reached();
}
+ trace_store_atom8_fallback(memop, ra);
cpu_loop_exit_atomic(cpu, ra);
}
@@ -1107,5 +1115,6 @@ static void store_atom_16(CPUState *cpu, uintptr_t ra,
default:
g_assert_not_reached();
}
+ trace_store_atom16_fallback(memop, ra);
cpu_loop_exit_atomic(cpu, ra);
}
diff --git a/accel/tcg/ldst_common.c.inc b/accel/tcg/ldst_common.c.inc
index 87ceb95..ebbf380 100644
--- a/accel/tcg/ldst_common.c.inc
+++ b/accel/tcg/ldst_common.c.inc
@@ -123,10 +123,15 @@ void helper_st_i128(CPUArchState *env, uint64_t addr, Int128 val, MemOpIdx oi)
* Load helpers for cpu_ldst.h
*/
-static void plugin_load_cb(CPUArchState *env, abi_ptr addr, MemOpIdx oi)
+static void plugin_load_cb(CPUArchState *env, abi_ptr addr,
+ uint64_t value_low,
+ uint64_t value_high,
+ MemOpIdx oi)
{
if (cpu_plugin_mem_cbs_enabled(env_cpu(env))) {
- qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R);
+ qemu_plugin_vcpu_mem_cb(env_cpu(env), addr,
+ value_low, value_high,
+ oi, QEMU_PLUGIN_MEM_R);
}
}
@@ -136,7 +141,7 @@ uint8_t cpu_ldb_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t ra)
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_UB);
ret = do_ld1_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD);
- plugin_load_cb(env, addr, oi);
+ plugin_load_cb(env, addr, ret, 0, oi);
return ret;
}
@@ -147,7 +152,7 @@ uint16_t cpu_ldw_mmu(CPUArchState *env, abi_ptr addr,
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16);
ret = do_ld2_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD);
- plugin_load_cb(env, addr, oi);
+ plugin_load_cb(env, addr, ret, 0, oi);
return ret;
}
@@ -158,7 +163,7 @@ uint32_t cpu_ldl_mmu(CPUArchState *env, abi_ptr addr,
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32);
ret = do_ld4_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD);
- plugin_load_cb(env, addr, oi);
+ plugin_load_cb(env, addr, ret, 0, oi);
return ret;
}
@@ -169,7 +174,7 @@ uint64_t cpu_ldq_mmu(CPUArchState *env, abi_ptr addr,
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64);
ret = do_ld8_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD);
- plugin_load_cb(env, addr, oi);
+ plugin_load_cb(env, addr, ret, 0, oi);
return ret;
}
@@ -180,7 +185,7 @@ Int128 cpu_ld16_mmu(CPUArchState *env, abi_ptr addr,
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128);
ret = do_ld16_mmu(env_cpu(env), addr, oi, ra);
- plugin_load_cb(env, addr, oi);
+ plugin_load_cb(env, addr, int128_getlo(ret), int128_gethi(ret), oi);
return ret;
}
@@ -188,10 +193,15 @@ Int128 cpu_ld16_mmu(CPUArchState *env, abi_ptr addr,
* Store helpers for cpu_ldst.h
*/
-static void plugin_store_cb(CPUArchState *env, abi_ptr addr, MemOpIdx oi)
+static void plugin_store_cb(CPUArchState *env, abi_ptr addr,
+ uint64_t value_low,
+ uint64_t value_high,
+ MemOpIdx oi)
{
if (cpu_plugin_mem_cbs_enabled(env_cpu(env))) {
- qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W);
+ qemu_plugin_vcpu_mem_cb(env_cpu(env), addr,
+ value_low, value_high,
+ oi, QEMU_PLUGIN_MEM_W);
}
}
@@ -199,7 +209,7 @@ void cpu_stb_mmu(CPUArchState *env, abi_ptr addr, uint8_t val,
MemOpIdx oi, uintptr_t retaddr)
{
helper_stb_mmu(env, addr, val, oi, retaddr);
- plugin_store_cb(env, addr, oi);
+ plugin_store_cb(env, addr, val, 0, oi);
}
void cpu_stw_mmu(CPUArchState *env, abi_ptr addr, uint16_t val,
@@ -207,7 +217,7 @@ void cpu_stw_mmu(CPUArchState *env, abi_ptr addr, uint16_t val,
{
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16);
do_st2_mmu(env_cpu(env), addr, val, oi, retaddr);
- plugin_store_cb(env, addr, oi);
+ plugin_store_cb(env, addr, val, 0, oi);
}
void cpu_stl_mmu(CPUArchState *env, abi_ptr addr, uint32_t val,
@@ -215,7 +225,7 @@ void cpu_stl_mmu(CPUArchState *env, abi_ptr addr, uint32_t val,
{
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32);
do_st4_mmu(env_cpu(env), addr, val, oi, retaddr);
- plugin_store_cb(env, addr, oi);
+ plugin_store_cb(env, addr, val, 0, oi);
}
void cpu_stq_mmu(CPUArchState *env, abi_ptr addr, uint64_t val,
@@ -223,7 +233,7 @@ void cpu_stq_mmu(CPUArchState *env, abi_ptr addr, uint64_t val,
{
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64);
do_st8_mmu(env_cpu(env), addr, val, oi, retaddr);
- plugin_store_cb(env, addr, oi);
+ plugin_store_cb(env, addr, val, 0, oi);
}
void cpu_st16_mmu(CPUArchState *env, abi_ptr addr, Int128 val,
@@ -231,7 +241,7 @@ void cpu_st16_mmu(CPUArchState *env, abi_ptr addr, Int128 val,
{
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128);
do_st16_mmu(env_cpu(env), addr, val, oi, retaddr);
- plugin_store_cb(env, addr, oi);
+ plugin_store_cb(env, addr, int128_getlo(val), int128_gethi(val), oi);
}
/*
diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c
index b6bae32..0f47bfb 100644
--- a/accel/tcg/plugin-gen.c
+++ b/accel/tcg/plugin-gen.c
@@ -85,8 +85,7 @@ static void gen_enable_mem_helper(struct qemu_plugin_tb *ptb,
len = insn->mem_cbs->len;
arr = g_array_sized_new(false, false,
sizeof(struct qemu_plugin_dyn_cb), len);
- memcpy(arr->data, insn->mem_cbs->data,
- len * sizeof(struct qemu_plugin_dyn_cb));
+ g_array_append_vals(arr, insn->mem_cbs->data, len);
qemu_plugin_add_dyn_cb_arr(arr);
tcg_gen_st_ptr(tcg_constant_ptr((intptr_t)arr), tcg_env,
@@ -252,7 +251,6 @@ static void inject_mem_cb(struct qemu_plugin_dyn_cb *cb,
break;
default:
g_assert_not_reached();
- break;
}
}
@@ -469,4 +467,8 @@ void plugin_gen_tb_end(CPUState *cpu, size_t num_insns)
/* inject the instrumentation at the appropriate places */
plugin_gen_inject(ptb);
+
+ /* reset plugin translation state (plugin_tb is reused between blocks) */
+ tcg_ctx->plugin_db = NULL;
+ tcg_ctx->plugin_insn = NULL;
}
diff --git a/accel/tcg/tcg-accel-ops-rr.c b/accel/tcg/tcg-accel-ops-rr.c
index 48c3871..8ebadf8 100644
--- a/accel/tcg/tcg-accel-ops-rr.c
+++ b/accel/tcg/tcg-accel-ops-rr.c
@@ -109,7 +109,7 @@ static void rr_wait_io_event(void)
{
CPUState *cpu;
- while (all_cpu_threads_idle() && replay_can_wait()) {
+ while (all_cpu_threads_idle()) {
rr_stop_kick_timer();
qemu_cond_wait_bql(first_cpu->halt_cond);
}
@@ -302,9 +302,7 @@ static void *rr_cpu_thread_fn(void *arg)
rr_deal_with_unplugged_cpus();
}
- rcu_remove_force_rcu_notifier(&force_rcu);
- rcu_unregister_thread();
- return NULL;
+ g_assert_not_reached();
}
void rr_start_vcpu_thread(CPUState *cpu)
diff --git a/accel/tcg/trace-events b/accel/tcg/trace-events
index 4e9b450..14f6388 100644
--- a/accel/tcg/trace-events
+++ b/accel/tcg/trace-events
@@ -12,3 +12,15 @@ memory_notdirty_set_dirty(uint64_t vaddr) "0x%" PRIx64
# translate-all.c
translate_block(void *tb, uintptr_t pc, const void *tb_code) "tb:%p, pc:0x%"PRIxPTR", tb_code:%p"
+
+# ldst_atomicity
+load_atom2_fallback(uint32_t memop, uintptr_t ra) "mop:0x%"PRIx32", ra:0x%"PRIxPTR""
+load_atom4_fallback(uint32_t memop, uintptr_t ra) "mop:0x%"PRIx32", ra:0x%"PRIxPTR""
+load_atom8_or_exit_fallback(uintptr_t ra) "ra:0x%"PRIxPTR""
+load_atom8_fallback(uint32_t memop, uintptr_t ra) "mop:0x%"PRIx32", ra:0x%"PRIxPTR""
+load_atom16_fallback(uint32_t memop, uintptr_t ra) "mop:0x%"PRIx32", ra:0x%"PRIxPTR""
+load_atom16_or_exit_fallback(uintptr_t ra) "ra:0x%"PRIxPTR""
+store_atom2_fallback(uint32_t memop, uintptr_t ra) "mop:0x%"PRIx32", ra:0x%"PRIxPTR""
+store_atom4_fallback(uint32_t memop, uintptr_t ra) "mop:0x%"PRIx32", ra:0x%"PRIxPTR""
+store_atom8_fallback(uint32_t memop, uintptr_t ra) "mop:0x%"PRIx32", ra:0x%"PRIxPTR""
+store_atom16_fallback(uint32_t memop, uintptr_t ra) "mop:0x%"PRIx32", ra:0x%"PRIxPTR""
diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
index 113edcf..cbad00a 100644
--- a/accel/tcg/translator.c
+++ b/accel/tcg/translator.c
@@ -129,7 +129,6 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
db->is_jmp = DISAS_NEXT;
db->num_insns = 0;
db->max_insns = *max_insns;
- db->singlestep_enabled = cflags & CF_SINGLE_STEP;
db->insn_start = NULL;
db->fake_insn = false;
db->host_addr[0] = host_pc;
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
index 80d2454..aa8af52 100644
--- a/accel/tcg/user-exec.c
+++ b/accel/tcg/user-exec.c
@@ -29,11 +29,10 @@
#include "exec/page-protection.h"
#include "exec/helper-proto.h"
#include "qemu/atomic128.h"
-#include "trace/trace-root.h"
+#include "trace.h"
#include "tcg/tcg-ldst.h"
#include "internal-common.h"
#include "internal-target.h"
-#include "user-retaddr.h"
__thread uintptr_t helper_retaddr;
@@ -486,11 +485,6 @@ static bool pageflags_set_clear(target_ulong start, target_ulong last,
return inval_tb;
}
-/*
- * Modify the flags of a page and invalidate the code if necessary.
- * The flag PAGE_WRITE_ORG is positioned automatically depending
- * on PAGE_WRITE. The mmap_lock should already be held.
- */
void page_set_flags(target_ulong start, target_ulong last, int flags)
{
bool reset = false;
@@ -960,7 +954,7 @@ void page_reset_target_data(target_ulong start, target_ulong last) { }
static void *cpu_mmu_lookup(CPUState *cpu, vaddr addr,
MemOp mop, uintptr_t ra, MMUAccessType type)
{
- int a_bits = get_alignment_bits(mop);
+ int a_bits = memop_alignment_bits(mop);
void *ret;
/* Enforce guest required alignment. */
@@ -1242,7 +1236,7 @@ static void *atomic_mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
int size, uintptr_t retaddr)
{
MemOp mop = get_memop(oi);
- int a_bits = get_alignment_bits(mop);
+ int a_bits = memop_alignment_bits(mop);
void *ret;
/* Enforce guest required alignment. */
diff --git a/accel/tcg/user-retaddr.h b/accel/tcg/user-retaddr.h
deleted file mode 100644
index e0f57e1..0000000
--- a/accel/tcg/user-retaddr.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef ACCEL_TCG_USER_RETADDR_H
-#define ACCEL_TCG_USER_RETADDR_H
-
-#include "qemu/atomic.h"
-
-extern __thread uintptr_t helper_retaddr;
-
-static inline void set_helper_retaddr(uintptr_t ra)
-{
- helper_retaddr = ra;
- /*
- * Ensure that this write is visible to the SIGSEGV handler that
- * may be invoked due to a subsequent invalid memory operation.
- */
- signal_barrier();
-}
-
-static inline void clear_helper_retaddr(void)
-{
- /*
- * Ensure that previous memory operations have succeeded before
- * removing the data visible to the signal handler.
- */
- signal_barrier();
- helper_retaddr = 0;
-}
-
-#endif
diff --git a/audio/dbusaudio.c b/audio/dbusaudio.c
index 60fcf64..095e739 100644
--- a/audio/dbusaudio.c
+++ b/audio/dbusaudio.c
@@ -105,7 +105,7 @@ static size_t dbus_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
assert(buf == vo->buf + vo->buf_pos && vo->buf_pos + size <= vo->buf_size);
vo->buf_pos += size;
- trace_dbus_audio_put_buffer_out(size);
+ trace_dbus_audio_put_buffer_out(vo->buf_pos, vo->buf_size);
if (vo->buf_pos < vo->buf_size) {
return size;
diff --git a/audio/pwaudio.c b/audio/pwaudio.c
index 3b14e04..8e13b58 100644
--- a/audio/pwaudio.c
+++ b/audio/pwaudio.c
@@ -769,13 +769,15 @@ qpw_audio_init(Audiodev *dev, Error **errp)
pw->core = pw_context_connect(pw->context, NULL, 0);
if (pw->core == NULL) {
pw_thread_loop_unlock(pw->thread_loop);
- goto fail_error;
+ error_setg_errno(errp, errno, "Failed to connect to PipeWire instance");
+ goto fail;
}
if (pw_core_add_listener(pw->core, &pw->core_listener,
&core_events, pw) < 0) {
pw_thread_loop_unlock(pw->thread_loop);
- goto fail_error;
+ error_setg(errp, "Failed to add PipeWire listener");
+ goto fail;
}
if (wait_resync(pw) < 0) {
pw_thread_loop_unlock(pw->thread_loop);
@@ -785,8 +787,6 @@ qpw_audio_init(Audiodev *dev, Error **errp)
return g_steal_pointer(&pw);
-fail_error:
- error_setg(errp, "Failed to initialize PW context");
fail:
if (pw->thread_loop) {
pw_thread_loop_stop(pw->thread_loop);
diff --git a/audio/trace-events b/audio/trace-events
index ab04f02..7e3f159 100644
--- a/audio/trace-events
+++ b/audio/trace-events
@@ -15,7 +15,7 @@ oss_version(int version) "OSS version = 0x%x"
# dbusaudio.c
dbus_audio_register(const char *s, const char *dir) "sender = %s, dir = %s"
-dbus_audio_put_buffer_out(size_t len) "len = %zu"
+dbus_audio_put_buffer_out(size_t pos, size_t size) "buf_pos = %zu, buf_size = %zu"
dbus_audio_read(size_t len) "len = %zu"
# pwaudio.c
diff --git a/backends/Kconfig b/backends/Kconfig
index 2cb23f6..d3dbe19 100644
--- a/backends/Kconfig
+++ b/backends/Kconfig
@@ -3,3 +3,7 @@ source tpm/Kconfig
config IOMMUFD
bool
depends on VFIO
+
+config SPDM_SOCKET
+ bool
+ default y
diff --git a/backends/cryptodev-builtin.c b/backends/cryptodev-builtin.c
index 940104e..b1486be 100644
--- a/backends/cryptodev-builtin.c
+++ b/backends/cryptodev-builtin.c
@@ -64,11 +64,11 @@ static void cryptodev_builtin_init_akcipher(CryptoDevBackend *backend)
{
QCryptoAkCipherOptions opts;
- opts.alg = QCRYPTO_AKCIPHER_ALG_RSA;
- opts.u.rsa.padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW;
+ opts.alg = QCRYPTO_AK_CIPHER_ALGO_RSA;
+ opts.u.rsa.padding_alg = QCRYPTO_RSA_PADDING_ALGO_RAW;
if (qcrypto_akcipher_supports(&opts)) {
backend->conf.crypto_services |=
- (1u << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER);
+ (1u << QCRYPTODEV_BACKEND_SERVICE_TYPE_AKCIPHER);
backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
}
}
@@ -93,9 +93,9 @@ static void cryptodev_builtin_init(
backend->conf.peers.ccs[0] = cc;
backend->conf.crypto_services =
- 1u << QCRYPTODEV_BACKEND_SERVICE_CIPHER |
- 1u << QCRYPTODEV_BACKEND_SERVICE_HASH |
- 1u << QCRYPTODEV_BACKEND_SERVICE_MAC;
+ 1u << QCRYPTODEV_BACKEND_SERVICE_TYPE_CIPHER |
+ 1u << QCRYPTODEV_BACKEND_SERVICE_TYPE_HASH |
+ 1u << QCRYPTODEV_BACKEND_SERVICE_TYPE_MAC;
backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
/*
@@ -138,18 +138,18 @@ cryptodev_builtin_get_aes_algo(uint32_t key_len, int mode, Error **errp)
int algo;
if (key_len == AES_KEYSIZE_128) {
- algo = QCRYPTO_CIPHER_ALG_AES_128;
+ algo = QCRYPTO_CIPHER_ALGO_AES_128;
} else if (key_len == AES_KEYSIZE_192) {
- algo = QCRYPTO_CIPHER_ALG_AES_192;
+ algo = QCRYPTO_CIPHER_ALGO_AES_192;
} else if (key_len == AES_KEYSIZE_256) { /* equals AES_KEYSIZE_128_XTS */
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
- algo = QCRYPTO_CIPHER_ALG_AES_128;
+ algo = QCRYPTO_CIPHER_ALGO_AES_128;
} else {
- algo = QCRYPTO_CIPHER_ALG_AES_256;
+ algo = QCRYPTO_CIPHER_ALGO_AES_256;
}
} else if (key_len == AES_KEYSIZE_256_XTS) {
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
- algo = QCRYPTO_CIPHER_ALG_AES_256;
+ algo = QCRYPTO_CIPHER_ALGO_AES_256;
} else {
goto err;
}
@@ -169,16 +169,16 @@ static int cryptodev_builtin_get_rsa_hash_algo(
{
switch (virtio_rsa_hash) {
case VIRTIO_CRYPTO_RSA_MD5:
- return QCRYPTO_HASH_ALG_MD5;
+ return QCRYPTO_HASH_ALGO_MD5;
case VIRTIO_CRYPTO_RSA_SHA1:
- return QCRYPTO_HASH_ALG_SHA1;
+ return QCRYPTO_HASH_ALGO_SHA1;
case VIRTIO_CRYPTO_RSA_SHA256:
- return QCRYPTO_HASH_ALG_SHA256;
+ return QCRYPTO_HASH_ALGO_SHA256;
case VIRTIO_CRYPTO_RSA_SHA512:
- return QCRYPTO_HASH_ALG_SHA512;
+ return QCRYPTO_HASH_ALGO_SHA512;
default:
error_setg(errp, "Unsupported rsa hash algo: %d", virtio_rsa_hash);
@@ -200,12 +200,12 @@ static int cryptodev_builtin_set_rsa_options(
return -1;
}
opt->hash_alg = hash_alg;
- opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1;
+ opt->padding_alg = QCRYPTO_RSA_PADDING_ALGO_PKCS1;
return 0;
}
if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_RAW_PADDING) {
- opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW;
+ opt->padding_alg = QCRYPTO_RSA_PADDING_ALGO_RAW;
return 0;
}
@@ -271,15 +271,15 @@ static int cryptodev_builtin_create_cipher_session(
break;
case VIRTIO_CRYPTO_CIPHER_3DES_ECB:
mode = QCRYPTO_CIPHER_MODE_ECB;
- algo = QCRYPTO_CIPHER_ALG_3DES;
+ algo = QCRYPTO_CIPHER_ALGO_3DES;
break;
case VIRTIO_CRYPTO_CIPHER_3DES_CBC:
mode = QCRYPTO_CIPHER_MODE_CBC;
- algo = QCRYPTO_CIPHER_ALG_3DES;
+ algo = QCRYPTO_CIPHER_ALGO_3DES;
break;
case VIRTIO_CRYPTO_CIPHER_3DES_CTR:
mode = QCRYPTO_CIPHER_MODE_CTR;
- algo = QCRYPTO_CIPHER_ALG_3DES;
+ algo = QCRYPTO_CIPHER_ALGO_3DES;
break;
default:
error_setg(errp, "Unsupported cipher alg :%u",
@@ -318,7 +318,7 @@ static int cryptodev_builtin_create_akcipher_session(
switch (sess_info->algo) {
case VIRTIO_CRYPTO_AKCIPHER_RSA:
- opts.alg = QCRYPTO_AKCIPHER_ALG_RSA;
+ opts.alg = QCRYPTO_AK_CIPHER_ALGO_RSA;
if (cryptodev_builtin_set_rsa_options(sess_info->u.rsa.padding_algo,
sess_info->u.rsa.hash_algo, &opts.u.rsa, errp) != 0) {
return -1;
@@ -334,11 +334,11 @@ static int cryptodev_builtin_create_akcipher_session(
switch (sess_info->keytype) {
case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
- type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC;
+ type = QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC;
break;
case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
- type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE;
+ type = QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE;
break;
default:
@@ -549,7 +549,7 @@ static int cryptodev_builtin_operation(
CryptoDevBackendBuiltinSession *sess;
CryptoDevBackendSymOpInfo *sym_op_info;
CryptoDevBackendAsymOpInfo *asym_op_info;
- QCryptodevBackendAlgType algtype = op_info->algtype;
+ QCryptodevBackendAlgoType algtype = op_info->algtype;
int status = -VIRTIO_CRYPTO_ERR;
Error *local_error = NULL;
@@ -561,11 +561,11 @@ static int cryptodev_builtin_operation(
}
sess = builtin->sessions[op_info->session_id];
- if (algtype == QCRYPTODEV_BACKEND_ALG_SYM) {
+ if (algtype == QCRYPTODEV_BACKEND_ALGO_TYPE_SYM) {
sym_op_info = op_info->u.sym_op_info;
status = cryptodev_builtin_sym_operation(sess, sym_op_info,
&local_error);
- } else if (algtype == QCRYPTODEV_BACKEND_ALG_ASYM) {
+ } else if (algtype == QCRYPTODEV_BACKEND_ALGO_TYPE_ASYM) {
asym_op_info = op_info->u.asym_op_info;
status = cryptodev_builtin_asym_operation(sess, op_info->op_code,
asym_op_info, &local_error);
diff --git a/backends/cryptodev-lkcf.c b/backends/cryptodev-lkcf.c
index 45aba1f..38deac0 100644
--- a/backends/cryptodev-lkcf.c
+++ b/backends/cryptodev-lkcf.c
@@ -133,20 +133,20 @@ static int cryptodev_lkcf_set_op_desc(QCryptoAkCipherOptions *opts,
Error **errp)
{
QCryptoAkCipherOptionsRSA *rsa_opt;
- if (opts->alg != QCRYPTO_AKCIPHER_ALG_RSA) {
+ if (opts->alg != QCRYPTO_AK_CIPHER_ALGO_RSA) {
error_setg(errp, "Unsupported alg: %u", opts->alg);
return -1;
}
rsa_opt = &opts->u.rsa;
- if (rsa_opt->padding_alg == QCRYPTO_RSA_PADDING_ALG_PKCS1) {
+ if (rsa_opt->padding_alg == QCRYPTO_RSA_PADDING_ALGO_PKCS1) {
snprintf(key_desc, desc_len, "enc=%s hash=%s",
- QCryptoRSAPaddingAlgorithm_str(rsa_opt->padding_alg),
- QCryptoHashAlgorithm_str(rsa_opt->hash_alg));
+ QCryptoRSAPaddingAlgo_str(rsa_opt->padding_alg),
+ QCryptoHashAlgo_str(rsa_opt->hash_alg));
} else {
snprintf(key_desc, desc_len, "enc=%s",
- QCryptoRSAPaddingAlgorithm_str(rsa_opt->padding_alg));
+ QCryptoRSAPaddingAlgo_str(rsa_opt->padding_alg));
}
return 0;
}
@@ -157,23 +157,23 @@ static int cryptodev_lkcf_set_rsa_opt(int virtio_padding_alg,
Error **errp)
{
if (virtio_padding_alg == VIRTIO_CRYPTO_RSA_PKCS1_PADDING) {
- opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1;
+ opt->padding_alg = QCRYPTO_RSA_PADDING_ALGO_PKCS1;
switch (virtio_hash_alg) {
case VIRTIO_CRYPTO_RSA_MD5:
- opt->hash_alg = QCRYPTO_HASH_ALG_MD5;
+ opt->hash_alg = QCRYPTO_HASH_ALGO_MD5;
break;
case VIRTIO_CRYPTO_RSA_SHA1:
- opt->hash_alg = QCRYPTO_HASH_ALG_SHA1;
+ opt->hash_alg = QCRYPTO_HASH_ALGO_SHA1;
break;
case VIRTIO_CRYPTO_RSA_SHA256:
- opt->hash_alg = QCRYPTO_HASH_ALG_SHA256;
+ opt->hash_alg = QCRYPTO_HASH_ALGO_SHA256;
break;
case VIRTIO_CRYPTO_RSA_SHA512:
- opt->hash_alg = QCRYPTO_HASH_ALG_SHA512;
+ opt->hash_alg = QCRYPTO_HASH_ALGO_SHA512;
break;
default:
@@ -184,7 +184,7 @@ static int cryptodev_lkcf_set_rsa_opt(int virtio_padding_alg,
}
if (virtio_padding_alg == VIRTIO_CRYPTO_RSA_RAW_PADDING) {
- opt->padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW;
+ opt->padding_alg = QCRYPTO_RSA_PADDING_ALGO_RAW;
return 0;
}
@@ -230,7 +230,7 @@ static void cryptodev_lkcf_init(CryptoDevBackend *backend, Error **errp)
backend->conf.peers.ccs[0] = cc;
backend->conf.crypto_services =
- 1u << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER;
+ 1u << QCRYPTODEV_BACKEND_SERVICE_TYPE_AKCIPHER;
backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
lkcf->running = true;
@@ -322,7 +322,7 @@ static void cryptodev_lkcf_execute_task(CryptoDevLKCFTask *task)
* 2. generally, public key related compution is fast, just compute it with
* thread-pool.
*/
- if (session->keytype == QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE) {
+ if (session->keytype == QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE) {
if (qcrypto_akcipher_export_p8info(&session->akcipher_opts,
session->key, session->keylen,
&p8info, &p8info_len,
@@ -474,7 +474,7 @@ static int cryptodev_lkcf_operation(
CryptoDevBackendLKCF *lkcf =
CRYPTODEV_BACKEND_LKCF(backend);
CryptoDevBackendLKCFSession *sess;
- QCryptodevBackendAlgType algtype = op_info->algtype;
+ QCryptodevBackendAlgoType algtype = op_info->algtype;
CryptoDevLKCFTask *task;
if (op_info->session_id >= MAX_SESSIONS ||
@@ -485,7 +485,7 @@ static int cryptodev_lkcf_operation(
}
sess = lkcf->sess[op_info->session_id];
- if (algtype != QCRYPTODEV_BACKEND_ALG_ASYM) {
+ if (algtype != QCRYPTODEV_BACKEND_ALGO_TYPE_ASYM) {
error_report("algtype not supported: %u", algtype);
return -VIRTIO_CRYPTO_NOTSUPP;
}
@@ -518,7 +518,7 @@ static int cryptodev_lkcf_create_asym_session(
switch (sess_info->algo) {
case VIRTIO_CRYPTO_AKCIPHER_RSA:
- sess->akcipher_opts.alg = QCRYPTO_AKCIPHER_ALG_RSA;
+ sess->akcipher_opts.alg = QCRYPTO_AK_CIPHER_ALGO_RSA;
if (cryptodev_lkcf_set_rsa_opt(
sess_info->u.rsa.padding_algo, sess_info->u.rsa.hash_algo,
&sess->akcipher_opts.u.rsa, &local_error) != 0) {
@@ -534,11 +534,11 @@ static int cryptodev_lkcf_create_asym_session(
switch (sess_info->keytype) {
case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
- sess->keytype = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC;
+ sess->keytype = QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC;
break;
case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
- sess->keytype = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE;
+ sess->keytype = QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE;
break;
default:
diff --git a/backends/cryptodev-vhost-user.c b/backends/cryptodev-vhost-user.c
index c3283ba..e33fb78 100644
--- a/backends/cryptodev-vhost-user.c
+++ b/backends/cryptodev-vhost-user.c
@@ -221,9 +221,9 @@ static void cryptodev_vhost_user_init(
cryptodev_vhost_user_event, NULL, s, NULL, true);
backend->conf.crypto_services =
- 1u << QCRYPTODEV_BACKEND_SERVICE_CIPHER |
- 1u << QCRYPTODEV_BACKEND_SERVICE_HASH |
- 1u << QCRYPTODEV_BACKEND_SERVICE_MAC;
+ 1u << QCRYPTODEV_BACKEND_SERVICE_TYPE_CIPHER |
+ 1u << QCRYPTODEV_BACKEND_SERVICE_TYPE_HASH |
+ 1u << QCRYPTODEV_BACKEND_SERVICE_TYPE_MAC;
backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
diff --git a/backends/cryptodev.c b/backends/cryptodev.c
index fff89fd..d8bd2a1 100644
--- a/backends/cryptodev.c
+++ b/backends/cryptodev.c
@@ -74,7 +74,7 @@ static int qmp_query_cryptodev_foreach(Object *obj, void *data)
backend = CRYPTODEV_BACKEND(obj);
services = backend->conf.crypto_services;
- for (i = 0; i < QCRYPTODEV_BACKEND_SERVICE__MAX; i++) {
+ for (i = 0; i < QCRYPTODEV_BACKEND_SERVICE_TYPE__MAX; i++) {
if (services & (1 << i)) {
QAPI_LIST_PREPEND(info->service, i);
}
@@ -185,10 +185,10 @@ static int cryptodev_backend_operation(
static int cryptodev_backend_account(CryptoDevBackend *backend,
CryptoDevBackendOpInfo *op_info)
{
- enum QCryptodevBackendAlgType algtype = op_info->algtype;
+ enum QCryptodevBackendAlgoType algtype = op_info->algtype;
int len;
- if (algtype == QCRYPTODEV_BACKEND_ALG_ASYM) {
+ if (algtype == QCRYPTODEV_BACKEND_ALGO_TYPE_ASYM) {
CryptoDevBackendAsymOpInfo *asym_op_info = op_info->u.asym_op_info;
len = asym_op_info->src_len;
@@ -212,7 +212,7 @@ static int cryptodev_backend_account(CryptoDevBackend *backend,
default:
return -VIRTIO_CRYPTO_NOTSUPP;
}
- } else if (algtype == QCRYPTODEV_BACKEND_ALG_SYM) {
+ } else if (algtype == QCRYPTODEV_BACKEND_ALGO_TYPE_SYM) {
CryptoDevBackendSymOpInfo *sym_op_info = op_info->u.sym_op_info;
len = sym_op_info->src_len;
@@ -424,11 +424,11 @@ cryptodev_backend_complete(UserCreatable *uc, Error **errp)
}
services = backend->conf.crypto_services;
- if (services & (1 << QCRYPTODEV_BACKEND_SERVICE_CIPHER)) {
+ if (services & (1 << QCRYPTODEV_BACKEND_SERVICE_TYPE_CIPHER)) {
backend->sym_stat = g_new0(CryptodevBackendSymStat, 1);
}
- if (services & (1 << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER)) {
+ if (services & (1 << QCRYPTODEV_BACKEND_SERVICE_TYPE_AKCIPHER)) {
backend->asym_stat = g_new0(CryptodevBackendAsymStat, 1);
}
}
diff --git a/backends/hostmem.c b/backends/hostmem.c
index 4e5576a..1814466 100644
--- a/backends/hostmem.c
+++ b/backends/hostmem.c
@@ -178,7 +178,7 @@ static void host_memory_backend_set_merge(Object *obj, bool value, Error **errp)
return;
}
- if (!host_memory_backend_mr_inited(backend) &&
+ if (host_memory_backend_mr_inited(backend) &&
value != backend->merge) {
void *ptr = memory_region_get_ram_ptr(&backend->mr);
uint64_t sz = memory_region_size(&backend->mr);
diff --git a/backends/iommufd.c b/backends/iommufd.c
index cabd1b5..9bc466a 100644
--- a/backends/iommufd.c
+++ b/backends/iommufd.c
@@ -18,6 +18,7 @@
#include "qemu/error-report.h"
#include "monitor/monitor.h"
#include "trace.h"
+#include "hw/vfio/vfio-common.h"
#include <sys/ioctl.h>
#include <linux/iommufd.h>
@@ -207,9 +208,91 @@ int iommufd_backend_unmap_dma(IOMMUFDBackend *be, uint32_t ioas_id,
return ret;
}
+bool iommufd_backend_alloc_hwpt(IOMMUFDBackend *be, uint32_t dev_id,
+ uint32_t pt_id, uint32_t flags,
+ uint32_t data_type, uint32_t data_len,
+ void *data_ptr, uint32_t *out_hwpt,
+ Error **errp)
+{
+ int ret, fd = be->fd;
+ struct iommu_hwpt_alloc alloc_hwpt = {
+ .size = sizeof(struct iommu_hwpt_alloc),
+ .flags = flags,
+ .dev_id = dev_id,
+ .pt_id = pt_id,
+ .data_type = data_type,
+ .data_len = data_len,
+ .data_uptr = (uintptr_t)data_ptr,
+ };
+
+ ret = ioctl(fd, IOMMU_HWPT_ALLOC, &alloc_hwpt);
+ trace_iommufd_backend_alloc_hwpt(fd, dev_id, pt_id, flags, data_type,
+ data_len, (uintptr_t)data_ptr,
+ alloc_hwpt.out_hwpt_id, ret);
+ if (ret) {
+ error_setg_errno(errp, errno, "Failed to allocate hwpt");
+ return false;
+ }
+
+ *out_hwpt = alloc_hwpt.out_hwpt_id;
+ return true;
+}
+
+bool iommufd_backend_set_dirty_tracking(IOMMUFDBackend *be,
+ uint32_t hwpt_id, bool start,
+ Error **errp)
+{
+ int ret;
+ struct iommu_hwpt_set_dirty_tracking set_dirty = {
+ .size = sizeof(set_dirty),
+ .hwpt_id = hwpt_id,
+ .flags = start ? IOMMU_HWPT_DIRTY_TRACKING_ENABLE : 0,
+ };
+
+ ret = ioctl(be->fd, IOMMU_HWPT_SET_DIRTY_TRACKING, &set_dirty);
+ trace_iommufd_backend_set_dirty(be->fd, hwpt_id, start, ret ? errno : 0);
+ if (ret) {
+ error_setg_errno(errp, errno,
+ "IOMMU_HWPT_SET_DIRTY_TRACKING(hwpt_id %u) failed",
+ hwpt_id);
+ return false;
+ }
+
+ return true;
+}
+
+bool iommufd_backend_get_dirty_bitmap(IOMMUFDBackend *be,
+ uint32_t hwpt_id,
+ uint64_t iova, ram_addr_t size,
+ uint64_t page_size, uint64_t *data,
+ Error **errp)
+{
+ int ret;
+ struct iommu_hwpt_get_dirty_bitmap get_dirty_bitmap = {
+ .size = sizeof(get_dirty_bitmap),
+ .hwpt_id = hwpt_id,
+ .iova = iova,
+ .length = size,
+ .page_size = page_size,
+ .data = (uintptr_t)data,
+ };
+
+ ret = ioctl(be->fd, IOMMU_HWPT_GET_DIRTY_BITMAP, &get_dirty_bitmap);
+ trace_iommufd_backend_get_dirty_bitmap(be->fd, hwpt_id, iova, size,
+ page_size, ret ? errno : 0);
+ if (ret) {
+ error_setg_errno(errp, errno,
+ "IOMMU_HWPT_GET_DIRTY_BITMAP (iova: 0x%"HWADDR_PRIx
+ " size: 0x"RAM_ADDR_FMT") failed", iova, size);
+ return false;
+ }
+
+ return true;
+}
+
bool iommufd_backend_get_device_info(IOMMUFDBackend *be, uint32_t devid,
uint32_t *type, void *data, uint32_t len,
- Error **errp)
+ uint64_t *caps, Error **errp)
{
struct iommu_hw_info info = {
.size = sizeof(info),
@@ -225,6 +308,8 @@ bool iommufd_backend_get_device_info(IOMMUFDBackend *be, uint32_t devid,
g_assert(type);
*type = info.out_data_type;
+ g_assert(caps);
+ *caps = info.out_capabilities;
return true;
}
@@ -237,7 +322,7 @@ static int hiod_iommufd_get_cap(HostIOMMUDevice *hiod, int cap, Error **errp)
case HOST_IOMMU_DEVICE_CAP_IOMMU_TYPE:
return caps->type;
case HOST_IOMMU_DEVICE_CAP_AW_BITS:
- return caps->aw_bits;
+ return vfio_device_get_aw_bits(hiod->agent);
default:
error_setg(errp, "%s: unsupported capability %x", hiod->name, cap);
return -EINVAL;
diff --git a/backends/meson.build b/backends/meson.build
index 749b491..da714b9 100644
--- a/backends/meson.build
+++ b/backends/meson.build
@@ -33,4 +33,6 @@ endif
system_ss.add(when: gio, if_true: files('dbus-vmstate.c'))
system_ss.add(when: 'CONFIG_SGX', if_true: files('hostmem-epc.c'))
+system_ss.add(when: 'CONFIG_SPDM_SOCKET', if_true: files('spdm-socket.c'))
+
subdir('tpm')
diff --git a/backends/spdm-socket.c b/backends/spdm-socket.c
new file mode 100644
index 0000000..d0663d6
--- /dev/null
+++ b/backends/spdm-socket.c
@@ -0,0 +1,216 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * QEMU SPDM socket support
+ *
+ * This is based on:
+ * https://github.com/DMTF/spdm-emu/blob/07c0a838bcc1c6207c656ac75885c0603e344b6f/spdm_emu/spdm_emu_common/command.c
+ * but has been re-written to match QEMU style
+ *
+ * Copyright (c) 2021, DMTF. All rights reserved.
+ * Copyright (c) 2023. Western Digital Corporation or its affiliates.
+ */
+
+#include "qemu/osdep.h"
+#include "sysemu/spdm-socket.h"
+#include "qapi/error.h"
+
+static bool read_bytes(const int socket, uint8_t *buffer,
+ size_t number_of_bytes)
+{
+ ssize_t number_received = 0;
+ ssize_t result;
+
+ while (number_received < number_of_bytes) {
+ result = recv(socket, buffer + number_received,
+ number_of_bytes - number_received, 0);
+ if (result <= 0) {
+ return false;
+ }
+ number_received += result;
+ }
+ return true;
+}
+
+static bool read_data32(const int socket, uint32_t *data)
+{
+ bool result;
+
+ result = read_bytes(socket, (uint8_t *)data, sizeof(uint32_t));
+ if (!result) {
+ return result;
+ }
+ *data = ntohl(*data);
+ return true;
+}
+
+static bool read_multiple_bytes(const int socket, uint8_t *buffer,
+ uint32_t *bytes_received,
+ uint32_t max_buffer_length)
+{
+ uint32_t length;
+ bool result;
+
+ result = read_data32(socket, &length);
+ if (!result) {
+ return result;
+ }
+
+ if (length > max_buffer_length) {
+ return false;
+ }
+
+ if (bytes_received) {
+ *bytes_received = length;
+ }
+
+ if (length == 0) {
+ return true;
+ }
+
+ return read_bytes(socket, buffer, length);
+}
+
+static bool receive_platform_data(const int socket,
+ uint32_t transport_type,
+ uint32_t *command,
+ uint8_t *receive_buffer,
+ uint32_t *bytes_to_receive)
+{
+ bool result;
+ uint32_t response;
+ uint32_t bytes_received;
+
+ result = read_data32(socket, &response);
+ if (!result) {
+ return result;
+ }
+ *command = response;
+
+ result = read_data32(socket, &transport_type);
+ if (!result) {
+ return result;
+ }
+
+ bytes_received = 0;
+ result = read_multiple_bytes(socket, receive_buffer, &bytes_received,
+ *bytes_to_receive);
+ if (!result) {
+ return result;
+ }
+ *bytes_to_receive = bytes_received;
+
+ return result;
+}
+
+static bool write_bytes(const int socket, const uint8_t *buffer,
+ uint32_t number_of_bytes)
+{
+ ssize_t number_sent = 0;
+ ssize_t result;
+
+ while (number_sent < number_of_bytes) {
+ result = send(socket, buffer + number_sent,
+ number_of_bytes - number_sent, 0);
+ if (result == -1) {
+ return false;
+ }
+ number_sent += result;
+ }
+ return true;
+}
+
+static bool write_data32(const int socket, uint32_t data)
+{
+ data = htonl(data);
+ return write_bytes(socket, (uint8_t *)&data, sizeof(uint32_t));
+}
+
+static bool write_multiple_bytes(const int socket, const uint8_t *buffer,
+ uint32_t bytes_to_send)
+{
+ bool result;
+
+ result = write_data32(socket, bytes_to_send);
+ if (!result) {
+ return result;
+ }
+
+ return write_bytes(socket, buffer, bytes_to_send);
+}
+
+static bool send_platform_data(const int socket,
+ uint32_t transport_type, uint32_t command,
+ const uint8_t *send_buffer, size_t bytes_to_send)
+{
+ bool result;
+
+ result = write_data32(socket, command);
+ if (!result) {
+ return result;
+ }
+
+ result = write_data32(socket, transport_type);
+ if (!result) {
+ return result;
+ }
+
+ return write_multiple_bytes(socket, send_buffer, bytes_to_send);
+}
+
+int spdm_socket_connect(uint16_t port, Error **errp)
+{
+ int client_socket;
+ struct sockaddr_in server_addr;
+
+ client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (client_socket < 0) {
+ error_setg(errp, "cannot create socket: %s", strerror(errno));
+ return -1;
+ }
+
+ memset((char *)&server_addr, 0, sizeof(server_addr));
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ server_addr.sin_port = htons(port);
+
+
+ if (connect(client_socket, (struct sockaddr *)&server_addr,
+ sizeof(server_addr)) < 0) {
+ error_setg(errp, "cannot connect: %s", strerror(errno));
+ close(client_socket);
+ return -1;
+ }
+
+ return client_socket;
+}
+
+uint32_t spdm_socket_rsp(const int socket, uint32_t transport_type,
+ void *req, uint32_t req_len,
+ void *rsp, uint32_t rsp_len)
+{
+ uint32_t command;
+ bool result;
+
+ result = send_platform_data(socket, transport_type,
+ SPDM_SOCKET_COMMAND_NORMAL,
+ req, req_len);
+ if (!result) {
+ return 0;
+ }
+
+ result = receive_platform_data(socket, transport_type, &command,
+ (uint8_t *)rsp, &rsp_len);
+ if (!result) {
+ return 0;
+ }
+
+ assert(command != 0);
+
+ return rsp_len;
+}
+
+void spdm_socket_close(const int socket, uint32_t transport_type)
+{
+ send_platform_data(socket, transport_type,
+ SPDM_SOCKET_COMMAND_SHUTDOWN, NULL, 0);
+}
diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c
index 5a8fba9..aa05dab 100644
--- a/backends/tpm/tpm_emulator.c
+++ b/backends/tpm/tpm_emulator.c
@@ -72,7 +72,7 @@ struct TPMEmulator {
CharBackend ctrl_chr;
QIOChannel *data_ioc;
TPMVersion tpm_version;
- ptm_cap caps; /* capabilities of the TPM */
+ uint32_t caps; /* capabilities of the TPM */
uint8_t cur_locty_number; /* last set locality */
Error *migration_blocker;
@@ -123,12 +123,14 @@ static const char *tpm_emulator_strerror(uint32_t tpm_result)
}
static int tpm_emulator_ctrlcmd(TPMEmulator *tpm, unsigned long cmd, void *msg,
- size_t msg_len_in, size_t msg_len_out)
+ size_t msg_len_in, size_t msg_len_out_err,
+ size_t msg_len_out_total)
{
CharBackend *dev = &tpm->ctrl_chr;
uint32_t cmd_no = cpu_to_be32(cmd);
ssize_t n = sizeof(uint32_t) + msg_len_in;
uint8_t *buf = NULL;
+ ptm_res res;
WITH_QEMU_LOCK_GUARD(&tpm->mutex) {
buf = g_alloca(n);
@@ -140,8 +142,25 @@ static int tpm_emulator_ctrlcmd(TPMEmulator *tpm, unsigned long cmd, void *msg,
return -1;
}
- if (msg_len_out != 0) {
- n = qemu_chr_fe_read_all(dev, msg, msg_len_out);
+ if (msg_len_out_total > 0) {
+ assert(msg_len_out_total >= msg_len_out_err);
+
+ n = qemu_chr_fe_read_all(dev, (uint8_t *)msg, msg_len_out_err);
+ if (n <= 0) {
+ return -1;
+ }
+ if (msg_len_out_err == msg_len_out_total) {
+ return 0;
+ }
+ /* result error code is always in the first 4 bytes */
+ assert(sizeof(res) <= msg_len_out_err);
+ memcpy(&res, msg, sizeof(res));
+ if (res) {
+ return 0;
+ }
+
+ n = qemu_chr_fe_read_all(dev, (uint8_t *)msg + msg_len_out_err,
+ msg_len_out_total - msg_len_out_err);
if (n <= 0) {
return -1;
}
@@ -204,7 +223,8 @@ static int tpm_emulator_set_locality(TPMEmulator *tpm_emu, uint8_t locty_number,
memset(&loc, 0, sizeof(loc));
loc.u.req.loc = locty_number;
if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_LOCALITY, &loc,
- sizeof(loc), sizeof(loc)) < 0) {
+ sizeof(loc), sizeof(loc.u.resp.tpm_result),
+ sizeof(loc)) < 0) {
error_setg(errp, "tpm-emulator: could not set locality : %s",
strerror(errno));
return -1;
@@ -239,13 +259,16 @@ static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd *cmd,
static int tpm_emulator_probe_caps(TPMEmulator *tpm_emu)
{
- if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_CAPABILITY,
- &tpm_emu->caps, 0, sizeof(tpm_emu->caps)) < 0) {
+ ptm_cap_n cap_n;
+
+ if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_CAPABILITY, &cap_n, 0,
+ sizeof(cap_n.u.resp.tpm_result),
+ sizeof(cap_n)) < 0) {
error_report("tpm-emulator: probing failed : %s", strerror(errno));
return -1;
}
- tpm_emu->caps = be64_to_cpu(tpm_emu->caps);
+ tpm_emu->caps = be32_to_cpu(cap_n.u.resp.caps);
trace_tpm_emulator_probe_caps(tpm_emu->caps);
@@ -254,7 +277,7 @@ static int tpm_emulator_probe_caps(TPMEmulator *tpm_emu)
static int tpm_emulator_check_caps(TPMEmulator *tpm_emu)
{
- ptm_cap caps = 0;
+ uint32_t caps = 0;
const char *tpm = NULL;
/* check for min. required capabilities */
@@ -290,7 +313,8 @@ static int tpm_emulator_stop_tpm(TPMBackend *tb)
TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
ptm_res res;
- if (tpm_emulator_ctrlcmd(tpm_emu, CMD_STOP, &res, 0, sizeof(res)) < 0) {
+ if (tpm_emulator_ctrlcmd(tpm_emu, CMD_STOP, &res, 0,
+ sizeof(ptm_res), sizeof(res)) < 0) {
error_report("tpm-emulator: Could not stop TPM: %s",
strerror(errno));
return -1;
@@ -317,8 +341,9 @@ static int tpm_emulator_lock_storage(TPMEmulator *tpm_emu)
/* give failing side 300 * 10ms time to release lock */
pls.u.req.retries = cpu_to_be32(300);
- if (tpm_emulator_ctrlcmd(tpm_emu, CMD_LOCK_STORAGE, &pls,
- sizeof(pls.u.req), sizeof(pls.u.resp)) < 0) {
+ if (tpm_emulator_ctrlcmd(tpm_emu, CMD_LOCK_STORAGE, &pls, sizeof(pls.u.req),
+ sizeof(pls.u.resp.tpm_result),
+ sizeof(pls.u.resp)) < 0) {
error_report("tpm-emulator: Could not lock storage within 3 seconds: "
"%s", strerror(errno));
return -1;
@@ -349,7 +374,8 @@ static int tpm_emulator_set_buffer_size(TPMBackend *tb,
psbs.u.req.buffersize = cpu_to_be32(wanted_size);
if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_BUFFERSIZE, &psbs,
- sizeof(psbs.u.req), sizeof(psbs.u.resp)) < 0) {
+ sizeof(psbs.u.req), sizeof(psbs.u.resp.tpm_result),
+ sizeof(psbs.u.resp)) < 0) {
error_report("tpm-emulator: Could not set buffer size: %s",
strerror(errno));
return -1;
@@ -396,6 +422,7 @@ static int tpm_emulator_startup_tpm_resume(TPMBackend *tb, size_t buffersize,
}
if (tpm_emulator_ctrlcmd(tpm_emu, CMD_INIT, &init, sizeof(init),
+ sizeof(init.u.resp.tpm_result),
sizeof(init)) < 0) {
error_report("tpm-emulator: could not send INIT: %s",
strerror(errno));
@@ -437,8 +464,9 @@ static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb)
return tpm_emu->established_flag;
}
- if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_TPMESTABLISHED, &est,
- 0, sizeof(est)) < 0) {
+ if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_TPMESTABLISHED, &est, 0,
+ sizeof(est) /* always returns resp.bit */,
+ sizeof(est)) < 0) {
error_report("tpm-emulator: Could not get the TPM established flag: %s",
strerror(errno));
return false;
@@ -466,6 +494,7 @@ static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb,
reset_est.u.req.loc = tpm_emu->cur_locty_number;
if (tpm_emulator_ctrlcmd(tpm_emu, CMD_RESET_TPMESTABLISHED,
&reset_est, sizeof(reset_est),
+ sizeof(reset_est.u.resp.tpm_result),
sizeof(reset_est)) < 0) {
error_report("tpm-emulator: Could not reset the establishment bit: %s",
strerror(errno));
@@ -497,7 +526,7 @@ static void tpm_emulator_cancel_cmd(TPMBackend *tb)
/* FIXME: make the function non-blocking, or it may block a VCPU */
if (tpm_emulator_ctrlcmd(tpm_emu, CMD_CANCEL_TPM_CMD, &res, 0,
- sizeof(res)) < 0) {
+ sizeof(ptm_res), sizeof(res)) < 0) {
error_report("tpm-emulator: Could not cancel command: %s",
strerror(errno));
} else if (res != 0) {
@@ -527,8 +556,8 @@ static size_t tpm_emulator_get_buffer_size(TPMBackend *tb)
static int tpm_emulator_block_migration(TPMEmulator *tpm_emu)
{
Error *err = NULL;
- ptm_cap caps = PTM_CAP_GET_STATEBLOB | PTM_CAP_SET_STATEBLOB |
- PTM_CAP_STOP;
+ uint32_t caps = PTM_CAP_GET_STATEBLOB | PTM_CAP_SET_STATEBLOB |
+ PTM_CAP_STOP;
if (!TPM_EMULATOR_IMPLEMENTS_ALL_CAPS(tpm_emu, caps)) {
error_setg(&tpm_emu->migration_blocker,
@@ -557,7 +586,7 @@ static int tpm_emulator_prepare_data_fd(TPMEmulator *tpm_emu)
qemu_chr_fe_set_msgfds(&tpm_emu->ctrl_chr, fds + 1, 1);
if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_DATAFD, &res, 0,
- sizeof(res)) < 0 || res != 0) {
+ sizeof(ptm_res), sizeof(res)) < 0 || res != 0) {
error_report("tpm-emulator: Failed to send CMD_SET_DATAFD: %s",
strerror(errno));
goto err_exit;
@@ -704,6 +733,8 @@ static int tpm_emulator_get_state_blob(TPMEmulator *tpm_emu,
if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_STATEBLOB,
&pgs, sizeof(pgs.u.req),
+ /* always returns up to resp.data */
+ offsetof(ptm_getstate, u.resp.data),
offsetof(ptm_getstate, u.resp.data)) < 0) {
error_report("tpm-emulator: could not get state blob type %d : %s",
type, strerror(errno));
@@ -806,7 +837,7 @@ static int tpm_emulator_set_state_blob(TPMEmulator *tpm_emu,
/* write the header only */
if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_STATEBLOB, &pss,
- offsetof(ptm_setstate, u.req.data), 0) < 0) {
+ offsetof(ptm_setstate, u.req.data), 0, 0) < 0) {
error_report("tpm-emulator: could not set state blob type %d : %s",
type, strerror(errno));
return -1;
@@ -990,7 +1021,8 @@ static void tpm_emulator_shutdown(TPMEmulator *tpm_emu)
return;
}
- if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SHUTDOWN, &res, 0, sizeof(res)) < 0) {
+ if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SHUTDOWN, &res, 0,
+ sizeof(ptm_res), sizeof(res)) < 0) {
error_report("tpm-emulator: Could not cleanly shutdown the TPM: %s",
strerror(errno));
} else if (res != 0) {
diff --git a/backends/tpm/tpm_ioctl.h b/backends/tpm/tpm_ioctl.h
index 1933ab6..ee2dd15 100644
--- a/backends/tpm/tpm_ioctl.h
+++ b/backends/tpm/tpm_ioctl.h
@@ -29,6 +29,16 @@
typedef uint32_t ptm_res;
+/* PTM_GET_CAPABILITY: Get supported capabilities (ioctl's) */
+struct ptm_cap_n {
+ union {
+ struct {
+ ptm_res tpm_result; /* will always be TPM_SUCCESS (0) */
+ uint32_t caps;
+ } resp; /* response */
+ } u;
+};
+
/* PTM_GET_TPMESTABLISHED: get the establishment bit */
struct ptm_est {
union {
@@ -242,7 +252,8 @@ struct ptm_lockstorage {
} u;
};
-typedef uint64_t ptm_cap;
+typedef uint64_t ptm_cap; /* CUSE-only; use ptm_cap_n otherwise */
+typedef struct ptm_cap_n ptm_cap_n;
typedef struct ptm_est ptm_est;
typedef struct ptm_reset_est ptm_reset_est;
typedef struct ptm_loc ptm_loc;
diff --git a/backends/tpm/trace-events b/backends/tpm/trace-events
index cb5cfa6..05e3053 100644
--- a/backends/tpm/trace-events
+++ b/backends/tpm/trace-events
@@ -16,7 +16,7 @@ tpm_util_show_buffer_content(const char *buf) "%s"
# tpm_emulator.c
tpm_emulator_set_locality(uint8_t locty) "setting locality to %d"
tpm_emulator_handle_request(void) "processing TPM command"
-tpm_emulator_probe_caps(uint64_t caps) "capabilities: 0x%"PRIx64
+tpm_emulator_probe_caps(uint32_t caps) "capabilities: 0x%x"
tpm_emulator_set_buffer_size(uint32_t buffersize, uint32_t minsize, uint32_t maxsize) "buffer size: %u, min: %u, max: %u"
tpm_emulator_startup_tpm_resume(bool is_resume, size_t buffersize) "is_resume: %d, buffer size: %zu"
tpm_emulator_get_tpm_established_flag(uint8_t flag) "got established flag: %d"
diff --git a/backends/trace-events b/backends/trace-events
index 211e6f3..40811a3 100644
--- a/backends/trace-events
+++ b/backends/trace-events
@@ -14,4 +14,7 @@ iommufd_backend_map_dma(int iommufd, uint32_t ioas, uint64_t iova, uint64_t size
iommufd_backend_unmap_dma_non_exist(int iommufd, uint32_t ioas, uint64_t iova, uint64_t size, int ret) " Unmap nonexistent mapping: iommufd=%d ioas=%d iova=0x%"PRIx64" size=0x%"PRIx64" (%d)"
iommufd_backend_unmap_dma(int iommufd, uint32_t ioas, uint64_t iova, uint64_t size, int ret) " iommufd=%d ioas=%d iova=0x%"PRIx64" size=0x%"PRIx64" (%d)"
iommufd_backend_alloc_ioas(int iommufd, uint32_t ioas) " iommufd=%d ioas=%d"
+iommufd_backend_alloc_hwpt(int iommufd, uint32_t dev_id, uint32_t pt_id, uint32_t flags, uint32_t hwpt_type, uint32_t len, uint64_t data_ptr, uint32_t out_hwpt_id, int ret) " iommufd=%d dev_id=%u pt_id=%u flags=0x%x hwpt_type=%u len=%u data_ptr=0x%"PRIx64" out_hwpt=%u (%d)"
iommufd_backend_free_id(int iommufd, uint32_t id, int ret) " iommufd=%d id=%d (%d)"
+iommufd_backend_set_dirty(int iommufd, uint32_t hwpt_id, bool start, int ret) " iommufd=%d hwpt=%u enable=%d (%d)"
+iommufd_backend_get_dirty_bitmap(int iommufd, uint32_t hwpt_id, uint64_t iova, uint64_t size, uint64_t page_size, int ret) " iommufd=%d hwpt=%u iova=0x%"PRIx64" size=0x%"PRIx64" page_size=0x%"PRIx64" (%d)"
diff --git a/block.c b/block.c
index c317de9..7d90007 100644
--- a/block.c
+++ b/block.c
@@ -6351,7 +6351,7 @@ XDbgBlockGraph *bdrv_get_xdbg_block_graph(Error **errp)
if (!*name) {
name = allocated_name = blk_get_attached_dev_id(blk);
}
- xdbg_graph_add_node(gr, blk, X_DBG_BLOCK_GRAPH_NODE_TYPE_BLOCK_BACKEND,
+ xdbg_graph_add_node(gr, blk, XDBG_BLOCK_GRAPH_NODE_TYPE_BLOCK_BACKEND,
name);
g_free(allocated_name);
if (blk_root(blk)) {
@@ -6364,7 +6364,7 @@ XDbgBlockGraph *bdrv_get_xdbg_block_graph(Error **errp)
job = block_job_next_locked(job)) {
GSList *el;
- xdbg_graph_add_node(gr, job, X_DBG_BLOCK_GRAPH_NODE_TYPE_BLOCK_JOB,
+ xdbg_graph_add_node(gr, job, XDBG_BLOCK_GRAPH_NODE_TYPE_BLOCK_JOB,
job->job.id);
for (el = job->nodes; el; el = el->next) {
xdbg_graph_add_edge(gr, job, (BdrvChild *)el->data);
@@ -6373,7 +6373,7 @@ XDbgBlockGraph *bdrv_get_xdbg_block_graph(Error **errp)
}
QTAILQ_FOREACH(bs, &graph_bdrv_states, node_list) {
- xdbg_graph_add_node(gr, bs, X_DBG_BLOCK_GRAPH_NODE_TYPE_BLOCK_DRIVER,
+ xdbg_graph_add_node(gr, bs, XDBG_BLOCK_GRAPH_NODE_TYPE_BLOCK_DRIVER,
bs->node_name);
QLIST_FOREACH(child, &bs->children, next) {
xdbg_graph_add_edge(gr, bs, child);
diff --git a/block/aio_task.c b/block/aio_task.c
index 9bd17ea..bb5c05f 100644
--- a/block/aio_task.c
+++ b/block/aio_task.c
@@ -119,8 +119,3 @@ int aio_task_pool_status(AioTaskPool *pool)
return pool->status;
}
-
-bool aio_task_pool_empty(AioTaskPool *pool)
-{
- return pool->busy_tasks == 0;
-}
diff --git a/block/backup.c b/block/backup.c
index 3dd2e22..a1292c0 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -458,7 +458,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
}
cbw = bdrv_cbw_append(bs, target, filter_node_name, discard_source,
- &bcs, errp);
+ perf->min_cluster_size, &bcs, errp);
if (!cbw) {
goto error;
}
diff --git a/block/blkio.c b/block/blkio.c
index 3d9a2e7..e0e765a 100644
--- a/block/blkio.c
+++ b/block/blkio.c
@@ -899,8 +899,10 @@ static int blkio_open(BlockDriverState *bs, QDict *options, int flags,
}
bs->supported_write_flags = BDRV_REQ_FUA | BDRV_REQ_REGISTERED_BUF;
- bs->supported_zero_flags = BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP |
- BDRV_REQ_NO_FALLBACK;
+ bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK;
+#ifdef CONFIG_BLKIO_WRITE_ZEROS_FUA
+ bs->supported_zero_flags |= BDRV_REQ_FUA;
+#endif
qemu_mutex_init(&s->blkio_lock);
qemu_co_mutex_init(&s->bounce_lock);
diff --git a/block/block-backend.c b/block/block-backend.c
index db6f9b9..85bcded 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -854,15 +854,6 @@ BlockBackendPublic *blk_get_public(BlockBackend *blk)
}
/*
- * Returns a BlockBackend given the associated @public fields.
- */
-BlockBackend *blk_by_public(BlockBackendPublic *public)
-{
- GLOBAL_STATE_CODE();
- return container_of(public, BlockBackend, public);
-}
-
-/*
* Disassociates the currently associated BlockDriverState from @blk.
*/
void blk_remove_bs(BlockBackend *blk)
@@ -1028,16 +1019,14 @@ DeviceState *blk_get_attached_dev(BlockBackend *blk)
return blk->dev;
}
-/* Return the qdev ID, or if no ID is assigned the QOM path, of the block
- * device attached to the BlockBackend. */
-char *blk_get_attached_dev_id(BlockBackend *blk)
+static char *blk_get_attached_dev_id_or_path(BlockBackend *blk, bool want_id)
{
DeviceState *dev = blk->dev;
IO_CODE();
if (!dev) {
return g_strdup("");
- } else if (dev->id) {
+ } else if (want_id && dev->id) {
return g_strdup(dev->id);
}
@@ -1045,6 +1034,20 @@ char *blk_get_attached_dev_id(BlockBackend *blk)
}
/*
+ * Return the qdev ID, or if no ID is assigned the QOM path, of the block
+ * device attached to the BlockBackend.
+ */
+char *blk_get_attached_dev_id(BlockBackend *blk)
+{
+ return blk_get_attached_dev_id_or_path(blk, true);
+}
+
+static char *blk_get_attached_dev_path(BlockBackend *blk)
+{
+ return blk_get_attached_dev_id_or_path(blk, false);
+}
+
+/*
* Return the BlockBackend which has the device model @dev attached if it
* exists, else null.
*
@@ -1214,12 +1217,6 @@ BlockDeviceIoStatus blk_iostatus(const BlockBackend *blk)
return blk->iostatus;
}
-void blk_iostatus_disable(BlockBackend *blk)
-{
- GLOBAL_STATE_CODE();
- blk->iostatus_enabled = false;
-}
-
void blk_iostatus_reset(BlockBackend *blk)
{
GLOBAL_STATE_CODE();
@@ -2140,6 +2137,7 @@ static void send_qmp_error_event(BlockBackend *blk,
optype = is_read ? IO_OPERATION_TYPE_READ : IO_OPERATION_TYPE_WRITE;
qapi_event_send_block_io_error(blk_name(blk),
+ blk_get_attached_dev_path(blk),
bs ? bdrv_get_node_name(bs) : NULL, optype,
action, blk_iostatus_is_enabled(blk),
error == ENOSPC, strerror(error));
@@ -2228,28 +2226,6 @@ void blk_set_enable_write_cache(BlockBackend *blk, bool wce)
blk->enable_write_cache = wce;
}
-void blk_activate(BlockBackend *blk, Error **errp)
-{
- BlockDriverState *bs = blk_bs(blk);
- GLOBAL_STATE_CODE();
-
- if (!bs) {
- error_setg(errp, "Device '%s' has no medium", blk->name);
- return;
- }
-
- /*
- * Migration code can call this function in coroutine context, so leave
- * coroutine context if necessary.
- */
- if (qemu_in_coroutine()) {
- bdrv_co_activate(bs, errp);
- } else {
- GRAPH_RDLOCK_GUARD_MAINLOOP();
- bdrv_activate(bs, errp);
- }
-}
-
bool coroutine_fn blk_co_is_inserted(BlockBackend *blk)
{
BlockDriverState *bs = blk_bs(blk);
@@ -2380,36 +2356,6 @@ bool blk_op_is_blocked(BlockBackend *blk, BlockOpType op, Error **errp)
return bdrv_op_is_blocked(bs, op, errp);
}
-void blk_op_unblock(BlockBackend *blk, BlockOpType op, Error *reason)
-{
- BlockDriverState *bs = blk_bs(blk);
- GLOBAL_STATE_CODE();
-
- if (bs) {
- bdrv_op_unblock(bs, op, reason);
- }
-}
-
-void blk_op_block_all(BlockBackend *blk, Error *reason)
-{
- BlockDriverState *bs = blk_bs(blk);
- GLOBAL_STATE_CODE();
-
- if (bs) {
- bdrv_op_block_all(bs, reason);
- }
-}
-
-void blk_op_unblock_all(BlockBackend *blk, Error *reason)
-{
- BlockDriverState *bs = blk_bs(blk);
- GLOBAL_STATE_CODE();
-
- if (bs) {
- bdrv_op_unblock_all(bs, reason);
- }
-}
-
/**
* Return BB's current AioContext. Note that this context may change
* concurrently at any time, with one exception: If the BB has a root node
@@ -2564,12 +2510,6 @@ void blk_add_remove_bs_notifier(BlockBackend *blk, Notifier *notify)
notifier_list_add(&blk->remove_bs_notifiers, notify);
}
-void blk_add_insert_bs_notifier(BlockBackend *blk, Notifier *notify)
-{
- GLOBAL_STATE_CODE();
- notifier_list_add(&blk->insert_bs_notifiers, notify);
-}
-
BlockAcctStats *blk_get_stats(BlockBackend *blk)
{
IO_CODE();
diff --git a/block/block-copy.c b/block/block-copy.c
index 7e3b378..eddb0b8 100644
--- a/block/block-copy.c
+++ b/block/block-copy.c
@@ -310,6 +310,7 @@ void block_copy_set_copy_opts(BlockCopyState *s, bool use_copy_range,
}
static int64_t block_copy_calculate_cluster_size(BlockDriverState *target,
+ int64_t min_cluster_size,
Error **errp)
{
int ret;
@@ -319,6 +320,9 @@ static int64_t block_copy_calculate_cluster_size(BlockDriverState *target,
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
+ min_cluster_size = MAX(min_cluster_size,
+ (int64_t)BLOCK_COPY_CLUSTER_SIZE_DEFAULT);
+
target_does_cow = bdrv_backing_chain_next(target);
/*
@@ -329,13 +333,13 @@ static int64_t block_copy_calculate_cluster_size(BlockDriverState *target,
ret = bdrv_get_info(target, &bdi);
if (ret == -ENOTSUP && !target_does_cow) {
/* Cluster size is not defined */
- warn_report("The target block device doesn't provide "
- "information about the block size and it doesn't have a "
- "backing file. The default block size of %u bytes is "
- "used. If the actual block size of the target exceeds "
- "this default, the backup may be unusable",
- BLOCK_COPY_CLUSTER_SIZE_DEFAULT);
- return BLOCK_COPY_CLUSTER_SIZE_DEFAULT;
+ warn_report("The target block device doesn't provide information about "
+ "the block size and it doesn't have a backing file. The "
+ "(default) block size of %" PRIi64 " bytes is used. If the "
+ "actual block size of the target exceeds this value, the "
+ "backup may be unusable",
+ min_cluster_size);
+ return min_cluster_size;
} else if (ret < 0 && !target_does_cow) {
error_setg_errno(errp, -ret,
"Couldn't determine the cluster size of the target image, "
@@ -345,16 +349,17 @@ static int64_t block_copy_calculate_cluster_size(BlockDriverState *target,
return ret;
} else if (ret < 0 && target_does_cow) {
/* Not fatal; just trudge on ahead. */
- return BLOCK_COPY_CLUSTER_SIZE_DEFAULT;
+ return min_cluster_size;
}
- return MAX(BLOCK_COPY_CLUSTER_SIZE_DEFAULT, bdi.cluster_size);
+ return MAX(min_cluster_size, bdi.cluster_size);
}
BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
BlockDriverState *copy_bitmap_bs,
const BdrvDirtyBitmap *bitmap,
bool discard_source,
+ uint64_t min_cluster_size,
Error **errp)
{
ERRP_GUARD();
@@ -365,7 +370,18 @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
GLOBAL_STATE_CODE();
- cluster_size = block_copy_calculate_cluster_size(target->bs, errp);
+ if (min_cluster_size > INT64_MAX) {
+ error_setg(errp, "min-cluster-size too large: %" PRIu64 " > %" PRIi64,
+ min_cluster_size, INT64_MAX);
+ return NULL;
+ } else if (min_cluster_size && !is_power_of_2(min_cluster_size)) {
+ error_setg(errp, "min-cluster-size needs to be a power of 2");
+ return NULL;
+ }
+
+ cluster_size = block_copy_calculate_cluster_size(target->bs,
+ (int64_t)min_cluster_size,
+ errp);
if (cluster_size < 0) {
return NULL;
}
@@ -568,7 +584,7 @@ static coroutine_fn int block_copy_task_entry(AioTask *task)
BlockCopyState *s = t->s;
bool error_is_read = false;
BlockCopyMethod method = t->method;
- int ret;
+ int ret = -1;
WITH_GRAPH_RDLOCK_GUARD() {
ret = block_copy_do_copy(s, t->req.offset, t->req.bytes, &method,
@@ -595,7 +611,9 @@ static coroutine_fn int block_copy_task_entry(AioTask *task)
if (s->discard_source && ret == 0) {
int64_t nbytes =
MIN(t->req.offset + t->req.bytes, s->len) - t->req.offset;
- bdrv_co_pdiscard(s->source, t->req.offset, nbytes);
+ WITH_GRAPH_RDLOCK_GUARD() {
+ bdrv_co_pdiscard(s->source, t->req.offset, nbytes);
+ }
}
return ret;
diff --git a/block/copy-before-write.c b/block/copy-before-write.c
index 853e01a..81afeff 100644
--- a/block/copy-before-write.c
+++ b/block/copy-before-write.c
@@ -66,7 +66,8 @@ typedef struct BDRVCopyBeforeWriteState {
/*
* @frozen_read_reqs: current read requests for fleecing user in bs->file
- * node. These areas must not be rewritten by guest.
+ * node. These areas must not be rewritten by guest. There can be multiple
+ * overlapping read requests.
*/
BlockReqList frozen_read_reqs;
@@ -417,6 +418,7 @@ static BlockdevOptions *cbw_parse_options(QDict *options, Error **errp)
qdict_extract_subqdict(options, NULL, "bitmap");
qdict_del(options, "on-cbw-error");
qdict_del(options, "cbw-timeout");
+ qdict_del(options, "min-cluster-size");
out:
visit_free(v);
@@ -476,8 +478,10 @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
bs->file->bs->supported_zero_flags);
s->discard_source = flags & BDRV_O_CBW_DISCARD_SOURCE;
+
s->bcs = block_copy_state_new(bs->file, s->target, bs, bitmap,
- flags & BDRV_O_CBW_DISCARD_SOURCE, errp);
+ flags & BDRV_O_CBW_DISCARD_SOURCE,
+ opts->min_cluster_size, errp);
if (!s->bcs) {
error_prepend(errp, "Cannot create block-copy-state: ");
return -EINVAL;
@@ -545,6 +549,7 @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source,
BlockDriverState *target,
const char *filter_node_name,
bool discard_source,
+ uint64_t min_cluster_size,
BlockCopyState **bcs,
Error **errp)
{
@@ -564,6 +569,14 @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source,
qdict_put_str(opts, "file", bdrv_get_node_name(source));
qdict_put_str(opts, "target", bdrv_get_node_name(target));
+ if (min_cluster_size > INT64_MAX) {
+ error_setg(errp, "min-cluster-size too large: %" PRIu64 " > %" PRIi64,
+ min_cluster_size, INT64_MAX);
+ qobject_unref(opts);
+ return NULL;
+ }
+ qdict_put_int(opts, "min-cluster-size", (int64_t)min_cluster_size);
+
top = bdrv_insert_node(source, opts, flags, errp);
if (!top) {
return NULL;
diff --git a/block/copy-before-write.h b/block/copy-before-write.h
index 01af0cd..2a5d4ba 100644
--- a/block/copy-before-write.h
+++ b/block/copy-before-write.h
@@ -40,6 +40,7 @@ BlockDriverState *bdrv_cbw_append(BlockDriverState *source,
BlockDriverState *target,
const char *filter_node_name,
bool discard_source,
+ uint64_t min_cluster_size,
BlockCopyState **bcs,
Error **errp);
void bdrv_cbw_drop(BlockDriverState *bs);
diff --git a/block/crypto.c b/block/crypto.c
index 4eed3ff..80b2dba 100644
--- a/block/crypto.c
+++ b/block/crypto.c
@@ -682,7 +682,7 @@ err:
static int block_crypto_probe_luks(const uint8_t *buf,
int buf_size,
const char *filename) {
- return block_crypto_probe_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
+ return block_crypto_probe_generic(QCRYPTO_BLOCK_FORMAT_LUKS,
buf, buf_size, filename);
}
@@ -691,7 +691,7 @@ static int block_crypto_open_luks(BlockDriverState *bs,
int flags,
Error **errp)
{
- return block_crypto_open_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
+ return block_crypto_open_generic(QCRYPTO_BLOCK_FORMAT_LUKS,
&block_crypto_runtime_opts_luks,
bs, options, flags, errp);
}
@@ -724,7 +724,7 @@ block_crypto_co_create_luks(BlockdevCreateOptions *create_options, Error **errp)
}
create_opts = (QCryptoBlockCreateOptions) {
- .format = Q_CRYPTO_BLOCK_FORMAT_LUKS,
+ .format = QCRYPTO_BLOCK_FORMAT_LUKS,
.u.luks = *qapi_BlockdevCreateOptionsLUKS_base(luks_opts),
};
@@ -889,7 +889,7 @@ block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp)
if (!info) {
return NULL;
}
- assert(info->format == Q_CRYPTO_BLOCK_FORMAT_LUKS);
+ assert(info->format == QCRYPTO_BLOCK_FORMAT_LUKS);
spec_info = g_new(ImageInfoSpecific, 1);
spec_info->type = IMAGE_INFO_SPECIFIC_KIND_LUKS;
@@ -1002,7 +1002,7 @@ coroutine_fn block_crypto_co_amend_luks(BlockDriverState *bs,
QCryptoBlockAmendOptions amend_opts;
amend_opts = (QCryptoBlockAmendOptions) {
- .format = Q_CRYPTO_BLOCK_FORMAT_LUKS,
+ .format = QCRYPTO_BLOCK_FORMAT_LUKS,
.u.luks = *qapi_BlockdevAmendOptionsLUKS_base(&opts->u.luks),
};
return block_crypto_amend_options_generic_luks(bs, &amend_opts,
diff --git a/block/export/vduse-blk.c b/block/export/vduse-blk.c
index 172f73c..bd852e5 100644
--- a/block/export/vduse-blk.c
+++ b/block/export/vduse-blk.c
@@ -273,7 +273,6 @@ static int vduse_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
uint64_t logical_block_size = VIRTIO_BLK_SECTOR_SIZE;
uint16_t num_queues = VDUSE_DEFAULT_NUM_QUEUE;
uint16_t queue_size = VDUSE_DEFAULT_QUEUE_SIZE;
- Error *local_err = NULL;
struct virtio_blk_config config = { 0 };
uint64_t features;
int i, ret;
@@ -297,10 +296,8 @@ static int vduse_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
if (vblk_opts->has_logical_block_size) {
logical_block_size = vblk_opts->logical_block_size;
- check_block_size(exp->id, "logical-block-size", logical_block_size,
- &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ if (!check_block_size("logical-block-size", logical_block_size,
+ errp)) {
return -EINVAL;
}
}
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
index 50c358e..d9d2014 100644
--- a/block/export/vhost-user-blk-server.c
+++ b/block/export/vhost-user-blk-server.c
@@ -319,7 +319,6 @@ static int vu_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
{
VuBlkExport *vexp = container_of(exp, VuBlkExport, export);
BlockExportOptionsVhostUserBlk *vu_opts = &opts->u.vhost_user_blk;
- Error *local_err = NULL;
uint64_t logical_block_size;
uint16_t num_queues = VHOST_USER_BLK_NUM_QUEUES_DEFAULT;
@@ -330,10 +329,7 @@ static int vu_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
} else {
logical_block_size = VIRTIO_BLK_SECTOR_SIZE;
}
- check_block_size(exp->id, "logical-block-size", logical_block_size,
- &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ if (!check_block_size("logical-block-size", logical_block_size, errp)) {
return -EINVAL;
}
diff --git a/block/file-posix.c b/block/file-posix.c
index ff928b5..90fa543 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -1398,7 +1398,7 @@ static void raw_refresh_zoned_limits(BlockDriverState *bs, struct stat *st,
Error **errp)
{
BDRVRawState *s = bs->opaque;
- BlockZoneModel zoned;
+ BlockZoneModel zoned = BLK_Z_NONE;
int ret;
ret = get_sysfs_zoned_model(st, &zoned);
diff --git a/block/gluster.c b/block/gluster.c
index f8b415f..e9c0380 100644
--- a/block/gluster.c
+++ b/block/gluster.c
@@ -514,7 +514,6 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
SocketAddressList **tail;
QDict *backing_options = NULL;
Error *local_err = NULL;
- char *str = NULL;
const char *ptr;
int i, type, num_servers;
@@ -547,7 +546,8 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
tail = &gconf->server;
for (i = 0; i < num_servers; i++) {
- str = g_strdup_printf(GLUSTER_OPT_SERVER_PATTERN"%d.", i);
+ g_autofree char *str = g_strdup_printf(GLUSTER_OPT_SERVER_PATTERN"%d.",
+ i);
qdict_extract_subqdict(options, &backing_options, str);
/* create opts info from runtime_type_opts list */
@@ -658,8 +658,6 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
qobject_unref(backing_options);
backing_options = NULL;
- g_free(str);
- str = NULL;
}
return 0;
@@ -668,7 +666,6 @@ out:
error_propagate(errp, local_err);
qapi_free_SocketAddress(gsconf);
qemu_opts_del(opts);
- g_free(str);
qobject_unref(backing_options);
errno = EINVAL;
return -errno;
@@ -809,6 +806,8 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
goto out;
}
+ warn_report_once("'gluster' is deprecated");
+
filename = qemu_opt_get(opts, GLUSTER_OPT_FILENAME);
s->debug = qemu_opt_get_number(opts, GLUSTER_OPT_DEBUG,
diff --git a/block/mirror.c b/block/mirror.c
index 61f0a71..2afe700 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -349,7 +349,7 @@ static void coroutine_fn mirror_co_read(void *opaque)
MirrorOp *op = opaque;
MirrorBlockJob *s = op->s;
int nb_chunks;
- uint64_t ret;
+ int ret = -1;
uint64_t max_bytes;
max_bytes = s->granularity * s->max_iov;
@@ -565,7 +565,7 @@ static void coroutine_fn GRAPH_UNLOCKED mirror_iteration(MirrorBlockJob *s)
bitmap_set(s->in_flight_bitmap, offset / s->granularity, nb_chunks);
while (nb_chunks > 0 && offset < s->bdev_length) {
- int ret;
+ int ret = -1;
int64_t io_bytes;
int64_t io_bytes_acct;
MirrorMethod mirror_method = MIRROR_METHOD_COPY;
@@ -841,7 +841,7 @@ static int coroutine_fn GRAPH_UNLOCKED mirror_dirty_init(MirrorBlockJob *s)
int64_t offset;
BlockDriverState *bs;
BlockDriverState *target_bs = blk_bs(s->target);
- int ret;
+ int ret = -1;
int64_t count;
bdrv_graph_co_rdlock();
@@ -931,7 +931,7 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
MirrorBDSOpaque *mirror_top_opaque = s->mirror_top_bs->opaque;
BlockDriverState *target_bs = blk_bs(s->target);
bool need_drain = true;
- BlockDeviceIoStatus iostatus;
+ BlockDeviceIoStatus iostatus = BLOCK_DEVICE_IO_STATUS__MAX;
int64_t length;
int64_t target_length;
BlockDriverInfo bdi;
diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c
index d954bec..bdf2eb5 100644
--- a/block/monitor/block-hmp-cmds.c
+++ b/block/monitor/block-hmp-cmds.c
@@ -402,7 +402,8 @@ void hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
goto exit;
}
- nbd_server_start(addr, NULL, NULL, 0, &local_err);
+ nbd_server_start(addr, NULL, NULL, NBD_DEFAULT_MAX_CONNECTIONS,
+ &local_err);
qapi_free_SocketAddress(addr);
if (local_err != NULL) {
goto exit;
diff --git a/block/parallels-ext.c b/block/parallels-ext.c
index b4e14c8..778b8f6 100644
--- a/block/parallels-ext.c
+++ b/block/parallels-ext.c
@@ -206,7 +206,7 @@ parallels_parse_format_extension(BlockDriverState *bs, uint8_t *ext_cluster,
goto fail;
}
- ret = qcrypto_hash_bytes(QCRYPTO_HASH_ALG_MD5, (char *)pos, remaining,
+ ret = qcrypto_hash_bytes(QCRYPTO_HASH_ALGO_MD5, (char *)pos, remaining,
&hash, &hash_len, errp);
if (ret < 0) {
goto fail;
diff --git a/block/qcow.c b/block/qcow.c
index c2f89db..84d1cca 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -831,7 +831,7 @@ qcow_co_create(BlockdevCreateOptions *opts, Error **errp)
}
if (qcow_opts->encrypt &&
- qcow_opts->encrypt->format != Q_CRYPTO_BLOCK_FORMAT_QCOW)
+ qcow_opts->encrypt->format != QCRYPTO_BLOCK_FORMAT_QCOW)
{
error_setg(errp, "Unsupported encryption format");
return -EINVAL;
diff --git a/block/qcow2.c b/block/qcow2.c
index 70b1973..803ca73 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -3214,10 +3214,10 @@ qcow2_set_up_encryption(BlockDriverState *bs,
int fmt, ret;
switch (cryptoopts->format) {
- case Q_CRYPTO_BLOCK_FORMAT_LUKS:
+ case QCRYPTO_BLOCK_FORMAT_LUKS:
fmt = QCOW_CRYPT_LUKS;
break;
- case Q_CRYPTO_BLOCK_FORMAT_QCOW:
+ case QCRYPTO_BLOCK_FORMAT_QCOW:
fmt = QCOW_CRYPT_AES;
break;
default:
@@ -5299,17 +5299,17 @@ qcow2_get_specific_info(BlockDriverState *bs, Error **errp)
} else {
/* if this assertion fails, this probably means a new version was
* added without having it covered here */
- assert(false);
+ g_assert_not_reached();
}
if (encrypt_info) {
ImageInfoSpecificQCow2Encryption *qencrypt =
g_new(ImageInfoSpecificQCow2Encryption, 1);
switch (encrypt_info->format) {
- case Q_CRYPTO_BLOCK_FORMAT_QCOW:
+ case QCRYPTO_BLOCK_FORMAT_QCOW:
qencrypt->format = BLOCKDEV_QCOW2_ENCRYPTION_FORMAT_AES;
break;
- case Q_CRYPTO_BLOCK_FORMAT_LUKS:
+ case QCRYPTO_BLOCK_FORMAT_LUKS:
qencrypt->format = BLOCKDEV_QCOW2_ENCRYPTION_FORMAT_LUKS;
qencrypt->u.luks = encrypt_info->u.luks;
break;
@@ -5948,7 +5948,7 @@ static int coroutine_fn qcow2_co_amend(BlockDriverState *bs,
return -EOPNOTSUPP;
}
- if (qopts->encrypt->format != Q_CRYPTO_BLOCK_FORMAT_LUKS) {
+ if (qopts->encrypt->format != QCRYPTO_BLOCK_FORMAT_LUKS) {
error_setg(errp,
"Amend can't be used to change the qcow2 encryption format");
return -EOPNOTSUPP;
diff --git a/block/quorum.c b/block/quorum.c
index db8fe89..46be65a 100644
--- a/block/quorum.c
+++ b/block/quorum.c
@@ -393,7 +393,7 @@ static int quorum_compute_hash(QuorumAIOCB *acb, int i, QuorumVoteValue *hash)
/* XXX - would be nice if we could pass in the Error **
* and propagate that back, but this quorum code is
* restricted to just errno values currently */
- if (qcrypto_hash_bytesv(QCRYPTO_HASH_ALG_SHA256,
+ if (qcrypto_hash_bytesv(QCRYPTO_HASH_ALGO_SHA256,
qiov->iov, qiov->niov,
&data, &len,
NULL) < 0) {
@@ -1308,7 +1308,7 @@ static BlockDriver bdrv_quorum = {
static void bdrv_quorum_init(void)
{
- if (!qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA256)) {
+ if (!qcrypto_hash_supports(QCRYPTO_HASH_ALGO_SHA256)) {
/* SHA256 hash support is required for quorum device */
return;
}
diff --git a/block/raw-format.c b/block/raw-format.c
index ac7e849..e08526e 100644
--- a/block/raw-format.c
+++ b/block/raw-format.c
@@ -111,7 +111,7 @@ raw_apply_options(BlockDriverState *bs, BDRVRawState *s, uint64_t offset,
if (offset > real_size) {
error_setg(errp, "Offset (%" PRIu64 ") cannot be greater than "
"size of the containing file (%" PRId64 ")",
- s->offset, real_size);
+ offset, real_size);
return -EINVAL;
}
@@ -119,7 +119,7 @@ raw_apply_options(BlockDriverState *bs, BDRVRawState *s, uint64_t offset,
error_setg(errp, "The sum of offset (%" PRIu64 ") and size "
"(%" PRIu64 ") has to be smaller or equal to the "
" actual size of the containing file (%" PRId64 ")",
- s->offset, s->size, real_size);
+ offset, size, real_size);
return -EINVAL;
}
diff --git a/block/rbd.c b/block/rbd.c
index 9c0fd0c..04ed0e2 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -367,11 +367,11 @@ static int qemu_rbd_convert_luks_create_options(
if (luks_opts->has_cipher_alg) {
switch (luks_opts->cipher_alg) {
- case QCRYPTO_CIPHER_ALG_AES_128: {
+ case QCRYPTO_CIPHER_ALGO_AES_128: {
*alg = RBD_ENCRYPTION_ALGORITHM_AES128;
break;
}
- case QCRYPTO_CIPHER_ALG_AES_256: {
+ case QCRYPTO_CIPHER_ALGO_AES_256: {
*alg = RBD_ENCRYPTION_ALGORITHM_AES256;
break;
}
diff --git a/block/reqlist.c b/block/reqlist.c
index 08cb57c..098e807 100644
--- a/block/reqlist.c
+++ b/block/reqlist.c
@@ -20,8 +20,6 @@
void reqlist_init_req(BlockReqList *reqs, BlockReq *req, int64_t offset,
int64_t bytes)
{
- assert(!reqlist_find_conflict(reqs, offset, bytes));
-
*req = (BlockReq) {
.offset = offset,
.bytes = bytes,
diff --git a/block/ssh.c b/block/ssh.c
index 27d582e..9f8140b 100644
--- a/block/ssh.c
+++ b/block/ssh.c
@@ -364,7 +364,7 @@ static unsigned hex2decimal(char ch)
return 10 + (ch - 'A');
}
- return -1;
+ return UINT_MAX;
}
/* Compare the binary fingerprint (hash of host key) with the
@@ -376,13 +376,15 @@ static int compare_fingerprint(const unsigned char *fingerprint, size_t len,
unsigned c;
while (len > 0) {
+ unsigned c0, c1;
while (*host_key_check == ':')
host_key_check++;
- if (!qemu_isxdigit(host_key_check[0]) ||
- !qemu_isxdigit(host_key_check[1]))
+ c0 = hex2decimal(host_key_check[0]);
+ c1 = hex2decimal(host_key_check[1]);
+ if (c0 > 0xf || c1 > 0xf) {
return 1;
- c = hex2decimal(host_key_check[0]) * 16 +
- hex2decimal(host_key_check[1]);
+ }
+ c = c0 * 16 + c1;
if (c - *fingerprint != 0)
return c - *fingerprint;
fingerprint++;
@@ -474,7 +476,6 @@ static int check_host_key(BDRVSSHState *s, SshHostKeyCheck *hkc, Error **errp)
errp);
}
g_assert_not_reached();
- break;
case SSH_HOST_KEY_CHECK_MODE_KNOWN_HOSTS:
return check_host_key_knownhosts(s, errp);
default:
diff --git a/block/stream.c b/block/stream.c
index 7031eef..9076203 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -155,8 +155,8 @@ static void stream_clean(Job *job)
static int coroutine_fn stream_run(Job *job, Error **errp)
{
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
- BlockDriverState *unfiltered_bs;
- int64_t len;
+ BlockDriverState *unfiltered_bs = NULL;
+ int64_t len = -1;
int64_t offset = 0;
int error = 0;
int64_t n = 0; /* bytes */
@@ -177,7 +177,7 @@ static int coroutine_fn stream_run(Job *job, Error **errp)
for ( ; offset < len; offset += n) {
bool copy;
- int ret;
+ int ret = -1;
/* Note that even when no rate limit is applied we need to yield
* with no pending I/O here so that bdrv_drain_all() returns.
diff --git a/block/vdi.c b/block/vdi.c
index 6363da0..26f7638 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -3,10 +3,12 @@
*
* Copyright (c) 2009, 2012 Stefan Weil
*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
* 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) version 3 or any later version.
+ * (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
@@ -85,7 +87,7 @@
/* Command line option for static images. */
#define BLOCK_OPT_STATIC "static"
-#define SECTOR_SIZE 512
+#define SECTOR_SIZE 512ULL
#define DEFAULT_CLUSTER_SIZE 1048576
/* Note: can't use 1 * MiB, because it's passed to stringify() */
@@ -440,7 +442,7 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
goto fail;
} else if (header.sector_size != SECTOR_SIZE) {
error_setg(errp, "unsupported VDI image (sector size %" PRIu32
- " is not %u)", header.sector_size, SECTOR_SIZE);
+ " is not %llu)", header.sector_size, SECTOR_SIZE);
ret = -ENOTSUP;
goto fail;
} else if (header.block_size != DEFAULT_CLUSTER_SIZE) {
diff --git a/block/vvfat.c b/block/vvfat.c
index 086fedf..8ffe8b3 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -1369,8 +1369,9 @@ static int open_file(BDRVVVFATState* s,mapping_t* mapping)
return -1;
vvfat_close_current_file(s);
s->current_fd = fd;
- s->current_mapping = mapping;
}
+
+ s->current_mapping = mapping;
return 0;
}
@@ -1408,7 +1409,9 @@ read_cluster_directory:
assert(s->current_fd);
- offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
+ offset = s->cluster_size *
+ ((cluster_num - s->current_mapping->begin)
+ + s->current_mapping->info.file.offset);
if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
return -3;
s->cluster=s->cluster_buffer;
@@ -1878,7 +1881,6 @@ get_cluster_count_for_direntry(BDRVVVFATState* s, direntry_t* direntry, const ch
uint32_t cluster_num = begin_of_direntry(direntry);
uint32_t offset = 0;
- int first_mapping_index = -1;
mapping_t* mapping = NULL;
const char* basename2 = NULL;
@@ -1929,8 +1931,9 @@ get_cluster_count_for_direntry(BDRVVVFATState* s, direntry_t* direntry, const ch
(mapping->mode & MODE_DIRECTORY) == 0) {
/* was modified in qcow */
- if (offset != mapping->info.file.offset + s->cluster_size
- * (cluster_num - mapping->begin)) {
+ if (offset != s->cluster_size
+ * ((cluster_num - mapping->begin)
+ + mapping->info.file.offset)) {
/* offset of this cluster in file chain has changed */
abort();
copy_it = 1;
@@ -1939,14 +1942,9 @@ get_cluster_count_for_direntry(BDRVVVFATState* s, direntry_t* direntry, const ch
if (strcmp(basename, basename2))
copy_it = 1;
- first_mapping_index = array_index(&(s->mapping), mapping);
- }
-
- if (mapping->first_mapping_index != first_mapping_index
- && mapping->info.file.offset > 0) {
- abort();
- copy_it = 1;
}
+ assert(mapping->first_mapping_index == -1
+ || mapping->info.file.offset > 0);
/* need to write out? */
if (!was_modified && is_file(direntry)) {
@@ -2404,7 +2402,7 @@ static int commit_mappings(BDRVVVFATState* s,
(mapping->end - mapping->begin);
} else
next_mapping->info.file.offset = mapping->info.file.offset +
- mapping->end - mapping->begin;
+ (mapping->end - mapping->begin);
mapping = next_mapping;
}
@@ -2525,8 +2523,9 @@ commit_one_file(BDRVVVFATState* s, int dir_index, uint32_t offset)
return -1;
}
- for (i = s->cluster_size; i < offset; i += s->cluster_size)
+ for (i = 0; i < offset; i += s->cluster_size) {
c = modified_fat_get(s, c);
+ }
fd = qemu_open_old(mapping->path, O_RDWR | O_CREAT | O_BINARY, 0666);
if (fd < 0) {
diff --git a/blockdev-nbd.c b/blockdev-nbd.c
index 2130124..b36f41b 100644
--- a/blockdev-nbd.c
+++ b/blockdev-nbd.c
@@ -21,12 +21,18 @@
#include "io/channel-socket.h"
#include "io/net-listener.h"
+typedef struct NBDConn {
+ QIOChannelSocket *cioc;
+ QLIST_ENTRY(NBDConn) next;
+} NBDConn;
+
typedef struct NBDServerData {
QIONetListener *listener;
QCryptoTLSCreds *tlscreds;
char *tlsauthz;
uint32_t max_connections;
uint32_t connections;
+ QLIST_HEAD(, NBDConn) conns;
} NBDServerData;
static NBDServerData *nbd_server;
@@ -51,6 +57,14 @@ int nbd_server_max_connections(void)
static void nbd_blockdev_client_closed(NBDClient *client, bool ignored)
{
+ NBDConn *conn = nbd_client_owner(client);
+
+ assert(qemu_in_main_thread() && nbd_server);
+
+ object_unref(OBJECT(conn->cioc));
+ QLIST_REMOVE(conn, next);
+ g_free(conn);
+
nbd_client_put(client);
assert(nbd_server->connections > 0);
nbd_server->connections--;
@@ -60,31 +74,56 @@ static void nbd_blockdev_client_closed(NBDClient *client, bool ignored)
static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc,
gpointer opaque)
{
+ NBDConn *conn = g_new0(NBDConn, 1);
+
+ assert(qemu_in_main_thread() && nbd_server);
nbd_server->connections++;
+ object_ref(OBJECT(cioc));
+ conn->cioc = cioc;
+ QLIST_INSERT_HEAD(&nbd_server->conns, conn, next);
nbd_update_server_watch(nbd_server);
qio_channel_set_name(QIO_CHANNEL(cioc), "nbd-server");
- nbd_client_new(cioc, nbd_server->tlscreds, nbd_server->tlsauthz,
- nbd_blockdev_client_closed);
+ /* TODO - expose handshake timeout as QMP option */
+ nbd_client_new(cioc, NBD_DEFAULT_HANDSHAKE_MAX_SECS,
+ nbd_server->tlscreds, nbd_server->tlsauthz,
+ nbd_blockdev_client_closed, conn);
}
static void nbd_update_server_watch(NBDServerData *s)
{
- if (!s->max_connections || s->connections < s->max_connections) {
- qio_net_listener_set_client_func(s->listener, nbd_accept, NULL, NULL);
- } else {
- qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL);
+ if (s->listener) {
+ if (!s->max_connections || s->connections < s->max_connections) {
+ qio_net_listener_set_client_func(s->listener, nbd_accept, NULL,
+ NULL);
+ } else {
+ qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL);
+ }
}
}
static void nbd_server_free(NBDServerData *server)
{
+ NBDConn *conn, *tmp;
+
if (!server) {
return;
}
+ /*
+ * Forcefully close the listener socket, and any clients that have
+ * not yet disconnected on their own.
+ */
qio_net_listener_disconnect(server->listener);
object_unref(OBJECT(server->listener));
+ server->listener = NULL;
+ QLIST_FOREACH_SAFE(conn, &server->conns, next, tmp) {
+ qio_channel_shutdown(QIO_CHANNEL(conn->cioc), QIO_CHANNEL_SHUTDOWN_BOTH,
+ NULL);
+ }
+
+ AIO_WAIT_WHILE_UNLOCKED(NULL, server->connections > 0);
+
if (server->tlscreds) {
object_unref(OBJECT(server->tlscreds));
}
@@ -168,6 +207,10 @@ void nbd_server_start(SocketAddress *addr, const char *tls_creds,
void nbd_server_start_options(NbdServerOptions *arg, Error **errp)
{
+ if (!arg->has_max_connections) {
+ arg->max_connections = NBD_DEFAULT_MAX_CONNECTIONS;
+ }
+
nbd_server_start(arg->addr, arg->tls_creds, arg->tls_authz,
arg->max_connections, errp);
}
@@ -180,6 +223,10 @@ void qmp_nbd_server_start(SocketAddressLegacy *addr,
{
SocketAddress *addr_flat = socket_address_flatten(addr);
+ if (!has_max_connections) {
+ max_connections = NBD_DEFAULT_MAX_CONNECTIONS;
+ }
+
nbd_server_start(addr_flat, tls_creds, tls_authz, max_connections, errp);
qapi_free_SocketAddress(addr_flat);
}
diff --git a/blockdev.c b/blockdev.c
index 835064e..6740663 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2655,6 +2655,9 @@ static BlockJob *do_backup_common(BackupCommon *backup,
if (backup->x_perf->has_max_chunk) {
perf.max_chunk = backup->x_perf->max_chunk;
}
+ if (backup->x_perf->has_min_cluster_size) {
+ perf.min_cluster_size = backup->x_perf->min_cluster_size;
+ }
}
if ((backup->sync == MIRROR_SYNC_MODE_BITMAP) ||
diff --git a/bsd-user/aarch64/signal.c b/bsd-user/aarch64/signal.c
new file mode 100644
index 0000000..6bc73a7
--- /dev/null
+++ b/bsd-user/aarch64/signal.c
@@ -0,0 +1,137 @@
+/*
+ * ARM AArch64 specific signal definitions for bsd-user
+ *
+ * Copyright (c) 2015 Stacey D. Son <sson at FreeBSD>
+ *
+ * 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 "qemu.h"
+
+/*
+ * Compare to sendsig() in sys/arm64/arm64/exec_machdep.c
+ * Assumes that target stack frame memory is locked.
+ */
+abi_long set_sigtramp_args(CPUARMState *regs, int sig,
+ struct target_sigframe *frame,
+ abi_ulong frame_addr,
+ struct target_sigaction *ka)
+{
+ /*
+ * Arguments to signal handler:
+ * x0 = signal number
+ * x1 = siginfo pointer
+ * x2 = ucontext pointer
+ * pc/elr = signal handler pointer
+ * sp = sigframe struct pointer
+ * lr = sigtramp at base of user stack
+ */
+
+ regs->xregs[0] = sig;
+ regs->xregs[1] = frame_addr +
+ offsetof(struct target_sigframe, sf_si);
+ regs->xregs[2] = frame_addr +
+ offsetof(struct target_sigframe, sf_uc);
+
+ regs->pc = ka->_sa_handler;
+ regs->xregs[TARGET_REG_SP] = frame_addr;
+ regs->xregs[TARGET_REG_LR] = TARGET_PS_STRINGS - TARGET_SZSIGCODE;
+
+ return 0;
+}
+
+/*
+ * Compare to get_mcontext() in arm64/arm64/machdep.c
+ * Assumes that the memory is locked if mcp points to user memory.
+ */
+abi_long get_mcontext(CPUARMState *regs, target_mcontext_t *mcp, int flags)
+{
+ int err = 0, i;
+ uint64_t *gr = mcp->mc_gpregs.gp_x;
+
+ mcp->mc_gpregs.gp_spsr = pstate_read(regs);
+ if (flags & TARGET_MC_GET_CLEAR_RET) {
+ gr[0] = 0UL;
+ mcp->mc_gpregs.gp_spsr &= ~CPSR_C;
+ } else {
+ gr[0] = tswap64(regs->xregs[0]);
+ }
+
+ for (i = 1; i < 30; i++) {
+ gr[i] = tswap64(regs->xregs[i]);
+ }
+
+ mcp->mc_gpregs.gp_sp = tswap64(regs->xregs[TARGET_REG_SP]);
+ mcp->mc_gpregs.gp_lr = tswap64(regs->xregs[TARGET_REG_LR]);
+ mcp->mc_gpregs.gp_elr = tswap64(regs->pc);
+
+ /* XXX FP? */
+
+ return err;
+}
+
+/*
+ * Compare to arm64/arm64/exec_machdep.c sendsig()
+ * Assumes that the memory is locked if frame points to user memory.
+ */
+abi_long setup_sigframe_arch(CPUARMState *env, abi_ulong frame_addr,
+ struct target_sigframe *frame, int flags)
+{
+ target_mcontext_t *mcp = &frame->sf_uc.uc_mcontext;
+
+ get_mcontext(env, mcp, flags);
+ return 0;
+}
+
+/*
+ * Compare to set_mcontext() in arm64/arm64/machdep.c
+ * Assumes that the memory is locked if frame points to user memory.
+ */
+abi_long set_mcontext(CPUARMState *regs, target_mcontext_t *mcp, int srflag)
+{
+ int err = 0, i;
+ const uint64_t *gr = mcp->mc_gpregs.gp_x;
+
+ for (i = 0; i < 30; i++) {
+ regs->xregs[i] = tswap64(gr[i]);
+ }
+
+ regs->xregs[TARGET_REG_SP] = tswap64(mcp->mc_gpregs.gp_sp);
+ regs->xregs[TARGET_REG_LR] = tswap64(mcp->mc_gpregs.gp_lr);
+ regs->pc = mcp->mc_gpregs.gp_elr;
+ pstate_write(regs, mcp->mc_gpregs.gp_spsr);
+
+ /* XXX FP? */
+
+ return err;
+}
+
+/* Compare to sys_sigreturn() in arm64/arm64/machdep.c */
+abi_long get_ucontext_sigreturn(CPUARMState *regs, abi_ulong target_sf,
+ abi_ulong *target_uc)
+{
+ uint32_t pstate = pstate_read(regs);
+
+ *target_uc = 0;
+
+ if ((pstate & PSTATE_M) != PSTATE_MODE_EL0t ||
+ (pstate & (PSTATE_F | PSTATE_I | PSTATE_A | PSTATE_D)) != 0) {
+ return -TARGET_EINVAL;
+ }
+
+ *target_uc = target_sf;
+
+ return 0;
+}
diff --git a/bsd-user/aarch64/target.h b/bsd-user/aarch64/target.h
new file mode 100644
index 0000000..702aeb7
--- /dev/null
+++ b/bsd-user/aarch64/target.h
@@ -0,0 +1,20 @@
+/*
+ * Aarch64 general target stuff that's common to all aarch details
+ *
+ * Copyright (c) 2022 M. Warner Losh <imp@bsdimp.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef TARGET_H
+#define TARGET_H
+
+/*
+ * aaarch64 ABI does not 'lump' the registers for 64-bit args.
+ */
+static inline bool regpairs_aligned(void *cpu_env)
+{
+ return false;
+}
+
+#endif /* TARGET_H */
diff --git a/bsd-user/aarch64/target_arch.h b/bsd-user/aarch64/target_arch.h
new file mode 100644
index 0000000..4815a56
--- /dev/null
+++ b/bsd-user/aarch64/target_arch.h
@@ -0,0 +1,29 @@
+/*
+ * ARM AArch64 specific prototypes for bsd-user
+ *
+ * Copyright (c) 2015 Stacey D. Son <sson at FreeBSD>
+ *
+ * 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 TARGET_ARCH_H
+#define TARGET_ARCH_H
+
+#include "qemu.h"
+#include "target/arm/cpu-features.h"
+
+void target_cpu_set_tls(CPUARMState *env, target_ulong newtls);
+target_ulong target_cpu_get_tls(CPUARMState *env);
+
+#endif /* TARGET_ARCH_H */
diff --git a/bsd-user/aarch64/target_arch_cpu.c b/bsd-user/aarch64/target_arch_cpu.c
new file mode 100644
index 0000000..b2fa59e
--- /dev/null
+++ b/bsd-user/aarch64/target_arch_cpu.c
@@ -0,0 +1,31 @@
+/*
+ * ARM AArch64 specific CPU for bsd-user
+ *
+ * Copyright (c) 2015 Stacey Son
+ *
+ * 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 "target_arch.h"
+
+/* See cpu_set_user_tls() in arm64/arm64/vm_machdep.c */
+void target_cpu_set_tls(CPUARMState *env, target_ulong newtls)
+{
+ env->cp15.tpidr_el[0] = newtls;
+}
+
+target_ulong target_cpu_get_tls(CPUARMState *env)
+{
+ return env->cp15.tpidr_el[0];
+}
diff --git a/bsd-user/aarch64/target_arch_cpu.h b/bsd-user/aarch64/target_arch_cpu.h
new file mode 100644
index 0000000..b288e0d
--- /dev/null
+++ b/bsd-user/aarch64/target_arch_cpu.h
@@ -0,0 +1,189 @@
+/*
+ * ARM AArch64 cpu init and loop
+ *
+ * Copyright (c) 2015 Stacey Son
+ *
+ * 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 TARGET_ARCH_CPU_H
+#define TARGET_ARCH_CPU_H
+
+#include "target_arch.h"
+#include "signal-common.h"
+#include "target/arm/syndrome.h"
+
+#define TARGET_DEFAULT_CPU_MODEL "any"
+
+static inline void target_cpu_init(CPUARMState *env,
+ struct target_pt_regs *regs)
+{
+ int i;
+
+ if (!(arm_feature(env, ARM_FEATURE_AARCH64))) {
+ fprintf(stderr, "The selected ARM CPU does not support 64 bit mode\n");
+ exit(1);
+ }
+ for (i = 0; i < 31; i++) {
+ env->xregs[i] = regs->regs[i];
+ }
+ env->pc = regs->pc;
+ env->xregs[31] = regs->sp;
+}
+
+
+static inline void target_cpu_loop(CPUARMState *env)
+{
+ CPUState *cs = env_cpu(env);
+ int trapnr, ec, fsc, si_code, si_signo;
+ uint64_t code, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
+ abi_long ret;
+
+ for (;;) {
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ process_queued_cpu_work(cs);
+
+ switch (trapnr) {
+ case EXCP_SWI:
+ /* See arm64/arm64/trap.c cpu_fetch_syscall_args() */
+ code = env->xregs[8];
+ if (code == TARGET_FREEBSD_NR_syscall ||
+ code == TARGET_FREEBSD_NR___syscall) {
+ code = env->xregs[0];
+ arg1 = env->xregs[1];
+ arg2 = env->xregs[2];
+ arg3 = env->xregs[3];
+ arg4 = env->xregs[4];
+ arg5 = env->xregs[5];
+ arg6 = env->xregs[6];
+ arg7 = env->xregs[7];
+ arg8 = 0;
+ } else {
+ arg1 = env->xregs[0];
+ arg2 = env->xregs[1];
+ arg3 = env->xregs[2];
+ arg4 = env->xregs[3];
+ arg5 = env->xregs[4];
+ arg6 = env->xregs[5];
+ arg7 = env->xregs[6];
+ arg8 = env->xregs[7];
+ }
+ ret = do_freebsd_syscall(env, code, arg1, arg2, arg3,
+ arg4, arg5, arg6, arg7, arg8);
+ /*
+ * The carry bit is cleared for no error; set for error.
+ * See arm64/arm64/vm_machdep.c cpu_set_syscall_retval()
+ */
+ if (ret >= 0) {
+ env->CF = 0;
+ env->xregs[0] = ret;
+ } else if (ret == -TARGET_ERESTART) {
+ env->pc -= 4;
+ break;
+ } else if (ret != -TARGET_EJUSTRETURN) {
+ env->CF = 1;
+ env->xregs[0] = -ret;
+ }
+ break;
+
+ case EXCP_INTERRUPT:
+ /* Just indicate that signals should be handle ASAP. */
+ break;
+
+ case EXCP_UDEF:
+ force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN, env->pc);
+ break;
+
+
+ case EXCP_PREFETCH_ABORT:
+ case EXCP_DATA_ABORT:
+ /* We should only arrive here with EC in {DATAABORT, INSNABORT}. */
+ ec = syn_get_ec(env->exception.syndrome);
+ assert(ec == EC_DATAABORT || ec == EC_INSNABORT);
+
+ /* Both EC have the same format for FSC, or close enough. */
+ fsc = extract32(env->exception.syndrome, 0, 6);
+ switch (fsc) {
+ case 0x04 ... 0x07: /* Translation fault, level {0-3} */
+ si_signo = TARGET_SIGSEGV;
+ si_code = TARGET_SEGV_MAPERR;
+ break;
+ case 0x09 ... 0x0b: /* Access flag fault, level {1-3} */
+ case 0x0d ... 0x0f: /* Permission fault, level {1-3} */
+ si_signo = TARGET_SIGSEGV;
+ si_code = TARGET_SEGV_ACCERR;
+ break;
+ case 0x11: /* Synchronous Tag Check Fault */
+ si_signo = TARGET_SIGSEGV;
+ si_code = /* TARGET_SEGV_MTESERR; */ TARGET_SEGV_ACCERR;
+ break;
+ case 0x21: /* Alignment fault */
+ si_signo = TARGET_SIGBUS;
+ si_code = TARGET_BUS_ADRALN;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ force_sig_fault(si_signo, si_code, env->exception.vaddress);
+ break;
+
+ case EXCP_DEBUG:
+ case EXCP_BKPT:
+ force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
+ break;
+
+ case EXCP_ATOMIC:
+ cpu_exec_step_atomic(cs);
+ break;
+
+ case EXCP_YIELD:
+ /* nothing to do here for user-mode, just resume guest code */
+ break;
+ default:
+ fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
+ trapnr);
+ cpu_dump_state(cs, stderr, 0);
+ abort();
+ } /* switch() */
+ process_pending_signals(env);
+ /*
+ * Exception return on AArch64 always clears the exclusive
+ * monitor, so any return to running guest code implies this.
+ * A strex (successful or otherwise) also clears the monitor, so
+ * we don't need to specialcase EXCP_STREX.
+ */
+ env->exclusive_addr = -1;
+ } /* for (;;) */
+}
+
+
+/* See arm64/arm64/vm_machdep.c cpu_fork() */
+static inline void target_cpu_clone_regs(CPUARMState *env, target_ulong newsp)
+{
+ if (newsp) {
+ env->xregs[31] = newsp;
+ }
+ env->regs[0] = 0;
+ env->regs[1] = 0;
+ pstate_write(env, 0);
+}
+
+static inline void target_cpu_reset(CPUArchState *env)
+{
+}
+
+
+#endif /* TARGET_ARCH_CPU_H */
diff --git a/bsd-user/aarch64/target_arch_elf.h b/bsd-user/aarch64/target_arch_elf.h
new file mode 100644
index 0000000..cc87f47
--- /dev/null
+++ b/bsd-user/aarch64/target_arch_elf.h
@@ -0,0 +1,163 @@
+/*
+ * ARM AArch64 ELF definitions for bsd-user
+ *
+ * Copyright (c) 2015 Stacey D. Son
+ *
+ * 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 TARGET_ARCH_ELF_H
+#define TARGET_ARCH_ELF_H
+
+#define ELF_START_MMAP 0x80000000
+#define ELF_ET_DYN_LOAD_ADDR 0x100000
+
+#define elf_check_arch(x) ((x) == EM_AARCH64)
+
+#define ELF_CLASS ELFCLASS64
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_AARCH64
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE 4096
+
+enum {
+ ARM_HWCAP_A64_FP = 1 << 0,
+ ARM_HWCAP_A64_ASIMD = 1 << 1,
+ ARM_HWCAP_A64_EVTSTRM = 1 << 2,
+ ARM_HWCAP_A64_AES = 1 << 3,
+ ARM_HWCAP_A64_PMULL = 1 << 4,
+ ARM_HWCAP_A64_SHA1 = 1 << 5,
+ ARM_HWCAP_A64_SHA2 = 1 << 6,
+ ARM_HWCAP_A64_CRC32 = 1 << 7,
+ ARM_HWCAP_A64_ATOMICS = 1 << 8,
+ ARM_HWCAP_A64_FPHP = 1 << 9,
+ ARM_HWCAP_A64_ASIMDHP = 1 << 10,
+ ARM_HWCAP_A64_CPUID = 1 << 11,
+ ARM_HWCAP_A64_ASIMDRDM = 1 << 12,
+ ARM_HWCAP_A64_JSCVT = 1 << 13,
+ ARM_HWCAP_A64_FCMA = 1 << 14,
+ ARM_HWCAP_A64_LRCPC = 1 << 15,
+ ARM_HWCAP_A64_DCPOP = 1 << 16,
+ ARM_HWCAP_A64_SHA3 = 1 << 17,
+ ARM_HWCAP_A64_SM3 = 1 << 18,
+ ARM_HWCAP_A64_SM4 = 1 << 19,
+ ARM_HWCAP_A64_ASIMDDP = 1 << 20,
+ ARM_HWCAP_A64_SHA512 = 1 << 21,
+ ARM_HWCAP_A64_SVE = 1 << 22,
+ ARM_HWCAP_A64_ASIMDFHM = 1 << 23,
+ ARM_HWCAP_A64_DIT = 1 << 24,
+ ARM_HWCAP_A64_USCAT = 1 << 25,
+ ARM_HWCAP_A64_ILRCPC = 1 << 26,
+ ARM_HWCAP_A64_FLAGM = 1 << 27,
+ ARM_HWCAP_A64_SSBS = 1 << 28,
+ ARM_HWCAP_A64_SB = 1 << 29,
+ ARM_HWCAP_A64_PACA = 1 << 30,
+ ARM_HWCAP_A64_PACG = 1UL << 31,
+
+ ARM_HWCAP2_A64_DCPODP = 1 << 0,
+ ARM_HWCAP2_A64_SVE2 = 1 << 1,
+ ARM_HWCAP2_A64_SVEAES = 1 << 2,
+ ARM_HWCAP2_A64_SVEPMULL = 1 << 3,
+ ARM_HWCAP2_A64_SVEBITPERM = 1 << 4,
+ ARM_HWCAP2_A64_SVESHA3 = 1 << 5,
+ ARM_HWCAP2_A64_SVESM4 = 1 << 6,
+ ARM_HWCAP2_A64_FLAGM2 = 1 << 7,
+ ARM_HWCAP2_A64_FRINT = 1 << 8,
+ ARM_HWCAP2_A64_SVEI8MM = 1 << 9,
+ ARM_HWCAP2_A64_SVEF32MM = 1 << 10,
+ ARM_HWCAP2_A64_SVEF64MM = 1 << 11,
+ ARM_HWCAP2_A64_SVEBF16 = 1 << 12,
+ ARM_HWCAP2_A64_I8MM = 1 << 13,
+ ARM_HWCAP2_A64_BF16 = 1 << 14,
+ ARM_HWCAP2_A64_DGH = 1 << 15,
+ ARM_HWCAP2_A64_RNG = 1 << 16,
+ ARM_HWCAP2_A64_BTI = 1 << 17,
+ ARM_HWCAP2_A64_MTE = 1 << 18,
+};
+
+#define ELF_HWCAP get_elf_hwcap()
+#define ELF_HWCAP2 get_elf_hwcap2()
+
+#define GET_FEATURE_ID(feat, hwcap) \
+ do { if (cpu_isar_feature(feat, cpu)) { hwcaps |= hwcap; } } while (0)
+
+static uint32_t get_elf_hwcap(void)
+{
+ ARMCPU *cpu = ARM_CPU(thread_cpu);
+ uint32_t hwcaps = 0;
+
+ hwcaps |= ARM_HWCAP_A64_FP;
+ hwcaps |= ARM_HWCAP_A64_ASIMD;
+ hwcaps |= ARM_HWCAP_A64_CPUID;
+
+ /* probe for the extra features */
+
+ GET_FEATURE_ID(aa64_aes, ARM_HWCAP_A64_AES);
+ GET_FEATURE_ID(aa64_pmull, ARM_HWCAP_A64_PMULL);
+ GET_FEATURE_ID(aa64_sha1, ARM_HWCAP_A64_SHA1);
+ GET_FEATURE_ID(aa64_sha256, ARM_HWCAP_A64_SHA2);
+ GET_FEATURE_ID(aa64_sha512, ARM_HWCAP_A64_SHA512);
+ GET_FEATURE_ID(aa64_crc32, ARM_HWCAP_A64_CRC32);
+ GET_FEATURE_ID(aa64_sha3, ARM_HWCAP_A64_SHA3);
+ GET_FEATURE_ID(aa64_sm3, ARM_HWCAP_A64_SM3);
+ GET_FEATURE_ID(aa64_sm4, ARM_HWCAP_A64_SM4);
+ GET_FEATURE_ID(aa64_fp16, ARM_HWCAP_A64_FPHP | ARM_HWCAP_A64_ASIMDHP);
+ GET_FEATURE_ID(aa64_atomics, ARM_HWCAP_A64_ATOMICS);
+ GET_FEATURE_ID(aa64_rdm, ARM_HWCAP_A64_ASIMDRDM);
+ GET_FEATURE_ID(aa64_dp, ARM_HWCAP_A64_ASIMDDP);
+ GET_FEATURE_ID(aa64_fcma, ARM_HWCAP_A64_FCMA);
+ GET_FEATURE_ID(aa64_sve, ARM_HWCAP_A64_SVE);
+ GET_FEATURE_ID(aa64_pauth, ARM_HWCAP_A64_PACA | ARM_HWCAP_A64_PACG);
+ GET_FEATURE_ID(aa64_fhm, ARM_HWCAP_A64_ASIMDFHM);
+ GET_FEATURE_ID(aa64_jscvt, ARM_HWCAP_A64_JSCVT);
+ GET_FEATURE_ID(aa64_sb, ARM_HWCAP_A64_SB);
+ GET_FEATURE_ID(aa64_condm_4, ARM_HWCAP_A64_FLAGM);
+ GET_FEATURE_ID(aa64_dcpop, ARM_HWCAP_A64_DCPOP);
+ GET_FEATURE_ID(aa64_rcpc_8_3, ARM_HWCAP_A64_LRCPC);
+ GET_FEATURE_ID(aa64_rcpc_8_4, ARM_HWCAP_A64_ILRCPC);
+
+ return hwcaps;
+}
+
+static uint32_t get_elf_hwcap2(void)
+{
+ ARMCPU *cpu = ARM_CPU(thread_cpu);
+ uint32_t hwcaps = 0;
+
+ GET_FEATURE_ID(aa64_dcpodp, ARM_HWCAP2_A64_DCPODP);
+ GET_FEATURE_ID(aa64_sve2, ARM_HWCAP2_A64_SVE2);
+ GET_FEATURE_ID(aa64_sve2_aes, ARM_HWCAP2_A64_SVEAES);
+ GET_FEATURE_ID(aa64_sve2_pmull128, ARM_HWCAP2_A64_SVEPMULL);
+ GET_FEATURE_ID(aa64_sve2_bitperm, ARM_HWCAP2_A64_SVEBITPERM);
+ GET_FEATURE_ID(aa64_sve2_sha3, ARM_HWCAP2_A64_SVESHA3);
+ GET_FEATURE_ID(aa64_sve2_sm4, ARM_HWCAP2_A64_SVESM4);
+ GET_FEATURE_ID(aa64_condm_5, ARM_HWCAP2_A64_FLAGM2);
+ GET_FEATURE_ID(aa64_frint, ARM_HWCAP2_A64_FRINT);
+ GET_FEATURE_ID(aa64_sve_i8mm, ARM_HWCAP2_A64_SVEI8MM);
+ GET_FEATURE_ID(aa64_sve_f32mm, ARM_HWCAP2_A64_SVEF32MM);
+ GET_FEATURE_ID(aa64_sve_f64mm, ARM_HWCAP2_A64_SVEF64MM);
+ GET_FEATURE_ID(aa64_sve_bf16, ARM_HWCAP2_A64_SVEBF16);
+ GET_FEATURE_ID(aa64_i8mm, ARM_HWCAP2_A64_I8MM);
+ GET_FEATURE_ID(aa64_bf16, ARM_HWCAP2_A64_BF16);
+ GET_FEATURE_ID(aa64_rndr, ARM_HWCAP2_A64_RNG);
+ GET_FEATURE_ID(aa64_bti, ARM_HWCAP2_A64_BTI);
+ GET_FEATURE_ID(aa64_mte, ARM_HWCAP2_A64_MTE);
+
+ return hwcaps;
+}
+
+#undef GET_FEATURE_ID
+
+#endif /* TARGET_ARCH_ELF_H */
diff --git a/bsd-user/aarch64/target_arch_reg.h b/bsd-user/aarch64/target_arch_reg.h
new file mode 100644
index 0000000..b53302e
--- /dev/null
+++ b/bsd-user/aarch64/target_arch_reg.h
@@ -0,0 +1,56 @@
+/*
+ * FreeBSD arm64 register structures
+ *
+ * Copyright (c) 2015 Stacey Son
+ * All rights reserved.
+ *
+ * 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/>.
+ */
+
+#ifndef TARGET_ARCH_REG_H
+#define TARGET_ARCH_REG_H
+
+/* See sys/arm64/include/reg.h */
+typedef struct target_reg {
+ uint64_t x[30];
+ uint64_t lr;
+ uint64_t sp;
+ uint64_t elr;
+ uint64_t spsr;
+} target_reg_t;
+
+typedef struct target_fpreg {
+ Int128 fp_q[32];
+ uint32_t fp_sr;
+ uint32_t fp_cr;
+} target_fpreg_t;
+
+#define tswapreg(ptr) tswapal(ptr)
+
+static inline void target_copy_regs(target_reg_t *regs, CPUARMState *env)
+{
+ int i;
+
+ for (i = 0; i < 30; i++) {
+ regs->x[i] = tswapreg(env->xregs[i]);
+ }
+ regs->lr = tswapreg(env->xregs[30]);
+ regs->sp = tswapreg(env->xregs[31]);
+ regs->elr = tswapreg(env->pc);
+ regs->spsr = tswapreg(pstate_read(env));
+}
+
+#undef tswapreg
+
+#endif /* TARGET_ARCH_REG_H */
diff --git a/bsd-user/aarch64/target_arch_signal.h b/bsd-user/aarch64/target_arch_signal.h
new file mode 100644
index 0000000..b72ba7a
--- /dev/null
+++ b/bsd-user/aarch64/target_arch_signal.h
@@ -0,0 +1,82 @@
+/*
+ * ARM AArch64 specific signal definitions for bsd-user
+ *
+ * Copyright (c) 2015 Stacey D. Son <sson at FreeBSD>
+ *
+ * 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 TARGET_ARCH_SIGNAL_H
+#define TARGET_ARCH_SIGNAL_H
+
+#include "cpu.h"
+
+#define TARGET_REG_X0 0
+#define TARGET_REG_X30 30
+#define TARGET_REG_X31 31
+#define TARGET_REG_LR TARGET_REG_X30
+#define TARGET_REG_SP TARGET_REG_X31
+
+#define TARGET_INSN_SIZE 4 /* arm64 instruction size */
+
+/* Size of the signal trampolin code. See _sigtramp(). */
+#define TARGET_SZSIGCODE ((abi_ulong)(9 * TARGET_INSN_SIZE))
+
+/* compare to sys/arm64/include/_limits.h */
+#define TARGET_MINSIGSTKSZ (1024 * 4) /* min sig stack size */
+#define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768) /* recommended size */
+
+/* struct __mcontext in sys/arm64/include/ucontext.h */
+
+struct target_gpregs {
+ uint64_t gp_x[30];
+ uint64_t gp_lr;
+ uint64_t gp_sp;
+ uint64_t gp_elr;
+ uint32_t gp_spsr;
+ uint32_t gp_pad;
+};
+
+struct target_fpregs {
+ Int128 fp_q[32];
+ uint32_t fp_sr;
+ uint32_t fp_cr;
+ uint32_t fp_flags;
+ uint32_t fp_pad;
+};
+
+struct target__mcontext {
+ struct target_gpregs mc_gpregs;
+ struct target_fpregs mc_fpregs;
+ uint32_t mc_flags;
+#define TARGET_MC_FP_VALID 0x1
+ uint32_t mc_pad;
+ uint64_t mc_spare[8];
+};
+
+typedef struct target__mcontext target_mcontext_t;
+
+#define TARGET_MCONTEXT_SIZE 880
+#define TARGET_UCONTEXT_SIZE 960
+
+#include "target_os_ucontext.h"
+
+struct target_sigframe {
+ target_siginfo_t sf_si; /* saved siginfo */
+ target_ucontext_t sf_uc; /* saved ucontext */
+};
+
+#define TARGET_SIGSTACK_ALIGN 16
+
+#endif /* TARGET_ARCH_SIGNAL_H */
diff --git a/bsd-user/aarch64/target_arch_sigtramp.h b/bsd-user/aarch64/target_arch_sigtramp.h
new file mode 100644
index 0000000..8cdd33b
--- /dev/null
+++ b/bsd-user/aarch64/target_arch_sigtramp.h
@@ -0,0 +1,48 @@
+/*
+ * ARM AArch64 sigcode for bsd-user
+ *
+ * Copyright (c) 2015 Stacey D. Son <sson at FreeBSD>
+ *
+ * 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 TARGET_ARCH_SIGTRAMP_H
+#define TARGET_ARCH_SIGTRAMP_H
+
+/* Compare to ENTRY(sigcode) in arm64/arm64/locore.S */
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+ unsigned sys_sigreturn)
+{
+ int i;
+ uint32_t sys_exit = TARGET_FREEBSD_NR_exit;
+
+ uint32_t sigtramp_code[] = {
+ /* 1 */ 0x910003e0, /* mov x0, sp */
+ /* 2 */ 0x91000000 + (sigf_uc << 10), /* add x0, x0, #SIGF_UC */
+ /* 3 */ 0xd2800000 + (sys_sigreturn << 5) + 0x8, /* mov x8, #SYS_sigreturn */
+ /* 4 */ 0xd4000001, /* svc #0 */
+ /* 5 */ 0xd2800028 + (sys_exit << 5) + 0x8, /* mov x8, #SYS_exit */
+ /* 6 */ 0xd4000001, /* svc #0 */
+ /* 7 */ 0x17fffffc, /* b -4 */
+ /* 8 */ sys_sigreturn,
+ /* 9 */ sys_exit
+ };
+
+ for (i = 0; i < 9; i++) {
+ tswap32s(&sigtramp_code[i]);
+ }
+
+ return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE);
+}
+#endif /* TARGET_ARCH_SIGTRAMP_H */
diff --git a/bsd-user/aarch64/target_arch_sysarch.h b/bsd-user/aarch64/target_arch_sysarch.h
new file mode 100644
index 0000000..b003015
--- /dev/null
+++ b/bsd-user/aarch64/target_arch_sysarch.h
@@ -0,0 +1,42 @@
+/*
+ * ARM AArch64 sysarch() system call emulation for bsd-user.
+ *
+ * Copyright (c) 2015 <sson at FreeBSD>
+ *
+ * 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 TARGET_ARCH_SYSARCH_H
+#define TARGET_ARCH_SYSARCH_H
+
+#include "target_syscall.h"
+#include "target_arch.h"
+
+/* See sysarch() in sys/arm64/arm64/sys_machdep.c */
+static inline abi_long do_freebsd_arch_sysarch(CPUARMState *env, int op,
+ abi_ulong parms)
+{
+ int ret = -TARGET_EOPNOTSUPP;
+
+ fprintf(stderr, "sysarch");
+ return ret;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+ const struct syscallname *name, abi_long arg1, abi_long arg2,
+ abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+}
+
+#endif /* TARGET_ARCH_SYSARCH_H */
diff --git a/bsd-user/aarch64/target_arch_thread.h b/bsd-user/aarch64/target_arch_thread.h
new file mode 100644
index 0000000..4c911e6
--- /dev/null
+++ b/bsd-user/aarch64/target_arch_thread.h
@@ -0,0 +1,61 @@
+/*
+ * ARM AArch64 thread support for bsd-user.
+ *
+ * Copyright (c) 2015 Stacey D. Son <sson at FreeBSD>
+ *
+ * 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 TARGET_ARCH_THREAD_H
+#define TARGET_ARCH_THREAD_H
+
+/* Compare to arm64/arm64/vm_machdep.c cpu_set_upcall_kse() */
+static inline void target_thread_set_upcall(CPUARMState *regs, abi_ulong entry,
+ abi_ulong arg, abi_ulong stack_base, abi_ulong stack_size)
+{
+ abi_ulong sp;
+
+ /*
+ * Make sure the stack is properly aligned.
+ * arm64/include/param.h (STACKLIGN() macro)
+ */
+ sp = ROUND_DOWN(stack_base + stack_size, 16);
+
+ /* sp = stack base */
+ regs->xregs[31] = sp;
+ /* pc = start function entry */
+ regs->pc = entry;
+ /* r0 = arg */
+ regs->xregs[0] = arg;
+
+
+}
+
+static inline void target_thread_init(struct target_pt_regs *regs,
+ struct image_info *infop)
+{
+ abi_long stack = infop->start_stack;
+
+ /*
+ * Make sure the stack is properly aligned.
+ * arm64/include/param.h (STACKLIGN() macro)
+ */
+
+ memset(regs, 0, sizeof(*regs));
+ regs->regs[0] = infop->start_stack;
+ regs->pc = infop->entry;
+ regs->sp = ROUND_DOWN(stack, 16);
+}
+
+#endif /* TARGET_ARCH_THREAD_H */
diff --git a/bsd-user/aarch64/target_arch_vmparam.h b/bsd-user/aarch64/target_arch_vmparam.h
new file mode 100644
index 0000000..0c35491
--- /dev/null
+++ b/bsd-user/aarch64/target_arch_vmparam.h
@@ -0,0 +1,74 @@
+/*
+ * ARM AArch64 VM parameters definitions for bsd-user.
+ *
+ * Copyright (c) 2015 Stacey D. Son <sson at FreeBSD>
+ *
+ * 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 TARGET_ARCH_VMPARAM_H
+#define TARGET_ARCH_VMPARAM_H
+
+#include "cpu.h"
+
+/**
+ * FreeBSD/arm64 Address space layout.
+ *
+ * ARMv8 implements up to a 48 bit virtual address space. The address space is
+ * split into 2 regions at each end of the 64 bit address space, with an
+ * out of range "hole" in the middle.
+ *
+ * We limit the size of the two spaces to 39 bits each.
+ *
+ * Upper region: 0xffffffffffffffff
+ * 0xffffff8000000000
+ *
+ * Hole: 0xffffff7fffffffff
+ * 0x0000008000000000
+ *
+ * Lower region: 0x0000007fffffffff
+ * 0x0000000000000000
+ *
+ * The upper region for the kernel, and the lower region for userland.
+ */
+
+
+/* compare to sys/arm64/include/vmparam.h */
+#define TARGET_MAXTSIZ (1 * GiB) /* max text size */
+#define TARGET_DFLDSIZ (128 * MiB) /* initial data size limit */
+#define TARGET_MAXDSIZ (1 * GiB) /* max data size */
+#define TARGET_DFLSSIZ (128 * MiB) /* initial stack size limit */
+#define TARGET_MAXSSIZ (1 * GiB) /* max stack size */
+#define TARGET_SGROWSIZ (128 * KiB) /* amount to grow stack */
+
+ /* KERNBASE - 512 MB */
+#define TARGET_VM_MAXUSER_ADDRESS (0x00007fffff000000ULL - (512 * MiB))
+#define TARGET_USRSTACK TARGET_VM_MAXUSER_ADDRESS
+
+static inline abi_ulong get_sp_from_cpustate(CPUARMState *state)
+{
+ return state->xregs[31]; /* sp */
+}
+
+static inline void set_second_rval(CPUARMState *state, abi_ulong retval2)
+{
+ state->xregs[1] = retval2; /* XXX not really used on 64-bit arch */
+}
+
+static inline abi_ulong get_second_rval(CPUARMState *state)
+{
+ return state->xregs[1];
+}
+
+#endif /* TARGET_ARCH_VMPARAM_H */
diff --git a/bsd-user/aarch64/target_syscall.h b/bsd-user/aarch64/target_syscall.h
new file mode 100644
index 0000000..08ae913
--- /dev/null
+++ b/bsd-user/aarch64/target_syscall.h
@@ -0,0 +1,51 @@
+/*
+ * ARM AArch64 specific CPU for bsd-user
+ *
+ * Copyright (c) 2015 Stacey D. Son <sson at Freebsd>
+ *
+ * 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 BSD_USER_AARCH64_TARGET_SYSCALL_H
+#define BSD_USER_AARCH64_TARGET_SYSCALL_H
+
+/*
+ * The aarch64 registers are named:
+ *
+ * x0 through x30 - for 64-bit-wide access (same registers)
+ * Register '31' is one of two registers depending on the instruction context:
+ * For instructions dealing with the stack, it is the stack pointer, named rsp
+ * For all other instructions, it is a "zero" register, which returns 0 when
+ * read and discards data when written - named rzr (xzr, wzr)
+ *
+ * Usage during syscall/function call:
+ * r0-r7 are used for arguments and return values
+ * For syscalls, the syscall number is in r8
+ * r9-r15 are for temporary values (may get trampled)
+ * r16-r18 are used for intra-procedure-call and platform values (avoid)
+ * The called routine is expected to preserve r19-r28
+ * r29 and r30 are used as the frame register and link register (avoid)
+ * See the ARM Procedure Call Reference for details.
+ */
+struct target_pt_regs {
+ uint64_t regs[31];
+ uint64_t sp;
+ uint64_t pc;
+ uint64_t pstate;
+};
+
+#define TARGET_HW_MACHINE "arm64"
+#define TARGET_HW_MACHINE_ARCH "aarch64"
+
+#endif /* BSD_USER_AARCH64_TARGET_SYSCALL_H */
diff --git a/bsd-user/arm/target_arch_signal.h b/bsd-user/arm/target_arch_signal.h
index 02b2b33..10f96b8 100644
--- a/bsd-user/arm/target_arch_signal.h
+++ b/bsd-user/arm/target_arch_signal.h
@@ -86,4 +86,6 @@ struct target_sigframe {
target_mcontext_vfp_t sf_vfp; /* actual saved VFP context */
};
+#define TARGET_SIGSTACK_ALIGN 8
+
#endif /* TARGET_ARCH_SIGNAL_H */
diff --git a/bsd-user/freebsd/os-proc.c b/bsd-user/freebsd/os-proc.c
index e0203e2..bf993f1 100644
--- a/bsd-user/freebsd/os-proc.c
+++ b/bsd-user/freebsd/os-proc.c
@@ -27,64 +27,12 @@ struct kinfo_proc;
#include "qemu.h"
/*
- * Get the filename for the given file descriptor.
- * Note that this may return NULL (fail) if no longer cached in the kernel.
- */
-static char *
-get_filename_from_fd(pid_t pid, int fd, char *filename, size_t len)
-{
- char *ret = NULL;
- unsigned int cnt;
- struct procstat *procstat = NULL;
- struct kinfo_proc *kp = NULL;
- struct filestat_list *head = NULL;
- struct filestat *fst;
-
- procstat = procstat_open_sysctl();
- if (procstat == NULL) {
- goto out;
- }
-
- kp = procstat_getprocs(procstat, KERN_PROC_PID, pid, &cnt);
- if (kp == NULL) {
- goto out;
- }
-
- head = procstat_getfiles(procstat, kp, 0);
- if (head == NULL) {
- goto out;
- }
-
- STAILQ_FOREACH(fst, head, next) {
- if (fd == fst->fs_fd) {
- if (fst->fs_path != NULL) {
- (void)strlcpy(filename, fst->fs_path, len);
- ret = filename;
- }
- break;
- }
- }
-
-out:
- if (head != NULL) {
- procstat_freefiles(procstat, head);
- }
- if (kp != NULL) {
- procstat_freeprocs(procstat, kp);
- }
- if (procstat != NULL) {
- procstat_close(procstat);
- }
- return ret;
-}
-
-/*
* execve/fexecve
*/
abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
abi_ulong guest_envp, int do_fexec)
{
- char **argp, **envp, **qargp, **qarg1, **qarg0, **qargend;
+ char **argp, **envp, **qarg0;
int argc, envc;
abi_ulong gp;
abi_ulong addr;
@@ -117,9 +65,7 @@ abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
qarg0 = argp = g_new0(char *, argc + 9);
/* save the first argument for the emulator */
*argp++ = (char *)getprogname();
- qargp = argp;
*argp++ = (char *)getprogname();
- qarg1 = argp;
envp = g_new0(char *, envc + 1);
for (gp = guest_argp, q = argp; gp; gp += sizeof(abi_ulong), q++) {
if (get_user_ual(addr, gp)) {
@@ -137,7 +83,6 @@ abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
total_size += strlen(*q) + 1;
}
*q++ = NULL;
- qargend = q;
for (gp = guest_envp, q = envp; gp; gp += sizeof(abi_ulong), q++) {
if (get_user_ual(addr, gp)) {
@@ -166,71 +111,14 @@ abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
}
if (do_fexec) {
- if (((int)path_or_fd > 0 &&
- is_target_elf_binary((int)path_or_fd)) == 1) {
- char execpath[PATH_MAX];
-
- /*
- * The executable is an elf binary for the target
- * arch. execve() it using the emulator if we can
- * determine the filename path from the fd.
- */
- if (get_filename_from_fd(getpid(), (int)path_or_fd, execpath,
- sizeof(execpath)) != NULL) {
- memmove(qarg1 + 2, qarg1, (qargend - qarg1) * sizeof(*qarg1));
- qarg1[1] = qarg1[0];
- qarg1[0] = (char *)"-0";
- qarg1 += 2;
- qargend += 2;
- *qarg1 = execpath;
-#ifndef DONT_INHERIT_INTERP_PREFIX
- memmove(qarg1 + 2, qarg1, (qargend - qarg1) * sizeof(*qarg1));
- *qarg1++ = (char *)"-L";
- *qarg1++ = (char *)interp_prefix;
-#endif
- ret = get_errno(execve(qemu_proc_pathname, qargp, envp));
- } else {
- /* Getting the filename path failed. */
- ret = -TARGET_EBADF;
- goto execve_end;
- }
- } else {
- ret = get_errno(fexecve((int)path_or_fd, argp, envp));
- }
+ ret = get_errno(fexecve((int)path_or_fd, argp, envp));
} else {
- int fd;
-
p = lock_user_string(path_or_fd);
if (p == NULL) {
ret = -TARGET_EFAULT;
goto execve_end;
}
-
- /*
- * Check the header and see if it a target elf binary. If so
- * then execute using qemu user mode emulator.
- */
- fd = open(p, O_RDONLY | O_CLOEXEC);
- if (fd > 0 && is_target_elf_binary(fd) == 1) {
- close(fd);
- /* execve() as a target binary using emulator. */
- memmove(qarg1 + 2, qarg1, (qargend - qarg1) * sizeof(*qarg1));
- qarg1[1] = qarg1[0];
- qarg1[0] = (char *)"-0";
- qarg1 += 2;
- qargend += 2;
- *qarg1 = (char *)p;
-#ifndef DONT_INHERIT_INTERP_PREFIX
- memmove(qarg1 + 2, qarg1, (qargend - qarg1) * sizeof(*qarg1));
- *qarg1++ = (char *)"-L";
- *qarg1++ = (char *)interp_prefix;
-#endif
- ret = get_errno(execve(qemu_proc_pathname, qargp, envp));
- } else {
- close(fd);
- /* Execve() as a host native binary. */
- ret = get_errno(execve(p, argp, envp));
- }
+ ret = get_errno(execve(p, argp, envp));
unlock_user(p, path_or_fd, 0);
}
diff --git a/bsd-user/i386/target_arch_signal.h b/bsd-user/i386/target_arch_signal.h
index 279dadc..2c14153 100644
--- a/bsd-user/i386/target_arch_signal.h
+++ b/bsd-user/i386/target_arch_signal.h
@@ -88,4 +88,6 @@ struct target_sigframe {
uint32_t __spare__[2];
};
+#define TARGET_SIGSTACK_ALIGN 8
+
#endif /* TARGET_ARCH_SIGNAL_H */
diff --git a/bsd-user/main.c b/bsd-user/main.c
index dcad266..cc980e6 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -35,6 +35,7 @@
#include "qemu/path.h"
#include "qemu/help_option.h"
#include "qemu/module.h"
+#include "qemu/plugin.h"
#include "exec/exec-all.h"
#include "user/guest-base.h"
#include "tcg/startup.h"
@@ -90,7 +91,6 @@ unsigned long reserved_va;
const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
const char *qemu_uname_release;
-char qemu_proc_pathname[PATH_MAX]; /* full path to exeutable */
unsigned long target_maxtsiz = TARGET_MAXTSIZ; /* max text size */
unsigned long target_dfldsiz = TARGET_DFLDSIZ; /* initial data size limit */
@@ -104,8 +104,9 @@ unsigned long target_sgrowsiz = TARGET_SGROWSIZ; /* amount to grow stack */
void fork_start(void)
{
start_exclusive();
- cpu_list_lock();
mmap_fork_start();
+ cpu_list_lock();
+ qemu_plugin_user_prefork_lock();
gdbserver_fork_start();
}
@@ -113,31 +114,31 @@ void fork_end(pid_t pid)
{
bool child = pid == 0;
+ qemu_plugin_user_postfork(child);
+ mmap_fork_end(child);
if (child) {
CPUState *cpu, *next_cpu;
/*
- * Child processes created by fork() only have a single thread. Discard
- * information about the parent threads.
+ * Child processes created by fork() only have a single thread.
+ * Discard information about the parent threads.
*/
CPU_FOREACH_SAFE(cpu, next_cpu) {
if (cpu != thread_cpu) {
QTAILQ_REMOVE_RCU(&cpus_queue, cpu, node);
}
}
- mmap_fork_end(child);
- /*
- * qemu_init_cpu_list() takes care of reinitializing the exclusive
- * state, so we don't need to end_exclusive() here.
- */
qemu_init_cpu_list();
get_task_state(thread_cpu)->ts_tid = qemu_get_thread_id();
- gdbserver_fork_end(thread_cpu, pid);
} else {
- mmap_fork_end(child);
cpu_list_unlock();
- gdbserver_fork_end(thread_cpu, pid);
- end_exclusive();
}
+ gdbserver_fork_end(thread_cpu, pid);
+ /*
+ * qemu_init_cpu_list() reinitialized the child exclusive state, but we
+ * also need to keep current_cpu consistent, so call end_exclusive() for
+ * both child and parent.
+ */
+ end_exclusive();
}
void cpu_loop(CPUArchState *env)
@@ -247,22 +248,6 @@ adjust_ssize(void)
setrlimit(RLIMIT_STACK, &rl);
}
-static void save_proc_pathname(char *argv0)
-{
- int mib[4];
- size_t len;
-
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROC;
- mib[2] = KERN_PROC_PATHNAME;
- mib[3] = -1;
-
- len = sizeof(qemu_proc_pathname);
- if (sysctl(mib, 4, qemu_proc_pathname, &len, NULL, 0)) {
- perror("sysctl");
- }
-}
-
int main(int argc, char **argv)
{
const char *filename;
@@ -292,7 +277,6 @@ int main(int argc, char **argv)
usage();
}
- save_proc_pathname(argv[0]);
error_init(argv[0]);
module_call_init(MODULE_INIT_TRACE);
diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c
index f3a4f17..775e905 100644
--- a/bsd-user/mmap.c
+++ b/bsd-user/mmap.c
@@ -129,6 +129,40 @@ error:
}
/*
+ * Perform a pread on behalf of target_mmap. We can reach EOF, we can be
+ * interrupted by signals, and in general there's no good error return path.
+ * If @zero, zero the rest of the block at EOF.
+ * Return true on success.
+ */
+static bool mmap_pread(int fd, void *p, size_t len, off_t offset, bool zero)
+{
+ while (1) {
+ ssize_t r = pread(fd, p, len, offset);
+
+ if (likely(r == len)) {
+ /* Complete */
+ return true;
+ }
+ if (r == 0) {
+ /* EOF */
+ if (zero) {
+ memset(p, 0, len);
+ }
+ return true;
+ }
+ if (r > 0) {
+ /* Short read */
+ p += r;
+ len -= r;
+ offset += r;
+ } else if (errno != EINTR) {
+ /* Error */
+ return false;
+ }
+ }
+}
+
+/*
* map an incomplete host page
*
* mmap_frag can be called with a valid fd, if flags doesn't contain one of
@@ -190,7 +224,7 @@ static int mmap_frag(abi_ulong real_start,
mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE);
/* read the corresponding file data */
- if (pread(fd, g2h_untagged(start), end - start, offset) == -1) {
+ if (!mmap_pread(fd, g2h_untagged(start), end - start, offset, true)) {
return -1;
}
@@ -565,7 +599,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
-1, 0);
if (retaddr == -1)
goto fail;
- if (pread(fd, g2h_untagged(start), len, offset) == -1) {
+ if (!mmap_pread(fd, g2h_untagged(start), len, offset, false)) {
goto fail;
}
if (!(prot & PROT_WRITE)) {
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 9d2fc71..3736c41 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -17,6 +17,9 @@
#ifndef QEMU_H
#define QEMU_H
+#include <sys/param.h>
+
+#include "qemu/int128.h"
#include "cpu.h"
#include "qemu/units.h"
#include "exec/cpu_ldst.h"
diff --git a/bsd-user/riscv/signal.c b/bsd-user/riscv/signal.c
new file mode 100644
index 0000000..10c940c
--- /dev/null
+++ b/bsd-user/riscv/signal.c
@@ -0,0 +1,170 @@
+/*
+ * RISC-V signal definitions
+ *
+ * Copyright (c) 2019 Mark Corbin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+
+#include "qemu.h"
+
+/*
+ * Compare with sendsig() in riscv/riscv/exec_machdep.c
+ * Assumes that target stack frame memory is locked.
+ */
+abi_long
+set_sigtramp_args(CPURISCVState *regs, int sig, struct target_sigframe *frame,
+ abi_ulong frame_addr, struct target_sigaction *ka)
+{
+ /*
+ * Arguments to signal handler:
+ * a0 (10) = signal number
+ * a1 (11) = siginfo pointer
+ * a2 (12) = ucontext pointer
+ * pc = signal pointer handler
+ * sp (2) = sigframe pointer
+ * ra (1) = sigtramp at base of user stack
+ */
+
+ regs->gpr[xA0] = sig;
+ regs->gpr[xA1] = frame_addr +
+ offsetof(struct target_sigframe, sf_si);
+ regs->gpr[xA2] = frame_addr +
+ offsetof(struct target_sigframe, sf_uc);
+ regs->pc = ka->_sa_handler;
+ regs->gpr[xSP] = frame_addr;
+ regs->gpr[xRA] = TARGET_PS_STRINGS - TARGET_SZSIGCODE;
+ return 0;
+}
+
+/*
+ * Compare to riscv/riscv/exec_machdep.c sendsig()
+ * Assumes that the memory is locked if frame points to user memory.
+ */
+abi_long setup_sigframe_arch(CPURISCVState *env, abi_ulong frame_addr,
+ struct target_sigframe *frame, int flags)
+{
+ target_mcontext_t *mcp = &frame->sf_uc.uc_mcontext;
+
+ get_mcontext(env, mcp, flags);
+ return 0;
+}
+
+/*
+ * Compare with get_mcontext() in riscv/riscv/machdep.c
+ * Assumes that the memory is locked if mcp points to user memory.
+ */
+abi_long get_mcontext(CPURISCVState *regs, target_mcontext_t *mcp,
+ int flags)
+{
+
+ mcp->mc_gpregs.gp_t[0] = tswap64(regs->gpr[5]);
+ mcp->mc_gpregs.gp_t[1] = tswap64(regs->gpr[6]);
+ mcp->mc_gpregs.gp_t[2] = tswap64(regs->gpr[7]);
+ mcp->mc_gpregs.gp_t[3] = tswap64(regs->gpr[28]);
+ mcp->mc_gpregs.gp_t[4] = tswap64(regs->gpr[29]);
+ mcp->mc_gpregs.gp_t[5] = tswap64(regs->gpr[30]);
+ mcp->mc_gpregs.gp_t[6] = tswap64(regs->gpr[31]);
+
+ mcp->mc_gpregs.gp_s[0] = tswap64(regs->gpr[8]);
+ mcp->mc_gpregs.gp_s[1] = tswap64(regs->gpr[9]);
+ mcp->mc_gpregs.gp_s[2] = tswap64(regs->gpr[18]);
+ mcp->mc_gpregs.gp_s[3] = tswap64(regs->gpr[19]);
+ mcp->mc_gpregs.gp_s[4] = tswap64(regs->gpr[20]);
+ mcp->mc_gpregs.gp_s[5] = tswap64(regs->gpr[21]);
+ mcp->mc_gpregs.gp_s[6] = tswap64(regs->gpr[22]);
+ mcp->mc_gpregs.gp_s[7] = tswap64(regs->gpr[23]);
+ mcp->mc_gpregs.gp_s[8] = tswap64(regs->gpr[24]);
+ mcp->mc_gpregs.gp_s[9] = tswap64(regs->gpr[25]);
+ mcp->mc_gpregs.gp_s[10] = tswap64(regs->gpr[26]);
+ mcp->mc_gpregs.gp_s[11] = tswap64(regs->gpr[27]);
+
+ mcp->mc_gpregs.gp_a[0] = tswap64(regs->gpr[10]);
+ mcp->mc_gpregs.gp_a[1] = tswap64(regs->gpr[11]);
+ mcp->mc_gpregs.gp_a[2] = tswap64(regs->gpr[12]);
+ mcp->mc_gpregs.gp_a[3] = tswap64(regs->gpr[13]);
+ mcp->mc_gpregs.gp_a[4] = tswap64(regs->gpr[14]);
+ mcp->mc_gpregs.gp_a[5] = tswap64(regs->gpr[15]);
+ mcp->mc_gpregs.gp_a[6] = tswap64(regs->gpr[16]);
+ mcp->mc_gpregs.gp_a[7] = tswap64(regs->gpr[17]);
+
+ if (flags & TARGET_MC_GET_CLEAR_RET) {
+ mcp->mc_gpregs.gp_a[0] = 0; /* a0 */
+ mcp->mc_gpregs.gp_a[1] = 0; /* a1 */
+ mcp->mc_gpregs.gp_t[0] = 0; /* clear syscall error */
+ }
+
+ mcp->mc_gpregs.gp_ra = tswap64(regs->gpr[1]);
+ mcp->mc_gpregs.gp_sp = tswap64(regs->gpr[2]);
+ mcp->mc_gpregs.gp_gp = tswap64(regs->gpr[3]);
+ mcp->mc_gpregs.gp_tp = tswap64(regs->gpr[4]);
+ mcp->mc_gpregs.gp_sepc = tswap64(regs->pc);
+
+ return 0;
+}
+
+/* Compare with set_mcontext() in riscv/riscv/exec_machdep.c */
+abi_long set_mcontext(CPURISCVState *regs, target_mcontext_t *mcp,
+ int srflag)
+{
+
+ regs->gpr[5] = tswap64(mcp->mc_gpregs.gp_t[0]);
+ regs->gpr[6] = tswap64(mcp->mc_gpregs.gp_t[1]);
+ regs->gpr[7] = tswap64(mcp->mc_gpregs.gp_t[2]);
+ regs->gpr[28] = tswap64(mcp->mc_gpregs.gp_t[3]);
+ regs->gpr[29] = tswap64(mcp->mc_gpregs.gp_t[4]);
+ regs->gpr[30] = tswap64(mcp->mc_gpregs.gp_t[5]);
+ regs->gpr[31] = tswap64(mcp->mc_gpregs.gp_t[6]);
+
+ regs->gpr[8] = tswap64(mcp->mc_gpregs.gp_s[0]);
+ regs->gpr[9] = tswap64(mcp->mc_gpregs.gp_s[1]);
+ regs->gpr[18] = tswap64(mcp->mc_gpregs.gp_s[2]);
+ regs->gpr[19] = tswap64(mcp->mc_gpregs.gp_s[3]);
+ regs->gpr[20] = tswap64(mcp->mc_gpregs.gp_s[4]);
+ regs->gpr[21] = tswap64(mcp->mc_gpregs.gp_s[5]);
+ regs->gpr[22] = tswap64(mcp->mc_gpregs.gp_s[6]);
+ regs->gpr[23] = tswap64(mcp->mc_gpregs.gp_s[7]);
+ regs->gpr[24] = tswap64(mcp->mc_gpregs.gp_s[8]);
+ regs->gpr[25] = tswap64(mcp->mc_gpregs.gp_s[9]);
+ regs->gpr[26] = tswap64(mcp->mc_gpregs.gp_s[10]);
+ regs->gpr[27] = tswap64(mcp->mc_gpregs.gp_s[11]);
+
+ regs->gpr[10] = tswap64(mcp->mc_gpregs.gp_a[0]);
+ regs->gpr[11] = tswap64(mcp->mc_gpregs.gp_a[1]);
+ regs->gpr[12] = tswap64(mcp->mc_gpregs.gp_a[2]);
+ regs->gpr[13] = tswap64(mcp->mc_gpregs.gp_a[3]);
+ regs->gpr[14] = tswap64(mcp->mc_gpregs.gp_a[4]);
+ regs->gpr[15] = tswap64(mcp->mc_gpregs.gp_a[5]);
+ regs->gpr[16] = tswap64(mcp->mc_gpregs.gp_a[6]);
+ regs->gpr[17] = tswap64(mcp->mc_gpregs.gp_a[7]);
+
+
+ regs->gpr[1] = tswap64(mcp->mc_gpregs.gp_ra);
+ regs->gpr[2] = tswap64(mcp->mc_gpregs.gp_sp);
+ regs->gpr[3] = tswap64(mcp->mc_gpregs.gp_gp);
+ regs->gpr[4] = tswap64(mcp->mc_gpregs.gp_tp);
+ regs->pc = tswap64(mcp->mc_gpregs.gp_sepc);
+
+ return 0;
+}
+
+/* Compare with sys_sigreturn() in riscv/riscv/machdep.c */
+abi_long get_ucontext_sigreturn(CPURISCVState *regs,
+ abi_ulong target_sf, abi_ulong *target_uc)
+{
+
+ *target_uc = target_sf;
+ return 0;
+}
diff --git a/bsd-user/riscv/target.h b/bsd-user/riscv/target.h
new file mode 100644
index 0000000..036ddd1
--- /dev/null
+++ b/bsd-user/riscv/target.h
@@ -0,0 +1,20 @@
+/*
+ * Riscv64 general target stuff that's common to all aarch details
+ *
+ * Copyright (c) 2022 M. Warner Losh <imp@bsdimp.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef TARGET_H
+#define TARGET_H
+
+/*
+ * riscv64 ABI does not 'lump' the registers for 64-bit args.
+ */
+static inline bool regpairs_aligned(void *cpu_env)
+{
+ return false;
+}
+
+#endif /* TARGET_H */
diff --git a/bsd-user/riscv/target_arch.h b/bsd-user/riscv/target_arch.h
new file mode 100644
index 0000000..26ce07f
--- /dev/null
+++ b/bsd-user/riscv/target_arch.h
@@ -0,0 +1,27 @@
+/*
+ * RISC-V specific prototypes
+ *
+ * Copyright (c) 2019 Mark Corbin <mark.corbin@embecsom.com>
+ *
+ * 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 TARGET_ARCH_H
+#define TARGET_ARCH_H
+
+#include "qemu.h"
+
+void target_cpu_set_tls(CPURISCVState *env, target_ulong newtls);
+
+#endif /* TARGET_ARCH_H */
diff --git a/bsd-user/riscv/target_arch_cpu.c b/bsd-user/riscv/target_arch_cpu.c
new file mode 100644
index 0000000..44e25d2
--- /dev/null
+++ b/bsd-user/riscv/target_arch_cpu.c
@@ -0,0 +1,29 @@
+/*
+ * RISC-V CPU related code
+ *
+ * Copyright (c) 2019 Mark Corbin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+
+#include "target_arch.h"
+
+#define TP_OFFSET 16
+
+/* Compare with cpu_set_user_tls() in riscv/riscv/vm_machdep.c */
+void target_cpu_set_tls(CPURISCVState *env, target_ulong newtls)
+{
+ env->gpr[xTP] = newtls + TP_OFFSET;
+}
diff --git a/bsd-user/riscv/target_arch_cpu.h b/bsd-user/riscv/target_arch_cpu.h
new file mode 100644
index 0000000..a93ea39
--- /dev/null
+++ b/bsd-user/riscv/target_arch_cpu.h
@@ -0,0 +1,148 @@
+/*
+ * RISC-V CPU init and loop
+ *
+ * Copyright (c) 2019 Mark Corbin
+ *
+ * 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/>.
+ */
+
+#ifndef TARGET_ARCH_CPU_H
+#define TARGET_ARCH_CPU_H
+
+#include "target_arch.h"
+#include "signal-common.h"
+
+#define TARGET_DEFAULT_CPU_MODEL "max"
+
+static inline void target_cpu_init(CPURISCVState *env,
+ struct target_pt_regs *regs)
+{
+ int i;
+
+ for (i = 1; i < 32; i++) {
+ env->gpr[i] = regs->regs[i];
+ }
+
+ env->pc = regs->sepc;
+}
+
+static inline void target_cpu_loop(CPURISCVState *env)
+{
+ CPUState *cs = env_cpu(env);
+ int trapnr;
+ abi_long ret;
+ unsigned int syscall_num;
+ int32_t signo, code;
+
+ for (;;) {
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ process_queued_cpu_work(cs);
+
+ signo = 0;
+
+ switch (trapnr) {
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+ case EXCP_ATOMIC:
+ cpu_exec_step_atomic(cs);
+ break;
+ case RISCV_EXCP_U_ECALL:
+ syscall_num = env->gpr[xT0];
+ env->pc += TARGET_INSN_SIZE;
+ /* Compare to cpu_fetch_syscall_args() in riscv/riscv/trap.c */
+ if (TARGET_FREEBSD_NR___syscall == syscall_num ||
+ TARGET_FREEBSD_NR_syscall == syscall_num) {
+ ret = do_freebsd_syscall(env,
+ env->gpr[xA0],
+ env->gpr[xA1],
+ env->gpr[xA2],
+ env->gpr[xA3],
+ env->gpr[xA4],
+ env->gpr[xA5],
+ env->gpr[xA6],
+ env->gpr[xA7],
+ 0);
+ } else {
+ ret = do_freebsd_syscall(env,
+ syscall_num,
+ env->gpr[xA0],
+ env->gpr[xA1],
+ env->gpr[xA2],
+ env->gpr[xA3],
+ env->gpr[xA4],
+ env->gpr[xA5],
+ env->gpr[xA6],
+ env->gpr[xA7]
+ );
+ }
+
+ /*
+ * Compare to cpu_set_syscall_retval() in
+ * riscv/riscv/vm_machdep.c
+ */
+ if (ret >= 0) {
+ env->gpr[xA0] = ret;
+ env->gpr[xT0] = 0;
+ } else if (ret == -TARGET_ERESTART) {
+ env->pc -= TARGET_INSN_SIZE;
+ } else if (ret != -TARGET_EJUSTRETURN) {
+ env->gpr[xA0] = -ret;
+ env->gpr[xT0] = 1;
+ }
+ break;
+ case RISCV_EXCP_ILLEGAL_INST:
+ signo = TARGET_SIGILL;
+ code = TARGET_ILL_ILLOPC;
+ break;
+ case RISCV_EXCP_BREAKPOINT:
+ signo = TARGET_SIGTRAP;
+ code = TARGET_TRAP_BRKPT;
+ break;
+ case EXCP_DEBUG:
+ signo = TARGET_SIGTRAP;
+ code = TARGET_TRAP_BRKPT;
+ break;
+ default:
+ fprintf(stderr, "qemu: unhandled CPU exception "
+ "0x%x - aborting\n", trapnr);
+ cpu_dump_state(cs, stderr, 0);
+ abort();
+ }
+
+ if (signo) {
+ force_sig_fault(signo, code, env->pc);
+ }
+
+ process_pending_signals(env);
+ }
+}
+
+static inline void target_cpu_clone_regs(CPURISCVState *env, target_ulong newsp)
+{
+ if (newsp) {
+ env->gpr[xSP] = newsp;
+ }
+
+ env->gpr[xA0] = 0;
+ env->gpr[xT0] = 0;
+}
+
+static inline void target_cpu_reset(CPUArchState *env)
+{
+}
+
+#endif /* TARGET_ARCH_CPU_H */
diff --git a/bsd-user/riscv/target_arch_elf.h b/bsd-user/riscv/target_arch_elf.h
new file mode 100644
index 0000000..4eb915e
--- /dev/null
+++ b/bsd-user/riscv/target_arch_elf.h
@@ -0,0 +1,42 @@
+/*
+ * RISC-V ELF definitions
+ *
+ * Copyright (c) 2019 Mark Corbin
+ *
+ * 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/>.
+ */
+
+#ifndef TARGET_ARCH_ELF_H
+#define TARGET_ARCH_ELF_H
+
+#define elf_check_arch(x) ((x) == EM_RISCV)
+#define ELF_START_MMAP 0x80000000
+#define ELF_ET_DYN_LOAD_ADDR 0x100000
+#define ELF_CLASS ELFCLASS64
+
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_RISCV
+
+#define ELF_HWCAP get_elf_hwcap()
+static uint32_t get_elf_hwcap(void)
+{
+ RISCVCPU *cpu = RISCV_CPU(thread_cpu);
+
+ return cpu->env.misa_ext_mask;
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE 4096
+
+#endif /* TARGET_ARCH_ELF_H */
diff --git a/bsd-user/riscv/target_arch_reg.h b/bsd-user/riscv/target_arch_reg.h
new file mode 100644
index 0000000..12b1c96
--- /dev/null
+++ b/bsd-user/riscv/target_arch_reg.h
@@ -0,0 +1,88 @@
+/*
+ * RISC-V register structures
+ *
+ * Copyright (c) 2019 Mark Corbin
+ *
+ * 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/>.
+ */
+
+#ifndef TARGET_ARCH_REG_H
+#define TARGET_ARCH_REG_H
+
+/* Compare with riscv/include/reg.h */
+typedef struct target_reg {
+ uint64_t ra; /* return address */
+ uint64_t sp; /* stack pointer */
+ uint64_t gp; /* global pointer */
+ uint64_t tp; /* thread pointer */
+ uint64_t t[7]; /* temporaries */
+ uint64_t s[12]; /* saved registers */
+ uint64_t a[8]; /* function arguments */
+ uint64_t sepc; /* exception program counter */
+ uint64_t sstatus; /* status register */
+} target_reg_t;
+
+typedef struct target_fpreg {
+ uint64_t fp_x[32][2]; /* Floating point registers */
+ uint64_t fp_fcsr; /* Floating point control reg */
+} target_fpreg_t;
+
+#define tswapreg(ptr) tswapal(ptr)
+
+/* Compare with struct trapframe in riscv/include/frame.h */
+static inline void target_copy_regs(target_reg_t *regs,
+ const CPURISCVState *env)
+{
+
+ regs->ra = tswapreg(env->gpr[1]);
+ regs->sp = tswapreg(env->gpr[2]);
+ regs->gp = tswapreg(env->gpr[3]);
+ regs->tp = tswapreg(env->gpr[4]);
+
+ regs->t[0] = tswapreg(env->gpr[5]);
+ regs->t[1] = tswapreg(env->gpr[6]);
+ regs->t[2] = tswapreg(env->gpr[7]);
+ regs->t[3] = tswapreg(env->gpr[28]);
+ regs->t[4] = tswapreg(env->gpr[29]);
+ regs->t[5] = tswapreg(env->gpr[30]);
+ regs->t[6] = tswapreg(env->gpr[31]);
+
+ regs->s[0] = tswapreg(env->gpr[8]);
+ regs->s[1] = tswapreg(env->gpr[9]);
+ regs->s[2] = tswapreg(env->gpr[18]);
+ regs->s[3] = tswapreg(env->gpr[19]);
+ regs->s[4] = tswapreg(env->gpr[20]);
+ regs->s[5] = tswapreg(env->gpr[21]);
+ regs->s[6] = tswapreg(env->gpr[22]);
+ regs->s[7] = tswapreg(env->gpr[23]);
+ regs->s[8] = tswapreg(env->gpr[24]);
+ regs->s[9] = tswapreg(env->gpr[25]);
+ regs->s[10] = tswapreg(env->gpr[26]);
+ regs->s[11] = tswapreg(env->gpr[27]);
+
+ regs->a[0] = tswapreg(env->gpr[10]);
+ regs->a[1] = tswapreg(env->gpr[11]);
+ regs->a[2] = tswapreg(env->gpr[12]);
+ regs->a[3] = tswapreg(env->gpr[13]);
+ regs->a[4] = tswapreg(env->gpr[14]);
+ regs->a[5] = tswapreg(env->gpr[15]);
+ regs->a[6] = tswapreg(env->gpr[16]);
+ regs->a[7] = tswapreg(env->gpr[17]);
+
+ regs->sepc = tswapreg(env->pc);
+}
+
+#undef tswapreg
+
+#endif /* TARGET_ARCH_REG_H */
diff --git a/bsd-user/riscv/target_arch_signal.h b/bsd-user/riscv/target_arch_signal.h
new file mode 100644
index 0000000..1a634b8
--- /dev/null
+++ b/bsd-user/riscv/target_arch_signal.h
@@ -0,0 +1,75 @@
+/*
+ * RISC-V signal definitions
+ *
+ * Copyright (c) 2019 Mark Corbin
+ *
+ * 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/>.
+ */
+
+#ifndef TARGET_ARCH_SIGNAL_H
+#define TARGET_ARCH_SIGNAL_H
+
+#include "cpu.h"
+
+
+#define TARGET_INSN_SIZE 4 /* riscv instruction size */
+
+/* Size of the signal trampoline code placed on the stack. */
+#define TARGET_SZSIGCODE ((abi_ulong)(7 * TARGET_INSN_SIZE))
+
+/* Compare with riscv/include/_limits.h */
+#define TARGET_MINSIGSTKSZ (1024 * 4)
+#define TARGET_SIGSTKSZ (TARGET_MINSIGSTKSZ + 32768)
+
+struct target_gpregs {
+ uint64_t gp_ra;
+ uint64_t gp_sp;
+ uint64_t gp_gp;
+ uint64_t gp_tp;
+ uint64_t gp_t[7];
+ uint64_t gp_s[12];
+ uint64_t gp_a[8];
+ uint64_t gp_sepc;
+ uint64_t gp_sstatus;
+};
+
+struct target_fpregs {
+ uint64_t fp_x[32][2];
+ uint64_t fp_fcsr;
+ uint32_t fp_flags;
+ uint32_t pad;
+};
+
+typedef struct target_mcontext {
+ struct target_gpregs mc_gpregs;
+ struct target_fpregs mc_fpregs;
+ uint32_t mc_flags;
+#define TARGET_MC_FP_VALID 0x01
+ uint32_t mc_pad;
+ uint64_t mc_spare[8];
+} target_mcontext_t;
+
+#define TARGET_MCONTEXT_SIZE 864
+#define TARGET_UCONTEXT_SIZE 936
+
+#include "target_os_ucontext.h"
+
+struct target_sigframe {
+ target_ucontext_t sf_uc; /* = *sf_uncontext */
+ target_siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case)*/
+};
+
+#define TARGET_SIGSTACK_ALIGN 16
+
+#endif /* TARGET_ARCH_SIGNAL_H */
diff --git a/bsd-user/riscv/target_arch_sigtramp.h b/bsd-user/riscv/target_arch_sigtramp.h
new file mode 100644
index 0000000..dfe5076
--- /dev/null
+++ b/bsd-user/riscv/target_arch_sigtramp.h
@@ -0,0 +1,41 @@
+/*
+ * RISC-V sigcode
+ *
+ * Copyright (c) 2019 Mark Corbin
+ *
+ * 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 TARGET_ARCH_SIGTRAMP_H
+#define TARGET_ARCH_SIGTRAMP_H
+
+/* Compare with sigcode() in riscv/riscv/locore.S */
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+ unsigned sys_sigreturn)
+{
+ uint32_t sys_exit = TARGET_FREEBSD_NR_exit;
+
+ uint32_t sigtramp_code[] = {
+ /*1*/ const_le32(0x00010513), /*mv a0, sp*/
+ /*2*/ const_le32(0x00050513 + (sigf_uc << 20)), /*addi a0,a0,sigf_uc*/
+ /*3*/ const_le32(0x00000293 + (sys_sigreturn << 20)),/*li t0,sys_sigreturn*/
+ /*4*/ const_le32(0x00000073), /*ecall*/
+ /*5*/ const_le32(0x00000293 + (sys_exit << 20)), /*li t0,sys_exit*/
+ /*6*/ const_le32(0x00000073), /*ecall*/
+ /*7*/ const_le32(0xFF1FF06F) /*b -16*/
+ };
+
+ return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE);
+}
+#endif /* TARGET_ARCH_SIGTRAMP_H */
diff --git a/bsd-user/riscv/target_arch_sysarch.h b/bsd-user/riscv/target_arch_sysarch.h
new file mode 100644
index 0000000..9af4233
--- /dev/null
+++ b/bsd-user/riscv/target_arch_sysarch.h
@@ -0,0 +1,41 @@
+/*
+ * RISC-V sysarch() system call emulation
+ *
+ * Copyright (c) 2019 Mark Corbin
+ *
+ * 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/>.
+ */
+
+#ifndef TARGET_ARCH_SYSARCH_H
+#define TARGET_ARCH_SYSARCH_H
+
+#include "target_syscall.h"
+#include "target_arch.h"
+
+static inline abi_long do_freebsd_arch_sysarch(CPURISCVState *env, int op,
+ abi_ulong parms)
+{
+
+ return -TARGET_EOPNOTSUPP;
+}
+
+static inline void do_freebsd_arch_print_sysarch(
+ const struct syscallname *name, abi_long arg1, abi_long arg2,
+ abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6)
+{
+
+ gemu_log("UNKNOWN OP: %d, " TARGET_ABI_FMT_lx ")", (int)arg1, arg2);
+}
+
+#endif /* TARGET_ARCH_SYSARCH_H */
diff --git a/bsd-user/riscv/target_arch_thread.h b/bsd-user/riscv/target_arch_thread.h
new file mode 100644
index 0000000..95cd0b6
--- /dev/null
+++ b/bsd-user/riscv/target_arch_thread.h
@@ -0,0 +1,47 @@
+/*
+ * RISC-V thread support
+ *
+ * Copyright (c) 2019 Mark Corbin
+ *
+ * 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/>.
+ */
+
+#ifndef TARGET_ARCH_THREAD_H
+#define TARGET_ARCH_THREAD_H
+
+/* Compare with cpu_set_upcall() in riscv/riscv/vm_machdep.c */
+static inline void target_thread_set_upcall(CPURISCVState *regs,
+ abi_ulong entry, abi_ulong arg, abi_ulong stack_base,
+ abi_ulong stack_size)
+{
+ abi_ulong sp;
+
+ sp = ROUND_DOWN(stack_base + stack_size, 16);
+
+ regs->gpr[xSP] = sp;
+ regs->pc = entry;
+ regs->gpr[xA0] = arg;
+}
+
+/* Compare with exec_setregs() in riscv/riscv/machdep.c */
+static inline void target_thread_init(struct target_pt_regs *regs,
+ struct image_info *infop)
+{
+ regs->sepc = infop->entry;
+ regs->regs[xRA] = infop->entry;
+ regs->regs[xA0] = infop->start_stack;
+ regs->regs[xSP] = ROUND_DOWN(infop->start_stack, 16);
+}
+
+#endif /* TARGET_ARCH_THREAD_H */
diff --git a/bsd-user/riscv/target_arch_vmparam.h b/bsd-user/riscv/target_arch_vmparam.h
new file mode 100644
index 0000000..0f2486d
--- /dev/null
+++ b/bsd-user/riscv/target_arch_vmparam.h
@@ -0,0 +1,53 @@
+/*
+ * RISC-V VM parameters definitions
+ *
+ * Copyright (c) 2019 Mark Corbin
+ *
+ * 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/>.
+ */
+
+#ifndef TARGET_ARCH_VMPARAM_H
+#define TARGET_ARCH_VMPARAM_H
+
+#include "cpu.h"
+
+/* Compare with riscv/include/vmparam.h */
+#define TARGET_MAXTSIZ (1 * GiB) /* max text size */
+#define TARGET_DFLDSIZ (128 * MiB) /* initial data size limit */
+#define TARGET_MAXDSIZ (1 * GiB) /* max data size */
+#define TARGET_DFLSSIZ (128 * MiB) /* initial stack size limit */
+#define TARGET_MAXSSIZ (1 * GiB) /* max stack size */
+#define TARGET_SGROWSIZ (128 * KiB) /* amount to grow stack */
+
+#define TARGET_VM_MINUSER_ADDRESS (0x0000000000000000UL)
+#define TARGET_VM_MAXUSER_ADDRESS (0x0000004000000000UL)
+
+#define TARGET_USRSTACK (TARGET_VM_MAXUSER_ADDRESS - TARGET_PAGE_SIZE)
+
+static inline abi_ulong get_sp_from_cpustate(CPURISCVState *state)
+{
+ return state->gpr[xSP];
+}
+
+static inline void set_second_rval(CPURISCVState *state, abi_ulong retval2)
+{
+ state->gpr[xA1] = retval2;
+}
+
+static inline abi_ulong get_second_rval(CPURISCVState *state)
+{
+ return state->gpr[xA1];
+}
+
+#endif /* TARGET_ARCH_VMPARAM_H */
diff --git a/bsd-user/riscv/target_syscall.h b/bsd-user/riscv/target_syscall.h
new file mode 100644
index 0000000..e7e5231
--- /dev/null
+++ b/bsd-user/riscv/target_syscall.h
@@ -0,0 +1,38 @@
+/*
+ * RISC-V system call definitions
+ *
+ * Copyright (c) Mark Corbin
+ *
+ * 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/>.
+ */
+
+#ifndef BSD_USER_RISCV_TARGET_SYSCALL_H
+#define BSD_USER_RISCV_TARGET_SYSCALL_H
+
+/*
+ * struct target_pt_regs defines the way the registers are stored on the stack
+ * during a system call.
+ */
+
+struct target_pt_regs {
+ abi_ulong regs[32];
+ abi_ulong sepc;
+};
+
+#define UNAME_MACHINE "riscv64"
+
+#define TARGET_HW_MACHINE "riscv"
+#define TARGET_HW_MACHINE_ARCH UNAME_MACHINE
+
+#endif /* BSD_USER_RISCV_TARGET_SYSCALL_H */
diff --git a/bsd-user/signal.c b/bsd-user/signal.c
index 8b6654b..da49b9b 100644
--- a/bsd-user/signal.c
+++ b/bsd-user/signal.c
@@ -728,14 +728,7 @@ static inline abi_ulong get_sigframe(struct target_sigaction *ka,
sp = ts->sigaltstack_used.ss_sp + ts->sigaltstack_used.ss_size;
}
-/* TODO: make this a target_arch function / define */
-#if defined(TARGET_ARM)
- return (sp - frame_size) & ~7;
-#elif defined(TARGET_AARCH64)
- return (sp - frame_size) & ~15;
-#else
- return sp - frame_size;
-#endif
+ return ROUND_DOWN(sp - frame_size, TARGET_SIGSTACK_ALIGN);
}
/* compare to $M/$M/exec_machdep.c sendsig and sys/kern/kern_sig.c sigexit */
diff --git a/bsd-user/x86_64/target_arch_signal.h b/bsd-user/x86_64/target_arch_signal.h
index ca24bf1..f833ee6 100644
--- a/bsd-user/x86_64/target_arch_signal.h
+++ b/bsd-user/x86_64/target_arch_signal.h
@@ -97,4 +97,6 @@ struct target_sigframe {
uint32_t __spare__[2];
};
+#define TARGET_SIGSTACK_ALIGN 16
+
#endif /* TARGET_ARCH_SIGNAL_H */
diff --git a/chardev/char-fe.c b/chardev/char-fe.c
index b214ba3..8ac6beb 100644
--- a/chardev/char-fe.c
+++ b/chardev/char-fe.c
@@ -191,22 +191,15 @@ bool qemu_chr_fe_backend_open(CharBackend *be)
bool qemu_chr_fe_init(CharBackend *b, Chardev *s, Error **errp)
{
- int tag = 0;
+ unsigned int tag = 0;
if (s) {
if (CHARDEV_IS_MUX(s)) {
MuxChardev *d = MUX_CHARDEV(s);
- if (d->mux_cnt >= MAX_MUX) {
- error_setg(errp,
- "too many uses of multiplexed chardev '%s'"
- " (maximum is " stringify(MAX_MUX) ")",
- s->label);
+ if (!mux_chr_attach_frontend(d, b, &tag, errp)) {
return false;
}
-
- d->backends[d->mux_cnt] = b;
- tag = d->mux_cnt++;
} else if (s->be) {
error_setg(errp, "chardev '%s' is already in use", s->label);
return false;
@@ -232,7 +225,7 @@ void qemu_chr_fe_deinit(CharBackend *b, bool del)
}
if (CHARDEV_IS_MUX(b->chr)) {
MuxChardev *d = MUX_CHARDEV(b->chr);
- d->backends[b->tag] = NULL;
+ mux_chr_detach_frontend(d, b->tag);
}
if (del) {
Object *obj = OBJECT(b->chr);
diff --git a/chardev/char-mux.c b/chardev/char-mux.c
index ee2d47b..bda5c45 100644
--- a/chardev/char-mux.c
+++ b/chardev/char-mux.c
@@ -26,6 +26,7 @@
#include "qapi/error.h"
#include "qemu/module.h"
#include "qemu/option.h"
+#include "qemu/bitops.h"
#include "chardev/char.h"
#include "sysemu/block-backend.h"
#include "qapi/qapi-commands-control.h"
@@ -73,11 +74,11 @@ static int mux_chr_write(Chardev *chr, const uint8_t *buf, int len)
* qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(&d->chr,
(uint8_t *)buf1, strlen(buf1));
- d->linestart = 0;
+ d->linestart = false;
}
ret += qemu_chr_fe_write(&d->chr, buf + i, 1);
if (buf[i] == '\n') {
- d->linestart = 1;
+ d->linestart = true;
}
}
}
@@ -124,7 +125,8 @@ static void mux_print_help(Chardev *chr)
}
}
-static void mux_chr_send_event(MuxChardev *d, int mux_nr, QEMUChrEvent event)
+static void mux_chr_send_event(MuxChardev *d, unsigned int mux_nr,
+ QEMUChrEvent event)
{
CharBackend *be = d->backends[mux_nr];
@@ -145,7 +147,7 @@ static void mux_chr_be_event(Chardev *chr, QEMUChrEvent event)
static int mux_proc_byte(Chardev *chr, MuxChardev *d, int ch)
{
if (d->term_got_escape) {
- d->term_got_escape = 0;
+ d->term_got_escape = false;
if (ch == term_escape_char) {
goto send_char;
}
@@ -167,19 +169,26 @@ static int mux_proc_byte(Chardev *chr, MuxChardev *d, int ch)
case 'b':
qemu_chr_be_event(chr, CHR_EVENT_BREAK);
break;
- case 'c':
- assert(d->mux_cnt > 0); /* handler registered with first fe */
+ case 'c': {
+ unsigned int bit;
+
+ /* Handler registered with first fe */
+ assert(d->mux_bitset != 0);
/* Switch to the next registered device */
- mux_set_focus(chr, (d->focus + 1) % d->mux_cnt);
+ bit = find_next_bit(&d->mux_bitset, MAX_MUX, d->focus + 1);
+ if (bit >= MAX_MUX) {
+ bit = find_next_bit(&d->mux_bitset, MAX_MUX, 0);
+ }
+ mux_set_focus(chr, bit);
break;
- case 't':
+ } case 't':
d->timestamps = !d->timestamps;
d->timestamps_start = -1;
- d->linestart = 0;
+ d->linestart = false;
break;
}
} else if (ch == term_escape_char) {
- d->term_got_escape = 1;
+ d->term_got_escape = true;
} else {
send_char:
return 1;
@@ -242,15 +251,16 @@ static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
void mux_chr_send_all_event(Chardev *chr, QEMUChrEvent event)
{
MuxChardev *d = MUX_CHARDEV(chr);
- int i;
+ int bit;
if (!muxes_opened) {
return;
}
/* Send the event to all registered listeners */
- for (i = 0; i < d->mux_cnt; i++) {
- mux_chr_send_event(d, i, event);
+ bit = -1;
+ while ((bit = find_next_bit(&d->mux_bitset, MAX_MUX, bit + 1)) < MAX_MUX) {
+ mux_chr_send_event(d, bit, event);
}
}
@@ -275,14 +285,15 @@ static GSource *mux_chr_add_watch(Chardev *s, GIOCondition cond)
static void char_mux_finalize(Object *obj)
{
MuxChardev *d = MUX_CHARDEV(obj);
- int i;
+ int bit;
- for (i = 0; i < d->mux_cnt; i++) {
- CharBackend *be = d->backends[i];
- if (be) {
- be->chr = NULL;
- }
+ bit = -1;
+ while ((bit = find_next_bit(&d->mux_bitset, MAX_MUX, bit + 1)) < MAX_MUX) {
+ CharBackend *be = d->backends[bit];
+ be->chr = NULL;
+ d->backends[bit] = NULL;
}
+ d->mux_bitset = 0;
qemu_chr_fe_deinit(&d->chr, false);
}
@@ -300,12 +311,47 @@ static void mux_chr_update_read_handlers(Chardev *chr)
chr->gcontext, true, false);
}
-void mux_set_focus(Chardev *chr, int focus)
+bool mux_chr_attach_frontend(MuxChardev *d, CharBackend *b,
+ unsigned int *tag, Error **errp)
+{
+ unsigned int bit;
+
+ bit = find_next_zero_bit(&d->mux_bitset, MAX_MUX, 0);
+ if (bit >= MAX_MUX) {
+ error_setg(errp,
+ "too many uses of multiplexed chardev '%s'"
+ " (maximum is " stringify(MAX_MUX) ")",
+ d->parent.label);
+ return false;
+ }
+
+ d->mux_bitset |= (1 << bit);
+ d->backends[bit] = b;
+ *tag = bit;
+
+ return true;
+}
+
+bool mux_chr_detach_frontend(MuxChardev *d, unsigned int tag)
+{
+ unsigned int bit;
+
+ bit = find_next_bit(&d->mux_bitset, MAX_MUX, tag);
+ if (bit != tag) {
+ return false;
+ }
+
+ d->mux_bitset &= ~(1 << bit);
+ d->backends[bit] = NULL;
+
+ return true;
+}
+
+void mux_set_focus(Chardev *chr, unsigned int focus)
{
MuxChardev *d = MUX_CHARDEV(chr);
- assert(focus >= 0);
- assert(focus < d->mux_cnt);
+ assert(find_next_bit(&d->mux_bitset, MAX_MUX, focus) == focus);
if (d->focus != -1) {
mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT);
diff --git a/chardev/char-pty.c b/chardev/char-pty.c
index cc2f761..cbb21b7 100644
--- a/chardev/char-pty.c
+++ b/chardev/char-pty.c
@@ -29,6 +29,7 @@
#include "qemu/sockets.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
+#include "qemu/option.h"
#include "qemu/qemu-print.h"
#include "chardev/char-io.h"
@@ -41,6 +42,7 @@ struct PtyChardev {
int connected;
GSource *timer_src;
+ char *path;
};
typedef struct PtyChardev PtyChardev;
@@ -204,6 +206,12 @@ static void char_pty_finalize(Object *obj)
Chardev *chr = CHARDEV(obj);
PtyChardev *s = PTY_CHARDEV(obj);
+ /* unlink symlink */
+ if (s->path) {
+ unlink(s->path);
+ g_free(s->path);
+ }
+
pty_chr_state(chr, 0);
object_unref(OBJECT(s->ioc));
pty_chr_timer_cancel(s);
@@ -330,6 +338,7 @@ static void char_pty_open(Chardev *chr,
int master_fd, slave_fd;
char pty_name[PATH_MAX];
char *name;
+ char *path = backend->u.pty.data->path;
master_fd = qemu_openpty_raw(&slave_fd, pty_name);
if (master_fd < 0) {
@@ -354,12 +363,36 @@ static void char_pty_open(Chardev *chr,
g_free(name);
s->timer_src = NULL;
*be_opened = false;
+
+ /* create symbolic link */
+ if (path) {
+ int res = symlink(pty_name, path);
+
+ if (res != 0) {
+ error_setg_errno(errp, errno, "Failed to create PTY symlink");
+ } else {
+ s->path = g_strdup(path);
+ }
+ }
+}
+
+static void char_pty_parse(QemuOpts *opts, ChardevBackend *backend,
+ Error **errp)
+{
+ const char *path = qemu_opt_get(opts, "path");
+ ChardevPty *pty;
+
+ backend->type = CHARDEV_BACKEND_KIND_PTY;
+ pty = backend->u.pty.data = g_new0(ChardevPty, 1);
+ qemu_chr_parse_common(opts, qapi_ChardevPty_base(pty));
+ pty->path = g_strdup(path);
}
static void char_pty_class_init(ObjectClass *oc, void *data)
{
ChardevClass *cc = CHARDEV_CLASS(oc);
+ cc->parse = char_pty_parse;
cc->open = char_pty_open;
cc->chr_write = char_pty_chr_write;
cc->chr_update_read_handler = pty_chr_update_read_handler;
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index 812d7aa..91496ce 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -33,6 +33,7 @@
#include "qapi/clone-visitor.h"
#include "qapi/qapi-visit-sockets.h"
#include "qemu/yank.h"
+#include "trace.h"
#include "chardev/char-io.h"
#include "chardev/char-socket.h"
@@ -73,7 +74,7 @@ static void qemu_chr_socket_restart_timer(Chardev *chr)
assert(!s->reconnect_timer);
name = g_strdup_printf("chardev-socket-reconnect-%s", chr->label);
s->reconnect_timer = qemu_chr_timeout_add_ms(chr,
- s->reconnect_time * 1000,
+ s->reconnect_time_ms,
socket_reconnect_timeout,
chr);
g_source_set_name(s->reconnect_timer, name);
@@ -126,6 +127,7 @@ static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len)
if (ret < 0 && errno != EAGAIN) {
if (tcp_chr_read_poll(chr) <= 0) {
/* Perform disconnect and return error. */
+ trace_chr_socket_poll_err(chr, chr->label);
tcp_chr_disconnect_locked(chr);
} /* else let the read handler finish it properly */
}
@@ -279,15 +281,16 @@ static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
size_t i;
int *msgfds = NULL;
size_t msgfds_num = 0;
+ Error *err = NULL;
if (qio_channel_has_feature(s->ioc, QIO_CHANNEL_FEATURE_FD_PASS)) {
ret = qio_channel_readv_full(s->ioc, &iov, 1,
&msgfds, &msgfds_num,
- 0, NULL);
+ 0, &err);
} else {
ret = qio_channel_readv_full(s->ioc, &iov, 1,
NULL, NULL,
- 0, NULL);
+ 0, &err);
}
if (msgfds_num) {
@@ -322,7 +325,11 @@ static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
errno = EAGAIN;
ret = -1;
} else if (ret == -1) {
+ trace_chr_socket_recv_err(chr, chr->label, error_get_pretty(err));
+ error_free(err);
errno = EIO;
+ } else if (ret == 0) {
+ trace_chr_socket_recv_eof(chr, chr->label);
}
return ret;
@@ -463,6 +470,7 @@ static void tcp_chr_disconnect_locked(Chardev *chr)
SocketChardev *s = SOCKET_CHARDEV(chr);
bool emit_close = s->state == TCP_CHARDEV_STATE_CONNECTED;
+ trace_chr_socket_disconnect(chr, chr->label);
tcp_chr_free_connection(chr);
if (s->listener) {
@@ -473,7 +481,7 @@ static void tcp_chr_disconnect_locked(Chardev *chr)
if (emit_close) {
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
}
- if (s->reconnect_time && !s->reconnect_timer) {
+ if (s->reconnect_time_ms && !s->reconnect_timer) {
qemu_chr_socket_restart_timer(chr);
}
}
@@ -521,6 +529,7 @@ static gboolean tcp_chr_hup(QIOChannel *channel,
void *opaque)
{
Chardev *chr = CHARDEV(opaque);
+ trace_chr_socket_hangup(chr, chr->label);
tcp_chr_disconnect(chr);
return G_SOURCE_REMOVE;
}
@@ -672,15 +681,18 @@ static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
SocketChardev *s = user_data;
Chardev *chr = CHARDEV(s);
TCPChardevTelnetInit *init = s->telnet_init;
+ Error *err = NULL;
ssize_t ret;
assert(init);
- ret = qio_channel_write(ioc, init->buf, init->buflen, NULL);
+ ret = qio_channel_write(ioc, init->buf, init->buflen, &err);
if (ret < 0) {
if (ret == QIO_CHANNEL_ERR_BLOCK) {
ret = 0;
} else {
+ trace_chr_socket_write_err(chr, chr->label, error_get_pretty(err));
+ error_free(err);
tcp_chr_disconnect(chr);
goto end;
}
@@ -765,9 +777,9 @@ static void tcp_chr_websock_handshake(QIOTask *task, gpointer user_data)
Error *err = NULL;
if (qio_task_propagate_error(task, &err)) {
- error_reportf_err(err,
- "websock handshake of character device %s failed: ",
- chr->label);
+ trace_chr_socket_ws_handshake_err(chr, chr->label,
+ error_get_pretty(err));
+ error_free(err);
tcp_chr_disconnect(chr);
} else {
if (s->do_telnetopt) {
@@ -805,9 +817,9 @@ static void tcp_chr_tls_handshake(QIOTask *task,
Error *err = NULL;
if (qio_task_propagate_error(task, &err)) {
- error_reportf_err(err,
- "TLS handshake of character device %s failed: ",
- chr->label);
+ trace_chr_socket_tls_handshake_err(chr, chr->label,
+ error_get_pretty(err));
+ error_free(err);
tcp_chr_disconnect(chr);
} else {
if (s->is_websock) {
@@ -826,19 +838,22 @@ static void tcp_chr_tls_init(Chardev *chr)
SocketChardev *s = SOCKET_CHARDEV(chr);
QIOChannelTLS *tioc;
gchar *name;
+ Error *err = NULL;
if (s->is_listen) {
tioc = qio_channel_tls_new_server(
s->ioc, s->tls_creds,
s->tls_authz,
- NULL);
+ &err);
} else {
tioc = qio_channel_tls_new_client(
s->ioc, s->tls_creds,
s->addr->u.inet.host,
- NULL);
+ &err);
}
if (tioc == NULL) {
+ trace_chr_socket_tls_init_err(chr, chr->label, error_get_pretty(err));
+ error_free(err);
tcp_chr_disconnect(chr);
return;
}
@@ -1065,9 +1080,9 @@ static int tcp_chr_wait_connected(Chardev *chr, Error **errp)
} else {
Error *err = NULL;
if (tcp_chr_connect_client_sync(chr, &err) < 0) {
- if (s->reconnect_time) {
+ if (s->reconnect_time_ms) {
error_free(err);
- g_usleep(s->reconnect_time * 1000ULL * 1000ULL);
+ g_usleep(s->reconnect_time_ms * 1000ULL);
} else {
error_propagate(errp, err);
return -1;
@@ -1252,13 +1267,13 @@ skip_listen:
static int qmp_chardev_open_socket_client(Chardev *chr,
- int64_t reconnect,
+ int64_t reconnect_ms,
Error **errp)
{
SocketChardev *s = SOCKET_CHARDEV(chr);
- if (reconnect > 0) {
- s->reconnect_time = reconnect;
+ if (reconnect_ms > 0) {
+ s->reconnect_time_ms = reconnect_ms;
tcp_chr_connect_client_async(chr);
return 0;
} else {
@@ -1339,6 +1354,12 @@ static bool qmp_chardev_validate_socket(ChardevSocket *sock,
}
}
+ if (sock->has_reconnect_ms && sock->has_reconnect) {
+ error_setg(errp,
+ "'reconnect' and 'reconnect-ms' are mutually exclusive");
+ return false;
+ }
+
return true;
}
@@ -1356,7 +1377,7 @@ static void qmp_chardev_open_socket(Chardev *chr,
bool is_tn3270 = sock->has_tn3270 ? sock->tn3270 : false;
bool is_waitconnect = sock->has_wait ? sock->wait : false;
bool is_websock = sock->has_websocket ? sock->websocket : false;
- int64_t reconnect = sock->has_reconnect ? sock->reconnect : 0;
+ int64_t reconnect_ms = 0;
SocketAddress *addr;
s->is_listen = is_listen;
@@ -1428,7 +1449,13 @@ static void qmp_chardev_open_socket(Chardev *chr,
return;
}
} else {
- if (qmp_chardev_open_socket_client(chr, reconnect, errp) < 0) {
+ if (sock->has_reconnect) {
+ reconnect_ms = sock->reconnect * 1000ULL;
+ } else if (sock->has_reconnect_ms) {
+ reconnect_ms = sock->reconnect_ms;
+ }
+
+ if (qmp_chardev_open_socket_client(chr, reconnect_ms, errp) < 0) {
return;
}
}
@@ -1494,6 +1521,9 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
sock->wait = qemu_opt_get_bool(opts, "wait", true);
sock->has_reconnect = qemu_opt_find(opts, "reconnect");
sock->reconnect = qemu_opt_get_number(opts, "reconnect", 0);
+ sock->has_reconnect_ms = qemu_opt_find(opts, "reconnect-ms");
+ sock->reconnect_ms = qemu_opt_get_number(opts, "reconnect-ms", 0);
+
sock->tls_creds = g_strdup(qemu_opt_get(opts, "tls-creds"));
sock->tls_authz = g_strdup(qemu_opt_get(opts, "tls-authz"));
diff --git a/chardev/char-win-stdio.c b/chardev/char-win-stdio.c
index 1a18999..13325ca 100644
--- a/chardev/char-win-stdio.c
+++ b/chardev/char-win-stdio.c
@@ -33,6 +33,7 @@
struct WinStdioChardev {
Chardev parent;
HANDLE hStdIn;
+ DWORD dwOldMode;
HANDLE hInputReadyEvent;
HANDLE hInputDoneEvent;
HANDLE hInputThread;
@@ -159,6 +160,7 @@ static void qemu_chr_open_stdio(Chardev *chr,
}
is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0;
+ stdio->dwOldMode = dwMode;
if (is_console) {
if (qemu_add_wait_object(stdio->hStdIn,
@@ -221,6 +223,9 @@ static void char_win_stdio_finalize(Object *obj)
{
WinStdioChardev *stdio = WIN_STDIO_CHARDEV(obj);
+ if (stdio->hStdIn != INVALID_HANDLE_VALUE) {
+ SetConsoleMode(stdio->hStdIn, stdio->dwOldMode);
+ }
if (stdio->hInputReadyEvent != INVALID_HANDLE_VALUE) {
CloseHandle(stdio->hInputReadyEvent);
}
diff --git a/chardev/char.c b/chardev/char.c
index 3c43fb1..a1722aa 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -333,7 +333,7 @@ static bool qemu_chr_is_busy(Chardev *s)
{
if (CHARDEV_IS_MUX(s)) {
MuxChardev *d = MUX_CHARDEV(s);
- return d->mux_cnt >= 0;
+ return d->mux_bitset != 0;
} else {
return s->be != NULL;
}
@@ -428,6 +428,11 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename,
qemu_opt_set(opts, "path", p, &error_abort);
return opts;
}
+ if (strstart(filename, "pty:", &p)) {
+ qemu_opt_set(opts, "backend", "pty", &error_abort);
+ qemu_opt_set(opts, "path", p, &error_abort);
+ return opts;
+ }
if (strstart(filename, "tcp:", &p) ||
strstart(filename, "telnet:", &p) ||
strstart(filename, "tn3270:", &p) ||
@@ -615,11 +620,24 @@ ChardevBackend *qemu_chr_parse_opts(QemuOpts *opts, Error **errp)
return backend;
}
-Chardev *qemu_chr_new_from_opts(QemuOpts *opts, GMainContext *context,
- Error **errp)
+static void qemu_chardev_set_replay(Chardev *chr, Error **errp)
+{
+ if (replay_mode != REPLAY_MODE_NONE) {
+ if (CHARDEV_GET_CLASS(chr)->chr_ioctl) {
+ error_setg(errp, "Replay: ioctl is not supported "
+ "for serial devices yet");
+ return;
+ }
+ qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_REPLAY);
+ replay_register_char_driver(chr);
+ }
+}
+
+static Chardev *__qemu_chr_new_from_opts(QemuOpts *opts, GMainContext *context,
+ bool replay, Error **errp)
{
const ChardevClass *cc;
- Chardev *chr = NULL;
+ Chardev *base = NULL, *chr = NULL;
ChardevBackend *backend = NULL;
const char *name = qemu_opt_get(opts, "backend");
const char *id = qemu_opts_id(opts);
@@ -657,11 +675,11 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts, GMainContext *context,
chr = qemu_chardev_new(bid ? bid : id,
object_class_get_name(OBJECT_CLASS(cc)),
backend, context, errp);
-
if (chr == NULL) {
goto out;
}
+ base = chr;
if (bid) {
Chardev *mux;
qapi_free_ChardevBackend(backend);
@@ -681,11 +699,25 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts, GMainContext *context,
out:
qapi_free_ChardevBackend(backend);
g_free(bid);
+
+ if (replay && base) {
+ /* RR should be set on the base device, not the mux */
+ qemu_chardev_set_replay(base, errp);
+ }
+
return chr;
}
-Chardev *qemu_chr_new_noreplay(const char *label, const char *filename,
- bool permit_mux_mon, GMainContext *context)
+Chardev *qemu_chr_new_from_opts(QemuOpts *opts, GMainContext *context,
+ Error **errp)
+{
+ /* XXX: should this really not record/replay? */
+ return __qemu_chr_new_from_opts(opts, context, false, errp);
+}
+
+static Chardev *__qemu_chr_new(const char *label, const char *filename,
+ bool permit_mux_mon, GMainContext *context,
+ bool replay)
{
const char *p;
Chardev *chr;
@@ -693,14 +725,22 @@ Chardev *qemu_chr_new_noreplay(const char *label, const char *filename,
Error *err = NULL;
if (strstart(filename, "chardev:", &p)) {
- return qemu_chr_find(p);
+ chr = qemu_chr_find(p);
+ if (replay) {
+ qemu_chardev_set_replay(chr, &err);
+ if (err) {
+ error_report_err(err);
+ return NULL;
+ }
+ }
+ return chr;
}
opts = qemu_chr_parse_compat(label, filename, permit_mux_mon);
if (!opts)
return NULL;
- chr = qemu_chr_new_from_opts(opts, context, &err);
+ chr = __qemu_chr_new_from_opts(opts, context, replay, &err);
if (!chr) {
error_report_err(err);
goto out;
@@ -722,24 +762,18 @@ out:
return chr;
}
+Chardev *qemu_chr_new_noreplay(const char *label, const char *filename,
+ bool permit_mux_mon, GMainContext *context)
+{
+ return __qemu_chr_new(label, filename, permit_mux_mon, context, false);
+}
+
static Chardev *qemu_chr_new_permit_mux_mon(const char *label,
const char *filename,
bool permit_mux_mon,
GMainContext *context)
{
- Chardev *chr;
- chr = qemu_chr_new_noreplay(label, filename, permit_mux_mon, context);
- if (chr) {
- if (replay_mode != REPLAY_MODE_NONE) {
- qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_REPLAY);
- }
- if (qemu_chr_replay(chr) && CHARDEV_GET_CLASS(chr)->chr_ioctl) {
- error_report("Replay: ioctl is not supported "
- "for serial devices yet");
- }
- replay_register_char_driver(chr);
- }
- return chr;
+ return __qemu_chr_new(label, filename, permit_mux_mon, context, true);
}
Chardev *qemu_chr_new(const char *label, const char *filename,
@@ -860,6 +894,9 @@ QemuOptsList qemu_chardev_opts = {
.name = "reconnect",
.type = QEMU_OPT_NUMBER,
},{
+ .name = "reconnect-ms",
+ .type = QEMU_OPT_NUMBER,
+ },{
.name = "telnet",
.type = QEMU_OPT_BOOL,
},{
diff --git a/chardev/chardev-internal.h b/chardev/chardev-internal.h
index 4e03af3..853807f 100644
--- a/chardev/chardev-internal.h
+++ b/chardev/chardev-internal.h
@@ -37,20 +37,19 @@ struct MuxChardev {
Chardev parent;
CharBackend *backends[MAX_MUX];
CharBackend chr;
+ unsigned long mux_bitset;
int focus;
- int mux_cnt;
- int term_got_escape;
- int max_size;
+ bool term_got_escape;
/* Intermediate input buffer catches escape sequences even if the
currently active device is not accepting any input - but only until it
is full as well. */
unsigned char buffer[MAX_MUX][MUX_BUFFER_SIZE];
- int prod[MAX_MUX];
- int cons[MAX_MUX];
+ unsigned int prod[MAX_MUX];
+ unsigned int cons[MAX_MUX];
int timestamps;
/* Protected by the Chardev chr_write_lock. */
- int linestart;
+ bool linestart;
int64_t timestamps_start;
};
typedef struct MuxChardev MuxChardev;
@@ -60,7 +59,10 @@ DECLARE_INSTANCE_CHECKER(MuxChardev, MUX_CHARDEV,
#define CHARDEV_IS_MUX(chr) \
object_dynamic_cast(OBJECT(chr), TYPE_CHARDEV_MUX)
-void mux_set_focus(Chardev *chr, int focus);
+bool mux_chr_attach_frontend(MuxChardev *d, CharBackend *b,
+ unsigned int *tag, Error **errp);
+bool mux_chr_detach_frontend(MuxChardev *d, unsigned int tag);
+void mux_set_focus(Chardev *chr, unsigned int focus);
void mux_chr_send_all_event(Chardev *chr, QEMUChrEvent event);
Object *get_chardevs_root(void);
diff --git a/chardev/msmouse.c b/chardev/msmouse.c
index a774c39..2279694 100644
--- a/chardev/msmouse.c
+++ b/chardev/msmouse.c
@@ -81,7 +81,7 @@ static void msmouse_chr_accept_input(Chardev *chr)
const uint8_t *buf;
uint32_t size;
- buf = fifo8_pop_buf(&mouse->outbuf, MIN(len, avail), &size);
+ buf = fifo8_pop_bufptr(&mouse->outbuf, MIN(len, avail), &size);
qemu_chr_be_write(chr, buf, size);
len = qemu_chr_be_can_write(chr);
avail -= size;
diff --git a/chardev/trace-events b/chardev/trace-events
index 027107b..7e97b8a 100644
--- a/chardev/trace-events
+++ b/chardev/trace-events
@@ -17,3 +17,13 @@ spice_vmc_register_interface(void *scd) "spice vmc registered interface %p"
spice_vmc_unregister_interface(void *scd) "spice vmc unregistered interface %p"
spice_vmc_event(int event) "spice vmc event %d"
+# char-socket.c
+chr_socket_poll_err(void *chrdev, const char *label) "chardev socket poll error %p (%s)"
+chr_socket_recv_err(void *chrdev, const char *label, const char *err) "chardev socket recv error %p (%s): %s"
+chr_socket_recv_eof(void *chrdev, const char *label) "chardev socket recv end-of-file %p (%s)"
+chr_socket_write_err(void *chrdev, const char *label, const char *err) "chardev socket write error %p (%s): %s"
+chr_socket_disconnect(void *chrdev, const char *label) "chardev socket disconnect %p (%s)"
+chr_socket_hangup(void *chrdev, const char *label) "chardev socket hangup %p (%s)"
+chr_socket_ws_handshake_err(void *chrdev, const char *label, const char *err) "chardev socket websock handshake error %p (%s): %s"
+chr_socket_tls_handshake_err(void *chrdev, const char *label, const char *err) "chardev socket TLS handshake error %p (%s): %s"
+chr_socket_tls_init_err(void *chrdev, const char *label, const char *err) "chardev socket TLS init error %p (%s): %s"
diff --git a/configs/devices/arm-softmmu/default.mak b/configs/devices/arm-softmmu/default.mak
index 31f77c2..57ef1b8 100644
--- a/configs/devices/arm-softmmu/default.mak
+++ b/configs/devices/arm-softmmu/default.mak
@@ -18,9 +18,7 @@
# CONFIG_MUSICPAL=n
# CONFIG_MPS3R=n
# CONFIG_MUSCA=n
-# CONFIG_CHEETAH=n
# CONFIG_SX1=n
-# CONFIG_NSERIES=n
# CONFIG_STELLARIS=n
# CONFIG_STM32VLDISCOVERY=n
# CONFIG_B_L475E_IOT01A=n
@@ -28,11 +26,6 @@
# CONFIG_VERSATILE=n
# CONFIG_VEXPRESS=n
# CONFIG_ZYNQ=n
-# CONFIG_MAINSTONE=n
-# CONFIG_GUMSTIX=n
-# CONFIG_SPITZ=n
-# CONFIG_TOSA=n
-# CONFIG_Z2=n
# CONFIG_NPCM7XX=n
# CONFIG_COLLIE=n
# CONFIG_ASPEED_SOC=n
diff --git a/configs/devices/cris-softmmu/default.mak b/configs/devices/cris-softmmu/default.mak
deleted file mode 100644
index ff73cd4..0000000
--- a/configs/devices/cris-softmmu/default.mak
+++ /dev/null
@@ -1,4 +0,0 @@
-# Default configuration for cris-softmmu
-
-# Boards are selected by default, uncomment to keep out of the build.
-# CONFIG_AXIS=n
diff --git a/configs/devices/sh4-softmmu/default.mak b/configs/devices/sh4-softmmu/default.mak
index c06a427..efb401b 100644
--- a/configs/devices/sh4-softmmu/default.mak
+++ b/configs/devices/sh4-softmmu/default.mak
@@ -1,4 +1,4 @@
-# Default configuration for sh4eb-softmmu
+# Default configuration for sh4-softmmu
# Uncomment the following lines to disable these optional devices:
#
@@ -7,4 +7,3 @@
# Boards are selected by default, uncomment to keep out of the build.
# CONFIG_R2D=n
-# CONFIG_SHIX=n
diff --git a/configs/devices/sh4eb-softmmu/default.mak b/configs/devices/sh4eb-softmmu/default.mak
deleted file mode 100644
index f18d1f6..0000000
--- a/configs/devices/sh4eb-softmmu/default.mak
+++ /dev/null
@@ -1,3 +0,0 @@
-# Default configuration for sh4eb-softmmu
-
-include ../sh4-softmmu/default.mak
diff --git a/configs/targets/aarch64-bsd-user.mak b/configs/targets/aarch64-bsd-user.mak
new file mode 100644
index 0000000..8aaa5d8
--- /dev/null
+++ b/configs/targets/aarch64-bsd-user.mak
@@ -0,0 +1,3 @@
+TARGET_ARCH=aarch64
+TARGET_BASE_ARCH=arm
+TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/aarch64-pauth.xml
diff --git a/configs/targets/aarch64-linux-user.mak b/configs/targets/aarch64-linux-user.mak
index 8f0ed21..4c6570f 100644
--- a/configs/targets/aarch64-linux-user.mak
+++ b/configs/targets/aarch64-linux-user.mak
@@ -4,3 +4,5 @@ TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/aarch
TARGET_HAS_BFLT=y
CONFIG_SEMIHOSTING=y
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
+TARGET_SYSTBL_ABI=common,64,renameat,rlimit,memfd_secret
+TARGET_SYSTBL=syscall_64.tbl
diff --git a/configs/targets/aarch64_be-linux-user.mak b/configs/targets/aarch64_be-linux-user.mak
index acb5620..dcef597 100644
--- a/configs/targets/aarch64_be-linux-user.mak
+++ b/configs/targets/aarch64_be-linux-user.mak
@@ -1,7 +1,9 @@
TARGET_ARCH=aarch64
TARGET_BASE_ARCH=arm
TARGET_BIG_ENDIAN=y
-TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/aarch64-pauth.xml
+TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/aarch64-pauth.xml gdb-xml/aarch64-mte.xml
TARGET_HAS_BFLT=y
CONFIG_SEMIHOSTING=y
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
+TARGET_SYSTBL_ABI=common,64,renameat,rlimit,memfd_secret
+TARGET_SYSTBL=syscall_64.tbl
diff --git a/configs/targets/cris-linux-user.mak b/configs/targets/cris-linux-user.mak
deleted file mode 100644
index e483c42..0000000
--- a/configs/targets/cris-linux-user.mak
+++ /dev/null
@@ -1 +0,0 @@
-TARGET_ARCH=cris
diff --git a/configs/targets/cris-softmmu.mak b/configs/targets/cris-softmmu.mak
deleted file mode 100644
index e483c42..0000000
--- a/configs/targets/cris-softmmu.mak
+++ /dev/null
@@ -1 +0,0 @@
-TARGET_ARCH=cris
diff --git a/configs/targets/hexagon-linux-user.mak b/configs/targets/hexagon-linux-user.mak
index 2765a4c..b912045 100644
--- a/configs/targets/hexagon-linux-user.mak
+++ b/configs/targets/hexagon-linux-user.mak
@@ -1,2 +1,4 @@
TARGET_ARCH=hexagon
TARGET_XML_FILES=gdb-xml/hexagon-core.xml gdb-xml/hexagon-hvx.xml
+TARGET_SYSTBL=syscall.tbl
+TARGET_SYSTBL_ABI=common,32,hexagon,time32,stat64,rlimit,renameat
diff --git a/configs/targets/i386-linux-user.mak b/configs/targets/i386-linux-user.mak
index 5b2546a..b72a156 100644
--- a/configs/targets/i386-linux-user.mak
+++ b/configs/targets/i386-linux-user.mak
@@ -1,4 +1,4 @@
TARGET_ARCH=i386
TARGET_SYSTBL_ABI=i386
TARGET_SYSTBL=syscall_32.tbl
-TARGET_XML_FILES= gdb-xml/i386-32bit.xml
+TARGET_XML_FILES= gdb-xml/i386-32bit.xml gdb-xml/i386-32bit-linux.xml
diff --git a/configs/targets/loongarch64-linux-user.mak b/configs/targets/loongarch64-linux-user.mak
index d878e5a..dfded79 100644
--- a/configs/targets/loongarch64-linux-user.mak
+++ b/configs/targets/loongarch64-linux-user.mak
@@ -1,4 +1,6 @@
# Default configuration for loongarch64-linux-user
TARGET_ARCH=loongarch64
TARGET_BASE_ARCH=loongarch
-TARGET_XML_FILES=gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu.xml
+TARGET_XML_FILES=gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu.xml gdb-xml/loongarch-lsx.xml gdb-xml/loongarch-lasx.xml
+TARGET_SYSTBL=syscall.tbl
+TARGET_SYSTBL_ABI=common,64
diff --git a/configs/targets/loongarch64-softmmu.mak b/configs/targets/loongarch64-softmmu.mak
index 65b65e0..ce19ab6 100644
--- a/configs/targets/loongarch64-softmmu.mak
+++ b/configs/targets/loongarch64-softmmu.mak
@@ -2,6 +2,6 @@ TARGET_ARCH=loongarch64
TARGET_BASE_ARCH=loongarch
TARGET_KVM_HAVE_GUEST_DEBUG=y
TARGET_SUPPORTS_MTTCG=y
-TARGET_XML_FILES= gdb-xml/loongarch-base32.xml gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu.xml
+TARGET_XML_FILES= gdb-xml/loongarch-base32.xml gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu.xml gdb-xml/loongarch-lsx.xml gdb-xml/loongarch-lasx.xml
# all boards require libfdt
TARGET_NEED_FDT=y
diff --git a/configs/targets/or1k-linux-user.mak b/configs/targets/or1k-linux-user.mak
index 39558f7..eecb1e2 100644
--- a/configs/targets/or1k-linux-user.mak
+++ b/configs/targets/or1k-linux-user.mak
@@ -1,2 +1,4 @@
TARGET_ARCH=openrisc
TARGET_BIG_ENDIAN=y
+TARGET_SYSTBL_ABI=common,32,or1k,time32,stat64,rlimit,renameat
+TARGET_SYSTBL=syscall.tbl
diff --git a/configs/targets/riscv32-linux-user.mak b/configs/targets/riscv32-linux-user.mak
index 9761618..0dbaf52 100644
--- a/configs/targets/riscv32-linux-user.mak
+++ b/configs/targets/riscv32-linux-user.mak
@@ -4,3 +4,6 @@ TARGET_ABI_DIR=riscv
TARGET_XML_FILES= gdb-xml/riscv-32bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-32bit-virtual.xml
CONFIG_SEMIHOSTING=y
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
+TARGET_SYSTBL_ABI=32
+TARGET_SYSTBL_ABI=common,32,riscv,memfd_secret
+TARGET_SYSTBL=syscall.tbl
diff --git a/configs/targets/riscv64-bsd-user.mak b/configs/targets/riscv64-bsd-user.mak
new file mode 100644
index 0000000..191c2c4
--- /dev/null
+++ b/configs/targets/riscv64-bsd-user.mak
@@ -0,0 +1,4 @@
+TARGET_ARCH=riscv64
+TARGET_BASE_ARCH=riscv
+TARGET_ABI_DIR=riscv
+TARGET_XML_FILES= gdb-xml/riscv-64bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-64bit-virtual.xml
diff --git a/configs/targets/riscv64-linux-user.mak b/configs/targets/riscv64-linux-user.mak
index cfd1fd3..477cd45 100644
--- a/configs/targets/riscv64-linux-user.mak
+++ b/configs/targets/riscv64-linux-user.mak
@@ -4,3 +4,6 @@ TARGET_ABI_DIR=riscv
TARGET_XML_FILES= gdb-xml/riscv-64bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-64bit-virtual.xml
CONFIG_SEMIHOSTING=y
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
+TARGET_SYSTBL_ABI=64
+TARGET_SYSTBL_ABI=common,64,riscv,rlimit,memfd_secret
+TARGET_SYSTBL=syscall.tbl
diff --git a/configs/targets/sh4eb-softmmu.mak b/configs/targets/sh4eb-softmmu.mak
deleted file mode 100644
index 226b1fc..0000000
--- a/configs/targets/sh4eb-softmmu.mak
+++ /dev/null
@@ -1,2 +0,0 @@
-TARGET_ARCH=sh4
-TARGET_BIG_ENDIAN=y
diff --git a/configs/targets/x86_64-linux-user.mak b/configs/targets/x86_64-linux-user.mak
index 9ceefbb..8604281 100644
--- a/configs/targets/x86_64-linux-user.mak
+++ b/configs/targets/x86_64-linux-user.mak
@@ -2,4 +2,4 @@ TARGET_ARCH=x86_64
TARGET_BASE_ARCH=i386
TARGET_SYSTBL_ABI=common,64
TARGET_SYSTBL=syscall_64.tbl
-TARGET_XML_FILES= gdb-xml/i386-64bit.xml
+TARGET_XML_FILES= gdb-xml/i386-64bit.xml gdb-xml/i386-64bit-linux.xml
diff --git a/configure b/configure
index 019fcbd..4a0159e 100755
--- a/configure
+++ b/configure
@@ -207,6 +207,8 @@ for opt do
;;
--objcc=*) objcc="$optarg"
;;
+ --rustc=*) RUSTC="$optarg"
+ ;;
--cpu=*) cpu="$optarg"
;;
--extra-cflags=*)
@@ -252,6 +254,8 @@ python=
download="enabled"
skip_meson=no
use_containers="yes"
+rust="disabled"
+rust_target_triple=""
gdb_bin=$(command -v "gdb-multiarch" || command -v "gdb")
gdb_arches=""
@@ -310,6 +314,7 @@ objcopy="${OBJCOPY-${cross_prefix}objcopy}"
ld="${LD-${cross_prefix}ld}"
ranlib="${RANLIB-${cross_prefix}ranlib}"
nm="${NM-${cross_prefix}nm}"
+readelf="${READELF-${cross_prefix}readelf}"
strip="${STRIP-${cross_prefix}strip}"
widl="${WIDL-${cross_prefix}widl}"
windres="${WINDRES-${cross_prefix}windres}"
@@ -317,6 +322,8 @@ windmc="${WINDMC-${cross_prefix}windmc}"
pkg_config="${PKG_CONFIG-${cross_prefix}pkg-config}"
sdl2_config="${SDL2_CONFIG-${cross_prefix}sdl2-config}"
+rustc="${RUSTC-rustc}"
+
check_define() {
cat > $TMPC <<EOF
#if !defined($1)
@@ -425,6 +432,7 @@ fi
# Please keep it sorted and synchronized with meson.build's host_arch.
host_arch=
linux_arch=
+raw_cpu=$cpu
case "$cpu" in
aarch64)
host_arch=aarch64
@@ -516,6 +524,25 @@ case "$cpu" in
;;
esac
+# Now we have our CPU_CFLAGS we can check if we are targeting a 32 or
+# 64 bit host.
+
+check_64bit_host() {
+cat > $TMPC <<EOF
+#if __SIZEOF_POINTER__ != 8
+#error not 64 bit system
+#endif
+int main(void) { return 0; }
+EOF
+ compile_object "$1"
+}
+
+if check_64bit_host "$CPU_CFLAGS"; then
+ host_bits=64
+else
+ host_bits=32
+fi
+
if test -n "$host_arch" && {
! test -d "$source_path/linux-user/include/host/$host_arch" ||
! test -d "$source_path/common-user/host/$host_arch"; }; then
@@ -610,6 +637,9 @@ meson_option_parse() {
exit 1
fi
}
+has_meson_option() {
+ test "${meson_options#*"$1"}" != "$meson_options"
+}
meson_add_machine_file() {
if test "$cross_compile" = "yes"; then
@@ -636,6 +666,8 @@ for opt do
;;
--objcc=*)
;;
+ --rustc=*)
+ ;;
--make=*)
;;
--install=*)
@@ -755,8 +787,14 @@ for opt do
;;
--container-engine=*) container_engine="$optarg"
;;
+ --rust-target-triple=*) rust_target_triple="$optarg"
+ ;;
--gdb=*) gdb_bin="$optarg"
;;
+ --enable-rust) rust=enabled
+ ;;
+ --disable-rust) rust=disabled
+ ;;
# everything else has the same name in configure and meson
--*) meson_option_parse "$opt" "$optarg"
;;
@@ -859,6 +897,7 @@ Advanced options (experts only):
at build time [$host_cc]
--cxx=CXX use C++ compiler CXX [$cxx]
--objcc=OBJCC use Objective-C compiler OBJCC [$objcc]
+ --rustc=RUSTC use Rust compiler RUSTC [$rustc]
--extra-cflags=CFLAGS append extra C compiler flags CFLAGS
--extra-cxxflags=CXXFLAGS append extra C++ compiler flags CXXFLAGS
--extra-objcflags=OBJCFLAGS append extra Objective C compiler flags OBJCFLAGS
@@ -869,8 +908,9 @@ Advanced options (experts only):
--python=PYTHON use specified python [$python]
--ninja=NINJA use specified ninja [$ninja]
--static enable static build [$static]
- --without-default-features default all --enable-* options to "disabled"
- --without-default-devices do not include any device that is not needed to
+ --rust-target-triple=TRIPLE compilation target for Rust code [autodetect]
+ --without-default-features default all --enable-* options to "disabled"
+ --without-default-devices do not include any device that is not needed to
start the emulator (only use if you are including
desired devices in configs/devices/)
--with-devices-ARCH=NAME override default configs/devices
@@ -1028,9 +1068,13 @@ if test "$static" = "yes" ; then
fi
plugins="no"
fi
-if test "$plugins" != "no"; then
- plugins=yes
- subdirs="$subdirs contrib/plugins"
+if test "$plugins" != "no" && test $host_bits -eq 64; then
+ if has_meson_option "-Dtcg_interpreter=true"; then
+ plugins="no"
+ else
+ plugins=yes
+ subdirs="$subdirs contrib/plugins"
+ fi
fi
cat > $TMPC << EOF
@@ -1103,8 +1147,10 @@ fi
# gdb test
if test -n "$gdb_bin"; then
- gdb_version=$($gdb_bin --version | head -n 1)
- if version_ge ${gdb_version##* } 9.1; then
+ gdb_version_string=$($gdb_bin --version | head -n 1)
+ # Extract last field in the version string
+ gdb_version=${gdb_version_string##* }
+ if version_ge $gdb_version 9.1; then
gdb_arches=$($python "$source_path/scripts/probe-gdb-support.py" $gdb_bin)
else
gdb_bin=""
@@ -1139,6 +1185,132 @@ EOF
fi
##########################################
+# detect rust triple
+
+if test "$rust" != disabled && has "$rustc" && $rustc -vV > "${TMPDIR1}/${TMPB}.out"; then
+ rust_host_triple=$(sed -n 's/^host: //p' "${TMPDIR1}/${TMPB}.out")
+else
+ if test "$rust" = enabled; then
+ error_exit "could not execute rustc binary \"$rustc\""
+ fi
+ rust=disabled
+fi
+if test "$rust" != disabled && test -z "$rust_target_triple"; then
+ # arch and os generally matches between meson and rust
+ rust_arch=$host_arch
+ rust_os=$host_os
+ rust_machine=unknown
+ rust_osvariant=
+
+ # tweak rust_os if needed; also, machine and variant depend on the OS
+ android=no
+ case "$host_os" in
+ darwin)
+ # e.g. aarch64-apple-darwin
+ rust_machine=apple
+ ;;
+
+ linux)
+ # detect android/glibc/musl
+ if check_define __ANDROID__; then
+ rust_osvariant=android
+ android=yes
+ else
+ cat > $TMPC << EOF
+#define _GNU_SOURCE
+#include <features.h>
+#ifndef __USE_GNU
+error using musl
+#endif
+EOF
+ if compile_object; then
+ rust_osvariant=gnu
+ else
+ rust_osvariant=musl
+ fi
+ fi
+
+ case "$host_arch" in
+ arm)
+ # e.g. arm-unknown-linux-gnueabi, arm-unknown-linux-gnueabihf
+ write_c_skeleton
+ compile_object
+ if $READELF -A $TMPO | grep Tag_API_VFP_args: > /dev/null; then
+ rust_osvariant=${rust_osvariant}eabihf
+ else
+ rust_osvariant=${rust_osvariant}eabi
+ fi
+ ;;
+
+ mips64)
+ # e.g. mips64-unknown-linux-gnuabi64
+ rust_osvariant=${rust_osvariant}abi64
+ ;;
+ esac
+ ;;
+
+ netbsd)
+ # e.g. arm-unknown-netbsd-eabihf
+ test "$host_arch" = arm && rust_osvariant=eabihf
+ ;;
+
+ sunos)
+ rust_machine=pc
+ rust_os=solaris
+ ;;
+
+ windows)
+ # e.g. aarch64-pc-windows-gnullvm, x86_64-pc-windows-gnu (MSVC not supported)
+ rust_machine=pc
+ if test "$host_arch" = aarch64; then
+ rust_osvariant=gnullvm
+ else
+ rust_osvariant=gnu
+ fi
+ ;;
+ esac
+
+ # now tweak the architecture part, possibly based on pre-canonicalization --cpu
+ case "$host_arch" in
+ arm)
+ # preserve ISA version (armv7 etc.) from $raw_cpu if passed via --cpu
+ rust_arch=$raw_cpu
+ test "$rust_arch" = arm && test "$rust_os" != linux && rust_arch=armv7
+ ;;
+
+ mips|mips64)
+ # preserve ISA version (mipsisa64r6 etc.) and include endianness
+ rust_arch=${raw_cpu%el}
+ test "$bigendian" = no && rust_arch=${rust_arch}el
+ ;;
+
+ riscv32|riscv64)
+ # e.g. riscv64gc-unknown-linux-gnu, but riscv64-linux-android
+ test "$android" = no && rust_arch=${rust_arch}gc
+ ;;
+
+ sparc64)
+ if test "$rust_os" = solaris; then
+ rust_arch=sparcv9
+ rust_machine=sun
+ fi
+ ;;
+
+ x86_64)
+ # e.g. x86_64-unknown-linux-gnux32
+ test "$raw_cpu" = x32 && rust_osvariant=${rust_osvariant}x32
+ ;;
+ esac
+
+ if test "$android" = yes; then
+ # e.g. aarch64-linux-android
+ rust_target_triple=$rust_arch-$rust_os-$rust_osvariant
+ else
+ rust_target_triple=$rust_arch-$rust_machine-$rust_os${rust_osvariant:+-$rust_osvariant}
+ fi
+fi
+
+##########################################
# functions to probe cross compilers
container="no"
@@ -1246,9 +1418,9 @@ probe_target_compiler() {
target_arch=${1%%-*}
case $target_arch in
aarch64) container_hosts="x86_64 aarch64" ;;
+ aarch64_be) container_hosts="x86_64 aarch64" ;;
alpha) container_hosts=x86_64 ;;
arm) container_hosts="x86_64 aarch64" ;;
- cris) container_hosts=x86_64 ;;
hexagon) container_hosts=x86_64 ;;
hppa) container_hosts=x86_64 ;;
i386) container_hosts=x86_64 ;;
@@ -1276,6 +1448,10 @@ probe_target_compiler() {
case $target_arch in
# debian-all-test-cross architectures
+ aarch64_be)
+ container_image=debian-all-test-cross
+ container_cross_prefix=aarch64-linux-gnu-
+ ;;
hppa|m68k|mips|riscv64|sparc64)
container_image=debian-all-test-cross
;;
@@ -1307,9 +1483,6 @@ probe_target_compiler() {
container_image=debian-armhf-cross
container_cross_prefix=arm-linux-gnueabihf-
;;
- cris)
- container_image=fedora-cris-cross
- ;;
hexagon)
container_cross_prefix=hexagon-unknown-linux-musl-
container_cross_cc=${container_cross_prefix}clang
@@ -1326,7 +1499,7 @@ probe_target_compiler() {
container_cross_prefix=microblaze-linux-musl-
;;
mips64el)
- container_image=debian-mips64el-cross
+ container_image=debian-all-test-cross
container_cross_prefix=mips64el-linux-gnuabi64-
;;
tricore)
@@ -1604,6 +1777,9 @@ if test "$container" != no; then
echo "RUNC=$runc" >> $config_host_mak
fi
echo "SUBDIRS=$subdirs" >> $config_host_mak
+if test "$rust" != disabled; then
+ echo "RUST_TARGET_TRIPLE=$rust_target_triple" >> $config_host_mak
+fi
echo "PYTHON=$python" >> $config_host_mak
echo "MKVENV_ENSUREGROUP=$mkvenv ensuregroup $mkvenv_online_flag" >> $config_host_mak
echo "GENISOIMAGE=$genisoimage" >> $config_host_mak
@@ -1673,10 +1849,15 @@ for target in $target_list; do
echo "GDB=$gdb_bin" >> $config_target_mak
fi
- if test "${arch}" = "aarch64" && version_ge ${gdb_version##* } 15.0; then
+ if test "${gdb_arches#*aarch64}" != "$gdb_arches" && version_ge $gdb_version 15.1; then
echo "GDB_HAS_MTE=y" >> $config_target_mak
fi
+ if test "${gdb_arches#*aarch64}" != "$gdb_arches" && version_ge $gdb_version 16.0; then
+ # GDB has to support MTE in baremetal to allow debugging MTE in QEMU system mode
+ echo "GDB_SUPPORTS_MTE_IN_BAREMETAL=y" >> $config_target_mak
+ fi
+
echo "run-tcg-tests-$target: $qemu\$(EXESUF)" >> Makefile.prereqs
tcg_tests_targets="$tcg_tests_targets $target"
fi
@@ -1735,12 +1916,20 @@ if test "$skip_meson" = no; then
echo "c = [$(meson_quote $cc $CPU_CFLAGS)]" >> $cross
test -n "$cxx" && echo "cpp = [$(meson_quote $cxx $CPU_CFLAGS)]" >> $cross
test -n "$objcc" && echo "objc = [$(meson_quote $objcc $CPU_CFLAGS)]" >> $cross
+ if test "$rust" != disabled; then
+ if test "$rust_host_triple" != "$rust_target_triple"; then
+ echo "rust = [$(meson_quote $rustc --target "$rust_target_triple")]" >> $cross
+ else
+ echo "rust = [$(meson_quote $rustc)]" >> $cross
+ fi
+ fi
echo "ar = [$(meson_quote $ar)]" >> $cross
echo "dlltool = [$(meson_quote $dlltool)]" >> $cross
echo "nm = [$(meson_quote $nm)]" >> $cross
echo "pkgconfig = [$(meson_quote $pkg_config)]" >> $cross
echo "pkg-config = [$(meson_quote $pkg_config)]" >> $cross
echo "ranlib = [$(meson_quote $ranlib)]" >> $cross
+ echo "readelf = [$(meson_quote $readelf)]" >> $cross
if has $sdl2_config; then
echo "sdl2-config = [$(meson_quote $sdl2_config)]" >> $cross
fi
@@ -1770,6 +1959,9 @@ if test "$skip_meson" = no; then
echo "# Automatically generated by configure - do not modify" > $native
echo "[binaries]" >> $native
echo "c = [$(meson_quote $host_cc)]" >> $native
+ if test "$rust" != disabled; then
+ echo "rust = [$(meson_quote $rustc)]" >> $cross
+ fi
mv $native config-meson.native
meson_option_add --native-file
meson_option_add config-meson.native
@@ -1788,6 +1980,7 @@ if test "$skip_meson" = no; then
test "$pie" = no && meson_option_add -Db_pie=false
# QEMU options
+ test "$rust" != "disabled" && meson_option_add "-Drust=$rust"
test "$cfi" != false && meson_option_add "-Dcfi=$cfi" "-Db_lto=$cfi"
test "$docs" != auto && meson_option_add "-Ddocs=$docs"
test -n "${LIB_FUZZING_ENGINE+xxx}" && meson_option_add "-Dfuzzing_engine=$LIB_FUZZING_ENGINE"
@@ -1872,3 +2065,11 @@ echo ' "$@"' >>config.status
chmod +x config.status
rm -r "$TMPDIR1"
+
+if test "$rust" != disabled; then
+ echo
+ echo 'INFO: Rust bindings generation with `bindgen` might fail in some cases where'
+ echo 'the detected `libclang` does not match the expected `clang` version/target. In'
+ echo 'this case you must pass the path to `clang` and `libclang` to your build'
+ echo 'command invocation using the environment variables CLANG_PATH and LIBCLANG_PATH'
+fi
diff --git a/contrib/plugins/Makefile b/contrib/plugins/Makefile
index 449ead1..bbddd48 100644
--- a/contrib/plugins/Makefile
+++ b/contrib/plugins/Makefile
@@ -13,6 +13,7 @@ TOP_SRC_PATH = $(SRC_PATH)/../..
VPATH += $(SRC_PATH)
NAMES :=
+NAMES += bbv
NAMES += execlog
NAMES += hotblocks
NAMES += hotpages
@@ -28,6 +29,8 @@ NAMES += hwprofile
NAMES += cache
NAMES += drcov
NAMES += ips
+NAMES += stoptrigger
+NAMES += cflow
ifeq ($(CONFIG_WIN32),y)
SO_SUFFIX := .dll
@@ -38,30 +41,45 @@ endif
SONAMES := $(addsuffix $(SO_SUFFIX),$(addprefix lib,$(NAMES)))
-# The main QEMU uses Glib extensively so it's perfectly fine to use it
+# The main QEMU uses Glib extensively so it is perfectly fine to use it
# in plugins (which many example do).
PLUGIN_CFLAGS := $(shell $(PKG_CONFIG) --cflags glib-2.0)
PLUGIN_CFLAGS += -fPIC -Wall
PLUGIN_CFLAGS += -I$(TOP_SRC_PATH)/include/qemu
+# Helper that honours V=1 so we get some output when compiling
+quiet-@ = $(if $(V),,@$(if $1,printf " %-7s %s\n" "$(strip $1)" "$(strip $2)" && ))
+quiet-command = $(call quiet-@,$2,$3)$1
+
+# for including , in command strings
+COMMA := ,
+
all: $(SONAMES)
%.o: %.c
- $(CC) $(CFLAGS) $(PLUGIN_CFLAGS) -c -o $@ $<
+ $(call quiet-command, \
+ $(CC) $(CFLAGS) $(PLUGIN_CFLAGS) -c -o $@ $<, \
+ BUILD, plugin $@)
ifeq ($(CONFIG_WIN32),y)
lib%$(SO_SUFFIX): %.o win32_linker.o ../../plugins/libqemu_plugin_api.a
- $(CC) -shared -o $@ $^ $(LDLIBS)
+ $(call quiet-command, \
+ $(CC) -shared -o $@ $^ $(LDLIBS), \
+ LINK, plugin $@)
else ifeq ($(CONFIG_DARWIN),y)
lib%$(SO_SUFFIX): %.o
- $(CC) -bundle -Wl,-undefined,dynamic_lookup -o $@ $^ $(LDLIBS)
+ $(call quiet-command, \
+ $(CC) -bundle -Wl$(COMMA)-undefined$(COMMA)dynamic_lookup -o $@ $^ $(LDLIBS), \
+ LINK, plugin $@)
else
lib%$(SO_SUFFIX): %.o
- $(CC) -shared -o $@ $^ $(LDLIBS)
+ $(call quiet-command, \
+ $(CC) -shared -o $@ $^ $(LDLIBS), \
+ LINK, plugin $@)
endif
-clean:
+clean distclean:
rm -f *.o *$(SO_SUFFIX) *.d
rm -Rf .libs
diff --git a/contrib/plugins/bbv.c b/contrib/plugins/bbv.c
new file mode 100644
index 0000000..a525651
--- /dev/null
+++ b/contrib/plugins/bbv.c
@@ -0,0 +1,158 @@
+/*
+ * Generate basic block vectors for use with the SimPoint analysis tool.
+ * SimPoint: https://cseweb.ucsd.edu/~calder/simpoint/
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <stdio.h>
+#include <glib.h>
+
+#include <qemu-plugin.h>
+
+typedef struct Bb {
+ uint64_t vaddr;
+ struct qemu_plugin_scoreboard *count;
+ unsigned int index;
+} Bb;
+
+typedef struct Vcpu {
+ uint64_t count;
+ FILE *file;
+} Vcpu;
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
+static GHashTable *bbs;
+static GRWLock bbs_lock;
+static char *filename;
+static struct qemu_plugin_scoreboard *vcpus;
+static uint64_t interval = 100000000;
+
+static void plugin_exit(qemu_plugin_id_t id, void *p)
+{
+ for (int i = 0; i < qemu_plugin_num_vcpus(); i++) {
+ fclose(((Vcpu *)qemu_plugin_scoreboard_find(vcpus, i))->file);
+ }
+
+ g_hash_table_unref(bbs);
+ g_free(filename);
+ qemu_plugin_scoreboard_free(vcpus);
+}
+
+static void free_bb(void *data)
+{
+ qemu_plugin_scoreboard_free(((Bb *)data)->count);
+ g_free(data);
+}
+
+static qemu_plugin_u64 count_u64(void)
+{
+ return qemu_plugin_scoreboard_u64_in_struct(vcpus, Vcpu, count);
+}
+
+static qemu_plugin_u64 bb_count_u64(Bb *bb)
+{
+ return qemu_plugin_scoreboard_u64(bb->count);
+}
+
+static void vcpu_init(qemu_plugin_id_t id, unsigned int vcpu_index)
+{
+ g_autofree gchar *vcpu_filename = NULL;
+ Vcpu *vcpu = qemu_plugin_scoreboard_find(vcpus, vcpu_index);
+
+ vcpu_filename = g_strdup_printf("%s.%u.bb", filename, vcpu_index);
+ vcpu->file = fopen(vcpu_filename, "w");
+}
+
+static void vcpu_interval_exec(unsigned int vcpu_index, void *udata)
+{
+ Vcpu *vcpu = qemu_plugin_scoreboard_find(vcpus, vcpu_index);
+ GHashTableIter iter;
+ void *value;
+
+ if (!vcpu->file) {
+ return;
+ }
+
+ vcpu->count -= interval;
+
+ fputc('T', vcpu->file);
+
+ g_rw_lock_reader_lock(&bbs_lock);
+ g_hash_table_iter_init(&iter, bbs);
+
+ while (g_hash_table_iter_next(&iter, NULL, &value)) {
+ Bb *bb = value;
+ uint64_t bb_count = qemu_plugin_u64_get(bb_count_u64(bb), vcpu_index);
+
+ if (!bb_count) {
+ continue;
+ }
+
+ fprintf(vcpu->file, ":%u:%" PRIu64 " ", bb->index, bb_count);
+ qemu_plugin_u64_set(bb_count_u64(bb), vcpu_index, 0);
+ }
+
+ g_rw_lock_reader_unlock(&bbs_lock);
+ fputc('\n', vcpu->file);
+}
+
+static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
+{
+ uint64_t n_insns = qemu_plugin_tb_n_insns(tb);
+ uint64_t vaddr = qemu_plugin_tb_vaddr(tb);
+ Bb *bb;
+
+ g_rw_lock_writer_lock(&bbs_lock);
+ bb = g_hash_table_lookup(bbs, &vaddr);
+ if (!bb) {
+ bb = g_new(Bb, 1);
+ bb->vaddr = vaddr;
+ bb->count = qemu_plugin_scoreboard_new(sizeof(uint64_t));
+ bb->index = g_hash_table_size(bbs);
+ g_hash_table_replace(bbs, &bb->vaddr, bb);
+ }
+ g_rw_lock_writer_unlock(&bbs_lock);
+
+ qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(
+ tb, QEMU_PLUGIN_INLINE_ADD_U64, count_u64(), n_insns);
+
+ qemu_plugin_register_vcpu_tb_exec_inline_per_vcpu(
+ tb, QEMU_PLUGIN_INLINE_ADD_U64, bb_count_u64(bb), n_insns);
+
+ qemu_plugin_register_vcpu_tb_exec_cond_cb(
+ tb, vcpu_interval_exec, QEMU_PLUGIN_CB_NO_REGS,
+ QEMU_PLUGIN_COND_GE, count_u64(), interval, NULL);
+}
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
+ const qemu_info_t *info,
+ int argc, char **argv)
+{
+ for (int i = 0; i < argc; i++) {
+ char *opt = argv[i];
+ g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
+ if (g_strcmp0(tokens[0], "interval") == 0) {
+ interval = g_ascii_strtoull(tokens[1], NULL, 10);
+ } else if (g_strcmp0(tokens[0], "outfile") == 0) {
+ filename = tokens[1];
+ tokens[1] = NULL;
+ } else {
+ fprintf(stderr, "option parsing failed: %s\n", opt);
+ return -1;
+ }
+ }
+
+ if (!filename) {
+ fputs("outfile unspecified\n", stderr);
+ return -1;
+ }
+
+ bbs = g_hash_table_new_full(g_int64_hash, g_int64_equal, NULL, free_bb);
+ vcpus = qemu_plugin_scoreboard_new(sizeof(Vcpu));
+ qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
+ qemu_plugin_register_vcpu_init_cb(id, vcpu_init);
+ qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
+
+ return 0;
+}
diff --git a/contrib/plugins/cache.c b/contrib/plugins/cache.c
index c5c8ac7..512ef67 100644
--- a/contrib/plugins/cache.c
+++ b/contrib/plugins/cache.c
@@ -558,7 +558,7 @@ static void append_stats_line(GString *line,
" %-12" PRIu64 " %-11" PRIu64 " %10.4lf%%",
l2_access,
l2_misses,
- l2_access ? l2_miss_rate : 0.0);
+ l2_miss_rate);
}
g_string_append(line, "\n");
diff --git a/contrib/plugins/cflow.c b/contrib/plugins/cflow.c
new file mode 100644
index 0000000..6faa55d
--- /dev/null
+++ b/contrib/plugins/cflow.c
@@ -0,0 +1,388 @@
+/*
+ * Control Flow plugin
+ *
+ * This plugin will track changes to control flow and detect where
+ * instructions fault.
+ *
+ * Copyright (c) 2024 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <glib.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <qemu-plugin.h>
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
+
+typedef enum {
+ SORT_HOTTEST, /* hottest branch insn */
+ SORT_EXCEPTION, /* most early exits */
+ SORT_POPDEST, /* most destinations (usually ret's) */
+} ReportType;
+
+ReportType report = SORT_HOTTEST;
+int topn = 10;
+
+typedef struct {
+ uint64_t daddr;
+ uint64_t dcount;
+} DestData;
+
+/* A node is an address where we can go to multiple places */
+typedef struct {
+ GMutex lock;
+ /* address of the branch point */
+ uint64_t addr;
+ /* array of DestData */
+ GArray *dests;
+ /* early exit/fault count */
+ uint64_t early_exit;
+ /* jump destination count */
+ uint64_t dest_count;
+ /* instruction data */
+ char *insn_disas;
+ /* symbol? */
+ const char *symbol;
+ /* times translated as last in block? */
+ int last_count;
+ /* times translated in the middle of block? */
+ int mid_count;
+} NodeData;
+
+typedef enum {
+ /* last insn in block, expected flow control */
+ LAST_INSN = (1 << 0),
+ /* mid-block insn, can only be an exception */
+ EXCP_INSN = (1 << 1),
+ /* multiple disassembly, may have changed */
+ MULT_INSN = (1 << 2),
+} InsnTypes;
+
+typedef struct {
+ /* address of the branch point */
+ uint64_t addr;
+ /* disassembly */
+ char *insn_disas;
+ /* symbol? */
+ const char *symbol;
+ /* types */
+ InsnTypes type_flag;
+} InsnData;
+
+/* We use this to track the current execution state */
+typedef struct {
+ /* address of end of block */
+ uint64_t end_block;
+ /* next pc after end of block */
+ uint64_t pc_after_block;
+ /* address of last executed PC */
+ uint64_t last_pc;
+} VCPUScoreBoard;
+
+/* descriptors for accessing the above scoreboard */
+static qemu_plugin_u64 end_block;
+static qemu_plugin_u64 pc_after_block;
+static qemu_plugin_u64 last_pc;
+
+
+static GMutex node_lock;
+static GHashTable *nodes;
+struct qemu_plugin_scoreboard *state;
+
+/* SORT_HOTTEST */
+static gint hottest(gconstpointer a, gconstpointer b)
+{
+ NodeData *na = (NodeData *) a;
+ NodeData *nb = (NodeData *) b;
+
+ return na->dest_count > nb->dest_count ? -1 :
+ na->dest_count == nb->dest_count ? 0 : 1;
+}
+
+static gint exception(gconstpointer a, gconstpointer b)
+{
+ NodeData *na = (NodeData *) a;
+ NodeData *nb = (NodeData *) b;
+
+ return na->early_exit > nb->early_exit ? -1 :
+ na->early_exit == nb->early_exit ? 0 : 1;
+}
+
+static gint popular(gconstpointer a, gconstpointer b)
+{
+ NodeData *na = (NodeData *) a;
+ NodeData *nb = (NodeData *) b;
+
+ return na->dests->len > nb->dests->len ? -1 :
+ na->dests->len == nb->dests->len ? 0 : 1;
+}
+
+/* Filter out non-branches - returns true to remove entry */
+static gboolean filter_non_branches(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ NodeData *node = (NodeData *) value;
+
+ return node->dest_count == 0;
+}
+
+static void plugin_exit(qemu_plugin_id_t id, void *p)
+{
+ g_autoptr(GString) result = g_string_new("collected ");
+ GList *data;
+ GCompareFunc sort = &hottest;
+ int n = 0;
+
+ g_mutex_lock(&node_lock);
+ g_string_append_printf(result, "%d control flow nodes in the hash table\n",
+ g_hash_table_size(nodes));
+
+ /* remove all nodes that didn't branch */
+ g_hash_table_foreach_remove(nodes, filter_non_branches, NULL);
+
+ data = g_hash_table_get_values(nodes);
+
+ switch (report) {
+ case SORT_HOTTEST:
+ sort = &hottest;
+ break;
+ case SORT_EXCEPTION:
+ sort = &exception;
+ break;
+ case SORT_POPDEST:
+ sort = &popular;
+ break;
+ }
+
+ data = g_list_sort(data, sort);
+
+ for (GList *l = data;
+ l != NULL && n < topn;
+ l = l->next, n++) {
+ NodeData *n = l->data;
+ const char *type = n->mid_count ? "sync fault" : "branch";
+ g_string_append_printf(result, " addr: 0x%"PRIx64 " %s: %s (%s)\n",
+ n->addr, n->symbol, n->insn_disas, type);
+ if (n->early_exit) {
+ g_string_append_printf(result, " early exits %"PRId64"\n",
+ n->early_exit);
+ }
+ g_string_append_printf(result, " branches %"PRId64"\n",
+ n->dest_count);
+ for (int j = 0; j < n->dests->len; j++) {
+ DestData *dd = &g_array_index(n->dests, DestData, j);
+ g_string_append_printf(result, " to 0x%"PRIx64" (%"PRId64")\n",
+ dd->daddr, dd->dcount);
+ }
+ }
+
+ qemu_plugin_outs(result->str);
+
+ g_mutex_unlock(&node_lock);
+}
+
+static void plugin_init(void)
+{
+ g_mutex_init(&node_lock);
+ nodes = g_hash_table_new(NULL, g_direct_equal);
+ state = qemu_plugin_scoreboard_new(sizeof(VCPUScoreBoard));
+
+ /* score board declarations */
+ end_block = qemu_plugin_scoreboard_u64_in_struct(state, VCPUScoreBoard,
+ end_block);
+ pc_after_block = qemu_plugin_scoreboard_u64_in_struct(state, VCPUScoreBoard,
+ pc_after_block);
+ last_pc = qemu_plugin_scoreboard_u64_in_struct(state, VCPUScoreBoard,
+ last_pc);
+}
+
+static NodeData *create_node(uint64_t addr)
+{
+ NodeData *node = g_new0(NodeData, 1);
+ g_mutex_init(&node->lock);
+ node->addr = addr;
+ node->dests = g_array_new(true, true, sizeof(DestData));
+ return node;
+}
+
+static NodeData *fetch_node(uint64_t addr, bool create_if_not_found)
+{
+ NodeData *node = NULL;
+
+ g_mutex_lock(&node_lock);
+ node = (NodeData *) g_hash_table_lookup(nodes, (gconstpointer) addr);
+ if (!node && create_if_not_found) {
+ node = create_node(addr);
+ g_hash_table_insert(nodes, (gpointer) addr, (gpointer) node);
+ }
+ g_mutex_unlock(&node_lock);
+ return node;
+}
+
+/*
+ * Called when we detect a non-linear execution (pc !=
+ * pc_after_block). This could be due to a fault causing some sort of
+ * exit exception (if last_pc != block_end) or just a taken branch.
+ */
+static void vcpu_tb_branched_exec(unsigned int cpu_index, void *udata)
+{
+ uint64_t lpc = qemu_plugin_u64_get(last_pc, cpu_index);
+ uint64_t ebpc = qemu_plugin_u64_get(end_block, cpu_index);
+ uint64_t npc = qemu_plugin_u64_get(pc_after_block, cpu_index);
+ uint64_t pc = GPOINTER_TO_UINT(udata);
+
+ /* return early for address 0 */
+ if (!lpc) {
+ return;
+ }
+
+ NodeData *node = fetch_node(lpc, true);
+ DestData *data = NULL;
+ bool early_exit = (lpc != ebpc);
+ GArray *dests;
+
+ /* the condition should never hit */
+ g_assert(pc != npc);
+
+ g_mutex_lock(&node->lock);
+
+ if (early_exit) {
+ fprintf(stderr, "%s: pc=%"PRIx64", epbc=%"PRIx64
+ " npc=%"PRIx64", lpc=%"PRIx64"\n",
+ __func__, pc, ebpc, npc, lpc);
+ node->early_exit++;
+ if (!node->mid_count) {
+ /* count now as we've only just allocated */
+ node->mid_count++;
+ }
+ }
+
+ dests = node->dests;
+ for (int i = 0; i < dests->len; i++) {
+ if (g_array_index(dests, DestData, i).daddr == pc) {
+ data = &g_array_index(dests, DestData, i);
+ }
+ }
+
+ /* we've never seen this before, allocate a new entry */
+ if (!data) {
+ DestData new_entry = { .daddr = pc };
+ g_array_append_val(dests, new_entry);
+ data = &g_array_index(dests, DestData, dests->len - 1);
+ g_assert(data->daddr == pc);
+ }
+
+ data->dcount++;
+ node->dest_count++;
+
+ g_mutex_unlock(&node->lock);
+}
+
+/*
+ * At the start of each block we need to resolve two things:
+ *
+ * - is last_pc == block_end, if not we had an early exit
+ * - is start of block last_pc + insn width, if not we jumped
+ *
+ * Once those are dealt with we can instrument the rest of the
+ * instructions for their execution.
+ *
+ */
+static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
+{
+ uint64_t pc = qemu_plugin_tb_vaddr(tb);
+ size_t insns = qemu_plugin_tb_n_insns(tb);
+ struct qemu_plugin_insn *first_insn = qemu_plugin_tb_get_insn(tb, 0);
+ struct qemu_plugin_insn *last_insn = qemu_plugin_tb_get_insn(tb, insns - 1);
+
+ /*
+ * check if we are executing linearly after the last block. We can
+ * handle both early block exits and normal branches in the
+ * callback if we hit it.
+ */
+ gpointer udata = GUINT_TO_POINTER(pc);
+ qemu_plugin_register_vcpu_tb_exec_cond_cb(
+ tb, vcpu_tb_branched_exec, QEMU_PLUGIN_CB_NO_REGS,
+ QEMU_PLUGIN_COND_NE, pc_after_block, pc, udata);
+
+ /*
+ * Now we can set start/end for this block so the next block can
+ * check where we are at. Do this on the first instruction and not
+ * the TB so we don't get mixed up with above.
+ */
+ qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(first_insn,
+ QEMU_PLUGIN_INLINE_STORE_U64,
+ end_block, qemu_plugin_insn_vaddr(last_insn));
+ qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(first_insn,
+ QEMU_PLUGIN_INLINE_STORE_U64,
+ pc_after_block,
+ qemu_plugin_insn_vaddr(last_insn) +
+ qemu_plugin_insn_size(last_insn));
+
+ for (int idx = 0; idx < qemu_plugin_tb_n_insns(tb); ++idx) {
+ struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, idx);
+ uint64_t ipc = qemu_plugin_insn_vaddr(insn);
+ /*
+ * If this is a potential branch point check if we could grab
+ * the disassembly for it. If it is the last instruction
+ * always create an entry.
+ */
+ NodeData *node = fetch_node(ipc, last_insn);
+ if (node) {
+ g_mutex_lock(&node->lock);
+ if (!node->insn_disas) {
+ node->insn_disas = qemu_plugin_insn_disas(insn);
+ }
+ if (!node->symbol) {
+ node->symbol = qemu_plugin_insn_symbol(insn);
+ }
+ if (last_insn == insn) {
+ node->last_count++;
+ } else {
+ node->mid_count++;
+ }
+ g_mutex_unlock(&node->lock);
+ }
+
+ /* Store the PC of what we are about to execute */
+ qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(insn,
+ QEMU_PLUGIN_INLINE_STORE_U64,
+ last_pc, ipc);
+ }
+}
+
+QEMU_PLUGIN_EXPORT
+int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info,
+ int argc, char **argv)
+{
+ for (int i = 0; i < argc; i++) {
+ char *opt = argv[i];
+ g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
+ if (g_strcmp0(tokens[0], "sort") == 0) {
+ if (g_strcmp0(tokens[1], "hottest") == 0) {
+ report = SORT_HOTTEST;
+ } else if (g_strcmp0(tokens[1], "early") == 0) {
+ report = SORT_EXCEPTION;
+ } else if (g_strcmp0(tokens[1], "exceptions") == 0) {
+ report = SORT_POPDEST;
+ } else {
+ fprintf(stderr, "failed to parse: %s\n", tokens[1]);
+ return -1;
+ }
+ } else {
+ fprintf(stderr, "option parsing failed: %s\n", opt);
+ return -1;
+ }
+ }
+
+ plugin_init();
+
+ qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
+ qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
+ return 0;
+}
diff --git a/contrib/plugins/execlog.c b/contrib/plugins/execlog.c
index 371db97..d67d010 100644
--- a/contrib/plugins/execlog.c
+++ b/contrib/plugins/execlog.c
@@ -101,7 +101,7 @@ static void insn_check_regs(CPU *cpu)
GByteArray *temp = reg->last;
g_string_append_printf(cpu->last_exec, ", %s -> 0x", reg->name);
/* TODO: handle BE properly */
- for (int i = sz; i >= 0; i--) {
+ for (int i = sz - 1; i >= 0; i--) {
g_string_append_printf(cpu->last_exec, "%02x",
reg->new->data[i]);
}
@@ -181,8 +181,8 @@ static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
bool check_regs_this = rmatches;
bool check_regs_next = false;
- size_t n = qemu_plugin_tb_n_insns(tb);
- for (size_t i = 0; i < n; i++) {
+ size_t n_insns = qemu_plugin_tb_n_insns(tb);
+ for (size_t i = 0; i < n_insns; i++) {
char *insn_disas;
uint64_t insn_vaddr;
diff --git a/contrib/plugins/ips.c b/contrib/plugins/ips.c
index 29fa556..e5297db 100644
--- a/contrib/plugins/ips.c
+++ b/contrib/plugins/ips.c
@@ -152,6 +152,12 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
vcpus = qemu_plugin_scoreboard_new(sizeof(vCPUTime));
max_insn_per_quantum = max_insn_per_second / NUM_TIME_UPDATE_PER_SEC;
+ if (max_insn_per_quantum == 0) {
+ fprintf(stderr, "minimum of %d instructions per second needed\n",
+ NUM_TIME_UPDATE_PER_SEC);
+ return -1;
+ }
+
time_handle = qemu_plugin_request_time_control();
g_assert(time_handle);
diff --git a/contrib/plugins/lockstep.c b/contrib/plugins/lockstep.c
index 6a7e9bb..62981d4 100644
--- a/contrib/plugins/lockstep.c
+++ b/contrib/plugins/lockstep.c
@@ -101,6 +101,31 @@ static void plugin_exit(qemu_plugin_id_t id, void *p)
plugin_cleanup(id);
}
+/*
+ * g_memdup has been deprecated in Glib since 2.68 and
+ * will complain about it if you try to use it. However until
+ * glib_req_ver for QEMU is bumped we make a copy of the glib-compat
+ * handler.
+ */
+static inline gpointer g_memdup2_qemu(gconstpointer mem, gsize byte_size)
+{
+#if GLIB_CHECK_VERSION(2, 68, 0)
+ return g_memdup2(mem, byte_size);
+#else
+ gpointer new_mem;
+
+ if (mem && byte_size != 0) {
+ new_mem = g_malloc(byte_size);
+ memcpy(new_mem, mem, byte_size);
+ } else {
+ new_mem = NULL;
+ }
+
+ return new_mem;
+#endif
+}
+#define g_memdup2(m, s) g_memdup2_qemu(m, s)
+
static void report_divergance(ExecState *us, ExecState *them)
{
DivergeState divrec = { log, 0 };
diff --git a/contrib/plugins/stoptrigger.c b/contrib/plugins/stoptrigger.c
new file mode 100644
index 0000000..03ee22f
--- /dev/null
+++ b/contrib/plugins/stoptrigger.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2024, Simon Hamelin <simon.hamelin@grenoble-inp.org>
+ *
+ * Stop execution once a given address is reached or if the
+ * count of executed instructions reached a specified limit
+ *
+ * License: GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <assert.h>
+#include <glib.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <qemu-plugin.h>
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
+
+/* Scoreboard to track executed instructions count */
+typedef struct {
+ uint64_t insn_count;
+} InstructionsCount;
+static struct qemu_plugin_scoreboard *insn_count_sb;
+static qemu_plugin_u64 insn_count;
+
+static uint64_t icount;
+static int icount_exit_code;
+
+static bool exit_on_icount;
+static bool exit_on_address;
+
+/* Map trigger addresses to exit code */
+static GHashTable *addrs_ht;
+
+static void exit_emulation(int return_code, char *message)
+{
+ qemu_plugin_outs(message);
+ g_free(message);
+ exit(return_code);
+}
+
+static void exit_icount_reached(unsigned int cpu_index, void *udata)
+{
+ uint64_t insn_vaddr = GPOINTER_TO_UINT(udata);
+ char *msg = g_strdup_printf("icount reached at 0x%" PRIx64 ", exiting\n",
+ insn_vaddr);
+
+ exit_emulation(icount_exit_code, msg);
+}
+
+static void exit_address_reached(unsigned int cpu_index, void *udata)
+{
+ uint64_t insn_vaddr = GPOINTER_TO_UINT(udata);
+ char *msg = g_strdup_printf("0x%" PRIx64 " reached, exiting\n", insn_vaddr);
+ int exit_code;
+
+ exit_code = GPOINTER_TO_INT(
+ g_hash_table_lookup(addrs_ht, GUINT_TO_POINTER(insn_vaddr)));
+
+ exit_emulation(exit_code, msg);
+}
+
+static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
+{
+ size_t tb_n = qemu_plugin_tb_n_insns(tb);
+ for (size_t i = 0; i < tb_n; i++) {
+ struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
+ gpointer insn_vaddr = GUINT_TO_POINTER(qemu_plugin_insn_vaddr(insn));
+
+ if (exit_on_icount) {
+ /* Increment and check scoreboard for each instruction */
+ qemu_plugin_register_vcpu_insn_exec_inline_per_vcpu(
+ insn, QEMU_PLUGIN_INLINE_ADD_U64, insn_count, 1);
+ qemu_plugin_register_vcpu_insn_exec_cond_cb(
+ insn, exit_icount_reached, QEMU_PLUGIN_CB_NO_REGS,
+ QEMU_PLUGIN_COND_EQ, insn_count, icount + 1, insn_vaddr);
+ }
+
+ if (exit_on_address) {
+ if (g_hash_table_contains(addrs_ht, insn_vaddr)) {
+ /* Exit triggered by address */
+ qemu_plugin_register_vcpu_insn_exec_cb(
+ insn, exit_address_reached, QEMU_PLUGIN_CB_NO_REGS,
+ insn_vaddr);
+ }
+ }
+ }
+}
+
+static void plugin_exit(qemu_plugin_id_t id, void *p)
+{
+ g_hash_table_destroy(addrs_ht);
+ qemu_plugin_scoreboard_free(insn_count_sb);
+}
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
+ const qemu_info_t *info, int argc,
+ char **argv)
+{
+ addrs_ht = g_hash_table_new(NULL, g_direct_equal);
+
+ insn_count_sb = qemu_plugin_scoreboard_new(sizeof(InstructionsCount));
+ insn_count = qemu_plugin_scoreboard_u64_in_struct(
+ insn_count_sb, InstructionsCount, insn_count);
+
+ for (int i = 0; i < argc; i++) {
+ char *opt = argv[i];
+ g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
+ if (g_strcmp0(tokens[0], "icount") == 0) {
+ g_auto(GStrv) icount_tokens = g_strsplit(tokens[1], ":", 2);
+ icount = g_ascii_strtoull(icount_tokens[0], NULL, 0);
+ if (icount < 1 || g_strrstr(icount_tokens[0], "-") != NULL) {
+ fprintf(stderr,
+ "icount parsing failed: '%s' must be a positive "
+ "integer\n",
+ icount_tokens[0]);
+ return -1;
+ }
+ if (icount_tokens[1]) {
+ icount_exit_code = g_ascii_strtoull(icount_tokens[1], NULL, 0);
+ }
+ exit_on_icount = true;
+ } else if (g_strcmp0(tokens[0], "addr") == 0) {
+ g_auto(GStrv) addr_tokens = g_strsplit(tokens[1], ":", 2);
+ uint64_t exit_addr = g_ascii_strtoull(addr_tokens[0], NULL, 0);
+ int exit_code = 0;
+ if (addr_tokens[1]) {
+ exit_code = g_ascii_strtoull(addr_tokens[1], NULL, 0);
+ }
+ g_hash_table_insert(addrs_ht, GUINT_TO_POINTER(exit_addr),
+ GINT_TO_POINTER(exit_code));
+ exit_on_address = true;
+ } else {
+ fprintf(stderr, "option parsing failed: %s\n", opt);
+ return -1;
+ }
+ }
+
+ if (!exit_on_icount && !exit_on_address) {
+ fprintf(stderr, "'icount' or 'addr' argument missing\n");
+ return -1;
+ }
+
+ /* Register translation block and exit callbacks */
+ qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
+ qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
+
+ return 0;
+}
diff --git a/contrib/systemd/qemu-vmsr-helper.service b/contrib/systemd/qemu-vmsr-helper.service
new file mode 100644
index 0000000..8fd397b
--- /dev/null
+++ b/contrib/systemd/qemu-vmsr-helper.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=Virtual RAPL MSR Daemon for QEMU
+
+[Service]
+WorkingDirectory=/tmp
+Type=simple
+ExecStart=/usr/bin/qemu-vmsr-helper
+PrivateTmp=yes
+ProtectSystem=strict
+ReadWritePaths=/var/run
+RestrictAddressFamilies=AF_UNIX
+Restart=always
+RestartSec=0
+
+[Install]
diff --git a/contrib/systemd/qemu-vmsr-helper.socket b/contrib/systemd/qemu-vmsr-helper.socket
new file mode 100644
index 0000000..183e830
--- /dev/null
+++ b/contrib/systemd/qemu-vmsr-helper.socket
@@ -0,0 +1,9 @@
+[Unit]
+Description=Virtual RAPL MSR helper for QEMU
+
+[Socket]
+ListenStream=/run/qemu-vmsr-helper.sock
+SocketMode=0600
+
+[Install]
+WantedBy=multi-user.target
diff --git a/contrib/vhost-user-blk/vhost-user-blk.c b/contrib/vhost-user-blk/vhost-user-blk.c
index 9492146..6cc18a1 100644
--- a/contrib/vhost-user-blk/vhost-user-blk.c
+++ b/contrib/vhost-user-blk/vhost-user-blk.c
@@ -196,7 +196,7 @@ vub_discard_write_zeroes(VubReq *req, struct iovec *iov, uint32_t iovcnt,
VubDev *vdev_blk = req->vdev_blk;
desc = buf;
uint64_t range[2] = { le64_to_cpu(desc->sector) << 9,
- le32_to_cpu(desc->num_sectors) << 9 };
+ (uint64_t)le32_to_cpu(desc->num_sectors) << 9 };
if (type == VIRTIO_BLK_T_DISCARD) {
if (ioctl(vdev_blk->blk_fd, BLKDISCARD, range) == 0) {
g_free(buf);
diff --git a/cpu-common.c b/cpu-common.c
index 7ae136f..6b26223 100644
--- a/cpu-common.c
+++ b/cpu-common.c
@@ -57,14 +57,12 @@ void cpu_list_unlock(void)
qemu_mutex_unlock(&qemu_cpu_list_lock);
}
-static bool cpu_index_auto_assigned;
-static int cpu_get_free_index(void)
+int cpu_get_free_index(void)
{
CPUState *some_cpu;
int max_cpu_index = 0;
- cpu_index_auto_assigned = true;
CPU_FOREACH(some_cpu) {
if (some_cpu->cpu_index >= max_cpu_index) {
max_cpu_index = some_cpu->cpu_index + 1;
@@ -83,8 +81,11 @@ unsigned int cpu_list_generation_id_get(void)
void cpu_list_add(CPUState *cpu)
{
+ static bool cpu_index_auto_assigned;
+
QEMU_LOCK_GUARD(&qemu_cpu_list_lock);
if (cpu->cpu_index == UNASSIGNED_CPU_INDEX) {
+ cpu_index_auto_assigned = true;
cpu->cpu_index = cpu_get_free_index();
assert(cpu->cpu_index != UNASSIGNED_CPU_INDEX);
} else {
diff --git a/crypto/afalg.c b/crypto/afalg.c
index 52a491d..246d067 100644
--- a/crypto/afalg.c
+++ b/crypto/afalg.c
@@ -66,13 +66,13 @@ qcrypto_afalg_socket_bind(const char *type, const char *name,
return sbind;
}
-QCryptoAFAlg *
+QCryptoAFAlgo *
qcrypto_afalg_comm_alloc(const char *type, const char *name,
Error **errp)
{
- QCryptoAFAlg *afalg;
+ QCryptoAFAlgo *afalg;
- afalg = g_new0(QCryptoAFAlg, 1);
+ afalg = g_new0(QCryptoAFAlgo, 1);
/* initialize crypto API socket */
afalg->opfd = -1;
afalg->tfmfd = qcrypto_afalg_socket_bind(type, name, errp);
@@ -93,7 +93,7 @@ error:
return NULL;
}
-void qcrypto_afalg_comm_free(QCryptoAFAlg *afalg)
+void qcrypto_afalg_comm_free(QCryptoAFAlgo *afalg)
{
if (!afalg) {
return;
diff --git a/crypto/afalgpriv.h b/crypto/afalgpriv.h
index 5a2393f..3fdcc0f 100644
--- a/crypto/afalgpriv.h
+++ b/crypto/afalgpriv.h
@@ -30,9 +30,9 @@
#define ALG_OPTYPE_LEN 4
#define ALG_MSGIV_LEN(len) (sizeof(struct af_alg_iv) + (len))
-typedef struct QCryptoAFAlg QCryptoAFAlg;
+typedef struct QCryptoAFAlgo QCryptoAFAlgo;
-struct QCryptoAFAlg {
+struct QCryptoAFAlgo {
QCryptoCipher base;
int tfmfd;
@@ -46,22 +46,22 @@ struct QCryptoAFAlg {
* @type: the type of crypto operation
* @name: the name of crypto operation
*
- * Allocate a QCryptoAFAlg object and bind itself to
+ * Allocate a QCryptoAFAlgo object and bind itself to
* a AF_ALG socket.
*
* Returns:
- * a new QCryptoAFAlg object, or NULL in error.
+ * a new QCryptoAFAlgo object, or NULL in error.
*/
-QCryptoAFAlg *
+QCryptoAFAlgo *
qcrypto_afalg_comm_alloc(const char *type, const char *name,
Error **errp);
/**
* afalg_comm_free:
- * @afalg: the QCryptoAFAlg object
+ * @afalg: the QCryptoAFAlgo object
*
* Free the @afalg.
*/
-void qcrypto_afalg_comm_free(QCryptoAFAlg *afalg);
+void qcrypto_afalg_comm_free(QCryptoAFAlgo *afalg);
#endif
diff --git a/crypto/afsplit.c b/crypto/afsplit.c
index b1a5a20..b2e383a 100644
--- a/crypto/afsplit.c
+++ b/crypto/afsplit.c
@@ -40,7 +40,7 @@ static void qcrypto_afsplit_xor(size_t blocklen,
}
-static int qcrypto_afsplit_hash(QCryptoHashAlgorithm hash,
+static int qcrypto_afsplit_hash(QCryptoHashAlgo hash,
size_t blocklen,
uint8_t *block,
Error **errp)
@@ -85,7 +85,7 @@ static int qcrypto_afsplit_hash(QCryptoHashAlgorithm hash,
}
-int qcrypto_afsplit_encode(QCryptoHashAlgorithm hash,
+int qcrypto_afsplit_encode(QCryptoHashAlgo hash,
size_t blocklen,
uint32_t stripes,
const uint8_t *in,
@@ -117,7 +117,7 @@ int qcrypto_afsplit_encode(QCryptoHashAlgorithm hash,
}
-int qcrypto_afsplit_decode(QCryptoHashAlgorithm hash,
+int qcrypto_afsplit_decode(QCryptoHashAlgo hash,
size_t blocklen,
uint32_t stripes,
const uint8_t *in,
diff --git a/crypto/akcipher-gcrypt.c.inc b/crypto/akcipher-gcrypt.c.inc
index abb1fb2..5a880f6 100644
--- a/crypto/akcipher-gcrypt.c.inc
+++ b/crypto/akcipher-gcrypt.c.inc
@@ -32,8 +32,8 @@
typedef struct QCryptoGcryptRSA {
QCryptoAkCipher akcipher;
gcry_sexp_t key;
- QCryptoRSAPaddingAlgorithm padding_alg;
- QCryptoHashAlgorithm hash_alg;
+ QCryptoRSAPaddingAlgo padding_alg;
+ QCryptoHashAlgo hash_alg;
} QCryptoGcryptRSA;
static void qcrypto_gcrypt_rsa_free(QCryptoAkCipher *akcipher)
@@ -59,7 +59,7 @@ QCryptoAkCipher *qcrypto_akcipher_new(const QCryptoAkCipherOptions *opts,
Error **errp)
{
switch (opts->alg) {
- case QCRYPTO_AKCIPHER_ALG_RSA:
+ case QCRYPTO_AK_CIPHER_ALGO_RSA:
return (QCryptoAkCipher *)qcrypto_gcrypt_rsa_new(
&opts->u.rsa, type, key, keylen, errp);
@@ -85,7 +85,7 @@ static int qcrypto_gcrypt_parse_rsa_private_key(
const uint8_t *key, size_t keylen, Error **errp)
{
g_autoptr(QCryptoAkCipherRSAKey) rsa_key = qcrypto_akcipher_rsakey_parse(
- QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE, key, keylen, errp);
+ QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE, key, keylen, errp);
gcry_mpi_t n = NULL, e = NULL, d = NULL, p = NULL, q = NULL, u = NULL;
bool compute_mul_inv = false;
int ret = -1;
@@ -178,7 +178,7 @@ static int qcrypto_gcrypt_parse_rsa_public_key(QCryptoGcryptRSA *rsa,
{
g_autoptr(QCryptoAkCipherRSAKey) rsa_key = qcrypto_akcipher_rsakey_parse(
- QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, key, keylen, errp);
+ QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC, key, keylen, errp);
gcry_mpi_t n = NULL, e = NULL;
int ret = -1;
gcry_error_t err;
@@ -241,7 +241,7 @@ static int qcrypto_gcrypt_rsa_encrypt(QCryptoAkCipher *akcipher,
err = gcry_sexp_build(&data_sexp, NULL,
"(data (flags %s) (value %b))",
- QCryptoRSAPaddingAlgorithm_str(rsa->padding_alg),
+ QCryptoRSAPaddingAlgo_str(rsa->padding_alg),
in_len, in);
if (gcry_err_code(err) != 0) {
error_setg(errp, "Failed to build plaintext: %s/%s",
@@ -263,7 +263,7 @@ static int qcrypto_gcrypt_rsa_encrypt(QCryptoAkCipher *akcipher,
goto cleanup;
}
- if (rsa->padding_alg == QCRYPTO_RSA_PADDING_ALG_RAW) {
+ if (rsa->padding_alg == QCRYPTO_RSA_PADDING_ALGO_RAW) {
cipher_mpi = gcry_sexp_nth_mpi(cipher_sexp_item, 1, GCRYMPI_FMT_USG);
if (!cipher_mpi) {
error_setg(errp, "Invalid ciphertext result");
@@ -332,7 +332,7 @@ static int qcrypto_gcrypt_rsa_decrypt(QCryptoAkCipher *akcipher,
err = gcry_sexp_build(&cipher_sexp, NULL,
"(enc-val (flags %s) (rsa (a %b) ))",
- QCryptoRSAPaddingAlgorithm_str(rsa->padding_alg),
+ QCryptoRSAPaddingAlgo_str(rsa->padding_alg),
in_len, in);
if (gcry_err_code(err) != 0) {
error_setg(errp, "Failed to build ciphertext: %s/%s",
@@ -348,7 +348,7 @@ static int qcrypto_gcrypt_rsa_decrypt(QCryptoAkCipher *akcipher,
}
/* S-expression of plaintext: (value plaintext) */
- if (rsa->padding_alg == QCRYPTO_RSA_PADDING_ALG_RAW) {
+ if (rsa->padding_alg == QCRYPTO_RSA_PADDING_ALGO_RAW) {
data_mpi = gcry_sexp_nth_mpi(data_sexp, 1, GCRYMPI_FMT_USG);
if (!data_mpi) {
error_setg(errp, "Invalid plaintext result");
@@ -410,14 +410,14 @@ static int qcrypto_gcrypt_rsa_sign(QCryptoAkCipher *akcipher,
return ret;
}
- if (rsa->padding_alg != QCRYPTO_RSA_PADDING_ALG_PKCS1) {
+ if (rsa->padding_alg != QCRYPTO_RSA_PADDING_ALGO_PKCS1) {
error_setg(errp, "Invalid padding %u", rsa->padding_alg);
return ret;
}
err = gcry_sexp_build(&dgst_sexp, NULL,
"(data (flags pkcs1) (hash %s %b))",
- QCryptoHashAlgorithm_str(rsa->hash_alg),
+ QCryptoHashAlgo_str(rsa->hash_alg),
in_len, in);
if (gcry_err_code(err) != 0) {
error_setg(errp, "Failed to build dgst: %s/%s",
@@ -482,7 +482,7 @@ static int qcrypto_gcrypt_rsa_verify(QCryptoAkCipher *akcipher,
return ret;
}
- if (rsa->padding_alg != QCRYPTO_RSA_PADDING_ALG_PKCS1) {
+ if (rsa->padding_alg != QCRYPTO_RSA_PADDING_ALGO_PKCS1) {
error_setg(errp, "Invalid padding %u", rsa->padding_alg);
return ret;
}
@@ -497,7 +497,7 @@ static int qcrypto_gcrypt_rsa_verify(QCryptoAkCipher *akcipher,
err = gcry_sexp_build(&dgst_sexp, NULL,
"(data (flags pkcs1) (hash %s %b))",
- QCryptoHashAlgorithm_str(rsa->hash_alg),
+ QCryptoHashAlgo_str(rsa->hash_alg),
in2_len, in2);
if (gcry_err_code(err) != 0) {
error_setg(errp, "Failed to build dgst: %s/%s",
@@ -540,13 +540,13 @@ static QCryptoGcryptRSA *qcrypto_gcrypt_rsa_new(
rsa->akcipher.driver = &gcrypt_rsa;
switch (type) {
- case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
+ case QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE:
if (qcrypto_gcrypt_parse_rsa_private_key(rsa, key, keylen, errp) != 0) {
goto error;
}
break;
- case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
+ case QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC:
if (qcrypto_gcrypt_parse_rsa_public_key(rsa, key, keylen, errp) != 0) {
goto error;
}
@@ -568,17 +568,17 @@ error:
bool qcrypto_akcipher_supports(QCryptoAkCipherOptions *opts)
{
switch (opts->alg) {
- case QCRYPTO_AKCIPHER_ALG_RSA:
+ case QCRYPTO_AK_CIPHER_ALGO_RSA:
switch (opts->u.rsa.padding_alg) {
- case QCRYPTO_RSA_PADDING_ALG_RAW:
+ case QCRYPTO_RSA_PADDING_ALGO_RAW:
return true;
- case QCRYPTO_RSA_PADDING_ALG_PKCS1:
+ case QCRYPTO_RSA_PADDING_ALGO_PKCS1:
switch (opts->u.rsa.hash_alg) {
- case QCRYPTO_HASH_ALG_MD5:
- case QCRYPTO_HASH_ALG_SHA1:
- case QCRYPTO_HASH_ALG_SHA256:
- case QCRYPTO_HASH_ALG_SHA512:
+ case QCRYPTO_HASH_ALGO_MD5:
+ case QCRYPTO_HASH_ALGO_SHA1:
+ case QCRYPTO_HASH_ALGO_SHA256:
+ case QCRYPTO_HASH_ALGO_SHA512:
return true;
default:
diff --git a/crypto/akcipher-nettle.c.inc b/crypto/akcipher-nettle.c.inc
index 02699e6..1720f84 100644
--- a/crypto/akcipher-nettle.c.inc
+++ b/crypto/akcipher-nettle.c.inc
@@ -33,8 +33,8 @@ typedef struct QCryptoNettleRSA {
QCryptoAkCipher akcipher;
struct rsa_public_key pub;
struct rsa_private_key priv;
- QCryptoRSAPaddingAlgorithm padding_alg;
- QCryptoHashAlgorithm hash_alg;
+ QCryptoRSAPaddingAlgo padding_alg;
+ QCryptoHashAlgo hash_alg;
} QCryptoNettleRSA;
static void qcrypto_nettle_rsa_free(QCryptoAkCipher *akcipher)
@@ -61,7 +61,7 @@ QCryptoAkCipher *qcrypto_akcipher_new(const QCryptoAkCipherOptions *opts,
Error **errp)
{
switch (opts->alg) {
- case QCRYPTO_AKCIPHER_ALG_RSA:
+ case QCRYPTO_AK_CIPHER_ALGO_RSA:
return qcrypto_nettle_rsa_new(&opts->u.rsa, type, key, keylen, errp);
default:
@@ -87,7 +87,7 @@ static int qcrypt_nettle_parse_rsa_private_key(QCryptoNettleRSA *rsa,
Error **errp)
{
g_autoptr(QCryptoAkCipherRSAKey) rsa_key = qcrypto_akcipher_rsakey_parse(
- QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE, key, keylen, errp);
+ QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE, key, keylen, errp);
if (!rsa_key) {
return -1;
@@ -137,7 +137,7 @@ static int qcrypt_nettle_parse_rsa_public_key(QCryptoNettleRSA *rsa,
Error **errp)
{
g_autoptr(QCryptoAkCipherRSAKey) rsa_key = qcrypto_akcipher_rsakey_parse(
- QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, key, keylen, errp);
+ QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC, key, keylen, errp);
if (!rsa_key) {
return -1;
@@ -184,11 +184,11 @@ static int qcrypto_nettle_rsa_encrypt(QCryptoAkCipher *akcipher,
/* Nettle do not support RSA encryption without any padding */
switch (rsa->padding_alg) {
- case QCRYPTO_RSA_PADDING_ALG_RAW:
+ case QCRYPTO_RSA_PADDING_ALGO_RAW:
error_setg(errp, "RSA with raw padding is not supported");
break;
- case QCRYPTO_RSA_PADDING_ALG_PKCS1:
+ case QCRYPTO_RSA_PADDING_ALGO_PKCS1:
mpz_init(c);
if (rsa_encrypt(&rsa->pub, NULL, wrap_nettle_random_func,
data_len, (uint8_t *)data, c) != 1) {
@@ -223,11 +223,11 @@ static int qcrypto_nettle_rsa_decrypt(QCryptoAkCipher *akcipher,
}
switch (rsa->padding_alg) {
- case QCRYPTO_RSA_PADDING_ALG_RAW:
+ case QCRYPTO_RSA_PADDING_ALGO_RAW:
error_setg(errp, "RSA with raw padding is not supported");
break;
- case QCRYPTO_RSA_PADDING_ALG_PKCS1:
+ case QCRYPTO_RSA_PADDING_ALGO_PKCS1:
nettle_mpz_init_set_str_256_u(c, enc_len, enc);
if (!rsa_decrypt(&rsa->priv, &data_len, (uint8_t *)data, c)) {
error_setg(errp, "Failed to decrypt");
@@ -257,7 +257,7 @@ static int qcrypto_nettle_rsa_sign(QCryptoAkCipher *akcipher,
* The RSA algorithm cannot be used for signature/verification
* without padding.
*/
- if (rsa->padding_alg == QCRYPTO_RSA_PADDING_ALG_RAW) {
+ if (rsa->padding_alg == QCRYPTO_RSA_PADDING_ALGO_RAW) {
error_setg(errp, "Try to make signature without padding");
return ret;
}
@@ -276,19 +276,19 @@ static int qcrypto_nettle_rsa_sign(QCryptoAkCipher *akcipher,
mpz_init(s);
switch (rsa->hash_alg) {
- case QCRYPTO_HASH_ALG_MD5:
+ case QCRYPTO_HASH_ALGO_MD5:
rv = rsa_md5_sign_digest(&rsa->priv, data, s);
break;
- case QCRYPTO_HASH_ALG_SHA1:
+ case QCRYPTO_HASH_ALGO_SHA1:
rv = rsa_sha1_sign_digest(&rsa->priv, data, s);
break;
- case QCRYPTO_HASH_ALG_SHA256:
+ case QCRYPTO_HASH_ALGO_SHA256:
rv = rsa_sha256_sign_digest(&rsa->priv, data, s);
break;
- case QCRYPTO_HASH_ALG_SHA512:
+ case QCRYPTO_HASH_ALGO_SHA512:
rv = rsa_sha512_sign_digest(&rsa->priv, data, s);
break;
@@ -324,7 +324,7 @@ static int qcrypto_nettle_rsa_verify(QCryptoAkCipher *akcipher,
* The RSA algorithm cannot be used for signature/verification
* without padding.
*/
- if (rsa->padding_alg == QCRYPTO_RSA_PADDING_ALG_RAW) {
+ if (rsa->padding_alg == QCRYPTO_RSA_PADDING_ALGO_RAW) {
error_setg(errp, "Try to verify signature without padding");
return ret;
}
@@ -341,19 +341,19 @@ static int qcrypto_nettle_rsa_verify(QCryptoAkCipher *akcipher,
nettle_mpz_init_set_str_256_u(s, sig_len, sig);
switch (rsa->hash_alg) {
- case QCRYPTO_HASH_ALG_MD5:
+ case QCRYPTO_HASH_ALGO_MD5:
rv = rsa_md5_verify_digest(&rsa->pub, data, s);
break;
- case QCRYPTO_HASH_ALG_SHA1:
+ case QCRYPTO_HASH_ALGO_SHA1:
rv = rsa_sha1_verify_digest(&rsa->pub, data, s);
break;
- case QCRYPTO_HASH_ALG_SHA256:
+ case QCRYPTO_HASH_ALGO_SHA256:
rv = rsa_sha256_verify_digest(&rsa->pub, data, s);
break;
- case QCRYPTO_HASH_ALG_SHA512:
+ case QCRYPTO_HASH_ALGO_SHA512:
rv = rsa_sha512_verify_digest(&rsa->pub, data, s);
break;
@@ -397,13 +397,13 @@ static QCryptoAkCipher *qcrypto_nettle_rsa_new(
rsa_private_key_init(&rsa->priv);
switch (type) {
- case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
+ case QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE:
if (qcrypt_nettle_parse_rsa_private_key(rsa, key, keylen, errp) != 0) {
goto error;
}
break;
- case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
+ case QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC:
if (qcrypt_nettle_parse_rsa_public_key(rsa, key, keylen, errp) != 0) {
goto error;
}
@@ -425,21 +425,21 @@ error:
bool qcrypto_akcipher_supports(QCryptoAkCipherOptions *opts)
{
switch (opts->alg) {
- case QCRYPTO_AKCIPHER_ALG_RSA:
+ case QCRYPTO_AK_CIPHER_ALGO_RSA:
switch (opts->u.rsa.padding_alg) {
- case QCRYPTO_RSA_PADDING_ALG_PKCS1:
+ case QCRYPTO_RSA_PADDING_ALGO_PKCS1:
switch (opts->u.rsa.hash_alg) {
- case QCRYPTO_HASH_ALG_MD5:
- case QCRYPTO_HASH_ALG_SHA1:
- case QCRYPTO_HASH_ALG_SHA256:
- case QCRYPTO_HASH_ALG_SHA512:
+ case QCRYPTO_HASH_ALGO_MD5:
+ case QCRYPTO_HASH_ALGO_SHA1:
+ case QCRYPTO_HASH_ALGO_SHA256:
+ case QCRYPTO_HASH_ALGO_SHA512:
return true;
default:
return false;
}
- case QCRYPTO_RSA_PADDING_ALG_RAW:
+ case QCRYPTO_RSA_PADDING_ALGO_RAW:
default:
return false;
}
diff --git a/crypto/akcipher.c b/crypto/akcipher.c
index e4bbc6e..0a0576b 100644
--- a/crypto/akcipher.c
+++ b/crypto/akcipher.c
@@ -115,7 +115,7 @@ int qcrypto_akcipher_export_p8info(const QCryptoAkCipherOptions *opts,
Error **errp)
{
switch (opts->alg) {
- case QCRYPTO_AKCIPHER_ALG_RSA:
+ case QCRYPTO_AK_CIPHER_ALGO_RSA:
qcrypto_akcipher_rsakey_export_p8info(key, keylen, dst, dst_len);
return 0;
diff --git a/crypto/akcipherpriv.h b/crypto/akcipherpriv.h
index 739f639..3b33e54 100644
--- a/crypto/akcipherpriv.h
+++ b/crypto/akcipherpriv.h
@@ -27,7 +27,7 @@
typedef struct QCryptoAkCipherDriver QCryptoAkCipherDriver;
struct QCryptoAkCipher {
- QCryptoAkCipherAlgorithm alg;
+ QCryptoAkCipherAlgo alg;
QCryptoAkCipherKeyType type;
int max_plaintext_len;
int max_ciphertext_len;
diff --git a/crypto/block-luks.c b/crypto/block-luks.c
index 5b777c1..0926ad2 100644
--- a/crypto/block-luks.c
+++ b/crypto/block-luks.c
@@ -33,6 +33,7 @@
#include "qemu/uuid.h"
#include "qemu/bitmap.h"
+#include "qemu/range.h"
/*
* Reference for the LUKS format implemented here is
@@ -67,38 +68,38 @@ struct QCryptoBlockLUKSCipherNameMap {
static const QCryptoBlockLUKSCipherSizeMap
qcrypto_block_luks_cipher_size_map_aes[] = {
- { 16, QCRYPTO_CIPHER_ALG_AES_128 },
- { 24, QCRYPTO_CIPHER_ALG_AES_192 },
- { 32, QCRYPTO_CIPHER_ALG_AES_256 },
+ { 16, QCRYPTO_CIPHER_ALGO_AES_128 },
+ { 24, QCRYPTO_CIPHER_ALGO_AES_192 },
+ { 32, QCRYPTO_CIPHER_ALGO_AES_256 },
{ 0, 0 },
};
static const QCryptoBlockLUKSCipherSizeMap
qcrypto_block_luks_cipher_size_map_cast5[] = {
- { 16, QCRYPTO_CIPHER_ALG_CAST5_128 },
+ { 16, QCRYPTO_CIPHER_ALGO_CAST5_128 },
{ 0, 0 },
};
static const QCryptoBlockLUKSCipherSizeMap
qcrypto_block_luks_cipher_size_map_serpent[] = {
- { 16, QCRYPTO_CIPHER_ALG_SERPENT_128 },
- { 24, QCRYPTO_CIPHER_ALG_SERPENT_192 },
- { 32, QCRYPTO_CIPHER_ALG_SERPENT_256 },
+ { 16, QCRYPTO_CIPHER_ALGO_SERPENT_128 },
+ { 24, QCRYPTO_CIPHER_ALGO_SERPENT_192 },
+ { 32, QCRYPTO_CIPHER_ALGO_SERPENT_256 },
{ 0, 0 },
};
static const QCryptoBlockLUKSCipherSizeMap
qcrypto_block_luks_cipher_size_map_twofish[] = {
- { 16, QCRYPTO_CIPHER_ALG_TWOFISH_128 },
- { 24, QCRYPTO_CIPHER_ALG_TWOFISH_192 },
- { 32, QCRYPTO_CIPHER_ALG_TWOFISH_256 },
+ { 16, QCRYPTO_CIPHER_ALGO_TWOFISH_128 },
+ { 24, QCRYPTO_CIPHER_ALGO_TWOFISH_192 },
+ { 32, QCRYPTO_CIPHER_ALGO_TWOFISH_256 },
{ 0, 0 },
};
#ifdef CONFIG_CRYPTO_SM4
static const QCryptoBlockLUKSCipherSizeMap
qcrypto_block_luks_cipher_size_map_sm4[] = {
- { 16, QCRYPTO_CIPHER_ALG_SM4},
+ { 16, QCRYPTO_CIPHER_ALGO_SM4},
{ 0, 0 },
};
#endif
@@ -122,25 +123,25 @@ struct QCryptoBlockLUKS {
QCryptoBlockLUKSHeader header;
/* Main encryption algorithm used for encryption*/
- QCryptoCipherAlgorithm cipher_alg;
+ QCryptoCipherAlgo cipher_alg;
/* Mode of encryption for the selected encryption algorithm */
QCryptoCipherMode cipher_mode;
/* Initialization vector generation algorithm */
- QCryptoIVGenAlgorithm ivgen_alg;
+ QCryptoIVGenAlgo ivgen_alg;
/* Hash algorithm used for IV generation*/
- QCryptoHashAlgorithm ivgen_hash_alg;
+ QCryptoHashAlgo ivgen_hash_alg;
/*
* Encryption algorithm used for IV generation.
* Usually the same as main encryption algorithm
*/
- QCryptoCipherAlgorithm ivgen_cipher_alg;
+ QCryptoCipherAlgo ivgen_cipher_alg;
/* Hash algorithm used in pbkdf2 function */
- QCryptoHashAlgorithm hash_alg;
+ QCryptoHashAlgo hash_alg;
/* Name of the secret that was used to open the image */
char *secret;
@@ -178,7 +179,7 @@ static int qcrypto_block_luks_cipher_name_lookup(const char *name,
}
static const char *
-qcrypto_block_luks_cipher_alg_lookup(QCryptoCipherAlgorithm alg,
+qcrypto_block_luks_cipher_alg_lookup(QCryptoCipherAlgo alg,
Error **errp)
{
const QCryptoBlockLUKSCipherNameMap *map =
@@ -194,7 +195,7 @@ qcrypto_block_luks_cipher_alg_lookup(QCryptoCipherAlgorithm alg,
}
error_setg(errp, "Algorithm '%s' not supported",
- QCryptoCipherAlgorithm_str(alg));
+ QCryptoCipherAlgo_str(alg));
return NULL;
}
@@ -222,13 +223,13 @@ static int qcrypto_block_luks_name_lookup(const char *name,
#define qcrypto_block_luks_hash_name_lookup(name, errp) \
qcrypto_block_luks_name_lookup(name, \
- &QCryptoHashAlgorithm_lookup, \
+ &QCryptoHashAlgo_lookup, \
"Hash algorithm", \
errp)
#define qcrypto_block_luks_ivgen_name_lookup(name, errp) \
qcrypto_block_luks_name_lookup(name, \
- &QCryptoIVGenAlgorithm_lookup, \
+ &QCryptoIVGenAlgo_lookup, \
"IV generator", \
errp)
@@ -261,9 +262,9 @@ qcrypto_block_luks_has_format(const uint8_t *buf,
* the cipher since that gets a key length matching the digest
* size, not AES 128 with truncated digest as might be imagined
*/
-static QCryptoCipherAlgorithm
-qcrypto_block_luks_essiv_cipher(QCryptoCipherAlgorithm cipher,
- QCryptoHashAlgorithm hash,
+static QCryptoCipherAlgo
+qcrypto_block_luks_essiv_cipher(QCryptoCipherAlgo cipher,
+ QCryptoHashAlgo hash,
Error **errp)
{
size_t digestlen = qcrypto_hash_digest_len(hash);
@@ -273,54 +274,54 @@ qcrypto_block_luks_essiv_cipher(QCryptoCipherAlgorithm cipher,
}
switch (cipher) {
- case QCRYPTO_CIPHER_ALG_AES_128:
- case QCRYPTO_CIPHER_ALG_AES_192:
- case QCRYPTO_CIPHER_ALG_AES_256:
+ case QCRYPTO_CIPHER_ALGO_AES_128:
+ case QCRYPTO_CIPHER_ALGO_AES_192:
+ case QCRYPTO_CIPHER_ALGO_AES_256:
if (digestlen == qcrypto_cipher_get_key_len(
- QCRYPTO_CIPHER_ALG_AES_128)) {
- return QCRYPTO_CIPHER_ALG_AES_128;
+ QCRYPTO_CIPHER_ALGO_AES_128)) {
+ return QCRYPTO_CIPHER_ALGO_AES_128;
} else if (digestlen == qcrypto_cipher_get_key_len(
- QCRYPTO_CIPHER_ALG_AES_192)) {
- return QCRYPTO_CIPHER_ALG_AES_192;
+ QCRYPTO_CIPHER_ALGO_AES_192)) {
+ return QCRYPTO_CIPHER_ALGO_AES_192;
} else if (digestlen == qcrypto_cipher_get_key_len(
- QCRYPTO_CIPHER_ALG_AES_256)) {
- return QCRYPTO_CIPHER_ALG_AES_256;
+ QCRYPTO_CIPHER_ALGO_AES_256)) {
+ return QCRYPTO_CIPHER_ALGO_AES_256;
} else {
error_setg(errp, "No AES cipher with key size %zu available",
digestlen);
return 0;
}
break;
- case QCRYPTO_CIPHER_ALG_SERPENT_128:
- case QCRYPTO_CIPHER_ALG_SERPENT_192:
- case QCRYPTO_CIPHER_ALG_SERPENT_256:
+ case QCRYPTO_CIPHER_ALGO_SERPENT_128:
+ case QCRYPTO_CIPHER_ALGO_SERPENT_192:
+ case QCRYPTO_CIPHER_ALGO_SERPENT_256:
if (digestlen == qcrypto_cipher_get_key_len(
- QCRYPTO_CIPHER_ALG_SERPENT_128)) {
- return QCRYPTO_CIPHER_ALG_SERPENT_128;
+ QCRYPTO_CIPHER_ALGO_SERPENT_128)) {
+ return QCRYPTO_CIPHER_ALGO_SERPENT_128;
} else if (digestlen == qcrypto_cipher_get_key_len(
- QCRYPTO_CIPHER_ALG_SERPENT_192)) {
- return QCRYPTO_CIPHER_ALG_SERPENT_192;
+ QCRYPTO_CIPHER_ALGO_SERPENT_192)) {
+ return QCRYPTO_CIPHER_ALGO_SERPENT_192;
} else if (digestlen == qcrypto_cipher_get_key_len(
- QCRYPTO_CIPHER_ALG_SERPENT_256)) {
- return QCRYPTO_CIPHER_ALG_SERPENT_256;
+ QCRYPTO_CIPHER_ALGO_SERPENT_256)) {
+ return QCRYPTO_CIPHER_ALGO_SERPENT_256;
} else {
error_setg(errp, "No Serpent cipher with key size %zu available",
digestlen);
return 0;
}
break;
- case QCRYPTO_CIPHER_ALG_TWOFISH_128:
- case QCRYPTO_CIPHER_ALG_TWOFISH_192:
- case QCRYPTO_CIPHER_ALG_TWOFISH_256:
+ case QCRYPTO_CIPHER_ALGO_TWOFISH_128:
+ case QCRYPTO_CIPHER_ALGO_TWOFISH_192:
+ case QCRYPTO_CIPHER_ALGO_TWOFISH_256:
if (digestlen == qcrypto_cipher_get_key_len(
- QCRYPTO_CIPHER_ALG_TWOFISH_128)) {
- return QCRYPTO_CIPHER_ALG_TWOFISH_128;
+ QCRYPTO_CIPHER_ALGO_TWOFISH_128)) {
+ return QCRYPTO_CIPHER_ALGO_TWOFISH_128;
} else if (digestlen == qcrypto_cipher_get_key_len(
- QCRYPTO_CIPHER_ALG_TWOFISH_192)) {
- return QCRYPTO_CIPHER_ALG_TWOFISH_192;
+ QCRYPTO_CIPHER_ALGO_TWOFISH_192)) {
+ return QCRYPTO_CIPHER_ALGO_TWOFISH_192;
} else if (digestlen == qcrypto_cipher_get_key_len(
- QCRYPTO_CIPHER_ALG_TWOFISH_256)) {
- return QCRYPTO_CIPHER_ALG_TWOFISH_256;
+ QCRYPTO_CIPHER_ALGO_TWOFISH_256)) {
+ return QCRYPTO_CIPHER_ALGO_TWOFISH_256;
} else {
error_setg(errp, "No Twofish cipher with key size %zu available",
digestlen);
@@ -329,7 +330,7 @@ qcrypto_block_luks_essiv_cipher(QCryptoCipherAlgorithm cipher,
break;
default:
error_setg(errp, "Cipher %s not supported with essiv",
- QCryptoCipherAlgorithm_str(cipher));
+ QCryptoCipherAlgo_str(cipher));
return 0;
}
}
@@ -572,7 +573,7 @@ qcrypto_block_luks_check_header(const QCryptoBlockLUKS *luks,
header_sectors,
slot2->stripes);
- if (start1 + len1 > start2 && start2 + len2 > start1) {
+ if (ranges_overlap(start1, len1, start2, len2)) {
error_setg(errp,
"Keyslots %zu and %zu are overlapping in the header",
i, j);
@@ -659,7 +660,7 @@ qcrypto_block_luks_parse_header(QCryptoBlockLUKS *luks, Error **errp)
return -1;
}
- if (luks->ivgen_alg == QCRYPTO_IVGEN_ALG_ESSIV) {
+ if (luks->ivgen_alg == QCRYPTO_IV_GEN_ALGO_ESSIV) {
if (!ivhash_name) {
error_setg(errp, "Missing IV generator hash specification");
return -1;
@@ -1321,20 +1322,20 @@ qcrypto_block_luks_create(QCryptoBlock *block,
luks_opts.iter_time = QCRYPTO_BLOCK_LUKS_DEFAULT_ITER_TIME_MS;
}
if (!luks_opts.has_cipher_alg) {
- luks_opts.cipher_alg = QCRYPTO_CIPHER_ALG_AES_256;
+ luks_opts.cipher_alg = QCRYPTO_CIPHER_ALGO_AES_256;
}
if (!luks_opts.has_cipher_mode) {
luks_opts.cipher_mode = QCRYPTO_CIPHER_MODE_XTS;
}
if (!luks_opts.has_ivgen_alg) {
- luks_opts.ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64;
+ luks_opts.ivgen_alg = QCRYPTO_IV_GEN_ALGO_PLAIN64;
}
if (!luks_opts.has_hash_alg) {
- luks_opts.hash_alg = QCRYPTO_HASH_ALG_SHA256;
+ luks_opts.hash_alg = QCRYPTO_HASH_ALGO_SHA256;
}
- if (luks_opts.ivgen_alg == QCRYPTO_IVGEN_ALG_ESSIV) {
+ if (luks_opts.ivgen_alg == QCRYPTO_IV_GEN_ALGO_ESSIV) {
if (!luks_opts.has_ivgen_hash_alg) {
- luks_opts.ivgen_hash_alg = QCRYPTO_HASH_ALG_SHA256;
+ luks_opts.ivgen_hash_alg = QCRYPTO_HASH_ALGO_SHA256;
luks_opts.has_ivgen_hash_alg = true;
}
}
@@ -1383,15 +1384,15 @@ qcrypto_block_luks_create(QCryptoBlock *block,
}
cipher_mode = QCryptoCipherMode_str(luks_opts.cipher_mode);
- ivgen_alg = QCryptoIVGenAlgorithm_str(luks_opts.ivgen_alg);
+ ivgen_alg = QCryptoIVGenAlgo_str(luks_opts.ivgen_alg);
if (luks_opts.has_ivgen_hash_alg) {
- ivgen_hash_alg = QCryptoHashAlgorithm_str(luks_opts.ivgen_hash_alg);
+ ivgen_hash_alg = QCryptoHashAlgo_str(luks_opts.ivgen_hash_alg);
cipher_mode_spec = g_strdup_printf("%s-%s:%s", cipher_mode, ivgen_alg,
ivgen_hash_alg);
} else {
cipher_mode_spec = g_strdup_printf("%s-%s", cipher_mode, ivgen_alg);
}
- hash_alg = QCryptoHashAlgorithm_str(luks_opts.hash_alg);
+ hash_alg = QCryptoHashAlgo_str(luks_opts.hash_alg);
if (strlen(cipher_alg) >= QCRYPTO_BLOCK_LUKS_CIPHER_NAME_LEN) {
@@ -1410,7 +1411,7 @@ qcrypto_block_luks_create(QCryptoBlock *block,
goto error;
}
- if (luks_opts.ivgen_alg == QCRYPTO_IVGEN_ALG_ESSIV) {
+ if (luks_opts.ivgen_alg == QCRYPTO_IV_GEN_ALGO_ESSIV) {
luks->ivgen_cipher_alg =
qcrypto_block_luks_essiv_cipher(luks_opts.cipher_alg,
luks_opts.ivgen_hash_alg,
@@ -1860,11 +1861,11 @@ qcrypto_block_luks_amend_options(QCryptoBlock *block,
QCryptoBlockAmendOptionsLUKS *opts_luks = &options->u.luks;
switch (opts_luks->state) {
- case Q_CRYPTO_BLOCKLUKS_KEYSLOT_STATE_ACTIVE:
+ case QCRYPTO_BLOCK_LUKS_KEYSLOT_STATE_ACTIVE:
return qcrypto_block_luks_amend_add_keyslot(block, readfunc,
writefunc, opaque,
opts_luks, force, errp);
- case Q_CRYPTO_BLOCKLUKS_KEYSLOT_STATE_INACTIVE:
+ case QCRYPTO_BLOCK_LUKS_KEYSLOT_STATE_INACTIVE:
return qcrypto_block_luks_amend_erase_keyslots(block, readfunc,
writefunc, opaque,
opts_luks, force, errp);
@@ -1885,7 +1886,7 @@ static int qcrypto_block_luks_get_info(QCryptoBlock *block,
info->u.luks.cipher_alg = luks->cipher_alg;
info->u.luks.cipher_mode = luks->cipher_mode;
info->u.luks.ivgen_alg = luks->ivgen_alg;
- if (info->u.luks.ivgen_alg == QCRYPTO_IVGEN_ALG_ESSIV) {
+ if (info->u.luks.ivgen_alg == QCRYPTO_IV_GEN_ALGO_ESSIV) {
info->u.luks.has_ivgen_hash_alg = true;
info->u.luks.ivgen_hash_alg = luks->ivgen_hash_alg;
}
diff --git a/crypto/block-qcow.c b/crypto/block-qcow.c
index 42e9556..054078b 100644
--- a/crypto/block-qcow.c
+++ b/crypto/block-qcow.c
@@ -62,16 +62,16 @@ qcrypto_block_qcow_init(QCryptoBlock *block,
memcpy(keybuf, password, MIN(len, sizeof(keybuf)));
g_free(password);
- block->niv = qcrypto_cipher_get_iv_len(QCRYPTO_CIPHER_ALG_AES_128,
+ block->niv = qcrypto_cipher_get_iv_len(QCRYPTO_CIPHER_ALGO_AES_128,
QCRYPTO_CIPHER_MODE_CBC);
- block->ivgen = qcrypto_ivgen_new(QCRYPTO_IVGEN_ALG_PLAIN64,
+ block->ivgen = qcrypto_ivgen_new(QCRYPTO_IV_GEN_ALGO_PLAIN64,
0, 0, NULL, 0, errp);
if (!block->ivgen) {
ret = -ENOTSUP;
goto fail;
}
- ret = qcrypto_block_init_cipher(block, QCRYPTO_CIPHER_ALG_AES_128,
+ ret = qcrypto_block_init_cipher(block, QCRYPTO_CIPHER_ALGO_AES_128,
QCRYPTO_CIPHER_MODE_CBC,
keybuf, G_N_ELEMENTS(keybuf),
errp);
diff --git a/crypto/block.c b/crypto/block.c
index 3bcc427..96c83e6 100644
--- a/crypto/block.c
+++ b/crypto/block.c
@@ -26,8 +26,8 @@
#include "block-luks.h"
static const QCryptoBlockDriver *qcrypto_block_drivers[] = {
- [Q_CRYPTO_BLOCK_FORMAT_QCOW] = &qcrypto_block_driver_qcow,
- [Q_CRYPTO_BLOCK_FORMAT_LUKS] = &qcrypto_block_driver_luks,
+ [QCRYPTO_BLOCK_FORMAT_QCOW] = &qcrypto_block_driver_qcow,
+ [QCRYPTO_BLOCK_FORMAT_LUKS] = &qcrypto_block_driver_luks,
};
@@ -267,7 +267,7 @@ static void qcrypto_block_push_cipher(QCryptoBlock *block,
int qcrypto_block_init_cipher(QCryptoBlock *block,
- QCryptoCipherAlgorithm alg,
+ QCryptoCipherAlgo alg,
QCryptoCipherMode mode,
const uint8_t *key, size_t nkey,
Error **errp)
@@ -332,7 +332,7 @@ QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block)
}
-QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block)
+QCryptoHashAlgo qcrypto_block_get_kdf_hash(QCryptoBlock *block)
{
return block->kdfhash;
}
diff --git a/crypto/blockpriv.h b/crypto/blockpriv.h
index b8f77cb..edf0b3a 100644
--- a/crypto/blockpriv.h
+++ b/crypto/blockpriv.h
@@ -33,7 +33,7 @@ struct QCryptoBlock {
void *opaque;
/* Cipher parameters */
- QCryptoCipherAlgorithm alg;
+ QCryptoCipherAlgo alg;
QCryptoCipherMode mode;
uint8_t *key;
size_t nkey;
@@ -44,7 +44,7 @@ struct QCryptoBlock {
QCryptoIVGen *ivgen;
QemuMutex mutex;
- QCryptoHashAlgorithm kdfhash;
+ QCryptoHashAlgo kdfhash;
size_t niv;
uint64_t payload_offset; /* In bytes */
uint64_t sector_size; /* In bytes */
@@ -132,7 +132,7 @@ int qcrypto_block_encrypt_helper(QCryptoBlock *block,
Error **errp);
int qcrypto_block_init_cipher(QCryptoBlock *block,
- QCryptoCipherAlgorithm alg,
+ QCryptoCipherAlgo alg,
QCryptoCipherMode mode,
const uint8_t *key, size_t nkey,
Error **errp);
diff --git a/crypto/cipher-afalg.c b/crypto/cipher-afalg.c
index 3df8fc5..4980d41 100644
--- a/crypto/cipher-afalg.c
+++ b/crypto/cipher-afalg.c
@@ -18,7 +18,7 @@
static char *
-qcrypto_afalg_cipher_format_name(QCryptoCipherAlgorithm alg,
+qcrypto_afalg_cipher_format_name(QCryptoCipherAlgo alg,
QCryptoCipherMode mode,
Error **errp)
{
@@ -27,22 +27,22 @@ qcrypto_afalg_cipher_format_name(QCryptoCipherAlgorithm alg,
const char *mode_name;
switch (alg) {
- case QCRYPTO_CIPHER_ALG_AES_128:
- case QCRYPTO_CIPHER_ALG_AES_192:
- case QCRYPTO_CIPHER_ALG_AES_256:
+ case QCRYPTO_CIPHER_ALGO_AES_128:
+ case QCRYPTO_CIPHER_ALGO_AES_192:
+ case QCRYPTO_CIPHER_ALGO_AES_256:
alg_name = "aes";
break;
- case QCRYPTO_CIPHER_ALG_CAST5_128:
+ case QCRYPTO_CIPHER_ALGO_CAST5_128:
alg_name = "cast5";
break;
- case QCRYPTO_CIPHER_ALG_SERPENT_128:
- case QCRYPTO_CIPHER_ALG_SERPENT_192:
- case QCRYPTO_CIPHER_ALG_SERPENT_256:
+ case QCRYPTO_CIPHER_ALGO_SERPENT_128:
+ case QCRYPTO_CIPHER_ALGO_SERPENT_192:
+ case QCRYPTO_CIPHER_ALGO_SERPENT_256:
alg_name = "serpent";
break;
- case QCRYPTO_CIPHER_ALG_TWOFISH_128:
- case QCRYPTO_CIPHER_ALG_TWOFISH_192:
- case QCRYPTO_CIPHER_ALG_TWOFISH_256:
+ case QCRYPTO_CIPHER_ALGO_TWOFISH_128:
+ case QCRYPTO_CIPHER_ALGO_TWOFISH_192:
+ case QCRYPTO_CIPHER_ALGO_TWOFISH_256:
alg_name = "twofish";
break;
@@ -60,12 +60,12 @@ qcrypto_afalg_cipher_format_name(QCryptoCipherAlgorithm alg,
static const struct QCryptoCipherDriver qcrypto_cipher_afalg_driver;
QCryptoCipher *
-qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgorithm alg,
+qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgo alg,
QCryptoCipherMode mode,
const uint8_t *key,
size_t nkey, Error **errp)
{
- QCryptoAFAlg *afalg;
+ QCryptoAFAlgo *afalg;
size_t expect_niv;
char *name;
@@ -119,7 +119,7 @@ qcrypto_afalg_cipher_setiv(QCryptoCipher *cipher,
const uint8_t *iv,
size_t niv, Error **errp)
{
- QCryptoAFAlg *afalg = container_of(cipher, QCryptoAFAlg, base);
+ QCryptoAFAlgo *afalg = container_of(cipher, QCryptoAFAlgo, base);
struct af_alg_iv *alg_iv;
size_t expect_niv;
@@ -143,7 +143,7 @@ qcrypto_afalg_cipher_setiv(QCryptoCipher *cipher,
}
static int
-qcrypto_afalg_cipher_op(QCryptoAFAlg *afalg,
+qcrypto_afalg_cipher_op(QCryptoAFAlgo *afalg,
const void *in, void *out,
size_t len, bool do_encrypt,
Error **errp)
@@ -202,7 +202,7 @@ qcrypto_afalg_cipher_encrypt(QCryptoCipher *cipher,
const void *in, void *out,
size_t len, Error **errp)
{
- QCryptoAFAlg *afalg = container_of(cipher, QCryptoAFAlg, base);
+ QCryptoAFAlgo *afalg = container_of(cipher, QCryptoAFAlgo, base);
return qcrypto_afalg_cipher_op(afalg, in, out, len, true, errp);
}
@@ -212,14 +212,14 @@ qcrypto_afalg_cipher_decrypt(QCryptoCipher *cipher,
const void *in, void *out,
size_t len, Error **errp)
{
- QCryptoAFAlg *afalg = container_of(cipher, QCryptoAFAlg, base);
+ QCryptoAFAlgo *afalg = container_of(cipher, QCryptoAFAlgo, base);
return qcrypto_afalg_cipher_op(afalg, in, out, len, false, errp);
}
static void qcrypto_afalg_comm_ctx_free(QCryptoCipher *cipher)
{
- QCryptoAFAlg *afalg = container_of(cipher, QCryptoAFAlg, base);
+ QCryptoAFAlgo *afalg = container_of(cipher, QCryptoAFAlgo, base);
qcrypto_afalg_comm_free(afalg);
}
diff --git a/crypto/cipher-builtin.c.inc b/crypto/cipher-builtin.c.inc
index b409089..da5fcbd 100644
--- a/crypto/cipher-builtin.c.inc
+++ b/crypto/cipher-builtin.c.inc
@@ -221,13 +221,13 @@ static const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_cbc = {
.cipher_free = qcrypto_cipher_ctx_free,
};
-bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
+bool qcrypto_cipher_supports(QCryptoCipherAlgo alg,
QCryptoCipherMode mode)
{
switch (alg) {
- case QCRYPTO_CIPHER_ALG_AES_128:
- case QCRYPTO_CIPHER_ALG_AES_192:
- case QCRYPTO_CIPHER_ALG_AES_256:
+ case QCRYPTO_CIPHER_ALGO_AES_128:
+ case QCRYPTO_CIPHER_ALGO_AES_192:
+ case QCRYPTO_CIPHER_ALGO_AES_256:
switch (mode) {
case QCRYPTO_CIPHER_MODE_ECB:
case QCRYPTO_CIPHER_MODE_CBC:
@@ -241,7 +241,7 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
}
}
-static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
+static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg,
QCryptoCipherMode mode,
const uint8_t *key,
size_t nkey,
@@ -252,9 +252,9 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
}
switch (alg) {
- case QCRYPTO_CIPHER_ALG_AES_128:
- case QCRYPTO_CIPHER_ALG_AES_192:
- case QCRYPTO_CIPHER_ALG_AES_256:
+ case QCRYPTO_CIPHER_ALGO_AES_128:
+ case QCRYPTO_CIPHER_ALGO_AES_192:
+ case QCRYPTO_CIPHER_ALGO_AES_256:
{
QCryptoCipherBuiltinAES *ctx;
const QCryptoCipherDriver *drv;
@@ -292,7 +292,7 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
default:
error_setg(errp,
"Unsupported cipher algorithm %s",
- QCryptoCipherAlgorithm_str(alg));
+ QCryptoCipherAlgo_str(alg));
return NULL;
}
diff --git a/crypto/cipher-gcrypt.c.inc b/crypto/cipher-gcrypt.c.inc
index 4a83147..12eb9dd 100644
--- a/crypto/cipher-gcrypt.c.inc
+++ b/crypto/cipher-gcrypt.c.inc
@@ -20,33 +20,33 @@
#include <gcrypt.h>
-static int qcrypto_cipher_alg_to_gcry_alg(QCryptoCipherAlgorithm alg)
+static int qcrypto_cipher_alg_to_gcry_alg(QCryptoCipherAlgo alg)
{
switch (alg) {
- case QCRYPTO_CIPHER_ALG_DES:
+ case QCRYPTO_CIPHER_ALGO_DES:
return GCRY_CIPHER_DES;
- case QCRYPTO_CIPHER_ALG_3DES:
+ case QCRYPTO_CIPHER_ALGO_3DES:
return GCRY_CIPHER_3DES;
- case QCRYPTO_CIPHER_ALG_AES_128:
+ case QCRYPTO_CIPHER_ALGO_AES_128:
return GCRY_CIPHER_AES128;
- case QCRYPTO_CIPHER_ALG_AES_192:
+ case QCRYPTO_CIPHER_ALGO_AES_192:
return GCRY_CIPHER_AES192;
- case QCRYPTO_CIPHER_ALG_AES_256:
+ case QCRYPTO_CIPHER_ALGO_AES_256:
return GCRY_CIPHER_AES256;
- case QCRYPTO_CIPHER_ALG_CAST5_128:
+ case QCRYPTO_CIPHER_ALGO_CAST5_128:
return GCRY_CIPHER_CAST5;
- case QCRYPTO_CIPHER_ALG_SERPENT_128:
+ case QCRYPTO_CIPHER_ALGO_SERPENT_128:
return GCRY_CIPHER_SERPENT128;
- case QCRYPTO_CIPHER_ALG_SERPENT_192:
+ case QCRYPTO_CIPHER_ALGO_SERPENT_192:
return GCRY_CIPHER_SERPENT192;
- case QCRYPTO_CIPHER_ALG_SERPENT_256:
+ case QCRYPTO_CIPHER_ALGO_SERPENT_256:
return GCRY_CIPHER_SERPENT256;
- case QCRYPTO_CIPHER_ALG_TWOFISH_128:
+ case QCRYPTO_CIPHER_ALGO_TWOFISH_128:
return GCRY_CIPHER_TWOFISH128;
- case QCRYPTO_CIPHER_ALG_TWOFISH_256:
+ case QCRYPTO_CIPHER_ALGO_TWOFISH_256:
return GCRY_CIPHER_TWOFISH;
#ifdef CONFIG_CRYPTO_SM4
- case QCRYPTO_CIPHER_ALG_SM4:
+ case QCRYPTO_CIPHER_ALGO_SM4:
return GCRY_CIPHER_SM4;
#endif
default:
@@ -70,23 +70,23 @@ static int qcrypto_cipher_mode_to_gcry_mode(QCryptoCipherMode mode)
}
}
-bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
+bool qcrypto_cipher_supports(QCryptoCipherAlgo alg,
QCryptoCipherMode mode)
{
switch (alg) {
- case QCRYPTO_CIPHER_ALG_DES:
- case QCRYPTO_CIPHER_ALG_3DES:
- case QCRYPTO_CIPHER_ALG_AES_128:
- case QCRYPTO_CIPHER_ALG_AES_192:
- case QCRYPTO_CIPHER_ALG_AES_256:
- case QCRYPTO_CIPHER_ALG_CAST5_128:
- case QCRYPTO_CIPHER_ALG_SERPENT_128:
- case QCRYPTO_CIPHER_ALG_SERPENT_192:
- case QCRYPTO_CIPHER_ALG_SERPENT_256:
- case QCRYPTO_CIPHER_ALG_TWOFISH_128:
- case QCRYPTO_CIPHER_ALG_TWOFISH_256:
+ case QCRYPTO_CIPHER_ALGO_DES:
+ case QCRYPTO_CIPHER_ALGO_3DES:
+ case QCRYPTO_CIPHER_ALGO_AES_128:
+ case QCRYPTO_CIPHER_ALGO_AES_192:
+ case QCRYPTO_CIPHER_ALGO_AES_256:
+ case QCRYPTO_CIPHER_ALGO_CAST5_128:
+ case QCRYPTO_CIPHER_ALGO_SERPENT_128:
+ case QCRYPTO_CIPHER_ALGO_SERPENT_192:
+ case QCRYPTO_CIPHER_ALGO_SERPENT_256:
+ case QCRYPTO_CIPHER_ALGO_TWOFISH_128:
+ case QCRYPTO_CIPHER_ALGO_TWOFISH_256:
#ifdef CONFIG_CRYPTO_SM4
- case QCRYPTO_CIPHER_ALG_SM4:
+ case QCRYPTO_CIPHER_ALGO_SM4:
#endif
break;
default:
@@ -228,7 +228,7 @@ static const struct QCryptoCipherDriver qcrypto_gcrypt_ctr_driver = {
.cipher_free = qcrypto_gcrypt_ctx_free,
};
-static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
+static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg,
QCryptoCipherMode mode,
const uint8_t *key,
size_t nkey,
@@ -246,7 +246,7 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
gcryalg = qcrypto_cipher_alg_to_gcry_alg(alg);
if (gcryalg == GCRY_CIPHER_NONE) {
error_setg(errp, "Unsupported cipher algorithm %s",
- QCryptoCipherAlgorithm_str(alg));
+ QCryptoCipherAlgo_str(alg));
return NULL;
}
diff --git a/crypto/cipher-gnutls.c.inc b/crypto/cipher-gnutls.c.inc
index d3e231c..b9450d4 100644
--- a/crypto/cipher-gnutls.c.inc
+++ b/crypto/cipher-gnutls.c.inc
@@ -27,7 +27,7 @@
#define QEMU_GNUTLS_XTS
#endif
-bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
+bool qcrypto_cipher_supports(QCryptoCipherAlgo alg,
QCryptoCipherMode mode)
{
@@ -35,11 +35,11 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
case QCRYPTO_CIPHER_MODE_ECB:
case QCRYPTO_CIPHER_MODE_CBC:
switch (alg) {
- case QCRYPTO_CIPHER_ALG_AES_128:
- case QCRYPTO_CIPHER_ALG_AES_192:
- case QCRYPTO_CIPHER_ALG_AES_256:
- case QCRYPTO_CIPHER_ALG_DES:
- case QCRYPTO_CIPHER_ALG_3DES:
+ case QCRYPTO_CIPHER_ALGO_AES_128:
+ case QCRYPTO_CIPHER_ALGO_AES_192:
+ case QCRYPTO_CIPHER_ALGO_AES_256:
+ case QCRYPTO_CIPHER_ALGO_DES:
+ case QCRYPTO_CIPHER_ALGO_3DES:
return true;
default:
return false;
@@ -47,8 +47,8 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
#ifdef QEMU_GNUTLS_XTS
case QCRYPTO_CIPHER_MODE_XTS:
switch (alg) {
- case QCRYPTO_CIPHER_ALG_AES_128:
- case QCRYPTO_CIPHER_ALG_AES_256:
+ case QCRYPTO_CIPHER_ALGO_AES_128:
+ case QCRYPTO_CIPHER_ALGO_AES_256:
return true;
default:
return false;
@@ -229,7 +229,7 @@ static struct QCryptoCipherDriver gnutls_driver = {
.cipher_free = qcrypto_gnutls_cipher_free,
};
-static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
+static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg,
QCryptoCipherMode mode,
const uint8_t *key,
size_t nkey,
@@ -244,10 +244,10 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
#ifdef QEMU_GNUTLS_XTS
case QCRYPTO_CIPHER_MODE_XTS:
switch (alg) {
- case QCRYPTO_CIPHER_ALG_AES_128:
+ case QCRYPTO_CIPHER_ALGO_AES_128:
galg = GNUTLS_CIPHER_AES_128_XTS;
break;
- case QCRYPTO_CIPHER_ALG_AES_256:
+ case QCRYPTO_CIPHER_ALGO_AES_256:
galg = GNUTLS_CIPHER_AES_256_XTS;
break;
default:
@@ -259,19 +259,19 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
case QCRYPTO_CIPHER_MODE_ECB:
case QCRYPTO_CIPHER_MODE_CBC:
switch (alg) {
- case QCRYPTO_CIPHER_ALG_AES_128:
+ case QCRYPTO_CIPHER_ALGO_AES_128:
galg = GNUTLS_CIPHER_AES_128_CBC;
break;
- case QCRYPTO_CIPHER_ALG_AES_192:
+ case QCRYPTO_CIPHER_ALGO_AES_192:
galg = GNUTLS_CIPHER_AES_192_CBC;
break;
- case QCRYPTO_CIPHER_ALG_AES_256:
+ case QCRYPTO_CIPHER_ALGO_AES_256:
galg = GNUTLS_CIPHER_AES_256_CBC;
break;
- case QCRYPTO_CIPHER_ALG_DES:
+ case QCRYPTO_CIPHER_ALGO_DES:
galg = GNUTLS_CIPHER_DES_CBC;
break;
- case QCRYPTO_CIPHER_ALG_3DES:
+ case QCRYPTO_CIPHER_ALGO_3DES:
galg = GNUTLS_CIPHER_3DES_CBC;
break;
default:
@@ -284,7 +284,7 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
if (galg == GNUTLS_CIPHER_UNKNOWN) {
error_setg(errp, "Unsupported cipher algorithm %s with %s mode",
- QCryptoCipherAlgorithm_str(alg),
+ QCryptoCipherAlgo_str(alg),
QCryptoCipherMode_str(mode));
return NULL;
}
@@ -310,8 +310,8 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
}
}
- if (alg == QCRYPTO_CIPHER_ALG_DES ||
- alg == QCRYPTO_CIPHER_ALG_3DES)
+ if (alg == QCRYPTO_CIPHER_ALGO_DES ||
+ alg == QCRYPTO_CIPHER_ALGO_3DES)
ctx->blocksize = 8;
else
ctx->blocksize = 16;
diff --git a/crypto/cipher-nettle.c.inc b/crypto/cipher-nettle.c.inc
index 42b39e1..ae91363 100644
--- a/crypto/cipher-nettle.c.inc
+++ b/crypto/cipher-nettle.c.inc
@@ -454,24 +454,24 @@ DEFINE_ECB(qcrypto_nettle_sm4,
sm4_encrypt_native, sm4_decrypt_native)
#endif
-bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
+bool qcrypto_cipher_supports(QCryptoCipherAlgo alg,
QCryptoCipherMode mode)
{
switch (alg) {
- case QCRYPTO_CIPHER_ALG_DES:
- case QCRYPTO_CIPHER_ALG_3DES:
- case QCRYPTO_CIPHER_ALG_AES_128:
- case QCRYPTO_CIPHER_ALG_AES_192:
- case QCRYPTO_CIPHER_ALG_AES_256:
- case QCRYPTO_CIPHER_ALG_CAST5_128:
- case QCRYPTO_CIPHER_ALG_SERPENT_128:
- case QCRYPTO_CIPHER_ALG_SERPENT_192:
- case QCRYPTO_CIPHER_ALG_SERPENT_256:
- case QCRYPTO_CIPHER_ALG_TWOFISH_128:
- case QCRYPTO_CIPHER_ALG_TWOFISH_192:
- case QCRYPTO_CIPHER_ALG_TWOFISH_256:
+ case QCRYPTO_CIPHER_ALGO_DES:
+ case QCRYPTO_CIPHER_ALGO_3DES:
+ case QCRYPTO_CIPHER_ALGO_AES_128:
+ case QCRYPTO_CIPHER_ALGO_AES_192:
+ case QCRYPTO_CIPHER_ALGO_AES_256:
+ case QCRYPTO_CIPHER_ALGO_CAST5_128:
+ case QCRYPTO_CIPHER_ALGO_SERPENT_128:
+ case QCRYPTO_CIPHER_ALGO_SERPENT_192:
+ case QCRYPTO_CIPHER_ALGO_SERPENT_256:
+ case QCRYPTO_CIPHER_ALGO_TWOFISH_128:
+ case QCRYPTO_CIPHER_ALGO_TWOFISH_192:
+ case QCRYPTO_CIPHER_ALGO_TWOFISH_256:
#ifdef CONFIG_CRYPTO_SM4
- case QCRYPTO_CIPHER_ALG_SM4:
+ case QCRYPTO_CIPHER_ALGO_SM4:
#endif
break;
default:
@@ -489,7 +489,7 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
}
}
-static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
+static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg,
QCryptoCipherMode mode,
const uint8_t *key,
size_t nkey,
@@ -510,7 +510,7 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
}
switch (alg) {
- case QCRYPTO_CIPHER_ALG_DES:
+ case QCRYPTO_CIPHER_ALGO_DES:
{
QCryptoNettleDES *ctx;
const QCryptoCipherDriver *drv;
@@ -525,8 +525,10 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
case QCRYPTO_CIPHER_MODE_CTR:
drv = &qcrypto_nettle_des_driver_ctr;
break;
- default:
+ case QCRYPTO_CIPHER_MODE_XTS:
goto bad_cipher_mode;
+ default:
+ g_assert_not_reached();
}
ctx = g_new0(QCryptoNettleDES, 1);
@@ -536,7 +538,7 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
return &ctx->base;
}
- case QCRYPTO_CIPHER_ALG_3DES:
+ case QCRYPTO_CIPHER_ALGO_3DES:
{
QCryptoNettleDES3 *ctx;
const QCryptoCipherDriver *drv;
@@ -551,8 +553,10 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
case QCRYPTO_CIPHER_MODE_CTR:
drv = &qcrypto_nettle_des3_driver_ctr;
break;
- default:
+ case QCRYPTO_CIPHER_MODE_XTS:
goto bad_cipher_mode;
+ default:
+ g_assert_not_reached();
}
ctx = g_new0(QCryptoNettleDES3, 1);
@@ -561,7 +565,7 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
return &ctx->base;
}
- case QCRYPTO_CIPHER_ALG_AES_128:
+ case QCRYPTO_CIPHER_ALGO_AES_128:
{
QCryptoNettleAES128 *ctx = g_new0(QCryptoNettleAES128, 1);
@@ -590,7 +594,7 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
return &ctx->base;
}
- case QCRYPTO_CIPHER_ALG_AES_192:
+ case QCRYPTO_CIPHER_ALGO_AES_192:
{
QCryptoNettleAES192 *ctx = g_new0(QCryptoNettleAES192, 1);
@@ -619,7 +623,7 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
return &ctx->base;
}
- case QCRYPTO_CIPHER_ALG_AES_256:
+ case QCRYPTO_CIPHER_ALGO_AES_256:
{
QCryptoNettleAES256 *ctx = g_new0(QCryptoNettleAES256, 1);
@@ -648,7 +652,7 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
return &ctx->base;
}
- case QCRYPTO_CIPHER_ALG_CAST5_128:
+ case QCRYPTO_CIPHER_ALGO_CAST5_128:
{
QCryptoNettleCAST128 *ctx;
const QCryptoCipherDriver *drv;
@@ -663,8 +667,10 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
case QCRYPTO_CIPHER_MODE_CTR:
drv = &qcrypto_nettle_cast128_driver_ctr;
break;
- default:
+ case QCRYPTO_CIPHER_MODE_XTS:
goto bad_cipher_mode;
+ default:
+ g_assert_not_reached();
}
ctx = g_new0(QCryptoNettleCAST128, 1);
@@ -674,9 +680,9 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
return &ctx->base;
}
- case QCRYPTO_CIPHER_ALG_SERPENT_128:
- case QCRYPTO_CIPHER_ALG_SERPENT_192:
- case QCRYPTO_CIPHER_ALG_SERPENT_256:
+ case QCRYPTO_CIPHER_ALGO_SERPENT_128:
+ case QCRYPTO_CIPHER_ALGO_SERPENT_192:
+ case QCRYPTO_CIPHER_ALGO_SERPENT_256:
{
QCryptoNettleSerpent *ctx = g_new0(QCryptoNettleSerpent, 1);
@@ -703,9 +709,9 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
return &ctx->base;
}
- case QCRYPTO_CIPHER_ALG_TWOFISH_128:
- case QCRYPTO_CIPHER_ALG_TWOFISH_192:
- case QCRYPTO_CIPHER_ALG_TWOFISH_256:
+ case QCRYPTO_CIPHER_ALGO_TWOFISH_128:
+ case QCRYPTO_CIPHER_ALGO_TWOFISH_192:
+ case QCRYPTO_CIPHER_ALGO_TWOFISH_256:
{
QCryptoNettleTwofish *ctx = g_new0(QCryptoNettleTwofish, 1);
@@ -732,18 +738,25 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
return &ctx->base;
}
#ifdef CONFIG_CRYPTO_SM4
- case QCRYPTO_CIPHER_ALG_SM4:
+ case QCRYPTO_CIPHER_ALGO_SM4:
{
- QCryptoNettleSm4 *ctx = g_new0(QCryptoNettleSm4, 1);
+ QCryptoNettleSm4 *ctx;
+ const QCryptoCipherDriver *drv;
switch (mode) {
case QCRYPTO_CIPHER_MODE_ECB:
- ctx->base.driver = &qcrypto_nettle_sm4_driver_ecb;
+ drv = &qcrypto_nettle_sm4_driver_ecb;
break;
- default:
+ case QCRYPTO_CIPHER_MODE_CBC:
+ case QCRYPTO_CIPHER_MODE_CTR:
+ case QCRYPTO_CIPHER_MODE_XTS:
goto bad_cipher_mode;
+ default:
+ g_assert_not_reached();
}
+ ctx = g_new0(QCryptoNettleSm4, 1);
+ ctx->base.driver = drv;
sm4_set_encrypt_key(&ctx->key[0], key);
sm4_set_decrypt_key(&ctx->key[1], key);
@@ -753,7 +766,7 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
default:
error_setg(errp, "Unsupported cipher algorithm %s",
- QCryptoCipherAlgorithm_str(alg));
+ QCryptoCipherAlgo_str(alg));
return NULL;
}
diff --git a/crypto/cipher.c b/crypto/cipher.c
index 5f51276..c14a8b8 100644
--- a/crypto/cipher.c
+++ b/crypto/cipher.c
@@ -25,39 +25,39 @@
#include "cipherpriv.h"
-static const size_t alg_key_len[QCRYPTO_CIPHER_ALG__MAX] = {
- [QCRYPTO_CIPHER_ALG_AES_128] = 16,
- [QCRYPTO_CIPHER_ALG_AES_192] = 24,
- [QCRYPTO_CIPHER_ALG_AES_256] = 32,
- [QCRYPTO_CIPHER_ALG_DES] = 8,
- [QCRYPTO_CIPHER_ALG_3DES] = 24,
- [QCRYPTO_CIPHER_ALG_CAST5_128] = 16,
- [QCRYPTO_CIPHER_ALG_SERPENT_128] = 16,
- [QCRYPTO_CIPHER_ALG_SERPENT_192] = 24,
- [QCRYPTO_CIPHER_ALG_SERPENT_256] = 32,
- [QCRYPTO_CIPHER_ALG_TWOFISH_128] = 16,
- [QCRYPTO_CIPHER_ALG_TWOFISH_192] = 24,
- [QCRYPTO_CIPHER_ALG_TWOFISH_256] = 32,
+static const size_t alg_key_len[QCRYPTO_CIPHER_ALGO__MAX] = {
+ [QCRYPTO_CIPHER_ALGO_AES_128] = 16,
+ [QCRYPTO_CIPHER_ALGO_AES_192] = 24,
+ [QCRYPTO_CIPHER_ALGO_AES_256] = 32,
+ [QCRYPTO_CIPHER_ALGO_DES] = 8,
+ [QCRYPTO_CIPHER_ALGO_3DES] = 24,
+ [QCRYPTO_CIPHER_ALGO_CAST5_128] = 16,
+ [QCRYPTO_CIPHER_ALGO_SERPENT_128] = 16,
+ [QCRYPTO_CIPHER_ALGO_SERPENT_192] = 24,
+ [QCRYPTO_CIPHER_ALGO_SERPENT_256] = 32,
+ [QCRYPTO_CIPHER_ALGO_TWOFISH_128] = 16,
+ [QCRYPTO_CIPHER_ALGO_TWOFISH_192] = 24,
+ [QCRYPTO_CIPHER_ALGO_TWOFISH_256] = 32,
#ifdef CONFIG_CRYPTO_SM4
- [QCRYPTO_CIPHER_ALG_SM4] = 16,
+ [QCRYPTO_CIPHER_ALGO_SM4] = 16,
#endif
};
-static const size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = {
- [QCRYPTO_CIPHER_ALG_AES_128] = 16,
- [QCRYPTO_CIPHER_ALG_AES_192] = 16,
- [QCRYPTO_CIPHER_ALG_AES_256] = 16,
- [QCRYPTO_CIPHER_ALG_DES] = 8,
- [QCRYPTO_CIPHER_ALG_3DES] = 8,
- [QCRYPTO_CIPHER_ALG_CAST5_128] = 8,
- [QCRYPTO_CIPHER_ALG_SERPENT_128] = 16,
- [QCRYPTO_CIPHER_ALG_SERPENT_192] = 16,
- [QCRYPTO_CIPHER_ALG_SERPENT_256] = 16,
- [QCRYPTO_CIPHER_ALG_TWOFISH_128] = 16,
- [QCRYPTO_CIPHER_ALG_TWOFISH_192] = 16,
- [QCRYPTO_CIPHER_ALG_TWOFISH_256] = 16,
+static const size_t alg_block_len[QCRYPTO_CIPHER_ALGO__MAX] = {
+ [QCRYPTO_CIPHER_ALGO_AES_128] = 16,
+ [QCRYPTO_CIPHER_ALGO_AES_192] = 16,
+ [QCRYPTO_CIPHER_ALGO_AES_256] = 16,
+ [QCRYPTO_CIPHER_ALGO_DES] = 8,
+ [QCRYPTO_CIPHER_ALGO_3DES] = 8,
+ [QCRYPTO_CIPHER_ALGO_CAST5_128] = 8,
+ [QCRYPTO_CIPHER_ALGO_SERPENT_128] = 16,
+ [QCRYPTO_CIPHER_ALGO_SERPENT_192] = 16,
+ [QCRYPTO_CIPHER_ALGO_SERPENT_256] = 16,
+ [QCRYPTO_CIPHER_ALGO_TWOFISH_128] = 16,
+ [QCRYPTO_CIPHER_ALGO_TWOFISH_192] = 16,
+ [QCRYPTO_CIPHER_ALGO_TWOFISH_256] = 16,
#ifdef CONFIG_CRYPTO_SM4
- [QCRYPTO_CIPHER_ALG_SM4] = 16,
+ [QCRYPTO_CIPHER_ALGO_SM4] = 16,
#endif
};
@@ -69,21 +69,21 @@ static const bool mode_need_iv[QCRYPTO_CIPHER_MODE__MAX] = {
};
-size_t qcrypto_cipher_get_block_len(QCryptoCipherAlgorithm alg)
+size_t qcrypto_cipher_get_block_len(QCryptoCipherAlgo alg)
{
assert(alg < G_N_ELEMENTS(alg_key_len));
return alg_block_len[alg];
}
-size_t qcrypto_cipher_get_key_len(QCryptoCipherAlgorithm alg)
+size_t qcrypto_cipher_get_key_len(QCryptoCipherAlgo alg)
{
assert(alg < G_N_ELEMENTS(alg_key_len));
return alg_key_len[alg];
}
-size_t qcrypto_cipher_get_iv_len(QCryptoCipherAlgorithm alg,
+size_t qcrypto_cipher_get_iv_len(QCryptoCipherAlgo alg,
QCryptoCipherMode mode)
{
if (alg >= G_N_ELEMENTS(alg_block_len)) {
@@ -101,20 +101,20 @@ size_t qcrypto_cipher_get_iv_len(QCryptoCipherAlgorithm alg,
static bool
-qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
+qcrypto_cipher_validate_key_length(QCryptoCipherAlgo alg,
QCryptoCipherMode mode,
size_t nkey,
Error **errp)
{
- if ((unsigned)alg >= QCRYPTO_CIPHER_ALG__MAX) {
+ if ((unsigned)alg >= QCRYPTO_CIPHER_ALGO__MAX) {
error_setg(errp, "Cipher algorithm %d out of range",
alg);
return false;
}
if (mode == QCRYPTO_CIPHER_MODE_XTS) {
- if (alg == QCRYPTO_CIPHER_ALG_DES ||
- alg == QCRYPTO_CIPHER_ALG_3DES) {
+ if (alg == QCRYPTO_CIPHER_ALGO_DES ||
+ alg == QCRYPTO_CIPHER_ALGO_3DES) {
error_setg(errp, "XTS mode not compatible with DES/3DES");
return false;
}
@@ -148,7 +148,7 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
#include "cipher-builtin.c.inc"
#endif
-QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
+QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgo alg,
QCryptoCipherMode mode,
const uint8_t *key, size_t nkey,
Error **errp)
diff --git a/crypto/cipherpriv.h b/crypto/cipherpriv.h
index 3965278..64737ce 100644
--- a/crypto/cipherpriv.h
+++ b/crypto/cipherpriv.h
@@ -42,7 +42,7 @@ struct QCryptoCipherDriver {
#include "afalgpriv.h"
extern QCryptoCipher *
-qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgorithm alg,
+qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgo alg,
QCryptoCipherMode mode,
const uint8_t *key,
size_t nkey, Error **errp);
diff --git a/crypto/der.c b/crypto/der.c
index ebbecfc..8136752 100644
--- a/crypto/der.c
+++ b/crypto/der.c
@@ -408,19 +408,6 @@ void qcrypto_der_encode_octet_str(QCryptoEncodeContext *ctx,
qcrypto_der_encode_prim(ctx, tag, src, src_len);
}
-void qcrypto_der_encode_octet_str_begin(QCryptoEncodeContext *ctx)
-{
- uint8_t tag = QCRYPTO_DER_TAG(QCRYPTO_DER_TAG_CLASS_UNIV,
- QCRYPTO_DER_TAG_ENC_PRIM,
- QCRYPTO_DER_TYPE_TAG_OCT_STR);
- qcrypto_der_encode_cons_begin(ctx, tag);
-}
-
-void qcrypto_der_encode_octet_str_end(QCryptoEncodeContext *ctx)
-{
- qcrypto_der_encode_cons_end(ctx);
-}
-
size_t qcrypto_der_encode_ctx_buffer_len(QCryptoEncodeContext *ctx)
{
return ctx->root.dlen;
diff --git a/crypto/der.h b/crypto/der.h
index f4ba6da..bcfa4a2 100644
--- a/crypto/der.h
+++ b/crypto/der.h
@@ -243,28 +243,6 @@ void qcrypto_der_encode_octet_str(QCryptoEncodeContext *ctx,
const uint8_t *src, size_t src_len);
/**
- * qcrypto_der_encode_octet_str_begin:
- * @ctx: the encode context.
- *
- * Start encoding a octet string, All fields between
- * qcrypto_der_encode_octet_str_begin and qcrypto_der_encode_octet_str_end
- * are encoded as an octet string. This is useful when we need to encode a
- * encoded SEQUENCE as OCTET STRING.
- */
-void qcrypto_der_encode_octet_str_begin(QCryptoEncodeContext *ctx);
-
-/**
- * qcrypto_der_encode_octet_str_end:
- * @ctx: the encode context.
- *
- * Finish encoding a octet string, All fields between
- * qcrypto_der_encode_octet_str_begin and qcrypto_der_encode_octet_str_end
- * are encoded as an octet string. This is useful when we need to encode a
- * encoded SEQUENCE as OCTET STRING.
- */
-void qcrypto_der_encode_octet_str_end(QCryptoEncodeContext *ctx);
-
-/**
* qcrypto_der_encode_ctx_buffer_len:
* @ctx: the encode context.
*
diff --git a/crypto/hash-afalg.c b/crypto/hash-afalg.c
index 3ebea39..8c0ce5b 100644
--- a/crypto/hash-afalg.c
+++ b/crypto/hash-afalg.c
@@ -1,6 +1,7 @@
/*
* QEMU Crypto af_alg-backend hash/hmac support
*
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
* Copyright (c) 2017 HUAWEI TECHNOLOGIES CO., LTD.
*
* Authors:
@@ -20,7 +21,7 @@
#include "hmacpriv.h"
static char *
-qcrypto_afalg_hash_format_name(QCryptoHashAlgorithm alg,
+qcrypto_afalg_hash_format_name(QCryptoHashAlgo alg,
bool is_hmac,
Error **errp)
{
@@ -28,25 +29,25 @@ qcrypto_afalg_hash_format_name(QCryptoHashAlgorithm alg,
const char *alg_name;
switch (alg) {
- case QCRYPTO_HASH_ALG_MD5:
+ case QCRYPTO_HASH_ALGO_MD5:
alg_name = "md5";
break;
- case QCRYPTO_HASH_ALG_SHA1:
+ case QCRYPTO_HASH_ALGO_SHA1:
alg_name = "sha1";
break;
- case QCRYPTO_HASH_ALG_SHA224:
+ case QCRYPTO_HASH_ALGO_SHA224:
alg_name = "sha224";
break;
- case QCRYPTO_HASH_ALG_SHA256:
+ case QCRYPTO_HASH_ALGO_SHA256:
alg_name = "sha256";
break;
- case QCRYPTO_HASH_ALG_SHA384:
+ case QCRYPTO_HASH_ALGO_SHA384:
alg_name = "sha384";
break;
- case QCRYPTO_HASH_ALG_SHA512:
+ case QCRYPTO_HASH_ALGO_SHA512:
alg_name = "sha512";
break;
- case QCRYPTO_HASH_ALG_RIPEMD160:
+ case QCRYPTO_HASH_ALGO_RIPEMD160:
alg_name = "rmd160";
break;
@@ -64,12 +65,12 @@ qcrypto_afalg_hash_format_name(QCryptoHashAlgorithm alg,
return name;
}
-static QCryptoAFAlg *
-qcrypto_afalg_hash_hmac_ctx_new(QCryptoHashAlgorithm alg,
+static QCryptoAFAlgo *
+qcrypto_afalg_hash_hmac_ctx_new(QCryptoHashAlgo alg,
const uint8_t *key, size_t nkey,
bool is_hmac, Error **errp)
{
- QCryptoAFAlg *afalg;
+ QCryptoAFAlgo *afalg;
char *name;
name = qcrypto_afalg_hash_format_name(alg, is_hmac, errp);
@@ -98,89 +99,160 @@ qcrypto_afalg_hash_hmac_ctx_new(QCryptoHashAlgorithm alg,
return afalg;
}
-static QCryptoAFAlg *
-qcrypto_afalg_hash_ctx_new(QCryptoHashAlgorithm alg,
+static QCryptoAFAlgo *
+qcrypto_afalg_hash_ctx_new(QCryptoHashAlgo alg,
Error **errp)
{
return qcrypto_afalg_hash_hmac_ctx_new(alg, NULL, 0, false, errp);
}
-QCryptoAFAlg *
-qcrypto_afalg_hmac_ctx_new(QCryptoHashAlgorithm alg,
+QCryptoAFAlgo *
+qcrypto_afalg_hmac_ctx_new(QCryptoHashAlgo alg,
const uint8_t *key, size_t nkey,
Error **errp)
{
return qcrypto_afalg_hash_hmac_ctx_new(alg, key, nkey, true, errp);
}
-static int
-qcrypto_afalg_hash_hmac_bytesv(QCryptoAFAlg *hmac,
- QCryptoHashAlgorithm alg,
- const struct iovec *iov,
- size_t niov, uint8_t **result,
- size_t *resultlen,
- Error **errp)
+static
+QCryptoHash *qcrypto_afalg_hash_new(QCryptoHashAlgo alg, Error **errp)
{
- QCryptoAFAlg *afalg;
- struct iovec outv;
- int ret = 0;
- bool is_hmac = (hmac != NULL) ? true : false;
- const int expect_len = qcrypto_hash_digest_len(alg);
+ /* Check if hash algorithm is supported */
+ char *alg_name = qcrypto_afalg_hash_format_name(alg, false, NULL);
+ QCryptoHash *hash;
- if (*resultlen == 0) {
- *resultlen = expect_len;
- *result = g_new0(uint8_t, *resultlen);
- } else if (*resultlen != expect_len) {
- error_setg(errp,
- "Result buffer size %zu is not match hash %d",
- *resultlen, expect_len);
- return -1;
+ if (alg_name == NULL) {
+ error_setg(errp, "Unknown hash algorithm %d", alg);
+ return NULL;
}
- if (is_hmac) {
- afalg = hmac;
- } else {
- afalg = qcrypto_afalg_hash_ctx_new(alg, errp);
- if (!afalg) {
- return -1;
- }
+ g_free(alg_name);
+
+ hash = g_new(QCryptoHash, 1);
+ hash->alg = alg;
+ hash->opaque = qcrypto_afalg_hash_ctx_new(alg, errp);
+ if (!hash->opaque) {
+ free(hash);
+ return NULL;
}
+ return hash;
+}
+
+static
+void qcrypto_afalg_hash_free(QCryptoHash *hash)
+{
+ QCryptoAFAlgo *ctx = hash->opaque;
+
+ if (ctx) {
+ qcrypto_afalg_comm_free(ctx);
+ }
+
+ g_free(hash);
+}
+
+/**
+ * Send data to the kernel's crypto core.
+ *
+ * The more_data parameter is used to notify the crypto engine
+ * that this is an "update" operation, and that more data will
+ * be provided to calculate the final hash.
+ */
+static
+int qcrypto_afalg_send_to_kernel(QCryptoAFAlgo *afalg,
+ const struct iovec *iov,
+ size_t niov,
+ bool more_data,
+ Error **errp)
+{
+ int ret = 0;
+ int flags = (more_data ? MSG_MORE : 0);
+
/* send data to kernel's crypto core */
- ret = iov_send_recv(afalg->opfd, iov, niov,
- 0, iov_size(iov, niov), true);
+ ret = iov_send_recv_with_flags(afalg->opfd, flags, iov, niov,
+ 0, iov_size(iov, niov), true);
if (ret < 0) {
error_setg_errno(errp, errno, "Send data to afalg-core failed");
- goto out;
+ ret = -1;
+ } else {
+ /* No error, so return 0 */
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static
+int qcrypto_afalg_recv_from_kernel(QCryptoAFAlgo *afalg,
+ QCryptoHashAlgo alg,
+ uint8_t **result,
+ size_t *result_len,
+ Error **errp)
+{
+ struct iovec outv;
+ int ret;
+ const int expected_len = qcrypto_hash_digest_len(alg);
+
+ if (*result_len == 0) {
+ *result_len = expected_len;
+ *result = g_new0(uint8_t, *result_len);
+ } else if (*result_len != expected_len) {
+ error_setg(errp,
+ "Result buffer size %zu is not match hash %d",
+ *result_len, expected_len);
+ return -1;
}
/* hash && get result */
outv.iov_base = *result;
- outv.iov_len = *resultlen;
+ outv.iov_len = *result_len;
ret = iov_send_recv(afalg->opfd, &outv, 1,
0, iov_size(&outv, 1), false);
if (ret < 0) {
error_setg_errno(errp, errno, "Recv result from afalg-core failed");
- } else {
- ret = 0;
+ return -1;
}
-out:
- if (!is_hmac) {
- qcrypto_afalg_comm_free(afalg);
- }
- return ret;
+ return 0;
+}
+
+static
+int qcrypto_afalg_hash_update(QCryptoHash *hash,
+ const struct iovec *iov,
+ size_t niov,
+ Error **errp)
+{
+ return qcrypto_afalg_send_to_kernel((QCryptoAFAlgo *) hash->opaque,
+ iov, niov, true, errp);
+}
+
+static
+int qcrypto_afalg_hash_finalize(QCryptoHash *hash,
+ uint8_t **result,
+ size_t *result_len,
+ Error **errp)
+{
+ return qcrypto_afalg_recv_from_kernel((QCryptoAFAlgo *) hash->opaque,
+ hash->alg, result, result_len, errp);
}
static int
-qcrypto_afalg_hash_bytesv(QCryptoHashAlgorithm alg,
- const struct iovec *iov,
- size_t niov, uint8_t **result,
- size_t *resultlen,
- Error **errp)
+qcrypto_afalg_hash_hmac_bytesv(QCryptoAFAlgo *hmac,
+ QCryptoHashAlgo alg,
+ const struct iovec *iov,
+ size_t niov, uint8_t **result,
+ size_t *resultlen,
+ Error **errp)
{
- return qcrypto_afalg_hash_hmac_bytesv(NULL, alg, iov, niov, result,
- resultlen, errp);
+ int ret = 0;
+
+ ret = qcrypto_afalg_send_to_kernel(hmac, iov, niov, false, errp);
+ if (ret == 0) {
+ ret = qcrypto_afalg_recv_from_kernel(hmac, alg, result,
+ resultlen, errp);
+ }
+
+ return ret;
}
static int
@@ -197,14 +269,17 @@ qcrypto_afalg_hmac_bytesv(QCryptoHmac *hmac,
static void qcrypto_afalg_hmac_ctx_free(QCryptoHmac *hmac)
{
- QCryptoAFAlg *afalg;
+ QCryptoAFAlgo *afalg;
afalg = hmac->opaque;
qcrypto_afalg_comm_free(afalg);
}
QCryptoHashDriver qcrypto_hash_afalg_driver = {
- .hash_bytesv = qcrypto_afalg_hash_bytesv,
+ .hash_new = qcrypto_afalg_hash_new,
+ .hash_free = qcrypto_afalg_hash_free,
+ .hash_update = qcrypto_afalg_hash_update,
+ .hash_finalize = qcrypto_afalg_hash_finalize
};
QCryptoHmacDriver qcrypto_hmac_afalg_driver = {
diff --git a/crypto/hash-gcrypt.c b/crypto/hash-gcrypt.c
index 829e482..73533a4 100644
--- a/crypto/hash-gcrypt.c
+++ b/crypto/hash-gcrypt.c
@@ -1,6 +1,7 @@
/*
* QEMU Crypto hash algorithms
*
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
* Copyright (c) 2016 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
@@ -25,17 +26,17 @@
#include "hashpriv.h"
-static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALG__MAX] = {
- [QCRYPTO_HASH_ALG_MD5] = GCRY_MD_MD5,
- [QCRYPTO_HASH_ALG_SHA1] = GCRY_MD_SHA1,
- [QCRYPTO_HASH_ALG_SHA224] = GCRY_MD_SHA224,
- [QCRYPTO_HASH_ALG_SHA256] = GCRY_MD_SHA256,
- [QCRYPTO_HASH_ALG_SHA384] = GCRY_MD_SHA384,
- [QCRYPTO_HASH_ALG_SHA512] = GCRY_MD_SHA512,
- [QCRYPTO_HASH_ALG_RIPEMD160] = GCRY_MD_RMD160,
+static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALGO__MAX] = {
+ [QCRYPTO_HASH_ALGO_MD5] = GCRY_MD_MD5,
+ [QCRYPTO_HASH_ALGO_SHA1] = GCRY_MD_SHA1,
+ [QCRYPTO_HASH_ALGO_SHA224] = GCRY_MD_SHA224,
+ [QCRYPTO_HASH_ALGO_SHA256] = GCRY_MD_SHA256,
+ [QCRYPTO_HASH_ALGO_SHA384] = GCRY_MD_SHA384,
+ [QCRYPTO_HASH_ALGO_SHA512] = GCRY_MD_SHA512,
+ [QCRYPTO_HASH_ALGO_RIPEMD160] = GCRY_MD_RMD160,
};
-gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg)
+gboolean qcrypto_hash_supports(QCryptoHashAlgo alg)
{
if (alg < G_N_ELEMENTS(qcrypto_hash_alg_map) &&
qcrypto_hash_alg_map[alg] != GCRY_MD_NONE) {
@@ -44,73 +45,93 @@ gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg)
return false;
}
-
-static int
-qcrypto_gcrypt_hash_bytesv(QCryptoHashAlgorithm alg,
- const struct iovec *iov,
- size_t niov,
- uint8_t **result,
- size_t *resultlen,
- Error **errp)
+static
+QCryptoHash *qcrypto_gcrypt_hash_new(QCryptoHashAlgo alg, Error **errp)
{
- int i, ret;
- gcry_md_hd_t md;
- unsigned char *digest;
-
- if (!qcrypto_hash_supports(alg)) {
- error_setg(errp,
- "Unknown hash algorithm %d",
- alg);
- return -1;
- }
+ QCryptoHash *hash;
+ int ret;
- ret = gcry_md_open(&md, qcrypto_hash_alg_map[alg], 0);
+ hash = g_new(QCryptoHash, 1);
+ hash->alg = alg;
+ hash->opaque = g_new(gcry_md_hd_t, 1);
+ ret = gcry_md_open((gcry_md_hd_t *) hash->opaque,
+ qcrypto_hash_alg_map[alg], 0);
if (ret < 0) {
error_setg(errp,
"Unable to initialize hash algorithm: %s",
gcry_strerror(ret));
- return -1;
+ g_free(hash->opaque);
+ g_free(hash);
+ return NULL;
}
+ return hash;
+}
- for (i = 0; i < niov; i++) {
- gcry_md_write(md, iov[i].iov_base, iov[i].iov_len);
+static
+void qcrypto_gcrypt_hash_free(QCryptoHash *hash)
+{
+ gcry_md_hd_t *ctx = hash->opaque;
+
+ if (ctx) {
+ gcry_md_close(*ctx);
+ g_free(ctx);
}
- ret = gcry_md_get_algo_dlen(qcrypto_hash_alg_map[alg]);
- if (ret <= 0) {
- error_setg(errp,
- "Unable to get hash length: %s",
- gcry_strerror(ret));
- goto error;
+ g_free(hash);
+}
+
+
+static
+int qcrypto_gcrypt_hash_update(QCryptoHash *hash,
+ const struct iovec *iov,
+ size_t niov,
+ Error **errp)
+{
+ gcry_md_hd_t *ctx = hash->opaque;
+
+ for (int i = 0; i < niov; i++) {
+ gcry_md_write(*ctx, iov[i].iov_base, iov[i].iov_len);
}
- if (*resultlen == 0) {
- *resultlen = ret;
- *result = g_new0(uint8_t, *resultlen);
- } else if (*resultlen != ret) {
- error_setg(errp,
- "Result buffer size %zu is smaller than hash %d",
- *resultlen, ret);
- goto error;
+
+ return 0;
+}
+
+static
+int qcrypto_gcrypt_hash_finalize(QCryptoHash *hash,
+ uint8_t **result,
+ size_t *result_len,
+ Error **errp)
+{
+ int ret;
+ unsigned char *digest;
+ gcry_md_hd_t *ctx = hash->opaque;
+
+ ret = gcry_md_get_algo_dlen(qcrypto_hash_alg_map[hash->alg]);
+ if (ret == 0) {
+ error_setg(errp, "Unable to get hash length");
+ return -1;
}
- digest = gcry_md_read(md, 0);
- if (!digest) {
+ if (*result_len == 0) {
+ *result_len = ret;
+ *result = g_new(uint8_t, *result_len);
+ } else if (*result_len != ret) {
error_setg(errp,
- "No digest produced");
- goto error;
+ "Result buffer size %zu is smaller than hash %d",
+ *result_len, ret);
+ return -1;
}
- memcpy(*result, digest, *resultlen);
- gcry_md_close(md);
+ /* Digest is freed by gcry_md_close(), copy it */
+ digest = gcry_md_read(*ctx, 0);
+ memcpy(*result, digest, *result_len);
return 0;
-
- error:
- gcry_md_close(md);
- return -1;
}
-
QCryptoHashDriver qcrypto_hash_lib_driver = {
- .hash_bytesv = qcrypto_gcrypt_hash_bytesv,
+ .hash_new = qcrypto_gcrypt_hash_new,
+ .hash_update = qcrypto_gcrypt_hash_update,
+ .hash_finalize = qcrypto_gcrypt_hash_finalize,
+ .hash_free = qcrypto_gcrypt_hash_free,
};
diff --git a/crypto/hash-glib.c b/crypto/hash-glib.c
index 82de9db..809cef9 100644
--- a/crypto/hash-glib.c
+++ b/crypto/hash-glib.c
@@ -1,6 +1,7 @@
/*
* QEMU Crypto hash algorithms
*
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
* Copyright (c) 2016 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
@@ -24,17 +25,17 @@
#include "hashpriv.h"
-static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALG__MAX] = {
- [QCRYPTO_HASH_ALG_MD5] = G_CHECKSUM_MD5,
- [QCRYPTO_HASH_ALG_SHA1] = G_CHECKSUM_SHA1,
- [QCRYPTO_HASH_ALG_SHA224] = -1,
- [QCRYPTO_HASH_ALG_SHA256] = G_CHECKSUM_SHA256,
- [QCRYPTO_HASH_ALG_SHA384] = -1,
- [QCRYPTO_HASH_ALG_SHA512] = G_CHECKSUM_SHA512,
- [QCRYPTO_HASH_ALG_RIPEMD160] = -1,
+static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALGO__MAX] = {
+ [QCRYPTO_HASH_ALGO_MD5] = G_CHECKSUM_MD5,
+ [QCRYPTO_HASH_ALGO_SHA1] = G_CHECKSUM_SHA1,
+ [QCRYPTO_HASH_ALGO_SHA224] = -1,
+ [QCRYPTO_HASH_ALGO_SHA256] = G_CHECKSUM_SHA256,
+ [QCRYPTO_HASH_ALGO_SHA384] = G_CHECKSUM_SHA384,
+ [QCRYPTO_HASH_ALGO_SHA512] = G_CHECKSUM_SHA512,
+ [QCRYPTO_HASH_ALGO_RIPEMD160] = -1,
};
-gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg)
+gboolean qcrypto_hash_supports(QCryptoHashAlgo alg)
{
if (alg < G_N_ELEMENTS(qcrypto_hash_alg_map) &&
qcrypto_hash_alg_map[alg] != -1) {
@@ -43,58 +44,78 @@ gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg)
return false;
}
-
-static int
-qcrypto_glib_hash_bytesv(QCryptoHashAlgorithm alg,
- const struct iovec *iov,
- size_t niov,
- uint8_t **result,
- size_t *resultlen,
- Error **errp)
+static
+QCryptoHash *qcrypto_glib_hash_new(QCryptoHashAlgo alg,
+ Error **errp)
{
- int i, ret;
- GChecksum *cs;
+ QCryptoHash *hash;
- if (!qcrypto_hash_supports(alg)) {
- error_setg(errp,
- "Unknown hash algorithm %d",
- alg);
- return -1;
+ hash = g_new(QCryptoHash, 1);
+ hash->alg = alg;
+ hash->opaque = g_checksum_new(qcrypto_hash_alg_map[alg]);
+
+ return hash;
+}
+
+static
+void qcrypto_glib_hash_free(QCryptoHash *hash)
+{
+ if (hash->opaque) {
+ g_checksum_free(hash->opaque);
}
- cs = g_checksum_new(qcrypto_hash_alg_map[alg]);
+ g_free(hash);
+}
+
+
+static
+int qcrypto_glib_hash_update(QCryptoHash *hash,
+ const struct iovec *iov,
+ size_t niov,
+ Error **errp)
+{
+ GChecksum *ctx = hash->opaque;
- for (i = 0; i < niov; i++) {
- g_checksum_update(cs, iov[i].iov_base, iov[i].iov_len);
+ for (int i = 0; i < niov; i++) {
+ g_checksum_update(ctx, iov[i].iov_base, iov[i].iov_len);
}
- ret = g_checksum_type_get_length(qcrypto_hash_alg_map[alg]);
+ return 0;
+}
+
+static
+int qcrypto_glib_hash_finalize(QCryptoHash *hash,
+ uint8_t **result,
+ size_t *result_len,
+ Error **errp)
+{
+ int ret;
+ GChecksum *ctx = hash->opaque;
+
+ ret = g_checksum_type_get_length(qcrypto_hash_alg_map[hash->alg]);
if (ret < 0) {
- error_setg(errp, "%s",
- "Unable to get hash length");
- goto error;
+ error_setg(errp, "Unable to get hash length");
+ *result_len = 0;
+ return -1;
}
- if (*resultlen == 0) {
- *resultlen = ret;
- *result = g_new0(uint8_t, *resultlen);
- } else if (*resultlen != ret) {
+
+ if (*result_len == 0) {
+ *result_len = ret;
+ *result = g_new(uint8_t, *result_len);
+ } else if (*result_len != ret) {
error_setg(errp,
"Result buffer size %zu is smaller than hash %d",
- *resultlen, ret);
- goto error;
+ *result_len, ret);
+ return -1;
}
- g_checksum_get_digest(cs, *result, resultlen);
-
- g_checksum_free(cs);
+ g_checksum_get_digest(ctx, *result, result_len);
return 0;
-
- error:
- g_checksum_free(cs);
- return -1;
}
-
QCryptoHashDriver qcrypto_hash_lib_driver = {
- .hash_bytesv = qcrypto_glib_hash_bytesv,
+ .hash_new = qcrypto_glib_hash_new,
+ .hash_update = qcrypto_glib_hash_update,
+ .hash_finalize = qcrypto_glib_hash_finalize,
+ .hash_free = qcrypto_glib_hash_free,
};
diff --git a/crypto/hash-gnutls.c b/crypto/hash-gnutls.c
index 17911ac..99fbe82 100644
--- a/crypto/hash-gnutls.c
+++ b/crypto/hash-gnutls.c
@@ -1,6 +1,7 @@
/*
* QEMU Crypto hash algorithms
*
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
* Copyright (c) 2021 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
@@ -25,17 +26,17 @@
#include "hashpriv.h"
-static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALG__MAX] = {
- [QCRYPTO_HASH_ALG_MD5] = GNUTLS_DIG_MD5,
- [QCRYPTO_HASH_ALG_SHA1] = GNUTLS_DIG_SHA1,
- [QCRYPTO_HASH_ALG_SHA224] = GNUTLS_DIG_SHA224,
- [QCRYPTO_HASH_ALG_SHA256] = GNUTLS_DIG_SHA256,
- [QCRYPTO_HASH_ALG_SHA384] = GNUTLS_DIG_SHA384,
- [QCRYPTO_HASH_ALG_SHA512] = GNUTLS_DIG_SHA512,
- [QCRYPTO_HASH_ALG_RIPEMD160] = GNUTLS_DIG_RMD160,
+static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALGO__MAX] = {
+ [QCRYPTO_HASH_ALGO_MD5] = GNUTLS_DIG_MD5,
+ [QCRYPTO_HASH_ALGO_SHA1] = GNUTLS_DIG_SHA1,
+ [QCRYPTO_HASH_ALGO_SHA224] = GNUTLS_DIG_SHA224,
+ [QCRYPTO_HASH_ALGO_SHA256] = GNUTLS_DIG_SHA256,
+ [QCRYPTO_HASH_ALGO_SHA384] = GNUTLS_DIG_SHA384,
+ [QCRYPTO_HASH_ALGO_SHA512] = GNUTLS_DIG_SHA512,
+ [QCRYPTO_HASH_ALGO_RIPEMD160] = GNUTLS_DIG_RMD160,
};
-gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg)
+gboolean qcrypto_hash_supports(QCryptoHashAlgo alg)
{
size_t i;
const gnutls_digest_algorithm_t *algs;
@@ -52,53 +53,93 @@ gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg)
return false;
}
-
-static int
-qcrypto_gnutls_hash_bytesv(QCryptoHashAlgorithm alg,
- const struct iovec *iov,
- size_t niov,
- uint8_t **result,
- size_t *resultlen,
- Error **errp)
+static
+QCryptoHash *qcrypto_gnutls_hash_new(QCryptoHashAlgo alg, Error **errp)
{
- int i, ret;
- gnutls_hash_hd_t hash;
-
- if (!qcrypto_hash_supports(alg)) {
- error_setg(errp,
- "Unknown hash algorithm %d",
- alg);
- return -1;
- }
+ QCryptoHash *hash;
+ int ret;
- ret = gnutls_hash_get_len(qcrypto_hash_alg_map[alg]);
- if (*resultlen == 0) {
- *resultlen = ret;
- *result = g_new0(uint8_t, *resultlen);
- } else if (*resultlen != ret) {
- error_setg(errp,
- "Result buffer size %zu is smaller than hash %d",
- *resultlen, ret);
- return -1;
- }
+ hash = g_new(QCryptoHash, 1);
+ hash->alg = alg;
+ hash->opaque = g_new(gnutls_hash_hd_t, 1);
- ret = gnutls_hash_init(&hash, qcrypto_hash_alg_map[alg]);
+ ret = gnutls_hash_init(hash->opaque, qcrypto_hash_alg_map[alg]);
if (ret < 0) {
error_setg(errp,
"Unable to initialize hash algorithm: %s",
gnutls_strerror(ret));
- return -1;
+ g_free(hash->opaque);
+ g_free(hash);
+ return NULL;
}
- for (i = 0; i < niov; i++) {
- gnutls_hash(hash, iov[i].iov_base, iov[i].iov_len);
+ return hash;
+}
+
+static
+void qcrypto_gnutls_hash_free(QCryptoHash *hash)
+{
+ gnutls_hash_hd_t *ctx = hash->opaque;
+
+ gnutls_hash_deinit(*ctx, NULL);
+ g_free(ctx);
+ g_free(hash);
+}
+
+
+static
+int qcrypto_gnutls_hash_update(QCryptoHash *hash,
+ const struct iovec *iov,
+ size_t niov,
+ Error **errp)
+{
+ int ret = 0;
+ gnutls_hash_hd_t *ctx = hash->opaque;
+
+ for (int i = 0; i < niov; i++) {
+ ret = gnutls_hash(*ctx, iov[i].iov_base, iov[i].iov_len);
+ if (ret != 0) {
+ error_setg(errp, "Failed to hash data: %s",
+ gnutls_strerror(ret));
+ return -1;
+ }
}
- gnutls_hash_deinit(hash, *result);
return 0;
}
+static
+int qcrypto_gnutls_hash_finalize(QCryptoHash *hash,
+ uint8_t **result,
+ size_t *result_len,
+ Error **errp)
+{
+ gnutls_hash_hd_t *ctx = hash->opaque;
+ int ret;
+
+ ret = gnutls_hash_get_len(qcrypto_hash_alg_map[hash->alg]);
+ if (ret == 0) {
+ error_setg(errp, "Unable to get hash length");
+ return -1;
+ }
+
+ if (*result_len == 0) {
+ *result_len = ret;
+ *result = g_new(uint8_t, *result_len);
+ } else if (*result_len != ret) {
+ error_setg(errp,
+ "Result buffer size %zu is smaller than hash %d",
+ *result_len, ret);
+ return -1;
+ }
+
+ gnutls_hash_output(*ctx, *result);
+ return 0;
+}
QCryptoHashDriver qcrypto_hash_lib_driver = {
- .hash_bytesv = qcrypto_gnutls_hash_bytesv,
+ .hash_new = qcrypto_gnutls_hash_new,
+ .hash_update = qcrypto_gnutls_hash_update,
+ .hash_finalize = qcrypto_gnutls_hash_finalize,
+ .hash_free = qcrypto_gnutls_hash_free,
};
diff --git a/crypto/hash-nettle.c b/crypto/hash-nettle.c
index 1ca1a41..c78624b 100644
--- a/crypto/hash-nettle.c
+++ b/crypto/hash-nettle.c
@@ -1,6 +1,7 @@
/*
* QEMU Crypto hash algorithms
*
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
* Copyright (c) 2016 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
@@ -50,43 +51,43 @@ struct qcrypto_hash_alg {
qcrypto_nettle_result result;
size_t len;
} qcrypto_hash_alg_map[] = {
- [QCRYPTO_HASH_ALG_MD5] = {
+ [QCRYPTO_HASH_ALGO_MD5] = {
.init = (qcrypto_nettle_init)md5_init,
.write = (qcrypto_nettle_write)md5_update,
.result = (qcrypto_nettle_result)md5_digest,
.len = MD5_DIGEST_SIZE,
},
- [QCRYPTO_HASH_ALG_SHA1] = {
+ [QCRYPTO_HASH_ALGO_SHA1] = {
.init = (qcrypto_nettle_init)sha1_init,
.write = (qcrypto_nettle_write)sha1_update,
.result = (qcrypto_nettle_result)sha1_digest,
.len = SHA1_DIGEST_SIZE,
},
- [QCRYPTO_HASH_ALG_SHA224] = {
+ [QCRYPTO_HASH_ALGO_SHA224] = {
.init = (qcrypto_nettle_init)sha224_init,
.write = (qcrypto_nettle_write)sha224_update,
.result = (qcrypto_nettle_result)sha224_digest,
.len = SHA224_DIGEST_SIZE,
},
- [QCRYPTO_HASH_ALG_SHA256] = {
+ [QCRYPTO_HASH_ALGO_SHA256] = {
.init = (qcrypto_nettle_init)sha256_init,
.write = (qcrypto_nettle_write)sha256_update,
.result = (qcrypto_nettle_result)sha256_digest,
.len = SHA256_DIGEST_SIZE,
},
- [QCRYPTO_HASH_ALG_SHA384] = {
+ [QCRYPTO_HASH_ALGO_SHA384] = {
.init = (qcrypto_nettle_init)sha384_init,
.write = (qcrypto_nettle_write)sha384_update,
.result = (qcrypto_nettle_result)sha384_digest,
.len = SHA384_DIGEST_SIZE,
},
- [QCRYPTO_HASH_ALG_SHA512] = {
+ [QCRYPTO_HASH_ALGO_SHA512] = {
.init = (qcrypto_nettle_init)sha512_init,
.write = (qcrypto_nettle_write)sha512_update,
.result = (qcrypto_nettle_result)sha512_digest,
.len = SHA512_DIGEST_SIZE,
},
- [QCRYPTO_HASH_ALG_RIPEMD160] = {
+ [QCRYPTO_HASH_ALGO_RIPEMD160] = {
.init = (qcrypto_nettle_init)ripemd160_init,
.write = (qcrypto_nettle_write)ripemd160_update,
.result = (qcrypto_nettle_result)ripemd160_digest,
@@ -94,7 +95,7 @@ struct qcrypto_hash_alg {
},
};
-gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg)
+gboolean qcrypto_hash_supports(QCryptoHashAlgo alg)
{
if (alg < G_N_ELEMENTS(qcrypto_hash_alg_map) &&
qcrypto_hash_alg_map[alg].init != NULL) {
@@ -103,59 +104,72 @@ gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg)
return false;
}
+static
+QCryptoHash *qcrypto_nettle_hash_new(QCryptoHashAlgo alg, Error **errp)
+{
+ QCryptoHash *hash;
+
+ hash = g_new(QCryptoHash, 1);
+ hash->alg = alg;
+ hash->opaque = g_new(union qcrypto_hash_ctx, 1);
+
+ qcrypto_hash_alg_map[alg].init(hash->opaque);
+ return hash;
+}
-static int
-qcrypto_nettle_hash_bytesv(QCryptoHashAlgorithm alg,
- const struct iovec *iov,
- size_t niov,
- uint8_t **result,
- size_t *resultlen,
- Error **errp)
+static
+void qcrypto_nettle_hash_free(QCryptoHash *hash)
{
- size_t i;
- union qcrypto_hash_ctx ctx;
+ union qcrypto_hash_ctx *ctx = hash->opaque;
- if (!qcrypto_hash_supports(alg)) {
- error_setg(errp,
- "Unknown hash algorithm %d",
- alg);
- return -1;
- }
+ g_free(ctx);
+ g_free(hash);
+}
- qcrypto_hash_alg_map[alg].init(&ctx);
-
- for (i = 0; i < niov; i++) {
- /* Some versions of nettle have functions
- * declared with 'int' instead of 'size_t'
- * so to be safe avoid writing more than
- * UINT_MAX bytes at a time
- */
- size_t len = iov[i].iov_len;
- uint8_t *base = iov[i].iov_base;
- while (len) {
- size_t shortlen = MIN(len, UINT_MAX);
- qcrypto_hash_alg_map[alg].write(&ctx, len, base);
- len -= shortlen;
- base += len;
- }
+static
+int qcrypto_nettle_hash_update(QCryptoHash *hash,
+ const struct iovec *iov,
+ size_t niov,
+ Error **errp)
+{
+ union qcrypto_hash_ctx *ctx = hash->opaque;
+
+ for (int i = 0; i < niov; i++) {
+ qcrypto_hash_alg_map[hash->alg].write(ctx,
+ iov[i].iov_len,
+ iov[i].iov_base);
}
- if (*resultlen == 0) {
- *resultlen = qcrypto_hash_alg_map[alg].len;
- *result = g_new0(uint8_t, *resultlen);
- } else if (*resultlen != qcrypto_hash_alg_map[alg].len) {
+ return 0;
+}
+
+static
+int qcrypto_nettle_hash_finalize(QCryptoHash *hash,
+ uint8_t **result,
+ size_t *result_len,
+ Error **errp)
+{
+ union qcrypto_hash_ctx *ctx = hash->opaque;
+ int ret = qcrypto_hash_alg_map[hash->alg].len;
+
+ if (*result_len == 0) {
+ *result_len = ret;
+ *result = g_new(uint8_t, *result_len);
+ } else if (*result_len != ret) {
error_setg(errp,
- "Result buffer size %zu is smaller than hash %zu",
- *resultlen, qcrypto_hash_alg_map[alg].len);
+ "Result buffer size %zu is smaller than hash %d",
+ *result_len, ret);
return -1;
}
- qcrypto_hash_alg_map[alg].result(&ctx, *resultlen, *result);
+ qcrypto_hash_alg_map[hash->alg].result(ctx, *result_len, *result);
return 0;
}
-
QCryptoHashDriver qcrypto_hash_lib_driver = {
- .hash_bytesv = qcrypto_nettle_hash_bytesv,
+ .hash_new = qcrypto_nettle_hash_new,
+ .hash_update = qcrypto_nettle_hash_update,
+ .hash_finalize = qcrypto_nettle_hash_finalize,
+ .hash_free = qcrypto_nettle_hash_free,
};
diff --git a/crypto/hash.c b/crypto/hash.c
index b0f8228..0c8548c 100644
--- a/crypto/hash.c
+++ b/crypto/hash.c
@@ -1,6 +1,7 @@
/*
* QEMU Crypto hash algorithms
*
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
* Copyright (c) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
@@ -19,53 +20,50 @@
*/
#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qapi-types-crypto.h"
#include "crypto/hash.h"
#include "hashpriv.h"
-static size_t qcrypto_hash_alg_size[QCRYPTO_HASH_ALG__MAX] = {
- [QCRYPTO_HASH_ALG_MD5] = 16,
- [QCRYPTO_HASH_ALG_SHA1] = 20,
- [QCRYPTO_HASH_ALG_SHA224] = 28,
- [QCRYPTO_HASH_ALG_SHA256] = 32,
- [QCRYPTO_HASH_ALG_SHA384] = 48,
- [QCRYPTO_HASH_ALG_SHA512] = 64,
- [QCRYPTO_HASH_ALG_RIPEMD160] = 20,
+static size_t qcrypto_hash_alg_size[QCRYPTO_HASH_ALGO__MAX] = {
+ [QCRYPTO_HASH_ALGO_MD5] = QCRYPTO_HASH_DIGEST_LEN_MD5,
+ [QCRYPTO_HASH_ALGO_SHA1] = QCRYPTO_HASH_DIGEST_LEN_SHA1,
+ [QCRYPTO_HASH_ALGO_SHA224] = QCRYPTO_HASH_DIGEST_LEN_SHA224,
+ [QCRYPTO_HASH_ALGO_SHA256] = QCRYPTO_HASH_DIGEST_LEN_SHA256,
+ [QCRYPTO_HASH_ALGO_SHA384] = QCRYPTO_HASH_DIGEST_LEN_SHA384,
+ [QCRYPTO_HASH_ALGO_SHA512] = QCRYPTO_HASH_DIGEST_LEN_SHA512,
+ [QCRYPTO_HASH_ALGO_RIPEMD160] = QCRYPTO_HASH_DIGEST_LEN_RIPEMD160,
};
-size_t qcrypto_hash_digest_len(QCryptoHashAlgorithm alg)
+size_t qcrypto_hash_digest_len(QCryptoHashAlgo alg)
{
assert(alg < G_N_ELEMENTS(qcrypto_hash_alg_size));
return qcrypto_hash_alg_size[alg];
}
-int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg,
+int qcrypto_hash_bytesv(QCryptoHashAlgo alg,
const struct iovec *iov,
size_t niov,
uint8_t **result,
size_t *resultlen,
Error **errp)
{
-#ifdef CONFIG_AF_ALG
- int ret;
- /*
- * TODO:
- * Maybe we should treat some afalg errors as fatal
- */
- ret = qcrypto_hash_afalg_driver.hash_bytesv(alg, iov, niov,
- result, resultlen,
- NULL);
- if (ret == 0) {
- return ret;
+ g_autoptr(QCryptoHash) ctx = qcrypto_hash_new(alg, errp);
+
+ if (!ctx) {
+ return -1;
+ }
+
+ if (qcrypto_hash_updatev(ctx, iov, niov, errp) < 0 ||
+ qcrypto_hash_finalize_bytes(ctx, result, resultlen, errp) < 0) {
+ return -1;
}
-#endif
- return qcrypto_hash_lib_driver.hash_bytesv(alg, iov, niov,
- result, resultlen,
- errp);
+ return 0;
}
-int qcrypto_hash_bytes(QCryptoHashAlgorithm alg,
+int qcrypto_hash_bytes(QCryptoHashAlgo alg,
const char *buf,
size_t len,
uint8_t **result,
@@ -77,33 +75,134 @@ int qcrypto_hash_bytes(QCryptoHashAlgorithm alg,
return qcrypto_hash_bytesv(alg, &iov, 1, result, resultlen, errp);
}
+int qcrypto_hash_updatev(QCryptoHash *hash,
+ const struct iovec *iov,
+ size_t niov,
+ Error **errp)
+{
+ QCryptoHashDriver *drv = hash->driver;
+
+ return drv->hash_update(hash, iov, niov, errp);
+}
+
+int qcrypto_hash_update(QCryptoHash *hash,
+ const char *buf,
+ size_t len,
+ Error **errp)
+{
+ struct iovec iov = { .iov_base = (char *)buf, .iov_len = len };
+
+ return qcrypto_hash_updatev(hash, &iov, 1, errp);
+}
+
+QCryptoHash *qcrypto_hash_new(QCryptoHashAlgo alg, Error **errp)
+{
+ QCryptoHash *hash = NULL;
+
+ if (!qcrypto_hash_supports(alg)) {
+ error_setg(errp, "Unsupported hash algorithm %s",
+ QCryptoHashAlgo_str(alg));
+ return NULL;
+ }
+
+#ifdef CONFIG_AF_ALG
+ hash = qcrypto_hash_afalg_driver.hash_new(alg, NULL);
+ if (hash) {
+ hash->driver = &qcrypto_hash_afalg_driver;
+ return hash;
+ }
+#endif
+
+ hash = qcrypto_hash_lib_driver.hash_new(alg, errp);
+ if (!hash) {
+ return NULL;
+ }
+
+ hash->driver = &qcrypto_hash_lib_driver;
+ return hash;
+}
+
+void qcrypto_hash_free(QCryptoHash *hash)
+{
+ QCryptoHashDriver *drv;
+
+ if (hash) {
+ drv = hash->driver;
+ drv->hash_free(hash);
+ }
+}
+
+int qcrypto_hash_finalize_bytes(QCryptoHash *hash,
+ uint8_t **result,
+ size_t *result_len,
+ Error **errp)
+{
+ QCryptoHashDriver *drv = hash->driver;
+
+ return drv->hash_finalize(hash, result, result_len, errp);
+}
+
static const char hex[] = "0123456789abcdef";
-int qcrypto_hash_digestv(QCryptoHashAlgorithm alg,
+int qcrypto_hash_finalize_digest(QCryptoHash *hash,
+ char **digest,
+ Error **errp)
+{
+ int ret;
+ g_autofree uint8_t *result = NULL;
+ size_t resultlen = 0;
+ size_t i;
+
+ ret = qcrypto_hash_finalize_bytes(hash, &result, &resultlen, errp);
+ if (ret == 0) {
+ *digest = g_new0(char, (resultlen * 2) + 1);
+ for (i = 0 ; i < resultlen ; i++) {
+ (*digest)[(i * 2)] = hex[(result[i] >> 4) & 0xf];
+ (*digest)[(i * 2) + 1] = hex[result[i] & 0xf];
+ }
+ (*digest)[resultlen * 2] = '\0';
+ }
+
+ return ret;
+}
+
+int qcrypto_hash_finalize_base64(QCryptoHash *hash,
+ char **base64,
+ Error **errp)
+{
+ int ret;
+ g_autofree uint8_t *result = NULL;
+ size_t resultlen = 0;
+
+ ret = qcrypto_hash_finalize_bytes(hash, &result, &resultlen, errp);
+ if (ret == 0) {
+ *base64 = g_base64_encode(result, resultlen);
+ }
+
+ return ret;
+}
+
+int qcrypto_hash_digestv(QCryptoHashAlgo alg,
const struct iovec *iov,
size_t niov,
char **digest,
Error **errp)
{
- uint8_t *result = NULL;
- size_t resultlen = 0;
- size_t i;
+ g_autoptr(QCryptoHash) ctx = qcrypto_hash_new(alg, errp);
- if (qcrypto_hash_bytesv(alg, iov, niov, &result, &resultlen, errp) < 0) {
+ if (!ctx) {
return -1;
}
- *digest = g_new0(char, (resultlen * 2) + 1);
- for (i = 0 ; i < resultlen ; i++) {
- (*digest)[(i * 2)] = hex[(result[i] >> 4) & 0xf];
- (*digest)[(i * 2) + 1] = hex[result[i] & 0xf];
+ if (qcrypto_hash_updatev(ctx, iov, niov, errp) < 0 ||
+ qcrypto_hash_finalize_digest(ctx, digest, errp) < 0) {
+ return -1;
}
- (*digest)[resultlen * 2] = '\0';
- g_free(result);
+
return 0;
}
-int qcrypto_hash_digest(QCryptoHashAlgorithm alg,
+int qcrypto_hash_digest(QCryptoHashAlgo alg,
const char *buf,
size_t len,
char **digest,
@@ -114,25 +213,27 @@ int qcrypto_hash_digest(QCryptoHashAlgorithm alg,
return qcrypto_hash_digestv(alg, &iov, 1, digest, errp);
}
-int qcrypto_hash_base64v(QCryptoHashAlgorithm alg,
+int qcrypto_hash_base64v(QCryptoHashAlgo alg,
const struct iovec *iov,
size_t niov,
char **base64,
Error **errp)
{
- uint8_t *result = NULL;
- size_t resultlen = 0;
+ g_autoptr(QCryptoHash) ctx = qcrypto_hash_new(alg, errp);
+
+ if (!ctx) {
+ return -1;
+ }
- if (qcrypto_hash_bytesv(alg, iov, niov, &result, &resultlen, errp) < 0) {
+ if (qcrypto_hash_updatev(ctx, iov, niov, errp) < 0 ||
+ qcrypto_hash_finalize_base64(ctx, base64, errp) < 0) {
return -1;
}
- *base64 = g_base64_encode(result, resultlen);
- g_free(result);
return 0;
}
-int qcrypto_hash_base64(QCryptoHashAlgorithm alg,
+int qcrypto_hash_base64(QCryptoHashAlgo alg,
const char *buf,
size_t len,
char **base64,
diff --git a/crypto/hashpriv.h b/crypto/hashpriv.h
index cee26cc..83b9256 100644
--- a/crypto/hashpriv.h
+++ b/crypto/hashpriv.h
@@ -1,6 +1,7 @@
/*
* QEMU Crypto hash driver supports
*
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
* Copyright (c) 2017 HUAWEI TECHNOLOGIES CO., LTD.
*
* Authors:
@@ -15,15 +16,21 @@
#ifndef QCRYPTO_HASHPRIV_H
#define QCRYPTO_HASHPRIV_H
+#include "crypto/hash.h"
+
typedef struct QCryptoHashDriver QCryptoHashDriver;
struct QCryptoHashDriver {
- int (*hash_bytesv)(QCryptoHashAlgorithm alg,
+ QCryptoHash *(*hash_new)(QCryptoHashAlgo alg, Error **errp);
+ int (*hash_update)(QCryptoHash *hash,
const struct iovec *iov,
size_t niov,
- uint8_t **result,
- size_t *resultlen,
Error **errp);
+ int (*hash_finalize)(QCryptoHash *hash,
+ uint8_t **result,
+ size_t *resultlen,
+ Error **errp);
+ void (*hash_free)(QCryptoHash *hash);
};
extern QCryptoHashDriver qcrypto_hash_lib_driver;
diff --git a/crypto/hmac-gcrypt.c b/crypto/hmac-gcrypt.c
index 0c6f979..19990cb 100644
--- a/crypto/hmac-gcrypt.c
+++ b/crypto/hmac-gcrypt.c
@@ -18,14 +18,14 @@
#include "hmacpriv.h"
#include <gcrypt.h>
-static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = {
- [QCRYPTO_HASH_ALG_MD5] = GCRY_MAC_HMAC_MD5,
- [QCRYPTO_HASH_ALG_SHA1] = GCRY_MAC_HMAC_SHA1,
- [QCRYPTO_HASH_ALG_SHA224] = GCRY_MAC_HMAC_SHA224,
- [QCRYPTO_HASH_ALG_SHA256] = GCRY_MAC_HMAC_SHA256,
- [QCRYPTO_HASH_ALG_SHA384] = GCRY_MAC_HMAC_SHA384,
- [QCRYPTO_HASH_ALG_SHA512] = GCRY_MAC_HMAC_SHA512,
- [QCRYPTO_HASH_ALG_RIPEMD160] = GCRY_MAC_HMAC_RMD160,
+static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALGO__MAX] = {
+ [QCRYPTO_HASH_ALGO_MD5] = GCRY_MAC_HMAC_MD5,
+ [QCRYPTO_HASH_ALGO_SHA1] = GCRY_MAC_HMAC_SHA1,
+ [QCRYPTO_HASH_ALGO_SHA224] = GCRY_MAC_HMAC_SHA224,
+ [QCRYPTO_HASH_ALGO_SHA256] = GCRY_MAC_HMAC_SHA256,
+ [QCRYPTO_HASH_ALGO_SHA384] = GCRY_MAC_HMAC_SHA384,
+ [QCRYPTO_HASH_ALGO_SHA512] = GCRY_MAC_HMAC_SHA512,
+ [QCRYPTO_HASH_ALGO_RIPEMD160] = GCRY_MAC_HMAC_RMD160,
};
typedef struct QCryptoHmacGcrypt QCryptoHmacGcrypt;
@@ -33,7 +33,7 @@ struct QCryptoHmacGcrypt {
gcry_mac_hd_t handle;
};
-bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
+bool qcrypto_hmac_supports(QCryptoHashAlgo alg)
{
if (alg < G_N_ELEMENTS(qcrypto_hmac_alg_map) &&
qcrypto_hmac_alg_map[alg] != GCRY_MAC_NONE) {
@@ -43,7 +43,7 @@ bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
return false;
}
-void *qcrypto_hmac_ctx_new(QCryptoHashAlgorithm alg,
+void *qcrypto_hmac_ctx_new(QCryptoHashAlgo alg,
const uint8_t *key, size_t nkey,
Error **errp)
{
@@ -52,7 +52,7 @@ void *qcrypto_hmac_ctx_new(QCryptoHashAlgorithm alg,
if (!qcrypto_hmac_supports(alg)) {
error_setg(errp, "Unsupported hmac algorithm %s",
- QCryptoHashAlgorithm_str(alg));
+ QCryptoHashAlgo_str(alg));
return NULL;
}
diff --git a/crypto/hmac-glib.c b/crypto/hmac-glib.c
index 509bbc7..ea80c8d 100644
--- a/crypto/hmac-glib.c
+++ b/crypto/hmac-glib.c
@@ -17,14 +17,14 @@
#include "crypto/hmac.h"
#include "hmacpriv.h"
-static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = {
- [QCRYPTO_HASH_ALG_MD5] = G_CHECKSUM_MD5,
- [QCRYPTO_HASH_ALG_SHA1] = G_CHECKSUM_SHA1,
- [QCRYPTO_HASH_ALG_SHA256] = G_CHECKSUM_SHA256,
- [QCRYPTO_HASH_ALG_SHA512] = G_CHECKSUM_SHA512,
- [QCRYPTO_HASH_ALG_SHA224] = -1,
- [QCRYPTO_HASH_ALG_SHA384] = -1,
- [QCRYPTO_HASH_ALG_RIPEMD160] = -1,
+static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALGO__MAX] = {
+ [QCRYPTO_HASH_ALGO_MD5] = G_CHECKSUM_MD5,
+ [QCRYPTO_HASH_ALGO_SHA1] = G_CHECKSUM_SHA1,
+ [QCRYPTO_HASH_ALGO_SHA256] = G_CHECKSUM_SHA256,
+ [QCRYPTO_HASH_ALGO_SHA512] = G_CHECKSUM_SHA512,
+ [QCRYPTO_HASH_ALGO_SHA224] = -1,
+ [QCRYPTO_HASH_ALGO_SHA384] = -1,
+ [QCRYPTO_HASH_ALGO_RIPEMD160] = -1,
};
typedef struct QCryptoHmacGlib QCryptoHmacGlib;
@@ -32,7 +32,7 @@ struct QCryptoHmacGlib {
GHmac *ghmac;
};
-bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
+bool qcrypto_hmac_supports(QCryptoHashAlgo alg)
{
if (alg < G_N_ELEMENTS(qcrypto_hmac_alg_map) &&
qcrypto_hmac_alg_map[alg] != -1) {
@@ -42,7 +42,7 @@ bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
return false;
}
-void *qcrypto_hmac_ctx_new(QCryptoHashAlgorithm alg,
+void *qcrypto_hmac_ctx_new(QCryptoHashAlgo alg,
const uint8_t *key, size_t nkey,
Error **errp)
{
@@ -50,7 +50,7 @@ void *qcrypto_hmac_ctx_new(QCryptoHashAlgorithm alg,
if (!qcrypto_hmac_supports(alg)) {
error_setg(errp, "Unsupported hmac algorithm %s",
- QCryptoHashAlgorithm_str(alg));
+ QCryptoHashAlgo_str(alg));
return NULL;
}
diff --git a/crypto/hmac-gnutls.c b/crypto/hmac-gnutls.c
index 24db383..8229955 100644
--- a/crypto/hmac-gnutls.c
+++ b/crypto/hmac-gnutls.c
@@ -20,14 +20,14 @@
#include "crypto/hmac.h"
#include "hmacpriv.h"
-static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = {
- [QCRYPTO_HASH_ALG_MD5] = GNUTLS_MAC_MD5,
- [QCRYPTO_HASH_ALG_SHA1] = GNUTLS_MAC_SHA1,
- [QCRYPTO_HASH_ALG_SHA224] = GNUTLS_MAC_SHA224,
- [QCRYPTO_HASH_ALG_SHA256] = GNUTLS_MAC_SHA256,
- [QCRYPTO_HASH_ALG_SHA384] = GNUTLS_MAC_SHA384,
- [QCRYPTO_HASH_ALG_SHA512] = GNUTLS_MAC_SHA512,
- [QCRYPTO_HASH_ALG_RIPEMD160] = GNUTLS_MAC_RMD160,
+static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALGO__MAX] = {
+ [QCRYPTO_HASH_ALGO_MD5] = GNUTLS_MAC_MD5,
+ [QCRYPTO_HASH_ALGO_SHA1] = GNUTLS_MAC_SHA1,
+ [QCRYPTO_HASH_ALGO_SHA224] = GNUTLS_MAC_SHA224,
+ [QCRYPTO_HASH_ALGO_SHA256] = GNUTLS_MAC_SHA256,
+ [QCRYPTO_HASH_ALGO_SHA384] = GNUTLS_MAC_SHA384,
+ [QCRYPTO_HASH_ALGO_SHA512] = GNUTLS_MAC_SHA512,
+ [QCRYPTO_HASH_ALGO_RIPEMD160] = GNUTLS_MAC_RMD160,
};
typedef struct QCryptoHmacGnutls QCryptoHmacGnutls;
@@ -35,7 +35,7 @@ struct QCryptoHmacGnutls {
gnutls_hmac_hd_t handle;
};
-bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
+bool qcrypto_hmac_supports(QCryptoHashAlgo alg)
{
size_t i;
const gnutls_digest_algorithm_t *algs;
@@ -52,7 +52,7 @@ bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
return false;
}
-void *qcrypto_hmac_ctx_new(QCryptoHashAlgorithm alg,
+void *qcrypto_hmac_ctx_new(QCryptoHashAlgo alg,
const uint8_t *key, size_t nkey,
Error **errp)
{
@@ -61,7 +61,7 @@ void *qcrypto_hmac_ctx_new(QCryptoHashAlgorithm alg,
if (!qcrypto_hmac_supports(alg)) {
error_setg(errp, "Unsupported hmac algorithm %s",
- QCryptoHashAlgorithm_str(alg));
+ QCryptoHashAlgo_str(alg));
return NULL;
}
diff --git a/crypto/hmac-nettle.c b/crypto/hmac-nettle.c
index 1ad6c4f..54dd75d 100644
--- a/crypto/hmac-nettle.c
+++ b/crypto/hmac-nettle.c
@@ -46,44 +46,44 @@ struct qcrypto_nettle_hmac_alg {
qcrypto_nettle_hmac_update update;
qcrypto_nettle_hmac_digest digest;
size_t len;
-} qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = {
- [QCRYPTO_HASH_ALG_MD5] = {
+} qcrypto_hmac_alg_map[QCRYPTO_HASH_ALGO__MAX] = {
+ [QCRYPTO_HASH_ALGO_MD5] = {
.setkey = (qcrypto_nettle_hmac_setkey)hmac_md5_set_key,
.update = (qcrypto_nettle_hmac_update)hmac_md5_update,
.digest = (qcrypto_nettle_hmac_digest)hmac_md5_digest,
.len = MD5_DIGEST_SIZE,
},
- [QCRYPTO_HASH_ALG_SHA1] = {
+ [QCRYPTO_HASH_ALGO_SHA1] = {
.setkey = (qcrypto_nettle_hmac_setkey)hmac_sha1_set_key,
.update = (qcrypto_nettle_hmac_update)hmac_sha1_update,
.digest = (qcrypto_nettle_hmac_digest)hmac_sha1_digest,
.len = SHA1_DIGEST_SIZE,
},
- [QCRYPTO_HASH_ALG_SHA224] = {
+ [QCRYPTO_HASH_ALGO_SHA224] = {
.setkey = (qcrypto_nettle_hmac_setkey)hmac_sha224_set_key,
.update = (qcrypto_nettle_hmac_update)hmac_sha224_update,
.digest = (qcrypto_nettle_hmac_digest)hmac_sha224_digest,
.len = SHA224_DIGEST_SIZE,
},
- [QCRYPTO_HASH_ALG_SHA256] = {
+ [QCRYPTO_HASH_ALGO_SHA256] = {
.setkey = (qcrypto_nettle_hmac_setkey)hmac_sha256_set_key,
.update = (qcrypto_nettle_hmac_update)hmac_sha256_update,
.digest = (qcrypto_nettle_hmac_digest)hmac_sha256_digest,
.len = SHA256_DIGEST_SIZE,
},
- [QCRYPTO_HASH_ALG_SHA384] = {
+ [QCRYPTO_HASH_ALGO_SHA384] = {
.setkey = (qcrypto_nettle_hmac_setkey)hmac_sha384_set_key,
.update = (qcrypto_nettle_hmac_update)hmac_sha384_update,
.digest = (qcrypto_nettle_hmac_digest)hmac_sha384_digest,
.len = SHA384_DIGEST_SIZE,
},
- [QCRYPTO_HASH_ALG_SHA512] = {
+ [QCRYPTO_HASH_ALGO_SHA512] = {
.setkey = (qcrypto_nettle_hmac_setkey)hmac_sha512_set_key,
.update = (qcrypto_nettle_hmac_update)hmac_sha512_update,
.digest = (qcrypto_nettle_hmac_digest)hmac_sha512_digest,
.len = SHA512_DIGEST_SIZE,
},
- [QCRYPTO_HASH_ALG_RIPEMD160] = {
+ [QCRYPTO_HASH_ALGO_RIPEMD160] = {
.setkey = (qcrypto_nettle_hmac_setkey)hmac_ripemd160_set_key,
.update = (qcrypto_nettle_hmac_update)hmac_ripemd160_update,
.digest = (qcrypto_nettle_hmac_digest)hmac_ripemd160_digest,
@@ -91,7 +91,7 @@ struct qcrypto_nettle_hmac_alg {
},
};
-bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
+bool qcrypto_hmac_supports(QCryptoHashAlgo alg)
{
if (alg < G_N_ELEMENTS(qcrypto_hmac_alg_map) &&
qcrypto_hmac_alg_map[alg].setkey != NULL) {
@@ -101,7 +101,7 @@ bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
return false;
}
-void *qcrypto_hmac_ctx_new(QCryptoHashAlgorithm alg,
+void *qcrypto_hmac_ctx_new(QCryptoHashAlgo alg,
const uint8_t *key, size_t nkey,
Error **errp)
{
@@ -109,7 +109,7 @@ void *qcrypto_hmac_ctx_new(QCryptoHashAlgorithm alg,
if (!qcrypto_hmac_supports(alg)) {
error_setg(errp, "Unsupported hmac algorithm %s",
- QCryptoHashAlgorithm_str(alg));
+ QCryptoHashAlgo_str(alg));
return NULL;
}
diff --git a/crypto/hmac.c b/crypto/hmac.c
index 4de7e8c..422e005 100644
--- a/crypto/hmac.c
+++ b/crypto/hmac.c
@@ -83,7 +83,7 @@ int qcrypto_hmac_digest(QCryptoHmac *hmac,
return qcrypto_hmac_digestv(hmac, &iov, 1, digest, errp);
}
-QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg,
+QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgo alg,
const uint8_t *key, size_t nkey,
Error **errp)
{
diff --git a/crypto/hmacpriv.h b/crypto/hmacpriv.h
index 62dfe82..f339596 100644
--- a/crypto/hmacpriv.h
+++ b/crypto/hmacpriv.h
@@ -28,7 +28,7 @@ struct QCryptoHmacDriver {
void (*hmac_free)(QCryptoHmac *hmac);
};
-void *qcrypto_hmac_ctx_new(QCryptoHashAlgorithm alg,
+void *qcrypto_hmac_ctx_new(QCryptoHashAlgo alg,
const uint8_t *key, size_t nkey,
Error **errp);
extern QCryptoHmacDriver qcrypto_hmac_lib_driver;
@@ -37,7 +37,7 @@ extern QCryptoHmacDriver qcrypto_hmac_lib_driver;
#include "afalgpriv.h"
-QCryptoAFAlg *qcrypto_afalg_hmac_ctx_new(QCryptoHashAlgorithm alg,
+QCryptoAFAlgo *qcrypto_afalg_hmac_ctx_new(QCryptoHashAlgo alg,
const uint8_t *key, size_t nkey,
Error **errp);
extern QCryptoHmacDriver qcrypto_hmac_afalg_driver;
diff --git a/crypto/init.c b/crypto/init.c
index fb7f1bf..674d237 100644
--- a/crypto/init.c
+++ b/crypto/init.c
@@ -34,14 +34,11 @@
#include "crypto/random.h"
-/* #define DEBUG_GNUTLS */
-#ifdef DEBUG_GNUTLS
-static void qcrypto_gnutls_log(int level, const char *str)
-{
- fprintf(stderr, "%d: %s", level, str);
-}
-#endif
+/*
+ * To debug GNUTLS see env vars listed in
+ * https://gnutls.org/manual/html_node/Debugging-and-auditing.html
+ */
int qcrypto_init(Error **errp)
{
#ifdef CONFIG_GNUTLS
@@ -53,10 +50,6 @@ int qcrypto_init(Error **errp)
gnutls_strerror(ret));
return -1;
}
-#ifdef DEBUG_GNUTLS
- gnutls_global_set_log_level(10);
- gnutls_global_set_log_function(qcrypto_gnutls_log);
-#endif
#endif
#ifdef CONFIG_GCRYPT
diff --git a/crypto/ivgen.c b/crypto/ivgen.c
index 12822f8..6b7d24d 100644
--- a/crypto/ivgen.c
+++ b/crypto/ivgen.c
@@ -27,9 +27,9 @@
#include "ivgen-essiv.h"
-QCryptoIVGen *qcrypto_ivgen_new(QCryptoIVGenAlgorithm alg,
- QCryptoCipherAlgorithm cipheralg,
- QCryptoHashAlgorithm hash,
+QCryptoIVGen *qcrypto_ivgen_new(QCryptoIVGenAlgo alg,
+ QCryptoCipherAlgo cipheralg,
+ QCryptoHashAlgo hash,
const uint8_t *key, size_t nkey,
Error **errp)
{
@@ -40,13 +40,13 @@ QCryptoIVGen *qcrypto_ivgen_new(QCryptoIVGenAlgorithm alg,
ivgen->hash = hash;
switch (alg) {
- case QCRYPTO_IVGEN_ALG_PLAIN:
+ case QCRYPTO_IV_GEN_ALGO_PLAIN:
ivgen->driver = &qcrypto_ivgen_plain;
break;
- case QCRYPTO_IVGEN_ALG_PLAIN64:
+ case QCRYPTO_IV_GEN_ALGO_PLAIN64:
ivgen->driver = &qcrypto_ivgen_plain64;
break;
- case QCRYPTO_IVGEN_ALG_ESSIV:
+ case QCRYPTO_IV_GEN_ALGO_ESSIV:
ivgen->driver = &qcrypto_ivgen_essiv;
break;
default:
@@ -73,19 +73,19 @@ int qcrypto_ivgen_calculate(QCryptoIVGen *ivgen,
}
-QCryptoIVGenAlgorithm qcrypto_ivgen_get_algorithm(QCryptoIVGen *ivgen)
+QCryptoIVGenAlgo qcrypto_ivgen_get_algorithm(QCryptoIVGen *ivgen)
{
return ivgen->algorithm;
}
-QCryptoCipherAlgorithm qcrypto_ivgen_get_cipher(QCryptoIVGen *ivgen)
+QCryptoCipherAlgo qcrypto_ivgen_get_cipher(QCryptoIVGen *ivgen)
{
return ivgen->cipher;
}
-QCryptoHashAlgorithm qcrypto_ivgen_get_hash(QCryptoIVGen *ivgen)
+QCryptoHashAlgo qcrypto_ivgen_get_hash(QCryptoIVGen *ivgen)
{
return ivgen->hash;
}
diff --git a/crypto/ivgenpriv.h b/crypto/ivgenpriv.h
index cecdbed..e3388d3 100644
--- a/crypto/ivgenpriv.h
+++ b/crypto/ivgenpriv.h
@@ -40,9 +40,9 @@ struct QCryptoIVGen {
QCryptoIVGenDriver *driver;
void *private;
- QCryptoIVGenAlgorithm algorithm;
- QCryptoCipherAlgorithm cipher;
- QCryptoHashAlgorithm hash;
+ QCryptoIVGenAlgo algorithm;
+ QCryptoCipherAlgo cipher;
+ QCryptoHashAlgo hash;
};
diff --git a/crypto/meson.build b/crypto/meson.build
index c46f9c2..735635d 100644
--- a/crypto/meson.build
+++ b/crypto/meson.build
@@ -24,6 +24,10 @@ crypto_ss.add(files(
'rsakey.c',
))
+if gnutls.found()
+ crypto_ss.add(files('x509-utils.c'))
+endif
+
if nettle.found()
crypto_ss.add(nettle, files('hash-nettle.c', 'hmac-nettle.c', 'pbkdf-nettle.c'))
if hogweed.found()
diff --git a/crypto/pbkdf-gcrypt.c b/crypto/pbkdf-gcrypt.c
index a8d8e64..76bbb55 100644
--- a/crypto/pbkdf-gcrypt.c
+++ b/crypto/pbkdf-gcrypt.c
@@ -23,37 +23,37 @@
#include "qapi/error.h"
#include "crypto/pbkdf.h"
-bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
+bool qcrypto_pbkdf2_supports(QCryptoHashAlgo hash)
{
switch (hash) {
- case QCRYPTO_HASH_ALG_MD5:
- case QCRYPTO_HASH_ALG_SHA1:
- case QCRYPTO_HASH_ALG_SHA224:
- case QCRYPTO_HASH_ALG_SHA256:
- case QCRYPTO_HASH_ALG_SHA384:
- case QCRYPTO_HASH_ALG_SHA512:
- case QCRYPTO_HASH_ALG_RIPEMD160:
- return true;
+ case QCRYPTO_HASH_ALGO_MD5:
+ case QCRYPTO_HASH_ALGO_SHA1:
+ case QCRYPTO_HASH_ALGO_SHA224:
+ case QCRYPTO_HASH_ALGO_SHA256:
+ case QCRYPTO_HASH_ALGO_SHA384:
+ case QCRYPTO_HASH_ALGO_SHA512:
+ case QCRYPTO_HASH_ALGO_RIPEMD160:
+ return qcrypto_hash_supports(hash);
default:
return false;
}
}
-int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
+int qcrypto_pbkdf2(QCryptoHashAlgo hash,
const uint8_t *key, size_t nkey,
const uint8_t *salt, size_t nsalt,
uint64_t iterations,
uint8_t *out, size_t nout,
Error **errp)
{
- static const int hash_map[QCRYPTO_HASH_ALG__MAX] = {
- [QCRYPTO_HASH_ALG_MD5] = GCRY_MD_MD5,
- [QCRYPTO_HASH_ALG_SHA1] = GCRY_MD_SHA1,
- [QCRYPTO_HASH_ALG_SHA224] = GCRY_MD_SHA224,
- [QCRYPTO_HASH_ALG_SHA256] = GCRY_MD_SHA256,
- [QCRYPTO_HASH_ALG_SHA384] = GCRY_MD_SHA384,
- [QCRYPTO_HASH_ALG_SHA512] = GCRY_MD_SHA512,
- [QCRYPTO_HASH_ALG_RIPEMD160] = GCRY_MD_RMD160,
+ static const int hash_map[QCRYPTO_HASH_ALGO__MAX] = {
+ [QCRYPTO_HASH_ALGO_MD5] = GCRY_MD_MD5,
+ [QCRYPTO_HASH_ALGO_SHA1] = GCRY_MD_SHA1,
+ [QCRYPTO_HASH_ALGO_SHA224] = GCRY_MD_SHA224,
+ [QCRYPTO_HASH_ALGO_SHA256] = GCRY_MD_SHA256,
+ [QCRYPTO_HASH_ALGO_SHA384] = GCRY_MD_SHA384,
+ [QCRYPTO_HASH_ALGO_SHA512] = GCRY_MD_SHA512,
+ [QCRYPTO_HASH_ALGO_RIPEMD160] = GCRY_MD_RMD160,
};
int ret;
@@ -68,7 +68,7 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
hash_map[hash] == GCRY_MD_NONE) {
error_setg_errno(errp, ENOSYS,
"PBKDF does not support hash algorithm %s",
- QCryptoHashAlgorithm_str(hash));
+ QCryptoHashAlgo_str(hash));
return -1;
}
diff --git a/crypto/pbkdf-gnutls.c b/crypto/pbkdf-gnutls.c
index 2dfbbd3..f34423f 100644
--- a/crypto/pbkdf-gnutls.c
+++ b/crypto/pbkdf-gnutls.c
@@ -23,37 +23,37 @@
#include "qapi/error.h"
#include "crypto/pbkdf.h"
-bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
+bool qcrypto_pbkdf2_supports(QCryptoHashAlgo hash)
{
switch (hash) {
- case QCRYPTO_HASH_ALG_MD5:
- case QCRYPTO_HASH_ALG_SHA1:
- case QCRYPTO_HASH_ALG_SHA224:
- case QCRYPTO_HASH_ALG_SHA256:
- case QCRYPTO_HASH_ALG_SHA384:
- case QCRYPTO_HASH_ALG_SHA512:
- case QCRYPTO_HASH_ALG_RIPEMD160:
- return true;
+ case QCRYPTO_HASH_ALGO_MD5:
+ case QCRYPTO_HASH_ALGO_SHA1:
+ case QCRYPTO_HASH_ALGO_SHA224:
+ case QCRYPTO_HASH_ALGO_SHA256:
+ case QCRYPTO_HASH_ALGO_SHA384:
+ case QCRYPTO_HASH_ALGO_SHA512:
+ case QCRYPTO_HASH_ALGO_RIPEMD160:
+ return qcrypto_hash_supports(hash);
default:
return false;
}
}
-int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
+int qcrypto_pbkdf2(QCryptoHashAlgo hash,
const uint8_t *key, size_t nkey,
const uint8_t *salt, size_t nsalt,
uint64_t iterations,
uint8_t *out, size_t nout,
Error **errp)
{
- static const int hash_map[QCRYPTO_HASH_ALG__MAX] = {
- [QCRYPTO_HASH_ALG_MD5] = GNUTLS_DIG_MD5,
- [QCRYPTO_HASH_ALG_SHA1] = GNUTLS_DIG_SHA1,
- [QCRYPTO_HASH_ALG_SHA224] = GNUTLS_DIG_SHA224,
- [QCRYPTO_HASH_ALG_SHA256] = GNUTLS_DIG_SHA256,
- [QCRYPTO_HASH_ALG_SHA384] = GNUTLS_DIG_SHA384,
- [QCRYPTO_HASH_ALG_SHA512] = GNUTLS_DIG_SHA512,
- [QCRYPTO_HASH_ALG_RIPEMD160] = GNUTLS_DIG_RMD160,
+ static const int hash_map[QCRYPTO_HASH_ALGO__MAX] = {
+ [QCRYPTO_HASH_ALGO_MD5] = GNUTLS_DIG_MD5,
+ [QCRYPTO_HASH_ALGO_SHA1] = GNUTLS_DIG_SHA1,
+ [QCRYPTO_HASH_ALGO_SHA224] = GNUTLS_DIG_SHA224,
+ [QCRYPTO_HASH_ALGO_SHA256] = GNUTLS_DIG_SHA256,
+ [QCRYPTO_HASH_ALGO_SHA384] = GNUTLS_DIG_SHA384,
+ [QCRYPTO_HASH_ALGO_SHA512] = GNUTLS_DIG_SHA512,
+ [QCRYPTO_HASH_ALGO_RIPEMD160] = GNUTLS_DIG_RMD160,
};
int ret;
const gnutls_datum_t gkey = { (unsigned char *)key, nkey };
@@ -70,7 +70,7 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
hash_map[hash] == GNUTLS_DIG_UNKNOWN) {
error_setg_errno(errp, ENOSYS,
"PBKDF does not support hash algorithm %s",
- QCryptoHashAlgorithm_str(hash));
+ QCryptoHashAlgo_str(hash));
return -1;
}
diff --git a/crypto/pbkdf-nettle.c b/crypto/pbkdf-nettle.c
index d6293c2..93e686c 100644
--- a/crypto/pbkdf-nettle.c
+++ b/crypto/pbkdf-nettle.c
@@ -25,22 +25,22 @@
#include "crypto/pbkdf.h"
-bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
+bool qcrypto_pbkdf2_supports(QCryptoHashAlgo hash)
{
switch (hash) {
- case QCRYPTO_HASH_ALG_SHA1:
- case QCRYPTO_HASH_ALG_SHA224:
- case QCRYPTO_HASH_ALG_SHA256:
- case QCRYPTO_HASH_ALG_SHA384:
- case QCRYPTO_HASH_ALG_SHA512:
- case QCRYPTO_HASH_ALG_RIPEMD160:
+ case QCRYPTO_HASH_ALGO_SHA1:
+ case QCRYPTO_HASH_ALGO_SHA224:
+ case QCRYPTO_HASH_ALGO_SHA256:
+ case QCRYPTO_HASH_ALGO_SHA384:
+ case QCRYPTO_HASH_ALGO_SHA512:
+ case QCRYPTO_HASH_ALGO_RIPEMD160:
return true;
default:
return false;
}
}
-int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
+int qcrypto_pbkdf2(QCryptoHashAlgo hash,
const uint8_t *key, size_t nkey,
const uint8_t *salt, size_t nsalt,
uint64_t iterations,
@@ -65,43 +65,43 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
}
switch (hash) {
- case QCRYPTO_HASH_ALG_MD5:
+ case QCRYPTO_HASH_ALGO_MD5:
hmac_md5_set_key(&ctx.md5, nkey, key);
PBKDF2(&ctx.md5, hmac_md5_update, hmac_md5_digest,
MD5_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
break;
- case QCRYPTO_HASH_ALG_SHA1:
+ case QCRYPTO_HASH_ALGO_SHA1:
hmac_sha1_set_key(&ctx.sha1, nkey, key);
PBKDF2(&ctx.sha1, hmac_sha1_update, hmac_sha1_digest,
SHA1_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
break;
- case QCRYPTO_HASH_ALG_SHA224:
+ case QCRYPTO_HASH_ALGO_SHA224:
hmac_sha224_set_key(&ctx.sha224, nkey, key);
PBKDF2(&ctx.sha224, hmac_sha224_update, hmac_sha224_digest,
SHA224_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
break;
- case QCRYPTO_HASH_ALG_SHA256:
+ case QCRYPTO_HASH_ALGO_SHA256:
hmac_sha256_set_key(&ctx.sha256, nkey, key);
PBKDF2(&ctx.sha256, hmac_sha256_update, hmac_sha256_digest,
SHA256_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
break;
- case QCRYPTO_HASH_ALG_SHA384:
+ case QCRYPTO_HASH_ALGO_SHA384:
hmac_sha384_set_key(&ctx.sha384, nkey, key);
PBKDF2(&ctx.sha384, hmac_sha384_update, hmac_sha384_digest,
SHA384_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
break;
- case QCRYPTO_HASH_ALG_SHA512:
+ case QCRYPTO_HASH_ALGO_SHA512:
hmac_sha512_set_key(&ctx.sha512, nkey, key);
PBKDF2(&ctx.sha512, hmac_sha512_update, hmac_sha512_digest,
SHA512_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
break;
- case QCRYPTO_HASH_ALG_RIPEMD160:
+ case QCRYPTO_HASH_ALGO_RIPEMD160:
hmac_ripemd160_set_key(&ctx.ripemd160, nkey, key);
PBKDF2(&ctx.ripemd160, hmac_ripemd160_update, hmac_ripemd160_digest,
RIPEMD160_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
@@ -110,7 +110,7 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
default:
error_setg_errno(errp, ENOSYS,
"PBKDF does not support hash algorithm %s",
- QCryptoHashAlgorithm_str(hash));
+ QCryptoHashAlgo_str(hash));
return -1;
}
return 0;
diff --git a/crypto/pbkdf-stub.c b/crypto/pbkdf-stub.c
index 9c4622e..9f29d0e 100644
--- a/crypto/pbkdf-stub.c
+++ b/crypto/pbkdf-stub.c
@@ -22,12 +22,12 @@
#include "qapi/error.h"
#include "crypto/pbkdf.h"
-bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash G_GNUC_UNUSED)
+bool qcrypto_pbkdf2_supports(QCryptoHashAlgo hash G_GNUC_UNUSED)
{
return false;
}
-int qcrypto_pbkdf2(QCryptoHashAlgorithm hash G_GNUC_UNUSED,
+int qcrypto_pbkdf2(QCryptoHashAlgo hash G_GNUC_UNUSED,
const uint8_t *key G_GNUC_UNUSED,
size_t nkey G_GNUC_UNUSED,
const uint8_t *salt G_GNUC_UNUSED,
diff --git a/crypto/pbkdf.c b/crypto/pbkdf.c
index 8d198c1..0dd7c3a 100644
--- a/crypto/pbkdf.c
+++ b/crypto/pbkdf.c
@@ -19,6 +19,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/thread.h"
#include "qapi/error.h"
#include "crypto/pbkdf.h"
#ifndef _WIN32
@@ -85,12 +86,28 @@ static int qcrypto_pbkdf2_get_thread_cpu(unsigned long long *val_ms,
#endif
}
-uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
- const uint8_t *key, size_t nkey,
- const uint8_t *salt, size_t nsalt,
- size_t nout,
- Error **errp)
+typedef struct CountItersData {
+ QCryptoHashAlgo hash;
+ const uint8_t *key;
+ size_t nkey;
+ const uint8_t *salt;
+ size_t nsalt;
+ size_t nout;
+ uint64_t iterations;
+ Error **errp;
+} CountItersData;
+
+static void *threaded_qcrypto_pbkdf2_count_iters(void *data)
{
+ CountItersData *iters_data = (CountItersData *) data;
+ QCryptoHashAlgo hash = iters_data->hash;
+ const uint8_t *key = iters_data->key;
+ size_t nkey = iters_data->nkey;
+ const uint8_t *salt = iters_data->salt;
+ size_t nsalt = iters_data->nsalt;
+ size_t nout = iters_data->nout;
+ Error **errp = iters_data->errp;
+
uint64_t ret = -1;
g_autofree uint8_t *out = g_new(uint8_t, nout);
uint64_t iterations = (1 << 15);
@@ -114,7 +131,10 @@ uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
delta_ms = end_ms - start_ms;
- if (delta_ms > 500) {
+ if (delta_ms == 0) { /* sanity check */
+ error_setg(errp, "Unable to get accurate CPU usage");
+ goto cleanup;
+ } else if (delta_ms > 500) {
break;
} else if (delta_ms < 100) {
iterations = iterations * 10;
@@ -129,5 +149,24 @@ uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
cleanup:
memset(out, 0, nout);
- return ret;
+ iters_data->iterations = ret;
+ return NULL;
+}
+
+uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgo hash,
+ const uint8_t *key, size_t nkey,
+ const uint8_t *salt, size_t nsalt,
+ size_t nout,
+ Error **errp)
+{
+ CountItersData data = {
+ hash, key, nkey, salt, nsalt, nout, 0, errp
+ };
+ QemuThread thread;
+
+ qemu_thread_create(&thread, "pbkdf2", threaded_qcrypto_pbkdf2_count_iters,
+ &data, QEMU_THREAD_JOINABLE);
+ qemu_thread_join(&thread);
+
+ return data.iterations;
}
diff --git a/crypto/rsakey-builtin.c.inc b/crypto/rsakey-builtin.c.inc
index 46cc7af..6337b84 100644
--- a/crypto/rsakey-builtin.c.inc
+++ b/crypto/rsakey-builtin.c.inc
@@ -183,10 +183,10 @@ QCryptoAkCipherRSAKey *qcrypto_akcipher_rsakey_parse(
size_t keylen, Error **errp)
{
switch (type) {
- case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
+ case QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE:
return qcrypto_builtin_rsa_private_key_parse(key, keylen, errp);
- case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
+ case QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC:
return qcrypto_builtin_rsa_public_key_parse(key, keylen, errp);
default:
diff --git a/crypto/rsakey-nettle.c.inc b/crypto/rsakey-nettle.c.inc
index cc49872..b7f34b0 100644
--- a/crypto/rsakey-nettle.c.inc
+++ b/crypto/rsakey-nettle.c.inc
@@ -145,10 +145,10 @@ QCryptoAkCipherRSAKey *qcrypto_akcipher_rsakey_parse(
size_t keylen, Error **errp)
{
switch (type) {
- case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
+ case QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE:
return qcrypto_nettle_rsa_private_key_parse(key, keylen, errp);
- case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
+ case QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC:
return qcrypto_nettle_rsa_public_key_parse(key, keylen, errp);
default:
diff --git a/crypto/secret_common.c b/crypto/secret_common.c
index 3441c44..2c14110 100644
--- a/crypto/secret_common.c
+++ b/crypto/secret_common.c
@@ -71,7 +71,7 @@ static void qcrypto_secret_decrypt(QCryptoSecretCommon *secret,
return;
}
- aes = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_256,
+ aes = qcrypto_cipher_new(QCRYPTO_CIPHER_ALGO_AES_256,
QCRYPTO_CIPHER_MODE_CBC,
key, keylen,
errp);
diff --git a/crypto/tlscredspsk.c b/crypto/tlscredspsk.c
index 546cad1..0d6b71a 100644
--- a/crypto/tlscredspsk.c
+++ b/crypto/tlscredspsk.c
@@ -243,6 +243,7 @@ qcrypto_tls_creds_psk_finalize(Object *obj)
QCryptoTLSCredsPSK *creds = QCRYPTO_TLS_CREDS_PSK(obj);
qcrypto_tls_creds_psk_unload(creds);
+ g_free(creds->username);
}
static void
diff --git a/crypto/tlssession.c b/crypto/tlssession.c
index 1e98f44..77286e2 100644
--- a/crypto/tlssession.c
+++ b/crypto/tlssession.c
@@ -44,6 +44,13 @@ struct QCryptoTLSSession {
QCryptoTLSSessionReadFunc readFunc;
void *opaque;
char *peername;
+
+ /*
+ * Allow concurrent reads and writes, so track
+ * errors separately
+ */
+ Error *rerr;
+ Error *werr;
};
@@ -54,6 +61,9 @@ qcrypto_tls_session_free(QCryptoTLSSession *session)
return;
}
+ error_free(session->rerr);
+ error_free(session->werr);
+
gnutls_deinit(session->handle);
g_free(session->hostname);
g_free(session->peername);
@@ -67,13 +77,26 @@ static ssize_t
qcrypto_tls_session_push(void *opaque, const void *buf, size_t len)
{
QCryptoTLSSession *session = opaque;
+ ssize_t ret;
if (!session->writeFunc) {
errno = EIO;
return -1;
};
- return session->writeFunc(buf, len, session->opaque);
+ error_free(session->werr);
+ session->werr = NULL;
+
+ ret = session->writeFunc(buf, len, session->opaque, &session->werr);
+ if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
+ errno = EAGAIN;
+ return -1;
+ } else if (ret < 0) {
+ errno = EIO;
+ return -1;
+ } else {
+ return ret;
+ }
}
@@ -81,13 +104,26 @@ static ssize_t
qcrypto_tls_session_pull(void *opaque, void *buf, size_t len)
{
QCryptoTLSSession *session = opaque;
+ ssize_t ret;
if (!session->readFunc) {
errno = EIO;
return -1;
};
- return session->readFunc(buf, len, session->opaque);
+ error_free(session->rerr);
+ session->rerr = NULL;
+
+ ret = session->readFunc(buf, len, session->opaque, &session->rerr);
+ if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
+ errno = EAGAIN;
+ return -1;
+ } else if (ret < 0) {
+ errno = EIO;
+ return -1;
+ } else {
+ return ret;
+ }
}
#define TLS_PRIORITY_ADDITIONAL_ANON "+ANON-DH"
@@ -441,23 +477,25 @@ qcrypto_tls_session_set_callbacks(QCryptoTLSSession *session,
ssize_t
qcrypto_tls_session_write(QCryptoTLSSession *session,
const char *buf,
- size_t len)
+ size_t len,
+ Error **errp)
{
ssize_t ret = gnutls_record_send(session->handle, buf, len);
if (ret < 0) {
- switch (ret) {
- case GNUTLS_E_AGAIN:
- errno = EAGAIN;
- break;
- case GNUTLS_E_INTERRUPTED:
- errno = EINTR;
- break;
- default:
- errno = EIO;
- break;
+ if (ret == GNUTLS_E_AGAIN) {
+ return QCRYPTO_TLS_SESSION_ERR_BLOCK;
+ } else {
+ if (session->werr) {
+ error_propagate(errp, session->werr);
+ session->werr = NULL;
+ } else {
+ error_setg(errp,
+ "Cannot write to TLS channel: %s",
+ gnutls_strerror(ret));
+ }
+ return -1;
}
- ret = -1;
}
return ret;
@@ -467,26 +505,29 @@ qcrypto_tls_session_write(QCryptoTLSSession *session,
ssize_t
qcrypto_tls_session_read(QCryptoTLSSession *session,
char *buf,
- size_t len)
+ size_t len,
+ bool gracefulTermination,
+ Error **errp)
{
ssize_t ret = gnutls_record_recv(session->handle, buf, len);
if (ret < 0) {
- switch (ret) {
- case GNUTLS_E_AGAIN:
- errno = EAGAIN;
- break;
- case GNUTLS_E_INTERRUPTED:
- errno = EINTR;
- break;
- case GNUTLS_E_PREMATURE_TERMINATION:
- errno = ECONNABORTED;
- break;
- default:
- errno = EIO;
- break;
+ if (ret == GNUTLS_E_AGAIN) {
+ return QCRYPTO_TLS_SESSION_ERR_BLOCK;
+ } else if ((ret == GNUTLS_E_PREMATURE_TERMINATION) &&
+ gracefulTermination){
+ return 0;
+ } else {
+ if (session->rerr) {
+ error_propagate(errp, session->rerr);
+ session->rerr = NULL;
+ } else {
+ error_setg(errp,
+ "Cannot read from TLS channel: %s",
+ gnutls_strerror(ret));
+ }
+ return -1;
}
- ret = -1;
}
return ret;
@@ -512,11 +553,21 @@ qcrypto_tls_session_handshake(QCryptoTLSSession *session,
ret == GNUTLS_E_AGAIN) {
ret = 1;
} else {
- error_setg(errp, "TLS handshake failed: %s",
- gnutls_strerror(ret));
+ if (session->rerr || session->werr) {
+ error_setg(errp, "TLS handshake failed: %s: %s",
+ gnutls_strerror(ret),
+ error_get_pretty(session->rerr ?
+ session->rerr : session->werr));
+ } else {
+ error_setg(errp, "TLS handshake failed: %s",
+ gnutls_strerror(ret));
+ }
ret = -1;
}
}
+ error_free(session->rerr);
+ error_free(session->werr);
+ session->rerr = session->werr = NULL;
return ret;
}
@@ -605,9 +656,10 @@ qcrypto_tls_session_set_callbacks(
ssize_t
qcrypto_tls_session_write(QCryptoTLSSession *sess,
const char *buf,
- size_t len)
+ size_t len,
+ Error **errp)
{
- errno = -EIO;
+ error_setg(errp, "TLS requires GNUTLS support");
return -1;
}
@@ -615,9 +667,11 @@ qcrypto_tls_session_write(QCryptoTLSSession *sess,
ssize_t
qcrypto_tls_session_read(QCryptoTLSSession *sess,
char *buf,
- size_t len)
+ size_t len,
+ bool gracefulTermination,
+ Error **errp)
{
- errno = -EIO;
+ error_setg(errp, "TLS requires GNUTLS support");
return -1;
}
diff --git a/crypto/x509-utils.c b/crypto/x509-utils.c
new file mode 100644
index 0000000..8bad00a
--- /dev/null
+++ b/crypto/x509-utils.c
@@ -0,0 +1,76 @@
+/*
+ * X.509 certificate related helpers
+ *
+ * Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "crypto/x509-utils.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#include <gnutls/x509.h>
+
+static const int qcrypto_to_gnutls_hash_alg_map[QCRYPTO_HASH_ALGO__MAX] = {
+ [QCRYPTO_HASH_ALGO_MD5] = GNUTLS_DIG_MD5,
+ [QCRYPTO_HASH_ALGO_SHA1] = GNUTLS_DIG_SHA1,
+ [QCRYPTO_HASH_ALGO_SHA224] = GNUTLS_DIG_SHA224,
+ [QCRYPTO_HASH_ALGO_SHA256] = GNUTLS_DIG_SHA256,
+ [QCRYPTO_HASH_ALGO_SHA384] = GNUTLS_DIG_SHA384,
+ [QCRYPTO_HASH_ALGO_SHA512] = GNUTLS_DIG_SHA512,
+ [QCRYPTO_HASH_ALGO_RIPEMD160] = GNUTLS_DIG_RMD160,
+};
+
+int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
+ QCryptoHashAlgo alg,
+ uint8_t *result,
+ size_t *resultlen,
+ Error **errp)
+{
+ int ret = -1;
+ int hlen;
+ gnutls_x509_crt_t crt;
+ gnutls_datum_t datum = {.data = cert, .size = size};
+
+ if (alg >= G_N_ELEMENTS(qcrypto_to_gnutls_hash_alg_map)) {
+ error_setg(errp, "Unknown hash algorithm");
+ return -1;
+ }
+
+ if (result == NULL) {
+ error_setg(errp, "No valid buffer given");
+ return -1;
+ }
+
+ gnutls_x509_crt_init(&crt);
+
+ if (gnutls_x509_crt_import(crt, &datum, GNUTLS_X509_FMT_PEM) != 0) {
+ error_setg(errp, "Failed to import certificate");
+ goto cleanup;
+ }
+
+ hlen = gnutls_hash_get_len(qcrypto_to_gnutls_hash_alg_map[alg]);
+ if (*resultlen < hlen) {
+ error_setg(errp,
+ "Result buffer size %zu is smaller than hash %d",
+ *resultlen, hlen);
+ goto cleanup;
+ }
+
+ if (gnutls_x509_crt_get_fingerprint(crt,
+ qcrypto_to_gnutls_hash_alg_map[alg],
+ result, resultlen) != 0) {
+ error_setg(errp, "Failed to get fingerprint from certificate");
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ gnutls_x509_crt_deinit(crt);
+ return ret;
+}
diff --git a/disas/cris.c b/disas/cris.c
deleted file mode 100644
index 409a224..0000000
--- a/disas/cris.c
+++ /dev/null
@@ -1,2863 +0,0 @@
-/* Disassembler code for CRIS.
- Copyright 2000, 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
- Contributed by Axis Communications AB, Lund, Sweden.
- Written by Hans-Peter Nilsson.
-
- This file is part of the GNU binutils and GDB, the GNU debugger.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#include "qemu/osdep.h"
-#include "disas/dis-asm.h"
-#include "target/cris/opcode-cris.h"
-
-#define CONST_STRNEQ(STR1,STR2) (strncmp ((STR1), (STR2), sizeof (STR2) - 1) == 0)
-
-/* cris-opc.c -- Table of opcodes for the CRIS processor.
- Copyright 2000, 2001, 2004 Free Software Foundation, Inc.
- Contributed by Axis Communications AB, Lund, Sweden.
- Originally written for GAS 1.38.1 by Mikael Asker.
- Reorganized by Hans-Peter Nilsson.
-
-This file is part of GAS, GDB and the GNU binutils.
-
-GAS, GDB, and GNU binutils is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2, or (at your
-option) any later version.
-
-GAS, GDB, and GNU binutils are distributed in the hope that they 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 NULL
-#define NULL (0)
-#endif
-
-/* This table isn't used for CRISv32 and the size of immediate operands. */
-const struct cris_spec_reg
-cris_spec_regs[] =
-{
- {"bz", 0, 1, cris_ver_v32p, NULL},
- {"p0", 0, 1, 0, NULL},
- {"vr", 1, 1, 0, NULL},
- {"p1", 1, 1, 0, NULL},
- {"pid", 2, 1, cris_ver_v32p, NULL},
- {"p2", 2, 1, cris_ver_v32p, NULL},
- {"p2", 2, 1, cris_ver_warning, NULL},
- {"srs", 3, 1, cris_ver_v32p, NULL},
- {"p3", 3, 1, cris_ver_v32p, NULL},
- {"p3", 3, 1, cris_ver_warning, NULL},
- {"wz", 4, 2, cris_ver_v32p, NULL},
- {"p4", 4, 2, 0, NULL},
- {"ccr", 5, 2, cris_ver_v0_10, NULL},
- {"exs", 5, 4, cris_ver_v32p, NULL},
- {"p5", 5, 2, cris_ver_v0_10, NULL},
- {"p5", 5, 4, cris_ver_v32p, NULL},
- {"dcr0",6, 2, cris_ver_v0_3, NULL},
- {"eda", 6, 4, cris_ver_v32p, NULL},
- {"p6", 6, 2, cris_ver_v0_3, NULL},
- {"p6", 6, 4, cris_ver_v32p, NULL},
- {"dcr1/mof", 7, 4, cris_ver_v10p,
- "Register `dcr1/mof' with ambiguous size specified. Guessing 4 bytes"},
- {"dcr1/mof", 7, 2, cris_ver_v0_3,
- "Register `dcr1/mof' with ambiguous size specified. Guessing 2 bytes"},
- {"mof", 7, 4, cris_ver_v10p, NULL},
- {"dcr1",7, 2, cris_ver_v0_3, NULL},
- {"p7", 7, 4, cris_ver_v10p, NULL},
- {"p7", 7, 2, cris_ver_v0_3, NULL},
- {"dz", 8, 4, cris_ver_v32p, NULL},
- {"p8", 8, 4, 0, NULL},
- {"ibr", 9, 4, cris_ver_v0_10, NULL},
- {"ebp", 9, 4, cris_ver_v32p, NULL},
- {"p9", 9, 4, 0, NULL},
- {"irp", 10, 4, cris_ver_v0_10, NULL},
- {"erp", 10, 4, cris_ver_v32p, NULL},
- {"p10", 10, 4, 0, NULL},
- {"srp", 11, 4, 0, NULL},
- {"p11", 11, 4, 0, NULL},
- /* For disassembly use only. Accept at assembly with a warning. */
- {"bar/dtp0", 12, 4, cris_ver_warning,
- "Ambiguous register `bar/dtp0' specified"},
- {"nrp", 12, 4, cris_ver_v32p, NULL},
- {"bar", 12, 4, cris_ver_v8_10, NULL},
- {"dtp0",12, 4, cris_ver_v0_3, NULL},
- {"p12", 12, 4, 0, NULL},
- /* For disassembly use only. Accept at assembly with a warning. */
- {"dccr/dtp1",13, 4, cris_ver_warning,
- "Ambiguous register `dccr/dtp1' specified"},
- {"ccs", 13, 4, cris_ver_v32p, NULL},
- {"dccr",13, 4, cris_ver_v8_10, NULL},
- {"dtp1",13, 4, cris_ver_v0_3, NULL},
- {"p13", 13, 4, 0, NULL},
- {"brp", 14, 4, cris_ver_v3_10, NULL},
- {"usp", 14, 4, cris_ver_v32p, NULL},
- {"p14", 14, 4, cris_ver_v3p, NULL},
- {"usp", 15, 4, cris_ver_v10, NULL},
- {"spc", 15, 4, cris_ver_v32p, NULL},
- {"p15", 15, 4, cris_ver_v10p, NULL},
- {NULL, 0, 0, cris_ver_version_all, NULL}
-};
-
-/* Add version specifiers to this table when necessary.
- The (now) regular coding of register names suggests a simpler
- implementation. */
-const struct cris_support_reg cris_support_regs[] =
-{
- {"s0", 0},
- {"s1", 1},
- {"s2", 2},
- {"s3", 3},
- {"s4", 4},
- {"s5", 5},
- {"s6", 6},
- {"s7", 7},
- {"s8", 8},
- {"s9", 9},
- {"s10", 10},
- {"s11", 11},
- {"s12", 12},
- {"s13", 13},
- {"s14", 14},
- {"s15", 15},
- {NULL, 0}
-};
-
-/* All CRIS opcodes are 16 bits.
-
- - The match component is a mask saying which bits must match a
- particular opcode in order for an instruction to be an instance
- of that opcode.
-
- - The args component is a string containing characters symbolically
- matching the operands of an instruction. Used for both assembly
- and disassembly.
-
- Operand-matching characters:
- [ ] , space
- Verbatim.
- A The string "ACR" (case-insensitive).
- B Not really an operand. It causes a "BDAP -size,SP" prefix to be
- output for the PUSH alias-instructions and recognizes a push-
- prefix at disassembly. This letter isn't recognized for v32.
- Must be followed by a R or P letter.
- ! Non-match pattern, will not match if there's a prefix insn.
- b Non-matching operand, used for branches with 16-bit
- displacement. Only recognized by the disassembler.
- c 5-bit unsigned immediate in bits <4:0>.
- C 4-bit unsigned immediate in bits <3:0>.
- d At assembly, optionally (as in put other cases before this one)
- ".d" or ".D" at the start of the operands, followed by one space
- character. At disassembly, nothing.
- D General register in bits <15:12> and <3:0>.
- f List of flags in bits <15:12> and <3:0>.
- i 6-bit signed immediate in bits <5:0>.
- I 6-bit unsigned immediate in bits <5:0>.
- M Size modifier (B, W or D) for CLEAR instructions.
- m Size modifier (B, W or D) in bits <5:4>
- N A 32-bit dword, like in the difference between s and y.
- This has no effect on bits in the opcode. Can also be expressed
- as "[pc+]" in input.
- n As N, but PC-relative (to the start of the instruction).
- o [-128..127] word offset in bits <7:1> and <0>. Used by 8-bit
- branch instructions.
- O [-128..127] offset in bits <7:0>. Also matches a comma and a
- general register after the expression, in bits <15:12>. Used
- only for the BDAP prefix insn (in v32 the ADDOQ insn; same opcode).
- P Special register in bits <15:12>.
- p Indicates that the insn is a prefix insn. Must be first
- character.
- Q As O, but don't relax; force an 8-bit offset.
- R General register in bits <15:12>.
- r General register in bits <3:0>.
- S Source operand in bit <10> and a prefix; a 3-operand prefix
- without side-effect.
- s Source operand in bits <10> and <3:0>, optionally with a
- side-effect prefix, except [pc] (the name, not R15 as in ACR)
- isn't allowed for v32 and higher.
- T Support register in bits <15:12>.
- u 4-bit (PC-relative) unsigned immediate word offset in bits <3:0>.
- U Relaxes to either u or n, instruction is assumed LAPCQ or LAPC.
- Not recognized at disassembly.
- x Register-dot-modifier, for example "r5.w" in bits <15:12> and <5:4>.
- y Like 's' but do not allow an integer at assembly.
- Y The difference s-y; only an integer is allowed.
- z Size modifier (B or W) in bit <4>. */
-
-
-/* Please note the order of the opcodes in this table is significant.
- The assembler requires that all instances of the same mnemonic must
- be consecutive. If they aren't, the assembler might not recognize
- them, or may indicate an internal error.
-
- The disassembler should not normally care about the order of the
- opcodes, but will prefer an earlier alternative if the "match-score"
- (see cris-dis.c) is computed as equal.
-
- It should not be significant for proper execution that this table is
- in alphabetical order, but please follow that convention for an easy
- overview. */
-
-const struct cris_opcode
-cris_opcodes[] =
-{
- {"abs", 0x06B0, 0x0940, "r,R", 0, SIZE_NONE, 0,
- cris_abs_op},
-
- {"add", 0x0600, 0x09c0, "m r,R", 0, SIZE_NONE, 0,
- cris_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"add", 0x0A00, 0x01c0, "m s,R", 0, SIZE_FIELD, 0,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"add", 0x0A00, 0x01c0, "m S,D", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"add", 0x0a00, 0x05c0, "m S,R,r", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_three_operand_add_sub_cmp_and_or_op},
-
- {"add", 0x0A00, 0x01c0, "m s,R", 0, SIZE_FIELD,
- cris_ver_v32p,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"addc", 0x0570, 0x0A80, "r,R", 0, SIZE_FIX_32,
- cris_ver_v32p,
- cris_not_implemented_op},
-
- {"addc", 0x09A0, 0x0250, "s,R", 0, SIZE_FIX_32,
- cris_ver_v32p,
- cris_not_implemented_op},
-
- {"addi", 0x0540, 0x0A80, "x,r,A", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_addi_op},
-
- {"addi", 0x0500, 0x0Ac0, "x,r", 0, SIZE_NONE, 0,
- cris_addi_op},
-
- /* This collates after "addo", but we want to disassemble as "addoq",
- not "addo". */
- {"addoq", 0x0100, 0x0E00, "Q,A", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_not_implemented_op},
-
- {"addo", 0x0940, 0x0280, "m s,R,A", 0, SIZE_FIELD_SIGNED,
- cris_ver_v32p,
- cris_not_implemented_op},
-
- /* This must be located after the insn above, lest we misinterpret
- "addo.b -1,r0,acr" as "addo .b-1,r0,acr". FIXME: Sounds like a
- parser bug. */
- {"addo", 0x0100, 0x0E00, "O,A", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_not_implemented_op},
-
- {"addq", 0x0200, 0x0Dc0, "I,R", 0, SIZE_NONE, 0,
- cris_quick_mode_add_sub_op},
-
- {"adds", 0x0420, 0x0Bc0, "z r,R", 0, SIZE_NONE, 0,
- cris_reg_mode_add_sub_cmp_and_or_move_op},
-
- /* FIXME: SIZE_FIELD_SIGNED and all necessary changes. */
- {"adds", 0x0820, 0x03c0, "z s,R", 0, SIZE_FIELD, 0,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"adds", 0x0820, 0x03c0, "z S,D", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"adds", 0x0820, 0x07c0, "z S,R,r", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_three_operand_add_sub_cmp_and_or_op},
-
- {"addu", 0x0400, 0x0be0, "z r,R", 0, SIZE_NONE, 0,
- cris_reg_mode_add_sub_cmp_and_or_move_op},
-
- /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */
- {"addu", 0x0800, 0x03e0, "z s,R", 0, SIZE_FIELD, 0,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"addu", 0x0800, 0x03e0, "z S,D", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"addu", 0x0800, 0x07e0, "z S,R,r", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_three_operand_add_sub_cmp_and_or_op},
-
- {"and", 0x0700, 0x08C0, "m r,R", 0, SIZE_NONE, 0,
- cris_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"and", 0x0B00, 0x00C0, "m s,R", 0, SIZE_FIELD, 0,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"and", 0x0B00, 0x00C0, "m S,D", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"and", 0x0B00, 0x04C0, "m S,R,r", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_three_operand_add_sub_cmp_and_or_op},
-
- {"andq", 0x0300, 0x0CC0, "i,R", 0, SIZE_NONE, 0,
- cris_quick_mode_and_cmp_move_or_op},
-
- {"asr", 0x0780, 0x0840, "m r,R", 0, SIZE_NONE, 0,
- cris_asr_op},
-
- {"asrq", 0x03a0, 0x0c40, "c,R", 0, SIZE_NONE, 0,
- cris_asrq_op},
-
- {"ax", 0x15B0, 0xEA4F, "", 0, SIZE_NONE, 0,
- cris_ax_ei_setf_op},
-
- /* FIXME: Should use branch #defines. */
- {"b", 0x0dff, 0x0200, "b", 1, SIZE_NONE, 0,
- cris_sixteen_bit_offset_branch_op},
-
- {"ba",
- BA_QUICK_OPCODE,
- 0x0F00+(0xF-CC_A)*0x1000, "o", 1, SIZE_NONE, 0,
- cris_eight_bit_offset_branch_op},
-
- /* Needs to come after the usual "ba o", which might be relaxed to
- this one. */
- {"ba", BA_DWORD_OPCODE,
- 0xffff & (~BA_DWORD_OPCODE), "n", 0, SIZE_FIX_32,
- cris_ver_v32p,
- cris_none_reg_mode_jump_op},
-
- {"bas", 0x0EBF, 0x0140, "n,P", 0, SIZE_FIX_32,
- cris_ver_v32p,
- cris_none_reg_mode_jump_op},
-
- {"basc", 0x0EFF, 0x0100, "n,P", 0, SIZE_FIX_32,
- cris_ver_v32p,
- cris_none_reg_mode_jump_op},
-
- {"bcc",
- BRANCH_QUICK_OPCODE+CC_CC*0x1000,
- 0x0f00+(0xF-CC_CC)*0x1000, "o", 1, SIZE_NONE, 0,
- cris_eight_bit_offset_branch_op},
-
- {"bcs",
- BRANCH_QUICK_OPCODE+CC_CS*0x1000,
- 0x0f00+(0xF-CC_CS)*0x1000, "o", 1, SIZE_NONE, 0,
- cris_eight_bit_offset_branch_op},
-
- {"bdap",
- BDAP_INDIR_OPCODE, BDAP_INDIR_Z_BITS, "pm s,R", 0, SIZE_FIELD_SIGNED,
- cris_ver_v0_10,
- cris_bdap_prefix},
-
- {"bdap",
- BDAP_QUICK_OPCODE, BDAP_QUICK_Z_BITS, "pO", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_quick_mode_bdap_prefix},
-
- {"beq",
- BRANCH_QUICK_OPCODE+CC_EQ*0x1000,
- 0x0f00+(0xF-CC_EQ)*0x1000, "o", 1, SIZE_NONE, 0,
- cris_eight_bit_offset_branch_op},
-
- /* This is deliberately put before "bext" to trump it, even though not
- in alphabetical order, since we don't do excluding version checks
- for v0..v10. */
- {"bwf",
- BRANCH_QUICK_OPCODE+CC_EXT*0x1000,
- 0x0f00+(0xF-CC_EXT)*0x1000, "o", 1, SIZE_NONE,
- cris_ver_v10,
- cris_eight_bit_offset_branch_op},
-
- {"bext",
- BRANCH_QUICK_OPCODE+CC_EXT*0x1000,
- 0x0f00+(0xF-CC_EXT)*0x1000, "o", 1, SIZE_NONE,
- cris_ver_v0_3,
- cris_eight_bit_offset_branch_op},
-
- {"bge",
- BRANCH_QUICK_OPCODE+CC_GE*0x1000,
- 0x0f00+(0xF-CC_GE)*0x1000, "o", 1, SIZE_NONE, 0,
- cris_eight_bit_offset_branch_op},
-
- {"bgt",
- BRANCH_QUICK_OPCODE+CC_GT*0x1000,
- 0x0f00+(0xF-CC_GT)*0x1000, "o", 1, SIZE_NONE, 0,
- cris_eight_bit_offset_branch_op},
-
- {"bhi",
- BRANCH_QUICK_OPCODE+CC_HI*0x1000,
- 0x0f00+(0xF-CC_HI)*0x1000, "o", 1, SIZE_NONE, 0,
- cris_eight_bit_offset_branch_op},
-
- {"bhs",
- BRANCH_QUICK_OPCODE+CC_HS*0x1000,
- 0x0f00+(0xF-CC_HS)*0x1000, "o", 1, SIZE_NONE, 0,
- cris_eight_bit_offset_branch_op},
-
- {"biap", BIAP_OPCODE, BIAP_Z_BITS, "pm r,R", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_biap_prefix},
-
- {"ble",
- BRANCH_QUICK_OPCODE+CC_LE*0x1000,
- 0x0f00+(0xF-CC_LE)*0x1000, "o", 1, SIZE_NONE, 0,
- cris_eight_bit_offset_branch_op},
-
- {"blo",
- BRANCH_QUICK_OPCODE+CC_LO*0x1000,
- 0x0f00+(0xF-CC_LO)*0x1000, "o", 1, SIZE_NONE, 0,
- cris_eight_bit_offset_branch_op},
-
- {"bls",
- BRANCH_QUICK_OPCODE+CC_LS*0x1000,
- 0x0f00+(0xF-CC_LS)*0x1000, "o", 1, SIZE_NONE, 0,
- cris_eight_bit_offset_branch_op},
-
- {"blt",
- BRANCH_QUICK_OPCODE+CC_LT*0x1000,
- 0x0f00+(0xF-CC_LT)*0x1000, "o", 1, SIZE_NONE, 0,
- cris_eight_bit_offset_branch_op},
-
- {"bmi",
- BRANCH_QUICK_OPCODE+CC_MI*0x1000,
- 0x0f00+(0xF-CC_MI)*0x1000, "o", 1, SIZE_NONE, 0,
- cris_eight_bit_offset_branch_op},
-
- {"bmod", 0x0ab0, 0x0140, "s,R", 0, SIZE_FIX_32,
- cris_ver_sim_v0_10,
- cris_not_implemented_op},
-
- {"bmod", 0x0ab0, 0x0140, "S,D", 0, SIZE_NONE,
- cris_ver_sim_v0_10,
- cris_not_implemented_op},
-
- {"bmod", 0x0ab0, 0x0540, "S,R,r", 0, SIZE_NONE,
- cris_ver_sim_v0_10,
- cris_not_implemented_op},
-
- {"bne",
- BRANCH_QUICK_OPCODE+CC_NE*0x1000,
- 0x0f00+(0xF-CC_NE)*0x1000, "o", 1, SIZE_NONE, 0,
- cris_eight_bit_offset_branch_op},
-
- {"bound", 0x05c0, 0x0A00, "m r,R", 0, SIZE_NONE, 0,
- cris_two_operand_bound_op},
- /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */
- {"bound", 0x09c0, 0x0200, "m s,R", 0, SIZE_FIELD,
- cris_ver_v0_10,
- cris_two_operand_bound_op},
- /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */
- {"bound", 0x0dcf, 0x0200, "m Y,R", 0, SIZE_FIELD, 0,
- cris_two_operand_bound_op},
- {"bound", 0x09c0, 0x0200, "m S,D", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_two_operand_bound_op},
- {"bound", 0x09c0, 0x0600, "m S,R,r", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_three_operand_bound_op},
-
- {"bpl",
- BRANCH_QUICK_OPCODE+CC_PL*0x1000,
- 0x0f00+(0xF-CC_PL)*0x1000, "o", 1, SIZE_NONE, 0,
- cris_eight_bit_offset_branch_op},
-
- {"break", 0xe930, 0x16c0, "C", 0, SIZE_NONE,
- cris_ver_v3p,
- cris_break_op},
-
- {"bsb",
- BRANCH_QUICK_OPCODE+CC_EXT*0x1000,
- 0x0f00+(0xF-CC_EXT)*0x1000, "o", 1, SIZE_NONE,
- cris_ver_v32p,
- cris_eight_bit_offset_branch_op},
-
- {"bsr", 0xBEBF, 0x4140, "n", 0, SIZE_FIX_32,
- cris_ver_v32p,
- cris_none_reg_mode_jump_op},
-
- {"bsrc", 0xBEFF, 0x4100, "n", 0, SIZE_FIX_32,
- cris_ver_v32p,
- cris_none_reg_mode_jump_op},
-
- {"bstore", 0x0af0, 0x0100, "s,R", 0, SIZE_FIX_32,
- cris_ver_warning,
- cris_not_implemented_op},
-
- {"bstore", 0x0af0, 0x0100, "S,D", 0, SIZE_NONE,
- cris_ver_warning,
- cris_not_implemented_op},
-
- {"bstore", 0x0af0, 0x0500, "S,R,r", 0, SIZE_NONE,
- cris_ver_warning,
- cris_not_implemented_op},
-
- {"btst", 0x04F0, 0x0B00, "r,R", 0, SIZE_NONE, 0,
- cris_btst_nop_op},
- {"btstq", 0x0380, 0x0C60, "c,R", 0, SIZE_NONE, 0,
- cris_btst_nop_op},
-
- {"bvc",
- BRANCH_QUICK_OPCODE+CC_VC*0x1000,
- 0x0f00+(0xF-CC_VC)*0x1000, "o", 1, SIZE_NONE, 0,
- cris_eight_bit_offset_branch_op},
-
- {"bvs",
- BRANCH_QUICK_OPCODE+CC_VS*0x1000,
- 0x0f00+(0xF-CC_VS)*0x1000, "o", 1, SIZE_NONE, 0,
- cris_eight_bit_offset_branch_op},
-
- {"clear", 0x0670, 0x3980, "M r", 0, SIZE_NONE, 0,
- cris_reg_mode_clear_op},
-
- {"clear", 0x0A70, 0x3180, "M y", 0, SIZE_NONE, 0,
- cris_none_reg_mode_clear_test_op},
-
- {"clear", 0x0A70, 0x3180, "M S", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_clear_test_op},
-
- {"clearf", 0x05F0, 0x0A00, "f", 0, SIZE_NONE, 0,
- cris_clearf_di_op},
-
- {"cmp", 0x06C0, 0x0900, "m r,R", 0, SIZE_NONE, 0,
- cris_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"cmp", 0x0Ac0, 0x0100, "m s,R", 0, SIZE_FIELD, 0,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"cmp", 0x0Ac0, 0x0100, "m S,D", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"cmpq", 0x02C0, 0x0D00, "i,R", 0, SIZE_NONE, 0,
- cris_quick_mode_and_cmp_move_or_op},
-
- /* FIXME: SIZE_FIELD_SIGNED and all necessary changes. */
- {"cmps", 0x08e0, 0x0300, "z s,R", 0, SIZE_FIELD, 0,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"cmps", 0x08e0, 0x0300, "z S,D", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */
- {"cmpu", 0x08c0, 0x0320, "z s,R" , 0, SIZE_FIELD, 0,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"cmpu", 0x08c0, 0x0320, "z S,D", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"di", 0x25F0, 0xDA0F, "", 0, SIZE_NONE, 0,
- cris_clearf_di_op},
-
- {"dip", DIP_OPCODE, DIP_Z_BITS, "ps", 0, SIZE_FIX_32,
- cris_ver_v0_10,
- cris_dip_prefix},
-
- {"div", 0x0980, 0x0640, "m R,r", 0, SIZE_FIELD, 0,
- cris_not_implemented_op},
-
- {"dstep", 0x06f0, 0x0900, "r,R", 0, SIZE_NONE, 0,
- cris_dstep_logshift_mstep_neg_not_op},
-
- {"ei", 0x25B0, 0xDA4F, "", 0, SIZE_NONE, 0,
- cris_ax_ei_setf_op},
-
- {"fidxd", 0x0ab0, 0xf540, "[r]", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_not_implemented_op},
-
- {"fidxi", 0x0d30, 0xF2C0, "[r]", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_not_implemented_op},
-
- {"ftagd", 0x1AB0, 0xE540, "[r]", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_not_implemented_op},
-
- {"ftagi", 0x1D30, 0xE2C0, "[r]", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_not_implemented_op},
-
- {"halt", 0xF930, 0x06CF, "", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_not_implemented_op},
-
- {"jas", 0x09B0, 0x0640, "r,P", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_reg_mode_jump_op},
-
- {"jas", 0x0DBF, 0x0240, "N,P", 0, SIZE_FIX_32,
- cris_ver_v32p,
- cris_reg_mode_jump_op},
-
- {"jasc", 0x0B30, 0x04C0, "r,P", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_reg_mode_jump_op},
-
- {"jasc", 0x0F3F, 0x00C0, "N,P", 0, SIZE_FIX_32,
- cris_ver_v32p,
- cris_reg_mode_jump_op},
-
- {"jbrc", 0x69b0, 0x9640, "r", 0, SIZE_NONE,
- cris_ver_v8_10,
- cris_reg_mode_jump_op},
-
- {"jbrc", 0x6930, 0x92c0, "s", 0, SIZE_FIX_32,
- cris_ver_v8_10,
- cris_none_reg_mode_jump_op},
-
- {"jbrc", 0x6930, 0x92c0, "S", 0, SIZE_NONE,
- cris_ver_v8_10,
- cris_none_reg_mode_jump_op},
-
- {"jir", 0xA9b0, 0x5640, "r", 0, SIZE_NONE,
- cris_ver_v8_10,
- cris_reg_mode_jump_op},
-
- {"jir", 0xA930, 0x52c0, "s", 0, SIZE_FIX_32,
- cris_ver_v8_10,
- cris_none_reg_mode_jump_op},
-
- {"jir", 0xA930, 0x52c0, "S", 0, SIZE_NONE,
- cris_ver_v8_10,
- cris_none_reg_mode_jump_op},
-
- {"jirc", 0x29b0, 0xd640, "r", 0, SIZE_NONE,
- cris_ver_v8_10,
- cris_reg_mode_jump_op},
-
- {"jirc", 0x2930, 0xd2c0, "s", 0, SIZE_FIX_32,
- cris_ver_v8_10,
- cris_none_reg_mode_jump_op},
-
- {"jirc", 0x2930, 0xd2c0, "S", 0, SIZE_NONE,
- cris_ver_v8_10,
- cris_none_reg_mode_jump_op},
-
- {"jsr", 0xB9b0, 0x4640, "r", 0, SIZE_NONE, 0,
- cris_reg_mode_jump_op},
-
- {"jsr", 0xB930, 0x42c0, "s", 0, SIZE_FIX_32,
- cris_ver_v0_10,
- cris_none_reg_mode_jump_op},
-
- {"jsr", 0xBDBF, 0x4240, "N", 0, SIZE_FIX_32,
- cris_ver_v32p,
- cris_none_reg_mode_jump_op},
-
- {"jsr", 0xB930, 0x42c0, "S", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_jump_op},
-
- {"jsrc", 0x39b0, 0xc640, "r", 0, SIZE_NONE,
- cris_ver_v8_10,
- cris_reg_mode_jump_op},
-
- {"jsrc", 0x3930, 0xc2c0, "s", 0, SIZE_FIX_32,
- cris_ver_v8_10,
- cris_none_reg_mode_jump_op},
-
- {"jsrc", 0x3930, 0xc2c0, "S", 0, SIZE_NONE,
- cris_ver_v8_10,
- cris_none_reg_mode_jump_op},
-
- {"jsrc", 0xBB30, 0x44C0, "r", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_reg_mode_jump_op},
-
- {"jsrc", 0xBF3F, 0x40C0, "N", 0, SIZE_FIX_32,
- cris_ver_v32p,
- cris_reg_mode_jump_op},
-
- {"jump", 0x09b0, 0xF640, "r", 0, SIZE_NONE, 0,
- cris_reg_mode_jump_op},
-
- {"jump",
- JUMP_INDIR_OPCODE, JUMP_INDIR_Z_BITS, "s", 0, SIZE_FIX_32,
- cris_ver_v0_10,
- cris_none_reg_mode_jump_op},
-
- {"jump",
- JUMP_INDIR_OPCODE, JUMP_INDIR_Z_BITS, "S", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_jump_op},
-
- {"jump", 0x09F0, 0x060F, "P", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_none_reg_mode_jump_op},
-
- {"jump",
- JUMP_PC_INCR_OPCODE_V32,
- (0xffff & ~JUMP_PC_INCR_OPCODE_V32), "N", 0, SIZE_FIX_32,
- cris_ver_v32p,
- cris_none_reg_mode_jump_op},
-
- {"jmpu", 0x8930, 0x72c0, "s", 0, SIZE_FIX_32,
- cris_ver_v10,
- cris_none_reg_mode_jump_op},
-
- {"jmpu", 0x8930, 0x72c0, "S", 0, SIZE_NONE,
- cris_ver_v10,
- cris_none_reg_mode_jump_op},
-
- {"lapc", 0x0970, 0x0680, "U,R", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_not_implemented_op},
-
- {"lapc", 0x0D7F, 0x0280, "dn,R", 0, SIZE_FIX_32,
- cris_ver_v32p,
- cris_not_implemented_op},
-
- {"lapcq", 0x0970, 0x0680, "u,R", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_addi_op},
-
- {"lsl", 0x04C0, 0x0B00, "m r,R", 0, SIZE_NONE, 0,
- cris_dstep_logshift_mstep_neg_not_op},
-
- {"lslq", 0x03c0, 0x0C20, "c,R", 0, SIZE_NONE, 0,
- cris_dstep_logshift_mstep_neg_not_op},
-
- {"lsr", 0x07C0, 0x0800, "m r,R", 0, SIZE_NONE, 0,
- cris_dstep_logshift_mstep_neg_not_op},
-
- {"lsrq", 0x03e0, 0x0C00, "c,R", 0, SIZE_NONE, 0,
- cris_dstep_logshift_mstep_neg_not_op},
-
- {"lz", 0x0730, 0x08C0, "r,R", 0, SIZE_NONE,
- cris_ver_v3p,
- cris_not_implemented_op},
-
- {"mcp", 0x07f0, 0x0800, "P,r", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_not_implemented_op},
-
- {"move", 0x0640, 0x0980, "m r,R", 0, SIZE_NONE, 0,
- cris_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"move", 0x0A40, 0x0180, "m s,R", 0, SIZE_FIELD, 0,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"move", 0x0A40, 0x0180, "m S,D", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"move", 0x0630, 0x09c0, "r,P", 0, SIZE_NONE, 0,
- cris_move_to_preg_op},
-
- {"move", 0x0670, 0x0980, "P,r", 0, SIZE_NONE, 0,
- cris_reg_mode_move_from_preg_op},
-
- {"move", 0x0BC0, 0x0000, "m R,y", 0, SIZE_FIELD, 0,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"move", 0x0BC0, 0x0000, "m D,S", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"move",
- MOVE_M_TO_PREG_OPCODE, MOVE_M_TO_PREG_ZBITS,
- "s,P", 0, SIZE_SPEC_REG, 0,
- cris_move_to_preg_op},
-
- {"move", 0x0A30, 0x01c0, "S,P", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_move_to_preg_op},
-
- {"move", 0x0A70, 0x0180, "P,y", 0, SIZE_SPEC_REG, 0,
- cris_none_reg_mode_move_from_preg_op},
-
- {"move", 0x0A70, 0x0180, "P,S", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_move_from_preg_op},
-
- {"move", 0x0B70, 0x0480, "r,T", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_not_implemented_op},
-
- {"move", 0x0F70, 0x0080, "T,r", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_not_implemented_op},
-
- {"movem", 0x0BF0, 0x0000, "R,y", 0, SIZE_FIX_32, 0,
- cris_move_reg_to_mem_movem_op},
-
- {"movem", 0x0BF0, 0x0000, "D,S", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_move_reg_to_mem_movem_op},
-
- {"movem", 0x0BB0, 0x0040, "s,R", 0, SIZE_FIX_32, 0,
- cris_move_mem_to_reg_movem_op},
-
- {"movem", 0x0BB0, 0x0040, "S,D", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_move_mem_to_reg_movem_op},
-
- {"moveq", 0x0240, 0x0D80, "i,R", 0, SIZE_NONE, 0,
- cris_quick_mode_and_cmp_move_or_op},
-
- {"movs", 0x0460, 0x0B80, "z r,R", 0, SIZE_NONE, 0,
- cris_reg_mode_add_sub_cmp_and_or_move_op},
-
- /* FIXME: SIZE_FIELD_SIGNED and all necessary changes. */
- {"movs", 0x0860, 0x0380, "z s,R", 0, SIZE_FIELD, 0,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"movs", 0x0860, 0x0380, "z S,D", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"movu", 0x0440, 0x0Ba0, "z r,R", 0, SIZE_NONE, 0,
- cris_reg_mode_add_sub_cmp_and_or_move_op},
-
- /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */
- {"movu", 0x0840, 0x03a0, "z s,R", 0, SIZE_FIELD, 0,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"movu", 0x0840, 0x03a0, "z S,D", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"mstep", 0x07f0, 0x0800, "r,R", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_dstep_logshift_mstep_neg_not_op},
-
- {"muls", 0x0d00, 0x02c0, "m r,R", 0, SIZE_NONE,
- cris_ver_v10p,
- cris_muls_op},
-
- {"mulu", 0x0900, 0x06c0, "m r,R", 0, SIZE_NONE,
- cris_ver_v10p,
- cris_mulu_op},
-
- {"neg", 0x0580, 0x0A40, "m r,R", 0, SIZE_NONE, 0,
- cris_dstep_logshift_mstep_neg_not_op},
-
- {"nop", NOP_OPCODE, NOP_Z_BITS, "", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_btst_nop_op},
-
- {"nop", NOP_OPCODE_V32, NOP_Z_BITS_V32, "", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_btst_nop_op},
-
- {"not", 0x8770, 0x7880, "r", 0, SIZE_NONE, 0,
- cris_dstep_logshift_mstep_neg_not_op},
-
- {"or", 0x0740, 0x0880, "m r,R", 0, SIZE_NONE, 0,
- cris_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"or", 0x0B40, 0x0080, "m s,R", 0, SIZE_FIELD, 0,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"or", 0x0B40, 0x0080, "m S,D", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"or", 0x0B40, 0x0480, "m S,R,r", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_three_operand_add_sub_cmp_and_or_op},
-
- {"orq", 0x0340, 0x0C80, "i,R", 0, SIZE_NONE, 0,
- cris_quick_mode_and_cmp_move_or_op},
-
- {"pop", 0x0E6E, 0x0191, "!R", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"pop", 0x0e3e, 0x01c1, "!P", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_move_from_preg_op},
-
- {"push", 0x0FEE, 0x0011, "BR", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"push", 0x0E7E, 0x0181, "BP", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_move_to_preg_op},
-
- {"rbf", 0x3b30, 0xc0c0, "y", 0, SIZE_NONE,
- cris_ver_v10,
- cris_not_implemented_op},
-
- {"rbf", 0x3b30, 0xc0c0, "S", 0, SIZE_NONE,
- cris_ver_v10,
- cris_not_implemented_op},
-
- {"rfe", 0x2930, 0xD6CF, "", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_not_implemented_op},
-
- {"rfg", 0x4930, 0xB6CF, "", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_not_implemented_op},
-
- {"rfn", 0x5930, 0xA6CF, "", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_not_implemented_op},
-
- {"ret", 0xB67F, 0x4980, "", 1, SIZE_NONE,
- cris_ver_v0_10,
- cris_reg_mode_move_from_preg_op},
-
- {"ret", 0xB9F0, 0x460F, "", 1, SIZE_NONE,
- cris_ver_v32p,
- cris_reg_mode_move_from_preg_op},
-
- {"retb", 0xe67f, 0x1980, "", 1, SIZE_NONE,
- cris_ver_v0_10,
- cris_reg_mode_move_from_preg_op},
-
- {"rete", 0xA9F0, 0x560F, "", 1, SIZE_NONE,
- cris_ver_v32p,
- cris_reg_mode_move_from_preg_op},
-
- {"reti", 0xA67F, 0x5980, "", 1, SIZE_NONE,
- cris_ver_v0_10,
- cris_reg_mode_move_from_preg_op},
-
- {"retn", 0xC9F0, 0x360F, "", 1, SIZE_NONE,
- cris_ver_v32p,
- cris_reg_mode_move_from_preg_op},
-
- {"sbfs", 0x3b70, 0xc080, "y", 0, SIZE_NONE,
- cris_ver_v10,
- cris_not_implemented_op},
-
- {"sbfs", 0x3b70, 0xc080, "S", 0, SIZE_NONE,
- cris_ver_v10,
- cris_not_implemented_op},
-
- {"sa",
- 0x0530+CC_A*0x1000,
- 0x0AC0+(0xf-CC_A)*0x1000, "r", 0, SIZE_NONE, 0,
- cris_scc_op},
-
- {"ssb",
- 0x0530+CC_EXT*0x1000,
- 0x0AC0+(0xf-CC_EXT)*0x1000, "r", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_scc_op},
-
- {"scc",
- 0x0530+CC_CC*0x1000,
- 0x0AC0+(0xf-CC_CC)*0x1000, "r", 0, SIZE_NONE, 0,
- cris_scc_op},
-
- {"scs",
- 0x0530+CC_CS*0x1000,
- 0x0AC0+(0xf-CC_CS)*0x1000, "r", 0, SIZE_NONE, 0,
- cris_scc_op},
-
- {"seq",
- 0x0530+CC_EQ*0x1000,
- 0x0AC0+(0xf-CC_EQ)*0x1000, "r", 0, SIZE_NONE, 0,
- cris_scc_op},
-
- {"setf", 0x05b0, 0x0A40, "f", 0, SIZE_NONE, 0,
- cris_ax_ei_setf_op},
-
- {"sfe", 0x3930, 0xC6CF, "", 0, SIZE_NONE,
- cris_ver_v32p,
- cris_not_implemented_op},
-
- /* Need to have "swf" in front of "sext" so it is the one displayed in
- disassembly. */
- {"swf",
- 0x0530+CC_EXT*0x1000,
- 0x0AC0+(0xf-CC_EXT)*0x1000, "r", 0, SIZE_NONE,
- cris_ver_v10,
- cris_scc_op},
-
- {"sext",
- 0x0530+CC_EXT*0x1000,
- 0x0AC0+(0xf-CC_EXT)*0x1000, "r", 0, SIZE_NONE,
- cris_ver_v0_3,
- cris_scc_op},
-
- {"sge",
- 0x0530+CC_GE*0x1000,
- 0x0AC0+(0xf-CC_GE)*0x1000, "r", 0, SIZE_NONE, 0,
- cris_scc_op},
-
- {"sgt",
- 0x0530+CC_GT*0x1000,
- 0x0AC0+(0xf-CC_GT)*0x1000, "r", 0, SIZE_NONE, 0,
- cris_scc_op},
-
- {"shi",
- 0x0530+CC_HI*0x1000,
- 0x0AC0+(0xf-CC_HI)*0x1000, "r", 0, SIZE_NONE, 0,
- cris_scc_op},
-
- {"shs",
- 0x0530+CC_HS*0x1000,
- 0x0AC0+(0xf-CC_HS)*0x1000, "r", 0, SIZE_NONE, 0,
- cris_scc_op},
-
- {"sle",
- 0x0530+CC_LE*0x1000,
- 0x0AC0+(0xf-CC_LE)*0x1000, "r", 0, SIZE_NONE, 0,
- cris_scc_op},
-
- {"slo",
- 0x0530+CC_LO*0x1000,
- 0x0AC0+(0xf-CC_LO)*0x1000, "r", 0, SIZE_NONE, 0,
- cris_scc_op},
-
- {"sls",
- 0x0530+CC_LS*0x1000,
- 0x0AC0+(0xf-CC_LS)*0x1000, "r", 0, SIZE_NONE, 0,
- cris_scc_op},
-
- {"slt",
- 0x0530+CC_LT*0x1000,
- 0x0AC0+(0xf-CC_LT)*0x1000, "r", 0, SIZE_NONE, 0,
- cris_scc_op},
-
- {"smi",
- 0x0530+CC_MI*0x1000,
- 0x0AC0+(0xf-CC_MI)*0x1000, "r", 0, SIZE_NONE, 0,
- cris_scc_op},
-
- {"sne",
- 0x0530+CC_NE*0x1000,
- 0x0AC0+(0xf-CC_NE)*0x1000, "r", 0, SIZE_NONE, 0,
- cris_scc_op},
-
- {"spl",
- 0x0530+CC_PL*0x1000,
- 0x0AC0+(0xf-CC_PL)*0x1000, "r", 0, SIZE_NONE, 0,
- cris_scc_op},
-
- {"sub", 0x0680, 0x0940, "m r,R", 0, SIZE_NONE, 0,
- cris_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"sub", 0x0a80, 0x0140, "m s,R", 0, SIZE_FIELD, 0,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"sub", 0x0a80, 0x0140, "m S,D", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"sub", 0x0a80, 0x0540, "m S,R,r", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_three_operand_add_sub_cmp_and_or_op},
-
- {"subq", 0x0280, 0x0d40, "I,R", 0, SIZE_NONE, 0,
- cris_quick_mode_add_sub_op},
-
- {"subs", 0x04a0, 0x0b40, "z r,R", 0, SIZE_NONE, 0,
- cris_reg_mode_add_sub_cmp_and_or_move_op},
-
- /* FIXME: SIZE_FIELD_SIGNED and all necessary changes. */
- {"subs", 0x08a0, 0x0340, "z s,R", 0, SIZE_FIELD, 0,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"subs", 0x08a0, 0x0340, "z S,D", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"subs", 0x08a0, 0x0740, "z S,R,r", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_three_operand_add_sub_cmp_and_or_op},
-
- {"subu", 0x0480, 0x0b60, "z r,R", 0, SIZE_NONE, 0,
- cris_reg_mode_add_sub_cmp_and_or_move_op},
-
- /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes. */
- {"subu", 0x0880, 0x0360, "z s,R", 0, SIZE_FIELD, 0,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"subu", 0x0880, 0x0360, "z S,D", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
- {"subu", 0x0880, 0x0760, "z S,R,r", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_three_operand_add_sub_cmp_and_or_op},
-
- {"svc",
- 0x0530+CC_VC*0x1000,
- 0x0AC0+(0xf-CC_VC)*0x1000, "r", 0, SIZE_NONE, 0,
- cris_scc_op},
-
- {"svs",
- 0x0530+CC_VS*0x1000,
- 0x0AC0+(0xf-CC_VS)*0x1000, "r", 0, SIZE_NONE, 0,
- cris_scc_op},
-
- /* The insn "swapn" is the same as "not" and will be disassembled as
- such, but the swap* family of mnmonics are generally v8-and-higher
- only, so count it in. */
- {"swapn", 0x8770, 0x7880, "r", 0, SIZE_NONE,
- cris_ver_v8p,
- cris_not_implemented_op},
-
- {"swapw", 0x4770, 0xb880, "r", 0, SIZE_NONE,
- cris_ver_v8p,
- cris_not_implemented_op},
-
- {"swapnw", 0xc770, 0x3880, "r", 0, SIZE_NONE,
- cris_ver_v8p,
- cris_not_implemented_op},
-
- {"swapb", 0x2770, 0xd880, "r", 0, SIZE_NONE,
- cris_ver_v8p,
- cris_not_implemented_op},
-
- {"swapnb", 0xA770, 0x5880, "r", 0, SIZE_NONE,
- cris_ver_v8p,
- cris_not_implemented_op},
-
- {"swapwb", 0x6770, 0x9880, "r", 0, SIZE_NONE,
- cris_ver_v8p,
- cris_not_implemented_op},
-
- {"swapnwb", 0xE770, 0x1880, "r", 0, SIZE_NONE,
- cris_ver_v8p,
- cris_not_implemented_op},
-
- {"swapr", 0x1770, 0xe880, "r", 0, SIZE_NONE,
- cris_ver_v8p,
- cris_not_implemented_op},
-
- {"swapnr", 0x9770, 0x6880, "r", 0, SIZE_NONE,
- cris_ver_v8p,
- cris_not_implemented_op},
-
- {"swapwr", 0x5770, 0xa880, "r", 0, SIZE_NONE,
- cris_ver_v8p,
- cris_not_implemented_op},
-
- {"swapnwr", 0xd770, 0x2880, "r", 0, SIZE_NONE,
- cris_ver_v8p,
- cris_not_implemented_op},
-
- {"swapbr", 0x3770, 0xc880, "r", 0, SIZE_NONE,
- cris_ver_v8p,
- cris_not_implemented_op},
-
- {"swapnbr", 0xb770, 0x4880, "r", 0, SIZE_NONE,
- cris_ver_v8p,
- cris_not_implemented_op},
-
- {"swapwbr", 0x7770, 0x8880, "r", 0, SIZE_NONE,
- cris_ver_v8p,
- cris_not_implemented_op},
-
- {"swapnwbr", 0xf770, 0x0880, "r", 0, SIZE_NONE,
- cris_ver_v8p,
- cris_not_implemented_op},
-
- {"test", 0x0640, 0x0980, "m D", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_reg_mode_test_op},
-
- {"test", 0x0b80, 0xf040, "m y", 0, SIZE_FIELD, 0,
- cris_none_reg_mode_clear_test_op},
-
- {"test", 0x0b80, 0xf040, "m S", 0, SIZE_NONE,
- cris_ver_v0_10,
- cris_none_reg_mode_clear_test_op},
-
- {"xor", 0x07B0, 0x0840, "r,R", 0, SIZE_NONE, 0,
- cris_xor_op},
-
- {NULL, 0, 0, NULL, 0, 0, 0, cris_not_implemented_op}
-};
-
-/* Condition-names, indexed by the CC_* numbers as found in cris.h. */
-const char * const
-cris_cc_strings[] =
-{
- "hs",
- "lo",
- "ne",
- "eq",
- "vc",
- "vs",
- "pl",
- "mi",
- "ls",
- "hi",
- "ge",
- "lt",
- "gt",
- "le",
- "a",
- /* This is a placeholder. In v0, this would be "ext". In v32, this
- is "sb". */
- "wf"
-};
-
-/*
- * Local variables:
- * eval: (c-set-style "gnu")
- * indent-tabs-mode: t
- * End:
- */
-
-
-/* No instruction will be disassembled longer than this. In theory, and
- in silicon, address prefixes can be cascaded. In practice, cascading
- is not used by GCC, and not supported by the assembler. */
-#ifndef MAX_BYTES_PER_CRIS_INSN
-#define MAX_BYTES_PER_CRIS_INSN 8
-#endif
-
-/* Whether or not to decode prefixes, folding it into the following
- instruction. FIXME: Make this optional later. */
-#ifndef PARSE_PREFIX
-#define PARSE_PREFIX 1
-#endif
-
-/* Sometimes we prefix all registers with this character. */
-#define REGISTER_PREFIX_CHAR '$'
-
-/* Whether or not to trace the following sequence:
- sub* X,r%d
- bound* Y,r%d
- adds.w [pc+r%d.w],pc
-
- This is the assembly form of a switch-statement in C.
- The "sub is optional. If there is none, then X will be zero.
- X is the value of the first case,
- Y is the number of cases (including default).
-
- This results in case offsets printed on the form:
- case N: -> case_address
- where N is an estimation on the corresponding 'case' operand in C,
- and case_address is where execution of that case continues after the
- sequence presented above.
-
- The old style of output was to print the offsets as instructions,
- which made it hard to follow "case"-constructs in the disassembly,
- and caused a lot of annoying warnings about undefined instructions.
-
- FIXME: Make this optional later. */
-#ifndef TRACE_CASE
-#define TRACE_CASE (disdata->trace_case)
-#endif
-
-enum cris_disass_family
- { cris_dis_v0_v10, cris_dis_common_v10_v32, cris_dis_v32 };
-
-/* Stored in the disasm_info->private_data member. */
-struct cris_disasm_data
-{
- /* Whether to print something less confusing if we find something
- matching a switch-construct. */
- bfd_boolean trace_case;
-
- /* Whether this code is flagged as crisv32. FIXME: Should be an enum
- that includes "compatible". */
- enum cris_disass_family distype;
-};
-
-/* Value of first element in switch. */
-static long case_offset = 0;
-
-/* How many more case-offsets to print. */
-static long case_offset_counter = 0;
-
-/* Number of case offsets. */
-static long no_of_case_offsets = 0;
-
-/* Candidate for next case_offset. */
-static long last_immediate = 0;
-
-static int cris_constraint
- (const char *, unsigned, unsigned, struct cris_disasm_data *);
-
-/* Parse disassembler options and store state in info. FIXME: For the
- time being, we abuse static variables. */
-
-static void
-cris_parse_disassembler_options (struct cris_disasm_data *disdata,
- char *disassembler_options,
- enum cris_disass_family distype)
-{
- /* Default true. */
- disdata->trace_case
- = (disassembler_options == NULL
- || (strcmp (disassembler_options, "nocase") != 0));
-
- disdata->distype = distype;
-}
-
-static const struct cris_spec_reg *
-spec_reg_info (unsigned int sreg, enum cris_disass_family distype)
-{
- int i;
-
- for (i = 0; cris_spec_regs[i].name != NULL; i++)
- {
- if (cris_spec_regs[i].number == sreg)
- {
- if (distype == cris_dis_v32)
- switch (cris_spec_regs[i].applicable_version)
- {
- case cris_ver_warning:
- case cris_ver_version_all:
- case cris_ver_v3p:
- case cris_ver_v8p:
- case cris_ver_v10p:
- case cris_ver_v32p:
- /* No ambiguous sizes or register names with CRISv32. */
- if (cris_spec_regs[i].warning == NULL)
- return &cris_spec_regs[i];
- default:
- ;
- }
- else if (cris_spec_regs[i].applicable_version != cris_ver_v32p)
- return &cris_spec_regs[i];
- }
- }
-
- return NULL;
-}
-
-/* Return the number of bits in the argument. */
-
-static int
-number_of_bits (unsigned int val)
-{
- int bits;
-
- for (bits = 0; val != 0; val &= val - 1)
- bits++;
-
- return bits;
-}
-
-/* Get an entry in the opcode-table. */
-
-static const struct cris_opcode *
-get_opcode_entry (unsigned int insn,
- unsigned int prefix_insn,
- struct cris_disasm_data *disdata)
-{
- /* For non-prefixed insns, we keep a table of pointers, indexed by the
- insn code. Each entry is initialized when found to be NULL. */
- static const struct cris_opcode **opc_table = NULL;
-
- const struct cris_opcode *max_matchedp = NULL;
- const struct cris_opcode **prefix_opc_table = NULL;
-
- /* We hold a table for each prefix that need to be handled differently. */
- static const struct cris_opcode **dip_prefixes = NULL;
- static const struct cris_opcode **bdapq_m1_prefixes = NULL;
- static const struct cris_opcode **bdapq_m2_prefixes = NULL;
- static const struct cris_opcode **bdapq_m4_prefixes = NULL;
- static const struct cris_opcode **rest_prefixes = NULL;
-
- /* Allocate and clear the opcode-table. */
- if (opc_table == NULL)
- {
- opc_table = g_new0(const struct cris_opcode *, 65536);
- dip_prefixes = g_new0(const struct cris_opcode *, 65536);
- bdapq_m1_prefixes = g_new0(const struct cris_opcode *, 65536);
- bdapq_m2_prefixes = g_new0(const struct cris_opcode *, 65536);
- bdapq_m4_prefixes = g_new0(const struct cris_opcode *, 65536);
- rest_prefixes = g_new0(const struct cris_opcode *, 65536);
- }
-
- /* Get the right table if this is a prefix.
- This code is connected to cris_constraints in that it knows what
- prefixes play a role in recognition of patterns; the necessary
- state is reflected by which table is used. If constraints
- involving match or non-match of prefix insns are changed, then this
- probably needs changing too. */
- if (prefix_insn != NO_CRIS_PREFIX)
- {
- const struct cris_opcode *popcodep
- = (opc_table[prefix_insn] != NULL
- ? opc_table[prefix_insn]
- : get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata));
-
- if (popcodep == NULL)
- return NULL;
-
- if (popcodep->match == BDAP_QUICK_OPCODE)
- {
- /* Since some offsets are recognized with "push" macros, we
- have to have different tables for them. */
- int offset = (prefix_insn & 255);
-
- if (offset > 127)
- offset -= 256;
-
- switch (offset)
- {
- case -4:
- prefix_opc_table = bdapq_m4_prefixes;
- break;
-
- case -2:
- prefix_opc_table = bdapq_m2_prefixes;
- break;
-
- case -1:
- prefix_opc_table = bdapq_m1_prefixes;
- break;
-
- default:
- prefix_opc_table = rest_prefixes;
- break;
- }
- }
- else if (popcodep->match == DIP_OPCODE)
- /* We don't allow postincrement when the prefix is DIP, so use a
- different table for DIP. */
- prefix_opc_table = dip_prefixes;
- else
- prefix_opc_table = rest_prefixes;
- }
-
- if (prefix_insn != NO_CRIS_PREFIX
- && prefix_opc_table[insn] != NULL)
- max_matchedp = prefix_opc_table[insn];
- else if (prefix_insn == NO_CRIS_PREFIX && opc_table[insn] != NULL)
- max_matchedp = opc_table[insn];
- else
- {
- const struct cris_opcode *opcodep;
- int max_level_of_match = -1;
-
- for (opcodep = cris_opcodes;
- opcodep->name != NULL;
- opcodep++)
- {
- int level_of_match;
-
- if (disdata->distype == cris_dis_v32)
- {
- switch (opcodep->applicable_version)
- {
- case cris_ver_version_all:
- break;
-
- case cris_ver_v0_3:
- case cris_ver_v0_10:
- case cris_ver_v3_10:
- case cris_ver_sim_v0_10:
- case cris_ver_v8_10:
- case cris_ver_v10:
- case cris_ver_warning:
- continue;
-
- case cris_ver_v3p:
- case cris_ver_v8p:
- case cris_ver_v10p:
- case cris_ver_v32p:
- break;
-
- case cris_ver_v8:
- abort ();
- default:
- abort ();
- }
- }
- else
- {
- switch (opcodep->applicable_version)
- {
- case cris_ver_version_all:
- case cris_ver_v0_3:
- case cris_ver_v3p:
- case cris_ver_v0_10:
- case cris_ver_v8p:
- case cris_ver_v8_10:
- case cris_ver_v10:
- case cris_ver_sim_v0_10:
- case cris_ver_v10p:
- case cris_ver_warning:
- break;
-
- case cris_ver_v32p:
- continue;
-
- case cris_ver_v8:
- abort ();
- default:
- abort ();
- }
- }
-
- /* We give a double lead for bits matching the template in
- cris_opcodes. Not even, because then "move p8,r10" would
- be given 2 bits lead over "clear.d r10". When there's a
- tie, the first entry in the table wins. This is
- deliberate, to avoid a more complicated recognition
- formula. */
- if ((opcodep->match & insn) == opcodep->match
- && (opcodep->lose & insn) == 0
- && ((level_of_match
- = cris_constraint (opcodep->args,
- insn,
- prefix_insn,
- disdata))
- >= 0)
- && ((level_of_match
- += 2 * number_of_bits (opcodep->match
- | opcodep->lose))
- > max_level_of_match))
- {
- max_matchedp = opcodep;
- max_level_of_match = level_of_match;
-
- /* If there was a full match, never mind looking
- further. */
- if (level_of_match >= 2 * 16)
- break;
- }
- }
- /* Fill in the new entry.
-
- If there are changes to the opcode-table involving prefixes, and
- disassembly then does not work correctly, try removing the
- else-clause below that fills in the prefix-table. If that
- helps, you need to change the prefix_opc_table setting above, or
- something related. */
- if (prefix_insn == NO_CRIS_PREFIX)
- opc_table[insn] = max_matchedp;
- else
- prefix_opc_table[insn] = max_matchedp;
- }
-
- return max_matchedp;
-}
-
-/* Return -1 if the constraints of a bitwise-matched instruction say
- that there is no match. Otherwise return a nonnegative number
- indicating the confidence in the match (higher is better). */
-
-static int
-cris_constraint (const char *cs,
- unsigned int insn,
- unsigned int prefix_insn,
- struct cris_disasm_data *disdata)
-{
- int retval = 0;
- int tmp;
- int prefix_ok = 0;
- const char *s;
-
- for (s = cs; *s; s++)
- switch (*s)
- {
- case '!':
- /* Do not recognize "pop" if there's a prefix and then only for
- v0..v10. */
- if (prefix_insn != NO_CRIS_PREFIX
- || disdata->distype != cris_dis_v0_v10)
- return -1;
- break;
-
- case 'U':
- /* Not recognized at disassembly. */
- return -1;
-
- case 'M':
- /* Size modifier for "clear", i.e. special register 0, 4 or 8.
- Check that it is one of them. Only special register 12 could
- be mismatched, but checking for matches is more logical than
- checking for mismatches when there are only a few cases. */
- tmp = ((insn >> 12) & 0xf);
- if (tmp != 0 && tmp != 4 && tmp != 8)
- return -1;
- break;
-
- case 'm':
- if ((insn & 0x30) == 0x30)
- return -1;
- break;
-
- case 'S':
- /* A prefix operand without side-effect. */
- if (prefix_insn != NO_CRIS_PREFIX && (insn & 0x400) == 0)
- {
- prefix_ok = 1;
- break;
- }
- else
- return -1;
-
- case 's':
- case 'y':
- case 'Y':
- /* If this is a prefixed insn with postincrement (side-effect),
- the prefix must not be DIP. */
- if (prefix_insn != NO_CRIS_PREFIX)
- {
- if (insn & 0x400)
- {
- const struct cris_opcode *prefix_opcodep
- = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata);
-
- if (prefix_opcodep->match == DIP_OPCODE)
- return -1;
- }
-
- prefix_ok = 1;
- }
- break;
-
- case 'B':
- /* If we don't fall through, then the prefix is ok. */
- prefix_ok = 1;
-
- /* A "push" prefix. Check for valid "push" size.
- In case of special register, it may be != 4. */
- if (prefix_insn != NO_CRIS_PREFIX)
- {
- /* Match the prefix insn to BDAPQ. */
- const struct cris_opcode *prefix_opcodep
- = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata);
-
- if (prefix_opcodep->match == BDAP_QUICK_OPCODE)
- {
- int pushsize = (prefix_insn & 255);
-
- if (pushsize > 127)
- pushsize -= 256;
-
- if (s[1] == 'P')
- {
- unsigned int spec_reg = (insn >> 12) & 15;
- const struct cris_spec_reg *sregp
- = spec_reg_info (spec_reg, disdata->distype);
-
- /* For a special-register, the "prefix size" must
- match the size of the register. */
- if (sregp && sregp->reg_size == (unsigned int) -pushsize)
- break;
- }
- else if (s[1] == 'R')
- {
- if ((insn & 0x30) == 0x20 && pushsize == -4)
- break;
- }
- /* FIXME: Should abort here; next constraint letter
- *must* be 'P' or 'R'. */
- }
- }
- return -1;
-
- case 'D':
- retval = (((insn >> 12) & 15) == (insn & 15));
- if (!retval)
- return -1;
- else
- retval += 4;
- break;
-
- case 'P':
- {
- const struct cris_spec_reg *sregp
- = spec_reg_info ((insn >> 12) & 15, disdata->distype);
-
- /* Since we match four bits, we will give a value of 4-1 = 3
- in a match. If there is a corresponding exact match of a
- special register in another pattern, it will get a value of
- 4, which will be higher. This should be correct in that an
- exact pattern would match better than a general pattern.
-
- Note that there is a reason for not returning zero; the
- pattern for "clear" is partly matched in the bit-pattern
- (the two lower bits must be zero), while the bit-pattern
- for a move from a special register is matched in the
- register constraint. */
-
- if (sregp != NULL)
- {
- retval += 3;
- break;
- }
- else
- return -1;
- }
- }
-
- if (prefix_insn != NO_CRIS_PREFIX && ! prefix_ok)
- return -1;
-
- return retval;
-}
-
-/* Format number as hex with a leading "0x" into outbuffer. */
-
-static char *
-format_hex (unsigned long number,
- char *outbuffer,
- struct cris_disasm_data *disdata)
-{
- /* Truncate negative numbers on >32-bit hosts. */
- number &= 0xffffffff;
-
- sprintf (outbuffer, "0x%lx", number);
-
- /* Save this value for the "case" support. */
- if (TRACE_CASE)
- last_immediate = number;
-
- return outbuffer + strlen (outbuffer);
-}
-
-/* Format number as decimal into outbuffer. Parameter signedp says
- whether the number should be formatted as signed (!= 0) or
- unsigned (== 0). */
-
-static char *
-format_dec (long number, char *outbuffer, size_t outsize, int signedp)
-{
- last_immediate = number;
- snprintf (outbuffer, outsize, signedp ? "%ld" : "%lu", number);
-
- return outbuffer + strlen (outbuffer);
-}
-
-/* Format the name of the general register regno into outbuffer. */
-
-static char *
-format_reg (struct cris_disasm_data *disdata,
- int regno,
- char *outbuffer_start,
- bfd_boolean with_reg_prefix)
-{
- char *outbuffer = outbuffer_start;
-
- if (with_reg_prefix)
- *outbuffer++ = REGISTER_PREFIX_CHAR;
-
- switch (regno)
- {
- case 15:
- /* For v32, there is no context in which we output PC. */
- if (disdata->distype == cris_dis_v32)
- strcpy (outbuffer, "acr");
- else
- strcpy (outbuffer, "pc");
- break;
-
- case 14:
- strcpy (outbuffer, "sp");
- break;
-
- default:
- sprintf (outbuffer, "r%d", regno);
- break;
- }
-
- return outbuffer_start + strlen (outbuffer_start);
-}
-
-/* Format the name of a support register into outbuffer. */
-
-static char *
-format_sup_reg (unsigned int regno,
- char *outbuffer_start,
- bfd_boolean with_reg_prefix)
-{
- char *outbuffer = outbuffer_start;
- int i;
-
- if (with_reg_prefix)
- *outbuffer++ = REGISTER_PREFIX_CHAR;
-
- for (i = 0; cris_support_regs[i].name != NULL; i++)
- if (cris_support_regs[i].number == regno)
- {
- sprintf (outbuffer, "%s", cris_support_regs[i].name);
- return outbuffer_start + strlen (outbuffer_start);
- }
-
- /* There's supposed to be register names covering all numbers, though
- some may be generic names. */
- sprintf (outbuffer, "format_sup_reg-BUG");
- return outbuffer_start + strlen (outbuffer_start);
-}
-
-/* Return the length of an instruction. */
-
-static unsigned
-bytes_to_skip (unsigned int insn,
- const struct cris_opcode *matchedp,
- enum cris_disass_family distype,
- const struct cris_opcode *prefix_matchedp)
-{
- /* Each insn is a word plus "immediate" operands. */
- unsigned to_skip = 2;
- const char *template = matchedp->args;
- const char *s;
-
- for (s = template; *s; s++)
- if ((*s == 's' || *s == 'N' || *s == 'Y')
- && (insn & 0x400) && (insn & 15) == 15
- && prefix_matchedp == NULL)
- {
- /* Immediate via [pc+], so we have to check the size of the
- operand. */
- int mode_size = 1 << ((insn >> 4) & (*template == 'z' ? 1 : 3));
-
- if (matchedp->imm_oprnd_size == SIZE_FIX_32)
- to_skip += 4;
- else if (matchedp->imm_oprnd_size == SIZE_SPEC_REG)
- {
- const struct cris_spec_reg *sregp
- = spec_reg_info ((insn >> 12) & 15, distype);
-
- /* FIXME: Improve error handling; should have been caught
- earlier. */
- if (sregp == NULL)
- return 2;
-
- /* PC is incremented by two, not one, for a byte. Except on
- CRISv32, where constants are always DWORD-size for
- special registers. */
- to_skip +=
- distype == cris_dis_v32 ? 4 : (sregp->reg_size + 1) & ~1;
- }
- else
- to_skip += (mode_size + 1) & ~1;
- }
- else if (*s == 'n')
- to_skip += 4;
- else if (*s == 'b')
- to_skip += 2;
-
- return to_skip;
-}
-
-/* Print condition code flags. */
-
-static char *
-print_flags (struct cris_disasm_data *disdata, unsigned int insn, char *cp)
-{
- /* Use the v8 (Etrax 100) flag definitions for disassembly.
- The differences with v0 (Etrax 1..4) vs. Svinto are:
- v0 'd' <=> v8 'm'
- v0 'e' <=> v8 'b'.
- FIXME: Emit v0..v3 flag names somehow. */
- static const char v8_fnames[] = "cvznxibm";
- static const char v32_fnames[] = "cvznxiup";
- const char *fnames
- = disdata->distype == cris_dis_v32 ? v32_fnames : v8_fnames;
-
- unsigned char flagbits = (((insn >> 8) & 0xf0) | (insn & 15));
- int i;
-
- for (i = 0; i < 8; i++)
- if (flagbits & (1 << i))
- *cp++ = fnames[i];
-
- return cp;
-}
-
-#define FORMAT_DEC(number, tp, signedp) \
- format_dec (number, tp, ({ \
- assert(tp >= temp && tp <= temp + sizeof(temp)); \
- temp + sizeof(temp) - tp; \
- }), signedp)
-
-/* Print out an insn with its operands, and update the info->insn_type
- fields. The prefix_opcodep and the rest hold a prefix insn that is
- supposed to be output as an address mode. */
-
-static void
-print_with_operands (const struct cris_opcode *opcodep,
- unsigned int insn,
- unsigned char *buffer,
- bfd_vma addr,
- disassemble_info *info,
- /* If a prefix insn was before this insn (and is supposed
- to be output as an address), here is a description of
- it. */
- const struct cris_opcode *prefix_opcodep,
- unsigned int prefix_insn,
- unsigned char *prefix_buffer,
- bfd_boolean with_reg_prefix)
-{
- /* Get a buffer of somewhat reasonable size where we store
- intermediate parts of the insn. */
- char temp[sizeof (".d [$r13=$r12-2147483648],$r10") * 2];
- char *tp = temp;
- static const char mode_char[] = "bwd?";
- const char *s;
- const char *cs;
- struct cris_disasm_data *disdata
- = (struct cris_disasm_data *) info->private_data;
-
- /* Print out the name first thing we do. */
- (*info->fprintf_func) (info->stream, "%s", opcodep->name);
-
- cs = opcodep->args;
- s = cs;
-
- /* Ignore any prefix indicator. */
- if (*s == 'p')
- s++;
-
- if (*s == 'm' || *s == 'M' || *s == 'z')
- {
- *tp++ = '.';
-
- /* Get the size-letter. */
- *tp++ = *s == 'M'
- ? (insn & 0x8000 ? 'd'
- : insn & 0x4000 ? 'w' : 'b')
- : mode_char[(insn >> 4) & (*s == 'z' ? 1 : 3)];
-
- /* Ignore the size and the space character that follows. */
- s += 2;
- }
-
- /* Add a space if this isn't a long-branch, because for those will add
- the condition part of the name later. */
- if (opcodep->match != (BRANCH_PC_LOW + BRANCH_INCR_HIGH * 256))
- *tp++ = ' ';
-
- /* Fill in the insn-type if deducible from the name (and there's no
- better way). */
- if (opcodep->name[0] == 'j')
- {
- if (CONST_STRNEQ (opcodep->name, "jsr"))
- /* It's "jsr" or "jsrc". */
- info->insn_type = dis_jsr;
- else
- /* Any other jump-type insn is considered a branch. */
- info->insn_type = dis_branch;
- }
-
- /* We might know some more fields right now. */
- info->branch_delay_insns = opcodep->delayed;
-
- /* Handle operands. */
- for (; *s; s++)
- {
- switch (*s)
- {
- case 'T':
- tp = format_sup_reg ((insn >> 12) & 15, tp, with_reg_prefix);
- break;
-
- case 'A':
- if (with_reg_prefix)
- *tp++ = REGISTER_PREFIX_CHAR;
- *tp++ = 'a';
- *tp++ = 'c';
- *tp++ = 'r';
- break;
-
- case '[':
- case ']':
- case ',':
- *tp++ = *s;
- break;
-
- case '!':
- /* Ignore at this point; used at earlier stages to avoid
- recognition if there's a prefix at something that in other
- ways looks like a "pop". */
- break;
-
- case 'd':
- /* Ignore. This is an optional ".d " on the large one of
- relaxable insns. */
- break;
-
- case 'B':
- /* This was the prefix that made this a "push". We've already
- handled it by recognizing it, so signal that the prefix is
- handled by setting it to NULL. */
- prefix_opcodep = NULL;
- break;
-
- case 'D':
- case 'r':
- tp = format_reg (disdata, insn & 15, tp, with_reg_prefix);
- break;
-
- case 'R':
- tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix);
- break;
-
- case 'n':
- {
- /* Like N but pc-relative to the start of the insn. */
- uint32_t number
- = (buffer[2] + buffer[3] * 256 + buffer[4] * 65536
- + buffer[5] * 0x1000000 + addr);
-
- /* Finish off and output previous formatted bytes. */
- *tp = 0;
- if (temp[0])
- (*info->fprintf_func) (info->stream, "%s", temp);
- tp = temp;
-
- (*info->print_address_func) ((bfd_vma) number, info);
- }
- break;
-
- case 'u':
- {
- /* Like n but the offset is bits <3:0> in the instruction. */
- unsigned long number = (buffer[0] & 0xf) * 2 + addr;
-
- /* Finish off and output previous formatted bytes. */
- *tp = 0;
- if (temp[0])
- (*info->fprintf_func) (info->stream, "%s", temp);
- tp = temp;
-
- (*info->print_address_func) ((bfd_vma) number, info);
- }
- break;
-
- case 'N':
- case 'y':
- case 'Y':
- case 'S':
- case 's':
- /* Any "normal" memory operand. */
- if ((insn & 0x400) && (insn & 15) == 15 && prefix_opcodep == NULL)
- {
- /* We're looking at [pc+], i.e. we need to output an immediate
- number, where the size can depend on different things. */
- int32_t number;
- int signedp
- = ((*cs == 'z' && (insn & 0x20))
- || opcodep->match == BDAP_QUICK_OPCODE);
- int nbytes;
-
- if (opcodep->imm_oprnd_size == SIZE_FIX_32)
- nbytes = 4;
- else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG)
- {
- const struct cris_spec_reg *sregp
- = spec_reg_info ((insn >> 12) & 15, disdata->distype);
-
- /* A NULL return should have been as a non-match earlier,
- so catch it as an internal error in the error-case
- below. */
- if (sregp == NULL)
- /* Whatever non-valid size. */
- nbytes = 42;
- else
- /* PC is always incremented by a multiple of two.
- For CRISv32, immediates are always 4 bytes for
- special registers. */
- nbytes = disdata->distype == cris_dis_v32
- ? 4 : (sregp->reg_size + 1) & ~1;
- }
- else
- {
- int mode_size = 1 << ((insn >> 4) & (*cs == 'z' ? 1 : 3));
-
- if (mode_size == 1)
- nbytes = 2;
- else
- nbytes = mode_size;
- }
-
- switch (nbytes)
- {
- case 1:
- number = buffer[2];
- if (signedp && number > 127)
- number -= 256;
- break;
-
- case 2:
- number = buffer[2] + buffer[3] * 256;
- if (signedp && number > 32767)
- number -= 65536;
- break;
-
- case 4:
- number
- = buffer[2] + buffer[3] * 256 + buffer[4] * 65536
- + buffer[5] * 0x1000000;
- break;
-
- default:
- strcpy (tp, "bug");
- tp += 3;
- number = 42;
- }
-
- if ((*cs == 'z' && (insn & 0x20))
- || (opcodep->match == BDAP_QUICK_OPCODE
- && (nbytes <= 2 || buffer[1 + nbytes] == 0)))
- tp = FORMAT_DEC (number, tp, signedp);
- else
- {
- unsigned int highbyte = (number >> 24) & 0xff;
-
- /* Either output this as an address or as a number. If it's
- a dword with the same high-byte as the address of the
- insn, assume it's an address, and also if it's a non-zero
- non-0xff high-byte. If this is a jsr or a jump, then
- it's definitely an address. */
- if (nbytes == 4
- && (highbyte == ((addr >> 24) & 0xff)
- || (highbyte != 0 && highbyte != 0xff)
- || info->insn_type == dis_branch
- || info->insn_type == dis_jsr))
- {
- /* Finish off and output previous formatted bytes. */
- *tp = 0;
- tp = temp;
- if (temp[0])
- (*info->fprintf_func) (info->stream, "%s", temp);
-
- (*info->print_address_func) ((bfd_vma) number, info);
-
- info->target = number;
- }
- else
- tp = format_hex (number, tp, disdata);
- }
- }
- else
- {
- /* Not an immediate number. Then this is a (possibly
- prefixed) memory operand. */
- if (info->insn_type != dis_nonbranch)
- {
- int mode_size
- = 1 << ((insn >> 4)
- & (opcodep->args[0] == 'z' ? 1 : 3));
- int size;
- info->insn_type = dis_dref;
- info->flags |= CRIS_DIS_FLAG_MEMREF;
-
- if (opcodep->imm_oprnd_size == SIZE_FIX_32)
- size = 4;
- else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG)
- {
- const struct cris_spec_reg *sregp
- = spec_reg_info ((insn >> 12) & 15, disdata->distype);
-
- /* FIXME: Improve error handling; should have been caught
- earlier. */
- if (sregp == NULL)
- size = 4;
- else
- size = sregp->reg_size;
- }
- else
- size = mode_size;
-
- info->data_size = size;
- }
-
- *tp++ = '[';
-
- if (prefix_opcodep
- /* We don't match dip with a postincremented field
- as a side-effect address mode. */
- && ((insn & 0x400) == 0
- || prefix_opcodep->match != DIP_OPCODE))
- {
- if (insn & 0x400)
- {
- tp = format_reg (disdata, insn & 15, tp, with_reg_prefix);
- *tp++ = '=';
- }
-
-
- /* We mainly ignore the prefix format string when the
- address-mode syntax is output. */
- switch (prefix_opcodep->match)
- {
- case DIP_OPCODE:
- /* It's [r], [r+] or [pc+]. */
- if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15)
- {
- /* It's [pc+]. This cannot possibly be anything
- but an address. */
- uint32_t number
- = prefix_buffer[2] + prefix_buffer[3] * 256
- + prefix_buffer[4] * 65536
- + prefix_buffer[5] * 0x1000000;
-
- info->target = (bfd_vma) number;
-
- /* Finish off and output previous formatted
- data. */
- *tp = 0;
- tp = temp;
- if (temp[0])
- (*info->fprintf_func) (info->stream, "%s", temp);
-
- (*info->print_address_func) ((bfd_vma) number, info);
- }
- else
- {
- /* For a memref in an address, we use target2.
- In this case, target is zero. */
- info->flags
- |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG
- | CRIS_DIS_FLAG_MEM_TARGET2_MEM);
-
- info->target2 = prefix_insn & 15;
-
- *tp++ = '[';
- tp = format_reg (disdata, prefix_insn & 15, tp,
- with_reg_prefix);
- if (prefix_insn & 0x400)
- *tp++ = '+';
- *tp++ = ']';
- }
- break;
-
- case BDAP_QUICK_OPCODE:
- {
- int number;
-
- number = prefix_buffer[0];
- if (number > 127)
- number -= 256;
-
- /* Output "reg+num" or, if num < 0, "reg-num". */
- tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp,
- with_reg_prefix);
- if (number >= 0)
- *tp++ = '+';
- tp = FORMAT_DEC (number, tp, 1);
-
- info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG;
- info->target = (prefix_insn >> 12) & 15;
- info->target2 = (bfd_vma) number;
- break;
- }
-
- case BIAP_OPCODE:
- /* Output "r+R.m". */
- tp = format_reg (disdata, prefix_insn & 15, tp,
- with_reg_prefix);
- *tp++ = '+';
- tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp,
- with_reg_prefix);
- *tp++ = '.';
- *tp++ = mode_char[(prefix_insn >> 4) & 3];
-
- info->flags
- |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG
- | CRIS_DIS_FLAG_MEM_TARGET_IS_REG
-
- | ((prefix_insn & 0x8000)
- ? CRIS_DIS_FLAG_MEM_TARGET2_MULT4
- : ((prefix_insn & 0x8000)
- ? CRIS_DIS_FLAG_MEM_TARGET2_MULT2 : 0)));
-
- /* Is it the casejump? It's a "adds.w [pc+r%d.w],pc". */
- if (insn == 0xf83f && (prefix_insn & ~0xf000) == 0x55f)
- /* Then start interpreting data as offsets. */
- case_offset_counter = no_of_case_offsets;
- break;
-
- case BDAP_INDIR_OPCODE:
- /* Output "r+s.m", or, if "s" is [pc+], "r+s" or
- "r-s". */
- tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp,
- with_reg_prefix);
-
- if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15)
- {
- int32_t number;
- unsigned int nbytes;
-
- /* It's a value. Get its size. */
- int mode_size = 1 << ((prefix_insn >> 4) & 3);
-
- if (mode_size == 1)
- nbytes = 2;
- else
- nbytes = mode_size;
-
- switch (nbytes)
- {
- case 1:
- number = prefix_buffer[2];
- if (number > 127)
- number -= 256;
- break;
-
- case 2:
- number = prefix_buffer[2] + prefix_buffer[3] * 256;
- if (number > 32767)
- number -= 65536;
- break;
-
- case 4:
- number
- = prefix_buffer[2] + prefix_buffer[3] * 256
- + prefix_buffer[4] * 65536
- + prefix_buffer[5] * 0x1000000;
- break;
-
- default:
- strcpy (tp, "bug");
- tp += 3;
- number = 42;
- }
-
- info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG;
- info->target2 = (bfd_vma) number;
-
- /* If the size is dword, then assume it's an
- address. */
- if (nbytes == 4)
- {
- /* Finish off and output previous formatted
- bytes. */
- *tp++ = '+';
- *tp = 0;
- tp = temp;
- (*info->fprintf_func) (info->stream, "%s", temp);
-
- (*info->print_address_func) ((bfd_vma) number, info);
- }
- else
- {
- if (number >= 0)
- *tp++ = '+';
- tp = FORMAT_DEC (number, tp, 1);
- }
- }
- else
- {
- /* Output "r+[R].m" or "r+[R+].m". */
- *tp++ = '+';
- *tp++ = '[';
- tp = format_reg (disdata, prefix_insn & 15, tp,
- with_reg_prefix);
- if (prefix_insn & 0x400)
- *tp++ = '+';
- *tp++ = ']';
- *tp++ = '.';
- *tp++ = mode_char[(prefix_insn >> 4) & 3];
-
- info->flags
- |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG
- | CRIS_DIS_FLAG_MEM_TARGET2_MEM
- | CRIS_DIS_FLAG_MEM_TARGET_IS_REG
-
- | (((prefix_insn >> 4) == 2)
- ? 0
- : (((prefix_insn >> 4) & 3) == 1
- ? CRIS_DIS_FLAG_MEM_TARGET2_MEM_WORD
- : CRIS_DIS_FLAG_MEM_TARGET2_MEM_BYTE)));
- }
- break;
-
- default:
- (*info->fprintf_func) (info->stream, "?prefix-bug");
- }
-
- /* To mark that the prefix is used, reset it. */
- prefix_opcodep = NULL;
- }
- else
- {
- tp = format_reg (disdata, insn & 15, tp, with_reg_prefix);
-
- info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG;
- info->target = insn & 15;
-
- if (insn & 0x400)
- *tp++ = '+';
- }
- *tp++ = ']';
- }
- break;
-
- case 'x':
- tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix);
- *tp++ = '.';
- *tp++ = mode_char[(insn >> 4) & 3];
- break;
-
- case 'I':
- tp = FORMAT_DEC (insn & 63, tp, 0);
- break;
-
- case 'b':
- {
- int where = buffer[2] + buffer[3] * 256;
-
- if (where > 32767)
- where -= 65536;
-
- where += addr + ((disdata->distype == cris_dis_v32) ? 0 : 4);
-
- if (insn == BA_PC_INCR_OPCODE)
- info->insn_type = dis_branch;
- else
- info->insn_type = dis_condbranch;
-
- info->target = (bfd_vma) where;
-
- *tp = 0;
- tp = temp;
- (*info->fprintf_func) (info->stream, "%s%s ",
- temp, cris_cc_strings[insn >> 12]);
-
- (*info->print_address_func) ((bfd_vma) where, info);
- }
- break;
-
- case 'c':
- tp = FORMAT_DEC (insn & 31, tp, 0);
- break;
-
- case 'C':
- tp = FORMAT_DEC (insn & 15, tp, 0);
- break;
-
- case 'o':
- {
- long offset = insn & 0xfe;
- bfd_vma target;
-
- if (insn & 1)
- offset |= ~0xff;
-
- if (opcodep->match == BA_QUICK_OPCODE)
- info->insn_type = dis_branch;
- else
- info->insn_type = dis_condbranch;
-
- target = addr + ((disdata->distype == cris_dis_v32) ? 0 : 2) + offset;
- info->target = target;
- *tp = 0;
- tp = temp;
- (*info->fprintf_func) (info->stream, "%s", temp);
- (*info->print_address_func) (target, info);
- }
- break;
-
- case 'Q':
- case 'O':
- {
- long number = buffer[0];
-
- if (number > 127)
- number = number - 256;
-
- tp = FORMAT_DEC (number, tp, 1);
- *tp++ = ',';
- tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix);
- }
- break;
-
- case 'f':
- tp = print_flags (disdata, insn, tp);
- break;
-
- case 'i':
- tp = FORMAT_DEC ((insn & 32) ? (insn & 31) | ~31L : insn & 31, tp, 1);
- break;
-
- case 'P':
- {
- const struct cris_spec_reg *sregp
- = spec_reg_info ((insn >> 12) & 15, disdata->distype);
-
- if (sregp == NULL || sregp->name == NULL)
- /* Should have been caught as a non-match earlier. */
- *tp++ = '?';
- else
- {
- if (with_reg_prefix)
- *tp++ = REGISTER_PREFIX_CHAR;
- strcpy (tp, sregp->name);
- tp += strlen (tp);
- }
- }
- break;
-
- default:
- strcpy (tp, "???");
- tp += 3;
- }
- }
-
- *tp = 0;
-
- if (prefix_opcodep)
- (*info->fprintf_func) (info->stream, " (OOPS unused prefix \"%s: %s\")",
- prefix_opcodep->name, prefix_opcodep->args);
-
- (*info->fprintf_func) (info->stream, "%s", temp);
-
- /* Get info for matching case-tables, if we don't have any active.
- We assume that the last constant seen is used; either in the insn
- itself or in a "move.d const,rN, sub.d rN,rM"-like sequence. */
- if (TRACE_CASE && case_offset_counter == 0)
- {
- if (CONST_STRNEQ (opcodep->name, "sub"))
- case_offset = last_immediate;
-
- /* It could also be an "add", if there are negative case-values. */
- else if (CONST_STRNEQ (opcodep->name, "add"))
- /* The first case is the negated operand to the add. */
- case_offset = -last_immediate;
-
- /* A bound insn will tell us the number of cases. */
- else if (CONST_STRNEQ (opcodep->name, "bound"))
- no_of_case_offsets = last_immediate + 1;
-
- /* A jump or jsr or branch breaks the chain of insns for a
- case-table, so assume default first-case again. */
- else if (info->insn_type == dis_jsr
- || info->insn_type == dis_branch
- || info->insn_type == dis_condbranch)
- case_offset = 0;
- }
-}
-
-
-/* Print the CRIS instruction at address memaddr on stream. Returns
- length of the instruction, in bytes. Prefix register names with `$' if
- WITH_REG_PREFIX. */
-
-static int
-print_insn_cris_generic (bfd_vma memaddr,
- disassemble_info *info,
- bfd_boolean with_reg_prefix)
-{
- int nbytes;
- unsigned int insn;
- const struct cris_opcode *matchedp;
- int advance = 0;
- struct cris_disasm_data *disdata
- = (struct cris_disasm_data *) info->private_data;
-
- /* No instruction will be disassembled as longer than this number of
- bytes; stacked prefixes will not be expanded. */
- unsigned char buffer[MAX_BYTES_PER_CRIS_INSN];
- unsigned char *bufp;
- int status = 0;
- bfd_vma addr;
-
- /* There will be an "out of range" error after the last instruction.
- Reading pairs of bytes in decreasing number, we hope that we will get
- at least the amount that we will consume.
-
- If we can't get any data, or we do not get enough data, we print
- the error message. */
-
- nbytes = info->buffer_length ? info->buffer_length
- : MAX_BYTES_PER_CRIS_INSN;
- nbytes = MIN(nbytes, MAX_BYTES_PER_CRIS_INSN);
- status = (*info->read_memory_func) (memaddr, buffer, nbytes, info);
-
- /* If we did not get all we asked for, then clear the rest.
- Hopefully this makes a reproducible result in case of errors. */
- if (nbytes != MAX_BYTES_PER_CRIS_INSN)
- memset (buffer + nbytes, 0, MAX_BYTES_PER_CRIS_INSN - nbytes);
-
- addr = memaddr;
- bufp = buffer;
-
- /* Set some defaults for the insn info. */
- info->insn_info_valid = 1;
- info->branch_delay_insns = 0;
- info->data_size = 0;
- info->insn_type = dis_nonbranch;
- info->flags = 0;
- info->target = 0;
- info->target2 = 0;
-
- /* If we got any data, disassemble it. */
- if (nbytes != 0)
- {
- matchedp = NULL;
-
- insn = bufp[0] + bufp[1] * 256;
-
- /* If we're in a case-table, don't disassemble the offsets. */
- if (TRACE_CASE && case_offset_counter != 0)
- {
- info->insn_type = dis_noninsn;
- advance += 2;
-
- /* If to print data as offsets, then shortcut here. */
- (*info->fprintf_func) (info->stream, "case %ld%s: -> ",
- case_offset + no_of_case_offsets
- - case_offset_counter,
- case_offset_counter == 1 ? "/default" :
- "");
-
- (*info->print_address_func) ((bfd_vma)
- ((short) (insn)
- + (long) (addr
- - (no_of_case_offsets
- - case_offset_counter)
- * 2)), info);
- case_offset_counter--;
-
- /* The default case start (without a "sub" or "add") must be
- zero. */
- if (case_offset_counter == 0)
- case_offset = 0;
- }
- else if (insn == 0)
- {
- /* We're often called to disassemble zeroes. While this is a
- valid "bcc .+2" insn, it is also useless enough and enough
- of a nuiscance that we will just output "bcc .+2" for it
- and signal it as a noninsn. */
- (*info->fprintf_func) (info->stream,
- disdata->distype == cris_dis_v32
- ? "bcc ." : "bcc .+2");
- info->insn_type = dis_noninsn;
- advance += 2;
- }
- else
- {
- const struct cris_opcode *prefix_opcodep = NULL;
- unsigned char *prefix_buffer = bufp;
- unsigned int prefix_insn = insn;
- int prefix_size = 0;
-
- matchedp = get_opcode_entry (insn, NO_CRIS_PREFIX, disdata);
-
- /* Check if we're supposed to write out prefixes as address
- modes and if this was a prefix. */
- if (matchedp != NULL && PARSE_PREFIX && matchedp->args[0] == 'p')
- {
- /* If it's a prefix, put it into the prefix vars and get the
- main insn. */
- prefix_size = bytes_to_skip (prefix_insn, matchedp,
- disdata->distype, NULL);
- prefix_opcodep = matchedp;
-
- insn = bufp[prefix_size] + bufp[prefix_size + 1] * 256;
- matchedp = get_opcode_entry (insn, prefix_insn, disdata);
-
- if (matchedp != NULL)
- {
- addr += prefix_size;
- bufp += prefix_size;
- advance += prefix_size;
- }
- else
- {
- /* The "main" insn wasn't valid, at least not when
- prefixed. Put back things enough to output the
- prefix insn only, as a normal insn. */
- matchedp = prefix_opcodep;
- insn = prefix_insn;
- prefix_opcodep = NULL;
- }
- }
-
- if (matchedp == NULL)
- {
- (*info->fprintf_func) (info->stream, "??0x%x", insn);
- advance += 2;
-
- info->insn_type = dis_noninsn;
- }
- else
- {
- advance
- += bytes_to_skip (insn, matchedp, disdata->distype,
- prefix_opcodep);
-
- /* The info_type and assorted fields will be set according
- to the operands. */
- print_with_operands (matchedp, insn, bufp, addr, info,
- prefix_opcodep, prefix_insn,
- prefix_buffer, with_reg_prefix);
- }
- }
- }
- else
- info->insn_type = dis_noninsn;
-
- /* If we read less than MAX_BYTES_PER_CRIS_INSN, i.e. we got an error
- status when reading that much, and the insn decoding indicated a
- length exceeding what we read, there is an error. */
- if (status != 0 && (nbytes == 0 || advance > nbytes))
- {
- (*info->memory_error_func) (status, memaddr, info);
- return -1;
- }
-
- /* Max supported insn size with one folded prefix insn. */
- info->bytes_per_line = MAX_BYTES_PER_CRIS_INSN;
-
- /* I would like to set this to a fixed value larger than the actual
- number of bytes to print in order to avoid spaces between bytes,
- but objdump.c (2.9.1) does not like that, so we print 16-bit
- chunks, which is the next choice. */
- info->bytes_per_chunk = 2;
-
- /* Printing bytes in order of increasing addresses makes sense,
- especially on a little-endian target.
- This is completely the opposite of what you think; setting this to
- BFD_ENDIAN_LITTLE will print bytes in order N..0 rather than the 0..N
- we want. */
- info->display_endian = BFD_ENDIAN_BIG;
-
- return advance;
-}
-
-/* Disassemble, prefixing register names with `$'. CRIS v0..v10. */
-static int
-print_insn_cris_with_register_prefix (bfd_vma vma,
- disassemble_info *info)
-{
- struct cris_disasm_data disdata;
- info->private_data = &disdata;
- cris_parse_disassembler_options (&disdata, info->disassembler_options,
- cris_dis_v0_v10);
- return print_insn_cris_generic (vma, info, true);
-}
-/* Disassemble, prefixing register names with `$'. CRIS v32. */
-
-static int
-print_insn_crisv32_with_register_prefix (bfd_vma vma,
- disassemble_info *info)
-{
- struct cris_disasm_data disdata;
- info->private_data = &disdata;
- cris_parse_disassembler_options (&disdata, info->disassembler_options,
- cris_dis_v32);
- return print_insn_cris_generic (vma, info, true);
-}
-
-#if 0
-/* Disassemble, prefixing register names with `$'.
- Common v10 and v32 subset. */
-
-static int
-print_insn_crisv10_v32_with_register_prefix (bfd_vma vma,
- disassemble_info *info)
-{
- struct cris_disasm_data disdata;
- info->private_data = &disdata;
- cris_parse_disassembler_options (&disdata, info->disassembler_options,
- cris_dis_common_v10_v32);
- return print_insn_cris_generic (vma, info, true);
-}
-
-/* Disassemble, no prefixes on register names. CRIS v0..v10. */
-
-static int
-print_insn_cris_without_register_prefix (bfd_vma vma,
- disassemble_info *info)
-{
- struct cris_disasm_data disdata;
- info->private_data = &disdata;
- cris_parse_disassembler_options (&disdata, info->disassembler_options,
- cris_dis_v0_v10);
- return print_insn_cris_generic (vma, info, false);
-}
-
-/* Disassemble, no prefixes on register names. CRIS v32. */
-
-static int
-print_insn_crisv32_without_register_prefix (bfd_vma vma,
- disassemble_info *info)
-{
- struct cris_disasm_data disdata;
- info->private_data = &disdata;
- cris_parse_disassembler_options (&disdata, info->disassembler_options,
- cris_dis_v32);
- return print_insn_cris_generic (vma, info, false);
-}
-
-/* Disassemble, no prefixes on register names.
- Common v10 and v32 subset. */
-
-static int
-print_insn_crisv10_v32_without_register_prefix (bfd_vma vma,
- disassemble_info *info)
-{
- struct cris_disasm_data disdata;
- info->private_data = &disdata;
- cris_parse_disassembler_options (&disdata, info->disassembler_options,
- cris_dis_common_v10_v32);
- return print_insn_cris_generic (vma, info, false);
-}
-#endif
-
-int
-print_insn_crisv10 (bfd_vma vma,
- disassemble_info *info)
-{
- return print_insn_cris_with_register_prefix(vma, info);
-}
-
-int
-print_insn_crisv32 (bfd_vma vma,
- disassemble_info *info)
-{
- return print_insn_crisv32_with_register_prefix(vma, info);
-}
-
-/* Return a disassembler-function that prints registers with a `$' prefix,
- or one that prints registers without a prefix.
- FIXME: We should improve the solution to avoid the multitude of
- functions seen above. */
-#if 0
-disassembler_ftype
-cris_get_disassembler (bfd *abfd)
-{
- /* If there's no bfd in sight, we return what is valid as input in all
- contexts if fed back to the assembler: disassembly *with* register
- prefix. Unfortunately this will be totally wrong for v32. */
- if (abfd == NULL)
- return print_insn_cris_with_register_prefix;
-
- if (bfd_get_symbol_leading_char (abfd) == 0)
- {
- if (bfd_get_mach (abfd) == bfd_mach_cris_v32)
- return print_insn_crisv32_with_register_prefix;
- if (bfd_get_mach (abfd) == bfd_mach_cris_v10_v32)
- return print_insn_crisv10_v32_with_register_prefix;
-
- /* We default to v10. This may be specifically specified in the
- bfd mach, but is also the default setting. */
- return print_insn_cris_with_register_prefix;
- }
-
- if (bfd_get_mach (abfd) == bfd_mach_cris_v32)
- return print_insn_crisv32_without_register_prefix;
- if (bfd_get_mach (abfd) == bfd_mach_cris_v10_v32)
- return print_insn_crisv10_v32_without_register_prefix;
- return print_insn_cris_without_register_prefix;
-}
-#endif
-/* Local variables:
- eval: (c-set-style "gnu")
- indent-tabs-mode: t
- End: */
diff --git a/disas/meson.build b/disas/meson.build
index 20d6aef..bbfa119 100644
--- a/disas/meson.build
+++ b/disas/meson.build
@@ -1,5 +1,4 @@
common_ss.add(when: 'CONFIG_ALPHA_DIS', if_true: files('alpha.c'))
-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_M68K_DIS', if_true: files('m68k.c'))
diff --git a/disas/riscv.c b/disas/riscv.c
index 90d6b26..fc0331b 100644
--- a/disas/riscv.c
+++ b/disas/riscv.c
@@ -906,6 +906,76 @@ typedef enum {
rv_op_amocas_w = 875,
rv_op_amocas_d = 876,
rv_op_amocas_q = 877,
+ rv_mop_r_0 = 878,
+ rv_mop_r_1 = 879,
+ rv_mop_r_2 = 880,
+ rv_mop_r_3 = 881,
+ rv_mop_r_4 = 882,
+ rv_mop_r_5 = 883,
+ rv_mop_r_6 = 884,
+ rv_mop_r_7 = 885,
+ rv_mop_r_8 = 886,
+ rv_mop_r_9 = 887,
+ rv_mop_r_10 = 888,
+ rv_mop_r_11 = 889,
+ rv_mop_r_12 = 890,
+ rv_mop_r_13 = 891,
+ rv_mop_r_14 = 892,
+ rv_mop_r_15 = 893,
+ rv_mop_r_16 = 894,
+ rv_mop_r_17 = 895,
+ rv_mop_r_18 = 896,
+ rv_mop_r_19 = 897,
+ rv_mop_r_20 = 898,
+ rv_mop_r_21 = 899,
+ rv_mop_r_22 = 900,
+ rv_mop_r_23 = 901,
+ rv_mop_r_24 = 902,
+ rv_mop_r_25 = 903,
+ rv_mop_r_26 = 904,
+ rv_mop_r_27 = 905,
+ rv_mop_r_28 = 906,
+ rv_mop_r_29 = 907,
+ rv_mop_r_30 = 908,
+ rv_mop_r_31 = 909,
+ rv_mop_rr_0 = 910,
+ rv_mop_rr_1 = 911,
+ rv_mop_rr_2 = 912,
+ rv_mop_rr_3 = 913,
+ rv_mop_rr_4 = 914,
+ rv_mop_rr_5 = 915,
+ rv_mop_rr_6 = 916,
+ rv_mop_rr_7 = 917,
+ rv_c_mop_1 = 918,
+ rv_c_mop_3 = 919,
+ rv_c_mop_5 = 920,
+ rv_c_mop_7 = 921,
+ rv_c_mop_9 = 922,
+ rv_c_mop_11 = 923,
+ rv_c_mop_13 = 924,
+ rv_c_mop_15 = 925,
+ rv_op_amoswap_b = 926,
+ rv_op_amoadd_b = 927,
+ rv_op_amoxor_b = 928,
+ rv_op_amoor_b = 929,
+ rv_op_amoand_b = 930,
+ rv_op_amomin_b = 931,
+ rv_op_amomax_b = 932,
+ rv_op_amominu_b = 933,
+ rv_op_amomaxu_b = 934,
+ rv_op_amoswap_h = 935,
+ rv_op_amoadd_h = 936,
+ rv_op_amoxor_h = 937,
+ rv_op_amoor_h = 938,
+ rv_op_amoand_h = 939,
+ rv_op_amomin_h = 940,
+ rv_op_amomax_h = 941,
+ rv_op_amominu_h = 942,
+ rv_op_amomaxu_h = 943,
+ rv_op_amocas_b = 944,
+ rv_op_amocas_h = 945,
+ rv_op_wrs_sto = 946,
+ rv_op_wrs_nto = 947,
} rv_op;
/* register names */
@@ -2096,6 +2166,76 @@ const rv_opcode_data rvi_opcode_data[] = {
{ "amocas.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
{ "amocas.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
{ "amocas.q", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "mop.r.0", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.1", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.2", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.3", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.4", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.5", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.6", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.7", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.8", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.9", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.10", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.11", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.12", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.13", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.14", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.15", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.16", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.17", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.18", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.19", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.20", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.21", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.22", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.23", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.24", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.25", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.26", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.27", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.28", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.29", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.30", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.r.31", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0 },
+ { "mop.rr.0", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
+ { "mop.rr.1", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
+ { "mop.rr.2", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
+ { "mop.rr.3", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
+ { "mop.rr.4", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
+ { "mop.rr.5", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
+ { "mop.rr.6", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
+ { "mop.rr.7", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
+ { "c.mop.1", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 },
+ { "c.mop.3", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 },
+ { "c.mop.5", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 },
+ { "c.mop.7", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 },
+ { "c.mop.9", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 },
+ { "c.mop.11", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 },
+ { "c.mop.13", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 },
+ { "c.mop.15", rv_codec_ci_none, rv_fmt_none, NULL, 0, 0, 0 },
+ { "amoswap.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "amoadd.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "amoxor.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "amoor.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "amoand.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "amomin.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "amomax.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "amominu.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "amomaxu.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "amoswap.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "amoadd.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "amoxor.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "amoor.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "amoand.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "amomin.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "amomax.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "amominu.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "amomaxu.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "amocas.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "amocas.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "wrs.sto", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 },
+ { "wrs.nto", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 },
};
/* CSR names */
@@ -2452,6 +2592,13 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
break;
case 2: op = rv_op_c_li; break;
case 3:
+ if (dec->cfg->ext_zcmop) {
+ if ((((inst >> 2) & 0b111111) == 0b100000) &&
+ (((inst >> 11) & 0b11) == 0b0)) {
+ op = rv_c_mop_1 + ((inst >> 8) & 0b111);
+ break;
+ }
+ }
switch ((inst >> 7) & 0b11111) {
case 2: op = rv_op_c_addi16sp; break;
default: op = rv_op_c_lui; break;
@@ -2883,9 +3030,13 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
case 11:
switch (((inst >> 24) & 0b11111000) |
((inst >> 12) & 0b00000111)) {
+ case 0: op = rv_op_amoadd_b; break;
+ case 1: op = rv_op_amoadd_h; break;
case 2: op = rv_op_amoadd_w; break;
case 3: op = rv_op_amoadd_d; break;
case 4: op = rv_op_amoadd_q; break;
+ case 8: op = rv_op_amoswap_b; break;
+ case 9: op = rv_op_amoswap_h; break;
case 10: op = rv_op_amoswap_w; break;
case 11: op = rv_op_amoswap_d; break;
case 12: op = rv_op_amoswap_q; break;
@@ -2907,27 +3058,43 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
case 26: op = rv_op_sc_w; break;
case 27: op = rv_op_sc_d; break;
case 28: op = rv_op_sc_q; break;
+ case 32: op = rv_op_amoxor_b; break;
+ case 33: op = rv_op_amoxor_h; break;
case 34: op = rv_op_amoxor_w; break;
case 35: op = rv_op_amoxor_d; break;
case 36: op = rv_op_amoxor_q; break;
+ case 40: op = rv_op_amocas_b; break;
+ case 41: op = rv_op_amocas_h; break;
case 42: op = rv_op_amocas_w; break;
case 43: op = rv_op_amocas_d; break;
case 44: op = rv_op_amocas_q; break;
+ case 64: op = rv_op_amoor_b; break;
+ case 65: op = rv_op_amoor_h; break;
case 66: op = rv_op_amoor_w; break;
case 67: op = rv_op_amoor_d; break;
case 68: op = rv_op_amoor_q; break;
+ case 96: op = rv_op_amoand_b; break;
+ case 97: op = rv_op_amoand_h; break;
case 98: op = rv_op_amoand_w; break;
case 99: op = rv_op_amoand_d; break;
case 100: op = rv_op_amoand_q; break;
+ case 128: op = rv_op_amomin_b; break;
+ case 129: op = rv_op_amomin_h; break;
case 130: op = rv_op_amomin_w; break;
case 131: op = rv_op_amomin_d; break;
case 132: op = rv_op_amomin_q; break;
+ case 160: op = rv_op_amomax_b; break;
+ case 161: op = rv_op_amomax_h; break;
case 162: op = rv_op_amomax_w; break;
case 163: op = rv_op_amomax_d; break;
case 164: op = rv_op_amomax_q; break;
+ case 192: op = rv_op_amominu_b; break;
+ case 193: op = rv_op_amominu_h; break;
case 194: op = rv_op_amominu_w; break;
case 195: op = rv_op_amominu_d; break;
case 196: op = rv_op_amominu_q; break;
+ case 224: op = rv_op_amomaxu_b; break;
+ case 225: op = rv_op_amomaxu_h; break;
case 226: op = rv_op_amomaxu_w; break;
case 227: op = rv_op_amomaxu_d; break;
case 228: op = rv_op_amomaxu_q; break;
@@ -3817,6 +3984,8 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
case 0: op = rv_op_ecall; break;
case 32: op = rv_op_ebreak; break;
case 64: op = rv_op_uret; break;
+ case 416: op = rv_op_wrs_nto; break;
+ case 928: op = rv_op_wrs_sto; break;
}
break;
case 256:
@@ -3855,6 +4024,24 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
case 1: op = rv_op_csrrw; break;
case 2: op = rv_op_csrrs; break;
case 3: op = rv_op_csrrc; break;
+ case 4:
+ if (dec->cfg->ext_zimop) {
+ int imm_mop5, imm_mop3;
+ if ((extract32(inst, 22, 10) & 0b1011001111)
+ == 0b1000000111) {
+ imm_mop5 = deposit32(deposit32(extract32(inst, 20, 2),
+ 2, 2,
+ extract32(inst, 26, 2)),
+ 4, 1, extract32(inst, 30, 1));
+ op = rv_mop_r_0 + imm_mop5;
+ } else if ((extract32(inst, 25, 7) & 0b1011001)
+ == 0b1000001) {
+ imm_mop3 = deposit32(extract32(inst, 26, 2),
+ 2, 1, extract32(inst, 30, 1));
+ op = rv_mop_rr_0 + imm_mop3;
+ }
+ }
+ break;
case 5: op = rv_op_csrrwi; break;
case 6: op = rv_op_csrrsi; break;
case 7: op = rv_op_csrrci; break;
@@ -4621,7 +4808,7 @@ static void decode_inst_operands(rv_decode *dec, rv_isa isa)
break;
case rv_codec_vsetivli:
dec->rd = operand_rd(inst);
- dec->imm = operand_vimm(inst);
+ dec->imm = extract32(inst, 15, 5);
dec->vzimm = operand_vzimm10(inst);
break;
case rv_codec_zcb_lb:
diff --git a/disas/riscv.h b/disas/riscv.h
index 16a08e4..0d1f89c 100644
--- a/disas/riscv.h
+++ b/disas/riscv.h
@@ -290,7 +290,7 @@ enum {
#define rv_fmt_fd_vs2 "O\t3,F"
#define rv_fmt_vd_vm "O\tDm"
#define rv_fmt_vsetvli "O\t0,1,v"
-#define rv_fmt_vsetivli "O\t0,u,v"
+#define rv_fmt_vsetivli "O\t0,i,v"
#define rv_fmt_rs1_rs2_zce_ldst "O\t2,i(1)"
#define rv_fmt_push_rlist "O\tx,-i"
#define rv_fmt_pop_rlist "O\tx,i"
diff --git a/docs/COLO-FT.txt b/docs/COLO-FT.txt
index 2e760a4..2283a09 100644
--- a/docs/COLO-FT.txt
+++ b/docs/COLO-FT.txt
@@ -193,8 +193,8 @@ any IP's here, except for the $primary_ip variable.
-device piix3-usb-uhci -device usb-tablet -name secondary \
-netdev tap,id=hn0,vhost=off,helper=/usr/lib/qemu/qemu-bridge-helper \
-device rtl8139,id=e0,netdev=hn0 \
- -chardev socket,id=red0,host=$primary_ip,port=9003,reconnect=1 \
- -chardev socket,id=red1,host=$primary_ip,port=9004,reconnect=1 \
+ -chardev socket,id=red0,host=$primary_ip,port=9003,reconnect-ms=1000 \
+ -chardev socket,id=red1,host=$primary_ip,port=9004,reconnect-ms=1000 \
-object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0 \
-object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1 \
-object filter-rewriter,id=rew0,netdev=hn0,queue=all \
diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst
index 20b7a17..1e1e9f5 100644
--- a/docs/about/deprecated.rst
+++ b/docs/about/deprecated.rst
@@ -184,6 +184,25 @@ be an effective use of its limited resources, and thus intends to discontinue
it. Since all recent x86 hardware from the past >10 years is capable of the
64-bit x86 extensions, a corresponding 64-bit OS should be used instead.
+TCG Plugin support not enabled by default on 32-bit hosts (since 9.2)
+'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+While it is still possible to enable TCG plugin support for 32-bit
+hosts there are a number of potential pitfalls when instrumenting
+64-bit guests. The plugin APIs typically pass most addresses as
+uint64_t but practices like encoding that address in a host pointer
+for passing as user-data will lose data. As most software analysis
+benefits from having plenty of host memory it seems reasonable to
+encourage users to use 64 bit builds of QEMU for analysis work
+whatever targets they are instrumenting.
+
+TCG Plugin support not enabled by default with TCI (since 9.2)
+''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+While the TCG interpreter can interpret the TCG ops used by plugins it
+is going to be so much slower it wouldn't make sense for any serious
+instrumentation. Due to implementation differences there will also be
+anomalies in things like memory instrumentation.
System emulator CPUs
--------------------
@@ -206,14 +225,6 @@ in the QEMU object model anymore. ``Sun-UltraSparc-IIIi+`` and
but for consistency these will get removed in a future release, too.
Use ``Sun-UltraSparc-IIIi-plus`` and ``Sun-UltraSparc-IV-plus`` instead.
-CRIS CPU architecture (since 9.0)
-'''''''''''''''''''''''''''''''''
-
-The CRIS architecture was pulled from Linux in 4.17 and the compiler
-is no longer packaged in any distro making it harder to run the
-``check-tcg`` tests. Unless we can improve the testing situation there
-is a chance the code will bitrot without anyone noticing.
-
System emulator machines
------------------------
@@ -232,12 +243,6 @@ These old machine types are quite neglected nowadays and thus might have
various pitfalls with regards to live migration. Use a newer machine type
instead.
-``shix`` (since 9.0)
-''''''''''''''''''''
-
-The machine is no longer in existence and has been long unmaintained
-in QEMU. This also holds for the TC51828 16MiB flash that it uses.
-
``pseries-2.1`` up to ``pseries-2.12`` (since 9.0)
''''''''''''''''''''''''''''''''''''''''''''''''''
@@ -246,21 +251,6 @@ to correct issues, mostly regarding migration compatibility. These are
no longer maintained and removing them will make the code easier to
read and maintain. Use versions 3.0 and above as a replacement.
-Arm machines ``akita``, ``borzoi``, ``cheetah``, ``connex``, ``mainstone``, ``n800``, ``n810``, ``spitz``, ``terrier``, ``tosa``, ``verdex``, ``z2`` (since 9.0)
-''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
-
-QEMU includes models of some machine types where the QEMU code that
-emulates their SoCs is very old and unmaintained. This code is now
-blocking our ability to move forward with various changes across
-the codebase, and over many years nobody has been interested in
-trying to modernise it. We don't expect any of these machines to have
-a large number of users, because they're all modelling hardware that
-has now passed away into history. We are therefore dropping support
-for all machine types using the PXA2xx and OMAP2 SoCs. We are also
-dropping the ``cheetah`` OMAP1 board, because we don't have any
-test images for it and don't know of anybody who does; the ``sx1``
-and ``sx1-v1`` OMAP1 machines remain supported for now.
-
PPC 405 ``ref405ep`` machine (since 9.1)
''''''''''''''''''''''''''''''''''''''''
@@ -324,41 +314,6 @@ the addition of volatile memory support, it is now necessary to distinguish
between persistent and volatile memory backends. As such, memdev is deprecated
in favor of persistent-memdev.
-``-fsdev proxy`` and ``-virtfs proxy`` (since 8.1)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The 9p ``proxy`` filesystem backend driver has been deprecated and will be
-removed (along with its proxy helper daemon) in a future version of QEMU. Please
-use ``-fsdev local`` or ``-virtfs local`` for using the 9p ``local`` filesystem
-backend, or alternatively consider deploying virtiofsd instead.
-
-The 9p ``proxy`` backend was originally developed as an alternative to the 9p
-``local`` backend. The idea was to enhance security by dispatching actual low
-level filesystem operations from 9p server (QEMU process) over to a separate
-process (the virtfs-proxy-helper binary). However this alternative never gained
-momentum. The proxy backend is much slower than the local backend, hasn't seen
-any development in years, and showed to be less secure, especially due to the
-fact that its helper daemon must be run as root, whereas with the local backend
-QEMU is typically run as unprivileged user and allows to tighten behaviour by
-mapping permissions et al by using its 'mapped' security model option.
-
-Nowadays it would make sense to reimplement the ``proxy`` backend by using
-QEMU's ``vhost`` feature, which would eliminate the high latency costs under
-which the 9p ``proxy`` backend currently suffers. However as of to date nobody
-has indicated plans for such kind of reimplementation unfortunately.
-
-RISC-V 'any' CPU type ``-cpu any`` (since 8.2)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The 'any' CPU type was introduced back in 2018 and has been around since the
-initial RISC-V QEMU port. Its usage has always been unclear: users don't know
-what to expect from a CPU called 'any', and in fact the CPU does not do anything
-special that isn't already done by the default CPUs rv32/rv64.
-
-After the introduction of the 'max' CPU type, RISC-V now has a good coverage
-of generic CPUs: rv32 and rv64 as default CPUs and 'max' as a feature complete
-CPU for both 32 and 64 bit builds. Users are then discouraged to use the 'any'
-CPU type starting in 8.2.
RISC-V CPU properties which start with capital 'Z' (since 8.2)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -422,6 +377,15 @@ Specifying the iSCSI password in plain text on the command line using the
used instead, to refer to a ``--object secret...`` instance that provides
a password via a file, or encrypted.
+``gluster`` backend (since 9.2)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+According to https://marc.info/?l=fedora-devel-list&m=171934833215726
+the GlusterFS development effectively ended. Unless the development
+gains momentum again, the QEMU project will remove the gluster backend
+in a future release.
+
+
Character device options
''''''''''''''''''''''''
@@ -430,6 +394,22 @@ Backend ``memory`` (since 9.0)
``memory`` is a deprecated synonym for ``ringbuf``.
+``reconnect`` (since 9.2)
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``reconnect`` option only allows specifiying second granularity timeouts,
+which is not enough for all types of use cases, use ``reconnect-ms`` instead.
+
+
+Net device options
+''''''''''''''''''
+
+Stream ``reconnect`` (since 9.2)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``reconnect`` option only allows specifiying second granularity timeouts,
+which is not enough for all types of use cases, use ``reconnect-ms`` instead.
+
CPU device properties
'''''''''''''''''''''
@@ -479,6 +459,17 @@ versions, aliases will point to newer CPU model versions
depending on the machine type, so management software must
resolve CPU model aliases before starting a virtual machine.
+RISC-V "virt" board "riscv,delegate" DT property (since 9.1)
+''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+The "riscv,delegate" DT property was added in QEMU 7.0 as part of
+the AIA APLIC support. The property changed name during the review
+process in Linux and the correct name ended up being
+"riscv,delegation". Changing the DT property name will break all
+available firmwares that are using the current (wrong) name. The
+property is kept as is in 9.1, together with "riscv,delegation", to
+give more time for firmware developers to change their code.
+
Migration
---------
@@ -492,3 +483,9 @@ usage of providing a file descriptor to a plain file has been
deprecated in favor of explicitly using the ``file:`` URI with the
file descriptor being passed as an ``fdset``. Refer to the ``add-fd``
command documentation for details on the ``fdset`` usage.
+
+``zero-blocks`` capability (since 9.2)
+''''''''''''''''''''''''''''''''''''''
+
+The ``zero-blocks`` capability was part of the block migration which
+doesn't exist anymore since it was removed in QEMU v9.1.
diff --git a/docs/about/emulation.rst b/docs/about/emulation.rst
index b5ff9c5..3028d5f 100644
--- a/docs/about/emulation.rst
+++ b/docs/about/emulation.rst
@@ -26,10 +26,6 @@ depending on the guest architecture.
- :ref:`Yes<AVR-System-emulator>`
- No
- 8 bit micro controller, often used in maker projects
- * - Cris
- - Yes
- - Yes
- - Embedded RISC chip developed by AXIS
* - Hexagon
- No
- Yes
@@ -42,7 +38,7 @@ depending on the guest architecture.
- :ref:`Yes<QEMU-PC-System-emulator>`
- Yes
- The ubiquitous desktop PC CPU architecture, 32 and 64 bit.
- * - Loongarch
+ * - LoongArch
- Yes
- Yes
- A MIPS-like 64bit RISC architecture developed in China
@@ -95,9 +91,6 @@ depending on the guest architecture.
- Yes
- A configurable 32 bit soft core now owned by Cadence
-A number of features are only available when running under
-emulation including :ref:`Record/Replay<replay>` and :ref:`TCG Plugins`.
-
.. _Semihosting:
Semihosting
@@ -182,3 +175,644 @@ for that architecture.
* - Xtensa
- System
- Tensilica ISS SIMCALL
+
+TCG Plugins
+-----------
+
+QEMU TCG plugins provide a way for users to run experiments taking
+advantage of the total system control emulation can have over a guest.
+It provides a mechanism for plugins to subscribe to events during
+translation and execution and optionally callback into the plugin
+during these events. TCG plugins are unable to change the system state
+only monitor it passively. However they can do this down to an
+individual instruction granularity including potentially subscribing
+to all load and store operations.
+
+See the developer section of the manual for details about
+:ref:`writing plugins<TCG Plugins>`.
+
+Usage
+~~~~~
+
+Any QEMU binary with TCG support has plugins enabled by default.
+Earlier releases needed to be explicitly enabled with::
+
+ configure --enable-plugins
+
+Once built a program can be run with multiple plugins loaded each with
+their own arguments::
+
+ $QEMU $OTHER_QEMU_ARGS \
+ -plugin contrib/plugins/libhowvec.so,inline=on,count=hint \
+ -plugin contrib/plugins/libhotblocks.so
+
+Arguments are plugin specific and can be used to modify their
+behaviour. In this case the howvec plugin is being asked to use inline
+ops to count and break down the hint instructions by type.
+
+Linux user-mode emulation also evaluates the environment variable
+``QEMU_PLUGIN``::
+
+ QEMU_PLUGIN="file=contrib/plugins/libhowvec.so,inline=on,count=hint" $QEMU
+
+QEMU plugins avoid to write directly to stdin/stderr, and use the log provided
+by the API (see function ``qemu_plugin_outs``).
+To show output, you may use this additional parameter::
+
+ $QEMU $OTHER_QEMU_ARGS \
+ -d plugin \
+ -plugin contrib/plugins/libhowvec.so,inline=on,count=hint
+
+Example Plugins
+~~~~~~~~~~~~~~~
+
+There are a number of plugins included with QEMU and you are
+encouraged to contribute your own plugins plugins upstream. There is a
+``contrib/plugins`` directory where they can go. There are also some
+basic plugins that are used to test and exercise the API during the
+``make check-tcg`` target in ``tests/tcg/plugins`` that are never the
+less useful for basic analysis.
+
+Empty
+.....
+
+``tests/tcg/plugins/empty.c``
+
+Purely a test plugin for measuring the overhead of the plugins system
+itself. Does no instrumentation.
+
+Basic Blocks
+............
+
+``tests/tcg/plugins/bb.c``
+
+A very basic plugin which will measure execution in coarse terms as
+each basic block is executed. By default the results are shown once
+execution finishes::
+
+ $ qemu-aarch64 -plugin tests/plugin/libbb.so \
+ -d plugin ./tests/tcg/aarch64-linux-user/sha1
+ SHA1=15dd99a1991e0b3826fede3deffc1feba42278e6
+ bb's: 2277338, insns: 158483046
+
+Behaviour can be tweaked with the following arguments:
+
+.. list-table:: Basic Block plugin arguments
+ :widths: 20 80
+ :header-rows: 1
+
+ * - Option
+ - Description
+ * - inline=true|false
+ - Use faster inline addition of a single counter.
+ * - idle=true|false
+ - Dump the current execution stats whenever the guest vCPU idles
+
+Basic Block Vectors
+...................
+
+``contrib/plugins/bbv.c``
+
+The bbv plugin allows you to generate basic block vectors for use with the
+`SimPoint <https://cseweb.ucsd.edu/~calder/simpoint/>`__ analysis tool.
+
+.. list-table:: Basic block vectors arguments
+ :widths: 20 80
+ :header-rows: 1
+
+ * - Option
+ - Description
+ * - interval=N
+ - The interval to generate a basic block vector specified by the number of
+ instructions (Default: N = 100000000)
+ * - outfile=PATH
+ - The path to output files.
+ It will be suffixed with ``.N.bb`` where ``N`` is a vCPU index.
+
+Example::
+
+ $ qemu-aarch64 \
+ -plugin contrib/plugins/libbbv.so,interval=100,outfile=sha1 \
+ tests/tcg/aarch64-linux-user/sha1
+ SHA1=15dd99a1991e0b3826fede3deffc1feba42278e6
+ $ du sha1.0.bb
+ 23128 sha1.0.bb
+
+Instruction
+...........
+
+``tests/tcg/plugins/insn.c``
+
+This is a basic instruction level instrumentation which can count the
+number of instructions executed on each core/thread::
+
+ $ qemu-aarch64 -plugin tests/plugin/libinsn.so \
+ -d plugin ./tests/tcg/aarch64-linux-user/threadcount
+ Created 10 threads
+ Done
+ cpu 0 insns: 46765
+ cpu 1 insns: 3694
+ cpu 2 insns: 3694
+ cpu 3 insns: 2994
+ cpu 4 insns: 1497
+ cpu 5 insns: 1497
+ cpu 6 insns: 1497
+ cpu 7 insns: 1497
+ total insns: 63135
+
+Behaviour can be tweaked with the following arguments:
+
+.. list-table:: Instruction plugin arguments
+ :widths: 20 80
+ :header-rows: 1
+
+ * - Option
+ - Description
+ * - inline=true|false
+ - Use faster inline addition of a single counter.
+ * - sizes=true|false
+ - Give a summary of the instruction sizes for the execution
+ * - match=<string>
+ - Only instrument instructions matching the string prefix
+
+The ``match`` option will show some basic stats including how many
+instructions have executed since the last execution. For
+example::
+
+ $ qemu-aarch64 -plugin tests/plugin/libinsn.so,match=bl \
+ -d plugin ./tests/tcg/aarch64-linux-user/sha512-vector
+ ...
+ 0x40069c, 'bl #0x4002b0', 10 hits, 1093 match hits, Ī”+1257 since last match, 98 avg insns/match
+ 0x4006ac, 'bl #0x403690', 10 hits, 1094 match hits, Ī”+47 since last match, 98 avg insns/match
+ 0x4037fc, 'bl #0x4002b0', 18 hits, 1095 match hits, Ī”+22 since last match, 98 avg insns/match
+ 0x400720, 'bl #0x403690', 10 hits, 1096 match hits, Ī”+58 since last match, 98 avg insns/match
+ 0x4037fc, 'bl #0x4002b0', 19 hits, 1097 match hits, Ī”+22 since last match, 98 avg insns/match
+ 0x400730, 'bl #0x403690', 10 hits, 1098 match hits, Ī”+33 since last match, 98 avg insns/match
+ 0x4037ac, 'bl #0x4002b0', 12 hits, 1099 match hits, Ī”+20 since last match, 98 avg insns/match
+ ...
+
+For more detailed execution tracing see the ``execlog`` plugin for
+other options.
+
+Memory
+......
+
+``tests/tcg/plugins/mem.c``
+
+Basic instruction level memory instrumentation::
+
+ $ qemu-aarch64 -plugin tests/plugin/libmem.so,inline=true \
+ -d plugin ./tests/tcg/aarch64-linux-user/sha1
+ SHA1=15dd99a1991e0b3826fede3deffc1feba42278e6
+ inline mem accesses: 79525013
+
+Behaviour can be tweaked with the following arguments:
+
+.. list-table:: Memory plugin arguments
+ :widths: 20 80
+ :header-rows: 1
+
+ * - Option
+ - Description
+ * - inline=true|false
+ - Use faster inline addition of a single counter
+ * - callback=true|false
+ - Use callbacks on each memory instrumentation.
+ * - hwaddr=true|false
+ - Count IO accesses (only for system emulation)
+
+System Calls
+............
+
+``tests/tcg/plugins/syscall.c``
+
+A basic syscall tracing plugin. This only works for user-mode. By
+default it will give a summary of syscall stats at the end of the
+run::
+
+ $ qemu-aarch64 -plugin tests/plugin/libsyscall \
+ -d plugin ./tests/tcg/aarch64-linux-user/threadcount
+ Created 10 threads
+ Done
+ syscall no. calls errors
+ 226 12 0
+ 99 11 11
+ 115 11 0
+ 222 11 0
+ 93 10 0
+ 220 10 0
+ 233 10 0
+ 215 8 0
+ 214 4 0
+ 134 2 0
+ 64 2 0
+ 96 1 0
+ 94 1 0
+ 80 1 0
+ 261 1 0
+ 78 1 0
+ 160 1 0
+ 135 1 0
+
+Behaviour can be tweaked with the following arguments:
+
+.. list-table:: Syscall plugin arguments
+ :widths: 20 80
+ :header-rows: 1
+
+ * - Option
+ - Description
+ * - print=true|false
+ - Print the number of times each syscall is called
+ * - log_writes=true|false
+ - Log the buffer of each write syscall in hexdump format
+
+Test inline operations
+......................
+
+``tests/plugins/inline.c``
+
+This plugin is used for testing all inline operations, conditional callbacks and
+scoreboard. It prints a per-cpu summary of all events.
+
+
+Hot Blocks
+..........
+
+``contrib/plugins/hotblocks.c``
+
+The hotblocks plugin allows you to examine the where hot paths of
+execution are in your program. Once the program has finished you will
+get a sorted list of blocks reporting the starting PC, translation
+count, number of instructions and execution count. This will work best
+with linux-user execution as system emulation tends to generate
+re-translations as blocks from different programs get swapped in and
+out of system memory.
+
+Example::
+
+ $ qemu-aarch64 \
+ -plugin contrib/plugins/libhotblocks.so -d plugin \
+ ./tests/tcg/aarch64-linux-user/sha1
+ SHA1=15dd99a1991e0b3826fede3deffc1feba42278e6
+ collected 903 entries in the hash table
+ pc, tcount, icount, ecount
+ 0x0000000041ed10, 1, 5, 66087
+ 0x000000004002b0, 1, 4, 66087
+ ...
+
+
+Hot Pages
+.........
+
+``contrib/plugins/hotpages.c``
+
+Similar to hotblocks but this time tracks memory accesses::
+
+ $ qemu-aarch64 \
+ -plugin contrib/plugins/libhotpages.so -d plugin \
+ ./tests/tcg/aarch64-linux-user/sha1
+ SHA1=15dd99a1991e0b3826fede3deffc1feba42278e6
+ Addr, RCPUs, Reads, WCPUs, Writes
+ 0x000055007fe000, 0x0001, 31747952, 0x0001, 8835161
+ 0x000055007ff000, 0x0001, 29001054, 0x0001, 8780625
+ 0x00005500800000, 0x0001, 687465, 0x0001, 335857
+ 0x0000000048b000, 0x0001, 130594, 0x0001, 355
+ 0x0000000048a000, 0x0001, 1826, 0x0001, 11
+
+The hotpages plugin can be configured using the following arguments:
+
+.. list-table:: Hot pages arguments
+ :widths: 20 80
+ :header-rows: 1
+
+ * - Option
+ - Description
+ * - sortby=reads|writes|address
+ - Log the data sorted by either the number of reads, the number of writes, or
+ memory address. (Default: entries are sorted by the sum of reads and writes)
+ * - io=on
+ - Track IO addresses. Only relevant to full system emulation. (Default: off)
+ * - pagesize=N
+ - The page size used. (Default: N = 4096)
+
+Instruction Distribution
+........................
+
+``contrib/plugins/howvec.c``
+
+This is an instruction classifier so can be used to count different
+types of instructions. It has a number of options to refine which get
+counted. You can give a value to the ``count`` argument for a class of
+instructions to break it down fully, so for example to see all the system
+registers accesses::
+
+ $ qemu-system-aarch64 $(QEMU_ARGS) \
+ -append "root=/dev/sda2 systemd.unit=benchmark.service" \
+ -smp 4 -plugin ./contrib/plugins/libhowvec.so,count=sreg -d plugin
+
+which will lead to a sorted list after the class breakdown::
+
+ Instruction Classes:
+ Class: UDEF not counted
+ Class: SVE (68 hits)
+ Class: PCrel addr (47789483 hits)
+ Class: Add/Sub (imm) (192817388 hits)
+ Class: Logical (imm) (93852565 hits)
+ Class: Move Wide (imm) (76398116 hits)
+ Class: Bitfield (44706084 hits)
+ Class: Extract (5499257 hits)
+ Class: Cond Branch (imm) (147202932 hits)
+ Class: Exception Gen (193581 hits)
+ Class: NOP not counted
+ Class: Hints (6652291 hits)
+ Class: Barriers (8001661 hits)
+ Class: PSTATE (1801695 hits)
+ Class: System Insn (6385349 hits)
+ Class: System Reg counted individually
+ Class: Branch (reg) (69497127 hits)
+ Class: Branch (imm) (84393665 hits)
+ Class: Cmp & Branch (110929659 hits)
+ Class: Tst & Branch (44681442 hits)
+ Class: AdvSimd ldstmult (736 hits)
+ Class: ldst excl (9098783 hits)
+ Class: Load Reg (lit) (87189424 hits)
+ Class: ldst noalloc pair (3264433 hits)
+ Class: ldst pair (412526434 hits)
+ Class: ldst reg (imm) (314734576 hits)
+ Class: Loads & Stores (2117774 hits)
+ Class: Data Proc Reg (223519077 hits)
+ Class: Scalar FP (31657954 hits)
+ Individual Instructions:
+ Instr: mrs x0, sp_el0 (2682661 hits) (op=0xd5384100/ System Reg)
+ Instr: mrs x1, tpidr_el2 (1789339 hits) (op=0xd53cd041/ System Reg)
+ Instr: mrs x2, tpidr_el2 (1513494 hits) (op=0xd53cd042/ System Reg)
+ Instr: mrs x0, tpidr_el2 (1490823 hits) (op=0xd53cd040/ System Reg)
+ Instr: mrs x1, sp_el0 (933793 hits) (op=0xd5384101/ System Reg)
+ Instr: mrs x2, sp_el0 (699516 hits) (op=0xd5384102/ System Reg)
+ Instr: mrs x4, tpidr_el2 (528437 hits) (op=0xd53cd044/ System Reg)
+ Instr: mrs x30, ttbr1_el1 (480776 hits) (op=0xd538203e/ System Reg)
+ Instr: msr ttbr1_el1, x30 (480713 hits) (op=0xd518203e/ System Reg)
+ Instr: msr vbar_el1, x30 (480671 hits) (op=0xd518c01e/ System Reg)
+ ...
+
+To find the argument shorthand for the class you need to examine the
+source code of the plugin at the moment, specifically the ``*opt``
+argument in the InsnClassExecCount tables.
+
+Lockstep Execution
+..................
+
+``contrib/plugins/lockstep.c``
+
+This is a debugging tool for developers who want to find out when and
+where execution diverges after a subtle change to TCG code generation.
+It is not an exact science and results are likely to be mixed once
+asynchronous events are introduced. While the use of -icount can
+introduce determinism to the execution flow it doesn't always follow
+the translation sequence will be exactly the same. Typically this is
+caused by a timer firing to service the GUI causing a block to end
+early. However in some cases it has proved to be useful in pointing
+people at roughly where execution diverges. The only argument you need
+for the plugin is a path for the socket the two instances will
+communicate over::
+
+
+ $ qemu-system-sparc -monitor none -parallel none \
+ -net none -M SS-20 -m 256 -kernel day11/zImage.elf \
+ -plugin ./contrib/plugins/liblockstep.so,sockpath=lockstep-sparc.sock \
+ -d plugin,nochain
+
+which will eventually report::
+
+ qemu-system-sparc: warning: nic lance.0 has no peer
+ @ 0x000000ffd06678 vs 0x000000ffd001e0 (2/1 since last)
+ @ 0x000000ffd07d9c vs 0x000000ffd06678 (3/1 since last)
+ Ī” insn_count @ 0x000000ffd07d9c (809900609) vs 0x000000ffd06678 (809900612)
+ previously @ 0x000000ffd06678/10 (809900609 insns)
+ previously @ 0x000000ffd001e0/4 (809900599 insns)
+ previously @ 0x000000ffd080ac/2 (809900595 insns)
+ previously @ 0x000000ffd08098/5 (809900593 insns)
+ previously @ 0x000000ffd080c0/1 (809900588 insns)
+
+
+Hardware Profile
+................
+
+``contrib/plugins/hwprofile.c``
+
+The hwprofile tool can only be used with system emulation and allows
+the user to see what hardware is accessed how often. It has a number of options:
+
+.. list-table:: Hardware Profile arguments
+ :widths: 20 80
+ :header-rows: 1
+
+ * - Option
+ - Description
+ * - track=[read|write]
+ - By default the plugin tracks both reads and writes. You can use
+ this option to limit the tracking to just one class of accesses.
+ * - source
+ - Will include a detailed break down of what the guest PC that made the
+ access was. Not compatible with the pattern option. Example output::
+
+ cirrus-low-memory @ 0xfffffd00000a0000
+ pc:fffffc0000005cdc, 1, 256
+ pc:fffffc0000005ce8, 1, 256
+ pc:fffffc0000005cec, 1, 256
+
+ * - pattern
+ - Instead break down the accesses based on the offset into the HW
+ region. This can be useful for seeing the most used registers of
+ a device. Example output::
+
+ pci0-conf @ 0xfffffd01fe000000
+ off:00000004, 1, 1
+ off:00000010, 1, 3
+ off:00000014, 1, 3
+ off:00000018, 1, 2
+ off:0000001c, 1, 2
+ off:00000020, 1, 2
+ ...
+
+
+Execution Log
+.............
+
+``contrib/plugins/execlog.c``
+
+The execlog tool traces executed instructions with memory access. It can be used
+for debugging and security analysis purposes.
+Please be aware that this will generate a lot of output.
+
+The plugin needs default argument::
+
+ $ qemu-system-arm $(QEMU_ARGS) \
+ -plugin ./contrib/plugins/libexeclog.so -d plugin
+
+which will output an execution trace following this structure::
+
+ # vCPU, vAddr, opcode, disassembly[, load/store, memory addr, device]...
+ 0, 0xa12, 0xf8012400, "movs r4, #0"
+ 0, 0xa14, 0xf87f42b4, "cmp r4, r6"
+ 0, 0xa16, 0xd206, "bhs #0xa26"
+ 0, 0xa18, 0xfff94803, "ldr r0, [pc, #0xc]", load, 0x00010a28, RAM
+ 0, 0xa1a, 0xf989f000, "bl #0xd30"
+ 0, 0xd30, 0xfff9b510, "push {r4, lr}", store, 0x20003ee0, RAM, store, 0x20003ee4, RAM
+ 0, 0xd32, 0xf9893014, "adds r0, #0x14"
+ 0, 0xd34, 0xf9c8f000, "bl #0x10c8"
+ 0, 0x10c8, 0xfff96c43, "ldr r3, [r0, #0x44]", load, 0x200000e4, RAM
+
+Please note that you need to configure QEMU with Capstone support to get disassembly.
+
+The output can be filtered to only track certain instructions or
+addresses using the ``ifilter`` or ``afilter`` options. You can stack the
+arguments if required::
+
+ $ qemu-system-arm $(QEMU_ARGS) \
+ -plugin ./contrib/plugins/libexeclog.so,ifilter=st1w,afilter=0x40001808 -d plugin
+
+This plugin can also dump registers when they change value. Specify the name of the
+registers with multiple ``reg`` options. You can also use glob style matching if you wish::
+
+ $ qemu-system-arm $(QEMU_ARGS) \
+ -plugin ./contrib/plugins/libexeclog.so,reg=\*_el2,reg=sp -d plugin
+
+Be aware that each additional register to check will slow down
+execution quite considerably. You can optimise the number of register
+checks done by using the rdisas option. This will only instrument
+instructions that mention the registers in question in disassembly.
+This is not foolproof as some instructions implicitly change
+instructions. You can use the ifilter to catch these cases::
+
+ $ qemu-system-arm $(QEMU_ARGS) \
+ -plugin ./contrib/plugins/libexeclog.so,ifilter=msr,ifilter=blr,reg=x30,reg=\*_el1,rdisas=on
+
+Cache Modelling
+...............
+
+``contrib/plugins/cache.c``
+
+Cache modelling plugin that measures the performance of a given L1 cache
+configuration, and optionally a unified L2 per-core cache when a given working
+set is run::
+
+ $ qemu-x86_64 -plugin ./contrib/plugins/libcache.so \
+ -d plugin -D cache.log ./tests/tcg/x86_64-linux-user/float_convs
+
+will report the following::
+
+ core #, data accesses, data misses, dmiss rate, insn accesses, insn misses, imiss rate
+ 0 996695 508 0.0510% 2642799 18617 0.7044%
+
+ address, data misses, instruction
+ 0x424f1e (_int_malloc), 109, movq %rax, 8(%rcx)
+ 0x41f395 (_IO_default_xsputn), 49, movb %dl, (%rdi, %rax)
+ 0x42584d (ptmalloc_init.part.0), 33, movaps %xmm0, (%rax)
+ 0x454d48 (__tunables_init), 20, cmpb $0, (%r8)
+ ...
+
+ address, fetch misses, instruction
+ 0x4160a0 (__vfprintf_internal), 744, movl $1, %ebx
+ 0x41f0a0 (_IO_setb), 744, endbr64
+ 0x415882 (__vfprintf_internal), 744, movq %r12, %rdi
+ 0x4268a0 (__malloc), 696, andq $0xfffffffffffffff0, %rax
+ ...
+
+The plugin has a number of arguments, all of them are optional:
+
+.. list-table:: Cache modelling arguments
+ :widths: 20 80
+ :header-rows: 1
+
+ * - Option
+ - Description
+ * - limit=N
+ - Print top N icache and dcache thrashing instructions along with
+ their address, number of misses, and its disassembly. (default: 32)
+ * - icachesize=N
+ iblksize=B
+ iassoc=A
+ - Instruction cache configuration arguments. They specify the
+ cache size, block size, and associativity of the instruction
+ cache, respectively. (default: N = 16384, B = 64, A = 8)
+ * - dcachesize=N
+ - Data cache size (default: 16834)
+ * - dblksize=B
+ - Data cache block size (default: 64)
+ * - dassoc=A
+ - Data cache associativity (default: 8)
+ * - evict=POLICY
+ - Sets the eviction policy to POLICY. Available policies are:
+ ``lru``, ``fifo``, and ``rand``. The plugin will use
+ the specified policy for both instruction and data caches.
+ (default: POLICY = ``lru``)
+ * - cores=N
+ - Sets the number of cores for which we maintain separate icache
+ and dcache. (default: for linux-user, N = 1, for full system
+ emulation: N = cores available to guest)
+ * - l2=on
+ - Simulates a unified L2 cache (stores blocks for both
+ instructions and data) using the default L2 configuration (cache
+ size = 2MB, associativity = 16-way, block size = 64B).
+ * - l2cachesize=N
+ - L2 cache size (default: 2097152 (2MB)), implies ``l2=on``
+ * - l2blksize=B
+ - L2 cache block size (default: 64), implies ``l2=on``
+ * - l2assoc=A
+ - L2 cache associativity (default: 16), implies ``l2=on``
+
+Stop on Trigger
+...............
+
+``contrib/plugins/stoptrigger.c``
+
+The stoptrigger plugin allows to setup triggers to stop emulation.
+It can be used for research purposes to launch some code and precisely stop it
+and understand where its execution flow went.
+
+Two types of triggers can be configured: a count of instructions to stop at,
+or an address to stop at. Multiple triggers can be set at once.
+
+By default, QEMU will exit with return code 0. A custom return code can be
+configured for each trigger using ``:CODE`` syntax.
+
+For example, to stop at the 20-th instruction with return code 41, at address
+0xd4 with return code 0 or at address 0xd8 with return code 42::
+
+ $ qemu-system-aarch64 $(QEMU_ARGS) \
+ -plugin ./contrib/plugins/libstoptrigger.so,icount=20:41,addr=0xd4,addr=0xd8:42 -d plugin
+
+The plugin will log the reason of exit, for example::
+
+ 0xd4 reached, exiting
+
+Limit instructions per second
+.............................
+
+This plugin can limit the number of Instructions Per Second that are executed::
+
+ # get number of instructions
+ $ num_insn=$(./build/qemu-x86_64 -plugin ./build/tests/plugin/libinsn.so -d plugin /bin/true |& grep total | sed -e 's/.*: //')
+ # limit speed to execute in 10 seconds
+ $ time ./build/qemu-x86_64 -plugin ./build/contrib/plugins/libips.so,ips=$(($num_insn/10)) /bin/true
+ real 10.000s
+
+
+.. list-table:: IPS arguments
+ :widths: 20 80
+ :header-rows: 1
+
+ * - Option
+ - Description
+ * - ips=N
+ - Maximum number of instructions per cpu that can be executed in one second.
+ The plugin will sleep when the given number of instructions is reached.
+
+Other emulation features
+------------------------
+
+When running system emulation you can also enable deterministic
+execution which allows for repeatable record/replay debugging. See
+:ref:`Record/Replay<replay>` for more details.
diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst
index fc7b28e..912e0a1 100644
--- a/docs/about/removed-features.rst
+++ b/docs/about/removed-features.rst
@@ -517,6 +517,43 @@ The virtio-blk SCSI passthrough feature is a legacy VIRTIO feature. VIRTIO 1.0
and later do not support it because the virtio-scsi device was introduced for
full SCSI support. Use virtio-scsi instead when SCSI passthrough is required.
+``-fsdev proxy`` and ``-virtfs proxy`` (since 9.2)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The 9p ``proxy`` filesystem backend driver was originally developed to
+enhance security by dispatching low level filesystem operations from 9p
+server (QEMU process) over to a separate process (the virtfs-proxy-helper
+binary). However the proxy backend was much slower than the local backend,
+didn't see any development in years, and showed to be less secure,
+especially due to the fact that its helper daemon must be run as root.
+
+Use ``local``, possibly mapping permissions et al by using its 'mapped'
+security model option, or switch to ``virtiofs``. The virtiofs daemon
+``virtiofsd`` uses vhost to eliminate the high latency costs of the 9p
+``proxy`` backend.
+
+``-portrait`` and ``-rotate`` (since 9.2)
+'''''''''''''''''''''''''''''''''''''''''
+
+The ``-portrait`` and ``-rotate`` options were documented as only
+working with the PXA LCD device, and all the machine types using
+that display device were removed in 9.2, so these options also
+have been dropped.
+
+These options were intended to simulate a mobile device being
+rotated by the user, and had three effects:
+
+* the display output was rotated by 90, 180 or 270 degrees
+* the mouse/trackpad input was rotated the opposite way
+* the machine model would signal to the guest about its
+ orientation
+
+Of these three things, the input-rotation was coded without being
+restricted to boards which supported the full set of device-rotation
+handling, so in theory the options were usable on other machine models
+to produce an odd effect (rotating input but not display output). But
+this was never intended or documented behaviour, so we have dropped
+the options along with the machine models they were intended for.
User-mode emulator command line arguments
-----------------------------------------
@@ -850,6 +887,14 @@ The RISC-V no MMU cpus have been removed. The two CPUs: ``rv32imacu-nommu`` and
``rv64imacu-nommu`` can no longer be used. Instead the MMU status can be specified
via the CPU ``mmu`` option when using the ``rv32`` or ``rv64`` CPUs.
+RISC-V 'any' CPU type ``-cpu any`` (removed in 9.2)
+'''''''''''''''''''''''''''''''''''''''''''''''''''
+
+The 'any' CPU type was introduced back in 2018 and was around since the
+initial RISC-V QEMU port. Its usage was always been unclear: users don't know
+what to expect from a CPU called 'any', and in fact the CPU does not do anything
+special that isn't already done by the default CPUs rv32/rv64.
+
``compat`` property of server class POWER CPUs (removed in 6.0)
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
@@ -889,6 +934,13 @@ Nios II CPU (removed in 9.1)
QEMU Nios II architecture was orphan; Intel has EOL'ed the Nios II
processor IP (see `Intel discontinuance notification`_).
+CRIS CPU architecture (removed in 9.2)
+''''''''''''''''''''''''''''''''''''''
+
+The CRIS architecture was pulled from Linux in 4.17 and the compiler
+was no longer packaged in any distro making it harder to run the
+``check-tcg`` tests.
+
System accelerators
-------------------
@@ -978,6 +1030,25 @@ Nios II ``10m50-ghrd`` and ``nios2-generic-nommu`` machines (removed in 9.1)
The Nios II architecture was orphan.
+``shix`` (removed in 9.2)
+'''''''''''''''''''''''''
+
+The machine was unmaintained.
+
+Arm machines ``akita``, ``borzoi``, ``cheetah``, ``connex``, ``mainstone``, ``n800``, ``n810``, ``spitz``, ``terrier``, ``tosa``, ``verdex``, ``z2`` (removed in 9.2)
+'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+QEMU included models of some machine types where the QEMU code that
+emulates their SoCs was very old and unmaintained. This code was
+blocking our ability to move forward with various changes across
+the codebase, and over many years nobody has been interested in
+trying to modernise it. We don't expect any of these machines to have
+a large number of users, because they're all modelling hardware that
+has now passed away into history. We are therefore dropping support
+for all machine types using the PXA2xx and OMAP2 SoCs. We are also
+dropping the ``cheetah`` OMAP1 board, because we don't have any
+test images for it and don't know of anybody who does.
+
linux-user mode CPUs
--------------------
diff --git a/docs/conf.py b/docs/conf.py
index 876f676..c11a6ea 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -275,9 +275,6 @@ man_pages = [
('tools/qemu-trace-stap', 'qemu-trace-stap',
'QEMU SystemTap trace tool',
[], 1),
- ('tools/virtfs-proxy-helper', 'virtfs-proxy-helper',
- 'QEMU 9p virtfs proxy filesystem helper',
- ['M. Mohan Kumar'], 1),
]
man_make_section_directory = False
diff --git a/docs/devel/atomics.rst b/docs/devel/atomics.rst
index b77c6e1..95c7b77 100644
--- a/docs/devel/atomics.rst
+++ b/docs/devel/atomics.rst
@@ -204,7 +204,7 @@ They come in six kinds:
before the second with respect to the other components of the system.
Therefore, unlike ``smp_rmb()`` or ``qatomic_load_acquire()``,
``smp_read_barrier_depends()`` can be just a compiler barrier on
- weakly-ordered architectures such as Arm or PPC[#]_.
+ weakly-ordered architectures such as Arm or PPC\ [#alpha]_.
Note that the first load really has to have a _data_ dependency and not
a control dependency. If the address for the second load is dependent
@@ -212,7 +212,7 @@ They come in six kinds:
than actually loading the address itself, then it's a _control_
dependency and a full read barrier or better is required.
-.. [#] The DEC Alpha is an exception, because ``smp_read_barrier_depends()``
+.. [#alpha] The DEC Alpha is an exception, because ``smp_read_barrier_depends()``
needs a processor barrier. On strongly-ordered architectures such
as x86 or s390, ``smp_rmb()`` and ``qatomic_load_acquire()`` can
also be compiler barriers only.
@@ -295,7 +295,7 @@ Acquire/release pairing and the *synchronizes-with* relation
------------------------------------------------------------
Atomic operations other than ``qatomic_set()`` and ``qatomic_read()`` have
-either *acquire* or *release* semantics [#rmw]_. This has two effects:
+either *acquire* or *release* semantics\ [#rmw]_. This has two effects:
.. [#rmw] Read-modify-write operations can have both---acquire applies to the
read part, and release to the write.
diff --git a/docs/devel/blkdebug.txt b/docs/devel/blkdebug.txt
deleted file mode 100644
index 0b0c128..0000000
--- a/docs/devel/blkdebug.txt
+++ /dev/null
@@ -1,162 +0,0 @@
-Block I/O error injection using blkdebug
-----------------------------------------
-Copyright (C) 2014-2015 Red Hat Inc
-
-This work is licensed under the terms of the GNU GPL, version 2 or later. See
-the COPYING file in the top-level directory.
-
-The blkdebug block driver is a rule-based error injection engine. It can be
-used to exercise error code paths in block drivers including ENOSPC (out of
-space) and EIO.
-
-This document gives an overview of the features available in blkdebug.
-
-Background
-----------
-Block drivers have many error code paths that handle I/O errors. Image formats
-are especially complex since metadata I/O errors during cluster allocation or
-while updating tables happen halfway through request processing and require
-discipline to keep image files consistent.
-
-Error injection allows test cases to trigger I/O errors at specific points.
-This way, all error paths can be tested to make sure they are correct.
-
-Rules
------
-The blkdebug block driver takes a list of "rules" that tell the error injection
-engine when to fail an I/O request.
-
-Each I/O request is evaluated against the rules. If a rule matches the request
-then its "action" is executed.
-
-Rules can be placed in a configuration file; the configuration file
-follows the same .ini-like format used by QEMU's -readconfig option, and
-each section of the file represents a rule.
-
-The following configuration file defines a single rule:
-
- $ cat blkdebug.conf
- [inject-error]
- event = "read_aio"
- errno = "28"
-
-This rule fails all aio read requests with ENOSPC (28). Note that the errno
-value depends on the host. On Linux, see
-/usr/include/asm-generic/errno-base.h for errno values.
-
-Invoke QEMU as follows:
-
- $ qemu-system-x86_64
- -drive if=none,cache=none,file=blkdebug:blkdebug.conf:test.img,id=drive0 \
- -device virtio-blk-pci,drive=drive0,id=virtio-blk-pci0
-
-Rules support the following attributes:
-
- event - which type of operation to match (e.g. read_aio, write_aio,
- flush_to_os, flush_to_disk). See the "Events" section for
- information on events.
-
- state - (optional) the engine must be in this state number in order for this
- rule to match. See the "State transitions" section for information
- on states.
-
- errno - the numeric errno value to return when a request matches this rule.
- The errno values depend on the host since the numeric values are not
- standardized in the POSIX specification.
-
- sector - (optional) a sector number that the request must overlap in order to
- match this rule
-
- once - (optional, default "off") only execute this action on the first
- matching request
-
- immediately - (optional, default "off") return a NULL BlockAIOCB
- pointer and fail without an errno instead. This
- exercises the code path where BlockAIOCB fails and the
- caller's BlockCompletionFunc is not invoked.
-
-Events
-------
-Block drivers provide information about the type of I/O request they are about
-to make so rules can match specific types of requests. For example, the qcow2
-block driver tells blkdebug when it accesses the L1 table so rules can match
-only L1 table accesses and not other metadata or guest data requests.
-
-The core events are:
-
- read_aio - guest data read
-
- write_aio - guest data write
-
- flush_to_os - write out unwritten block driver state (e.g. cached metadata)
-
- flush_to_disk - flush the host block device's disk cache
-
-See qapi/block-core.json:BlkdebugEvent for the full list of events.
-You may need to grep block driver source code to understand the
-meaning of specific events.
-
-State transitions
------------------
-There are cases where more power is needed to match a particular I/O request in
-a longer sequence of requests. For example:
-
- write_aio
- flush_to_disk
- write_aio
-
-How do we match the 2nd write_aio but not the first? This is where state
-transitions come in.
-
-The error injection engine has an integer called the "state" that always starts
-initialized to 1. The state integer is internal to blkdebug and cannot be
-observed from outside but rules can interact with it for powerful matching
-behavior.
-
-Rules can be conditional on the current state and they can transition to a new
-state.
-
-When a rule's "state" attribute is non-zero then the current state must equal
-the attribute in order for the rule to match.
-
-For example, to match the 2nd write_aio:
-
- [set-state]
- event = "write_aio"
- state = "1"
- new_state = "2"
-
- [inject-error]
- event = "write_aio"
- state = "2"
- errno = "5"
-
-The first write_aio request matches the set-state rule and transitions from
-state 1 to state 2. Once state 2 has been entered, the set-state rule no
-longer matches since it requires state 1. But the inject-error rule now
-matches the next write_aio request and injects EIO (5).
-
-State transition rules support the following attributes:
-
- event - which type of operation to match (e.g. read_aio, write_aio,
- flush_to_os, flush_to_disk). See the "Events" section for
- information on events.
-
- state - (optional) the engine must be in this state number in order for this
- rule to match
-
- new_state - transition to this state number
-
-Suspend and resume
-------------------
-Exercising code paths in block drivers may require specific ordering amongst
-concurrent requests. The "breakpoint" feature allows requests to be halted on
-a blkdebug event and resumed later. This makes it possible to achieve
-deterministic ordering when multiple requests are in flight.
-
-Breakpoints on blkdebug events are associated with a user-defined "tag" string.
-This tag serves as an identifier by which the request can be resumed at a later
-point.
-
-See the qemu-io(1) break, resume, remove_break, and wait_break commands for
-details.
diff --git a/docs/devel/build-system.rst b/docs/devel/build-system.rst
index 79eceb1..d42045a 100644
--- a/docs/devel/build-system.rst
+++ b/docs/devel/build-system.rst
@@ -145,13 +145,13 @@ was installed in the ``site-packages`` directory of another interpreter,
or with the wrong ``pip`` program.
If a package is available for the chosen interpreter, ``configure``
-prepares a small script that invokes it from the venv itself[#distlib]_.
+prepares a small script that invokes it from the venv itself\ [#distlib]_.
If not, ``configure`` can also optionally install dependencies in the
virtual environment with ``pip``, either from wheels in ``python/wheels``
or by downloading the package with PyPI. Downloading can be disabled with
``--disable-download``; and anyway, it only happens when a ``configure``
option (currently, only ``--enable-docs``) is explicitly enabled but
-the dependencies are not present[#pip]_.
+the dependencies are not present\ [#pip]_.
.. [#distlib] The scripts are created based on the package's metadata,
specifically the ``console_script`` entry points. This is the
@@ -333,7 +333,7 @@ into each emulator:
``default-configs/targets/*.mak``
These files mostly define symbols that appear in the ``*-config-target.h``
- file for each emulator [#cfgtarget]_. However, the ``TARGET_ARCH``
+ file for each emulator\ [#cfgtarget]_. However, the ``TARGET_ARCH``
and ``TARGET_BASE_ARCH`` will also be used to select the ``hw/`` and
``target/`` subdirectories that are compiled into each target.
diff --git a/docs/devel/clocks.rst b/docs/devel/clocks.rst
index 177ee1c..3f744f2 100644
--- a/docs/devel/clocks.rst
+++ b/docs/devel/clocks.rst
@@ -358,6 +358,12 @@ humans (for instance in debugging), use ``clock_display_freq()``,
which returns a prettified string-representation, e.g. "33.3 MHz".
The caller must free the string with g_free() after use.
+It's also possible to retrieve the clock period from a QTest by
+accessing QOM property ``qtest-clock-period`` using a QMP command.
+This property is only present when the device is being run under
+the ``qtest`` accelerator; it is not available when QEMU is
+being run normally.
+
Calculating expiry deadlines
----------------------------
diff --git a/docs/devel/crypto.rst b/docs/devel/crypto.rst
new file mode 100644
index 0000000..39b1c91
--- /dev/null
+++ b/docs/devel/crypto.rst
@@ -0,0 +1,10 @@
+.. _crypto-ref:
+
+====================
+Cryptography in QEMU
+====================
+
+.. toctree::
+ :maxdepth: 2
+
+ luks-detached-header
diff --git a/docs/devel/index-api.rst b/docs/devel/index-api.rst
index fe01b2b..1c487c1 100644
--- a/docs/devel/index-api.rst
+++ b/docs/devel/index-api.rst
@@ -9,6 +9,7 @@ generated from in-code annotations to function prototypes.
bitops
loads-stores
+ lockcnt
memory
modules
pci
diff --git a/docs/devel/index-build.rst b/docs/devel/index-build.rst
index 90b406c..0023953 100644
--- a/docs/devel/index-build.rst
+++ b/docs/devel/index-build.rst
@@ -1,9 +1,8 @@
-QEMU Build and Test System
---------------------------
+QEMU Build System
+-----------------
-Details about how QEMU's build system works and how it is integrated
-into our testing infrastructure. You will need to understand some of
-the basics if you are adding new files and targets to the build.
+Details about how QEMU's build system works. You will need to understand
+some of the basics if you are adding new files and targets to the build.
.. toctree::
:maxdepth: 3
@@ -11,10 +10,5 @@ the basics if you are adding new files and targets to the build.
build-system
kconfig
docs
- testing
- acpi-bits
- qtest
- ci
qapi-code-gen
- fuzzing
control-flow-integrity
diff --git a/docs/devel/index-internals.rst b/docs/devel/index-internals.rst
index 5636e9c..ab9fbc4 100644
--- a/docs/devel/index-internals.rst
+++ b/docs/devel/index-internals.rst
@@ -8,6 +8,7 @@ Details about QEMU's various subsystems including how to add features to them.
qom
atomics
+ rcu
block-coroutine-wrapper
clocks
ebpf_rss
@@ -20,3 +21,5 @@ Details about QEMU's various subsystems including how to add features to them.
vfio-iommufd
writing-monitor-commands
virtio-backends
+ crypto
+ multiple-iothreads
diff --git a/docs/devel/index.rst b/docs/devel/index.rst
index abf6045..a53f1bf 100644
--- a/docs/devel/index.rst
+++ b/docs/devel/index.rst
@@ -31,6 +31,7 @@ the :ref:`tcg_internals`.
index-process
index-build
+ testing/index
index-api
index-internals
index-tcg
diff --git a/docs/devel/loads-stores.rst b/docs/devel/loads-stores.rst
index ec627aa..9471bac 100644
--- a/docs/devel/loads-stores.rst
+++ b/docs/devel/loads-stores.rst
@@ -95,7 +95,7 @@ guest CPU state in case of a guest CPU exception. This is passed
to ``cpu_restore_state()``. Therefore the value should either be 0,
to indicate that the guest CPU state is already synchronized, or
the result of ``GETPC()`` from the top level ``HELPER(foo)``
-function, which is a return address into the generated code [#gpc]_.
+function, which is a return address into the generated code\ [#gpc]_.
.. [#gpc] Note that ``GETPC()`` should be used with great care: calling
it in other functions that are *not* the top level
diff --git a/docs/devel/lockcnt.txt b/docs/devel/lockcnt.rst
index a3fb3bc..8b43578 100644
--- a/docs/devel/lockcnt.txt
+++ b/docs/devel/lockcnt.rst
@@ -1,9 +1,9 @@
-DOCUMENTATION FOR LOCKED COUNTERS (aka QemuLockCnt)
-===================================================
+Locked Counters (aka ``QemuLockCnt``)
+=====================================
QEMU often uses reference counts to track data structures that are being
accessed and should not be freed. For example, a loop that invoke
-callbacks like this is not safe:
+callbacks like this is not safe::
QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) {
if (ioh->revents & G_IO_OUT) {
@@ -11,11 +11,11 @@ callbacks like this is not safe:
}
}
-QLIST_FOREACH_SAFE protects against deletion of the current node (ioh)
-by stashing away its "next" pointer. However, ioh->fd_write could
+``QLIST_FOREACH_SAFE`` protects against deletion of the current node (``ioh``)
+by stashing away its ``next`` pointer. However, ``ioh->fd_write`` could
actually delete the next node from the list. The simplest way to
avoid this is to mark the node as deleted, and remove it from the
-list in the above loop:
+list in the above loop::
QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) {
if (ioh->deleted) {
@@ -29,7 +29,7 @@ list in the above loop:
}
If however this loop must also be reentrant, i.e. it is possible that
-ioh->fd_write invokes the loop again, some kind of counting is needed:
+``ioh->fd_write`` invokes the loop again, some kind of counting is needed::
walking_handlers++;
QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) {
@@ -46,8 +46,8 @@ ioh->fd_write invokes the loop again, some kind of counting is needed:
}
walking_handlers--;
-One may think of using the RCU primitives, rcu_read_lock() and
-rcu_read_unlock(); effectively, the RCU nesting count would take
+One may think of using the RCU primitives, ``rcu_read_lock()`` and
+``rcu_read_unlock()``; effectively, the RCU nesting count would take
the place of the walking_handlers global variable. Indeed,
reference counting and RCU have similar purposes, but their usage in
general is complementary:
@@ -70,14 +70,14 @@ general is complementary:
this can improve performance, but also delay reclamation undesirably.
With reference counting, reclamation is deterministic.
-This file documents QemuLockCnt, an abstraction for using reference
+This file documents ``QemuLockCnt``, an abstraction for using reference
counting in code that has to be both thread-safe and reentrant.
-QemuLockCnt concepts
---------------------
+``QemuLockCnt`` concepts
+------------------------
-A QemuLockCnt comprises both a counter and a mutex; it has primitives
+A ``QemuLockCnt`` comprises both a counter and a mutex; it has primitives
to increment and decrement the counter, and to take and release the
mutex. The counter notes how many visits to the data structures are
taking place (the visits could be from different threads, or there could
@@ -95,13 +95,14 @@ not just frees, though there could be cases where this is not necessary.
Reads, instead, can be done without taking the mutex, as long as the
readers and writers use the same macros that are used for RCU, for
-example qatomic_rcu_read, qatomic_rcu_set, QLIST_FOREACH_RCU, etc. This is
-because the reads are done outside a lock and a set or QLIST_INSERT_HEAD
+example ``qatomic_rcu_read``, ``qatomic_rcu_set``, ``QLIST_FOREACH_RCU``,
+etc. This is because the reads are done outside a lock and a set
+or ``QLIST_INSERT_HEAD``
can happen concurrently with the read. The RCU API ensures that the
processor and the compiler see all required memory barriers.
This could be implemented simply by protecting the counter with the
-mutex, for example:
+mutex, for example::
// (1)
qemu_mutex_lock(&walking_handlers_mutex);
@@ -125,33 +126,33 @@ mutex, for example:
Here, no frees can happen in the code represented by the ellipsis.
If another thread is executing critical section (2), that part of
the code cannot be entered, because the thread will not be able
-to increment the walking_handlers variable. And of course
+to increment the ``walking_handlers`` variable. And of course
during the visit any other thread will see a nonzero value for
-walking_handlers, as in the single-threaded code.
+``walking_handlers``, as in the single-threaded code.
Note that it is possible for multiple concurrent accesses to delay
-the cleanup arbitrarily; in other words, for the walking_handlers
+the cleanup arbitrarily; in other words, for the ``walking_handlers``
counter to never become zero. For this reason, this technique is
more easily applicable if concurrent access to the structure is rare.
However, critical sections are easy to forget since you have to do
-them for each modification of the counter. QemuLockCnt ensures that
+them for each modification of the counter. ``QemuLockCnt`` ensures that
all modifications of the counter take the lock appropriately, and it
can also be more efficient in two ways:
- it avoids taking the lock for many operations (for example
incrementing the counter while it is non-zero);
-- on some platforms, one can implement QemuLockCnt to hold the lock
+- on some platforms, one can implement ``QemuLockCnt`` to hold the lock
and the mutex in a single word, making the fast path no more expensive
than simply managing a counter using atomic operations (see
- docs/devel/atomics.rst). This can be very helpful if concurrent access to
+ :doc:`atomics`). This can be very helpful if concurrent access to
the data structure is expected to be rare.
Using the same mutex for frees and writes can still incur some small
inefficiencies; for example, a visit can never start if the counter is
-zero and the mutex is taken---even if the mutex is taken by a write,
+zero and the mutex is taken -- even if the mutex is taken by a write,
which in principle need not block a visit of the data structure.
However, these are usually not a problem if any of the following
assumptions are valid:
@@ -163,27 +164,27 @@ assumptions are valid:
- writes are frequent, but this kind of write (e.g. appending to a
list) has a very small critical section.
-For example, QEMU uses QemuLockCnt to manage an AioContext's list of
+For example, QEMU uses ``QemuLockCnt`` to manage an ``AioContext``'s list of
bottom halves and file descriptor handlers. Modifications to the list
of file descriptor handlers are rare. Creation of a new bottom half is
frequent and can happen on a fast path; however: 1) it is almost never
concurrent with a visit to the list of bottom halves; 2) it only has
-three instructions in the critical path, two assignments and a smp_wmb().
+three instructions in the critical path, two assignments and a ``smp_wmb()``.
-QemuLockCnt API
----------------
+``QemuLockCnt`` API
+-------------------
-The QemuLockCnt API is described in include/qemu/thread.h.
+.. kernel-doc:: include/qemu/lockcnt.h
-QemuLockCnt usage
------------------
+``QemuLockCnt`` usage
+---------------------
-This section explains the typical usage patterns for QemuLockCnt functions.
+This section explains the typical usage patterns for ``QemuLockCnt`` functions.
Setting a variable to a non-NULL value can be done between
-qemu_lockcnt_lock and qemu_lockcnt_unlock:
+``qemu_lockcnt_lock`` and ``qemu_lockcnt_unlock``::
qemu_lockcnt_lock(&xyz_lockcnt);
if (!xyz) {
@@ -193,8 +194,8 @@ qemu_lockcnt_lock and qemu_lockcnt_unlock:
}
qemu_lockcnt_unlock(&xyz_lockcnt);
-Accessing the value can be done between qemu_lockcnt_inc and
-qemu_lockcnt_dec:
+Accessing the value can be done between ``qemu_lockcnt_inc`` and
+``qemu_lockcnt_dec``::
qemu_lockcnt_inc(&xyz_lockcnt);
if (xyz) {
@@ -204,11 +205,11 @@ qemu_lockcnt_dec:
}
qemu_lockcnt_dec(&xyz_lockcnt);
-Freeing the object can similarly use qemu_lockcnt_lock and
-qemu_lockcnt_unlock, but you also need to ensure that the count
-is zero (i.e. there is no concurrent visit). Because qemu_lockcnt_inc
-takes the QemuLockCnt's lock, the count cannot become non-zero while
-the object is being freed. Freeing an object looks like this:
+Freeing the object can similarly use ``qemu_lockcnt_lock`` and
+``qemu_lockcnt_unlock``, but you also need to ensure that the count
+is zero (i.e. there is no concurrent visit). Because ``qemu_lockcnt_inc``
+takes the ``QemuLockCnt``'s lock, the count cannot become non-zero while
+the object is being freed. Freeing an object looks like this::
qemu_lockcnt_lock(&xyz_lockcnt);
if (!qemu_lockcnt_count(&xyz_lockcnt)) {
@@ -218,7 +219,7 @@ the object is being freed. Freeing an object looks like this:
qemu_lockcnt_unlock(&xyz_lockcnt);
If an object has to be freed right after a visit, you can combine
-the decrement, the locking and the check on count as follows:
+the decrement, the locking and the check on count as follows::
qemu_lockcnt_inc(&xyz_lockcnt);
if (xyz) {
@@ -232,7 +233,7 @@ the decrement, the locking and the check on count as follows:
qemu_lockcnt_unlock(&xyz_lockcnt);
}
-QemuLockCnt can also be used to access a list as follows:
+``QemuLockCnt`` can also be used to access a list as follows::
qemu_lockcnt_inc(&io_handlers_lockcnt);
QLIST_FOREACH_RCU(ioh, &io_handlers, pioh) {
@@ -252,10 +253,10 @@ QemuLockCnt can also be used to access a list as follows:
}
Again, the RCU primitives are used because new items can be added to the
-list during the walk. QLIST_FOREACH_RCU ensures that the processor and
+list during the walk. ``QLIST_FOREACH_RCU`` ensures that the processor and
the compiler see the appropriate memory barriers.
-An alternative pattern uses qemu_lockcnt_dec_if_lock:
+An alternative pattern uses ``qemu_lockcnt_dec_if_lock``::
qemu_lockcnt_inc(&io_handlers_lockcnt);
QLIST_FOREACH_SAFE_RCU(ioh, &io_handlers, next, pioh) {
@@ -273,5 +274,5 @@ An alternative pattern uses qemu_lockcnt_dec_if_lock:
}
qemu_lockcnt_dec(&io_handlers_lockcnt);
-Here you can use qemu_lockcnt_dec instead of qemu_lockcnt_dec_and_lock,
+Here you can use ``qemu_lockcnt_dec`` instead of ``qemu_lockcnt_dec_and_lock``,
because there is no special task to do if the count goes from 1 to 0.
diff --git a/docs/devel/luks-detached-header.rst b/docs/devel/luks-detached-header.rst
new file mode 100644
index 0000000..94ec285
--- /dev/null
+++ b/docs/devel/luks-detached-header.rst
@@ -0,0 +1,182 @@
+================================
+LUKS volume with detached header
+================================
+
+Introduction
+============
+
+This document gives an overview of the design of LUKS volume with detached
+header and how to use it.
+
+Background
+==========
+
+The LUKS format has ability to store the header in a separate volume from
+the payload. We could extend the LUKS driver in QEMU to support this use
+case.
+
+Normally a LUKS volume has a layout:
+
+::
+
+ +-----------------------------------------------+
+ | | | |
+ disk | header | key material | disk payload data |
+ | | | |
+ +-----------------------------------------------+
+
+With a detached LUKS header, you need 2 disks so getting:
+
+::
+
+ +--------------------------+
+ disk1 | header | key material |
+ +--------------------------+
+ +---------------------+
+ disk2 | disk payload data |
+ +---------------------+
+
+There are a variety of benefits to doing this:
+
+ * Secrecy - the disk2 cannot be identified as containing LUKS
+ volume since there's no header
+ * Control - if access to the disk1 is restricted, then even
+ if someone has access to disk2 they can't unlock
+ it. Might be useful if you have disks on NFS but
+ want to restrict which host can launch a VM
+ instance from it, by dynamically providing access
+ to the header to a designated host
+ * Flexibility - your application data volume may be a given
+ size and it is inconvenient to resize it to
+ add encryption.You can store the LUKS header
+ separately and use the existing storage
+ volume for payload
+ * Recovery - corruption of a bit in the header may make the
+ entire payload inaccessible. It might be
+ convenient to take backups of the header. If
+ your primary disk header becomes corrupt, you
+ can unlock the data still by pointing to the
+ backup detached header
+
+Architecture
+============
+
+Take the qcow2 encryption, for example. The architecture of the
+LUKS volume with detached header is shown in the diagram below.
+
+There are two children of the root node: a file and a header.
+Data from the disk payload is stored in the file node. The
+LUKS header and key material are located in the header node,
+as previously mentioned.
+
+::
+
+ +-----------------------------+
+ Root node | foo[luks] |
+ +-----------------------------+
+ | |
+ file | header |
+ | |
+ +---------------------+ +------------------+
+ Child node |payload-format[qcow2]| |header-format[raw]|
+ +---------------------+ +------------------+
+ | |
+ file | file |
+ | |
+ +----------------------+ +---------------------+
+ Child node |payload-protocol[file]| |header-protocol[file]|
+ +----------------------+ +---------------------+
+ | |
+ | |
+ | |
+ Host storage Host storage
+
+Usage
+=====
+
+Create a LUKS disk with a detached header using qemu-img
+--------------------------------------------------------
+
+Shell commandline::
+
+ # qemu-img create --object secret,id=sec0,data=abc123 -f luks \
+ -o cipher-alg=aes-256,cipher-mode=xts -o key-secret=sec0 \
+ -o detached-header=true test-header.img
+ # qemu-img create -f qcow2 test-payload.qcow2 200G
+ # qemu-img info 'json:{"driver":"luks","file":{"filename": \
+ "test-payload.img"},"header":{"filename":"test-header.img"}}'
+
+Set up a VM's LUKS volume with a detached header
+------------------------------------------------
+
+Qemu commandline::
+
+ # qemu-system-x86_64 ... \
+ -object '{"qom-type":"secret","id":"libvirt-3-format-secret", \
+ "data":"abc123"}' \
+ -blockdev '{"driver":"file","filename":"/path/to/test-header.img", \
+ "node-name":"libvirt-1-storage"}' \
+ -blockdev '{"node-name":"libvirt-1-format","read-only":false, \
+ "driver":"raw","file":"libvirt-1-storage"}' \
+ -blockdev '{"driver":"file","filename":"/path/to/test-payload.qcow2", \
+ "node-name":"libvirt-2-storage"}' \
+ -blockdev '{"node-name":"libvirt-2-format","read-only":false, \
+ "driver":"qcow2","file":"libvirt-2-storage"}' \
+ -blockdev '{"node-name":"libvirt-3-format","driver":"luks", \
+ "file":"libvirt-2-format","header":"libvirt-1-format","key-secret": \
+ "libvirt-3-format-secret"}' \
+ -device '{"driver":"virtio-blk-pci","bus":XXX,"addr":YYY,"drive": \
+ "libvirt-3-format","id":"virtio-disk1"}'
+
+Add LUKS volume to a VM with a detached header
+----------------------------------------------
+
+1. object-add the secret for decrypting the cipher stored in
+ LUKS header above::
+
+ # virsh qemu-monitor-command vm '{"execute":"object-add", \
+ "arguments":{"qom-type":"secret", "id": \
+ "libvirt-4-format-secret", "data":"abc123"}}'
+
+2. block-add the protocol node for LUKS header::
+
+ # virsh qemu-monitor-command vm '{"execute":"blockdev-add", \
+ "arguments":{"node-name":"libvirt-1-storage", "driver":"file", \
+ "filename": "/path/to/test-header.img" }}'
+
+3. block-add the raw-drived node for LUKS header::
+
+ # virsh qemu-monitor-command vm '{"execute":"blockdev-add", \
+ "arguments":{"node-name":"libvirt-1-format", "driver":"raw", \
+ "file":"libvirt-1-storage"}}'
+
+4. block-add the protocol node for disk payload image::
+
+ # virsh qemu-monitor-command vm '{"execute":"blockdev-add", \
+ "arguments":{"node-name":"libvirt-2-storage", "driver":"file", \
+ "filename":"/path/to/test-payload.qcow2"}}'
+
+5. block-add the qcow2-drived format node for disk payload data::
+
+ # virsh qemu-monitor-command vm '{"execute":"blockdev-add", \
+ "arguments":{"node-name":"libvirt-2-format", "driver":"qcow2", \
+ "file":"libvirt-2-storage"}}'
+
+6. block-add the luks-drived format node to link the qcow2 disk
+ with the LUKS header by specifying the field "header"::
+
+ # virsh qemu-monitor-command vm '{"execute":"blockdev-add", \
+ "arguments":{"node-name":"libvirt-3-format", "driver":"luks", \
+ "file":"libvirt-2-format", "header":"libvirt-1-format", \
+ "key-secret":"libvirt-2-format-secret"}}'
+
+7. hot-plug the virtio-blk device finally::
+
+ # virsh qemu-monitor-command vm '{"execute":"device_add", \
+ "arguments": {"driver":"virtio-blk-pci", \
+ "drive": "libvirt-3-format", "id":"virtio-disk2"}}
+
+TODO
+====
+
+1. Support the shared detached LUKS header within the VM.
diff --git a/docs/devel/maintainers.rst b/docs/devel/maintainers.rst
index 5c907d9..88a613e 100644
--- a/docs/devel/maintainers.rst
+++ b/docs/devel/maintainers.rst
@@ -99,9 +99,9 @@ members of the QEMU community, you should make arrangements to attend
a `KeySigningParty <https://wiki.qemu.org/KeySigningParty>`__ (for
example at KVM Forum) or make alternative arrangements to have your
key signed by an attendee. Key signing requires meeting another
-community member **in person** [#]_ so please make appropriate
+community member **in person**\ [#2020]_ so please make appropriate
arrangements.
-.. [#] In recent pandemic times we have had to exercise some
+.. [#2020] In recent pandemic times we have had to exercise some
flexibility here. Maintainers still need to sign their pull
requests though.
diff --git a/docs/devel/migration/features.rst b/docs/devel/migration/features.rst
index 58f8fd9..8f431d5 100644
--- a/docs/devel/migration/features.rst
+++ b/docs/devel/migration/features.rst
@@ -14,3 +14,4 @@ Migration has plenty of features to support different use cases.
CPR
qpl-compression
uadk-compression
+ qatzip-compression
diff --git a/docs/devel/migration/main.rst b/docs/devel/migration/main.rst
index 784c899..c2857fc 100644
--- a/docs/devel/migration/main.rst
+++ b/docs/devel/migration/main.rst
@@ -465,6 +465,12 @@ Examples of such API functions are:
- portio_list_set_address()
- portio_list_set_enabled()
+Since the order of device save/restore is not defined, you must
+avoid accessing or changing any other device's state in one of these
+callbacks. (For instance, don't do anything that calls ``update_irq()``
+in a ``post_load`` hook.) Otherwise, restore will not be deterministic,
+and this will break execution record/replay.
+
Iterative device migration
--------------------------
diff --git a/docs/devel/migration/mapped-ram.rst b/docs/devel/migration/mapped-ram.rst
index d352b54..b08c2b4 100644
--- a/docs/devel/migration/mapped-ram.rst
+++ b/docs/devel/migration/mapped-ram.rst
@@ -44,7 +44,7 @@ Use-cases
The mapped-ram feature was designed for use cases where the migration
stream will be directed to a file in the filesystem and not
-immediately restored on the destination VM [#]_. These could be
+immediately restored on the destination VM\ [#alternatives]_. These could be
thought of as snapshots. We can further categorize them into live and
non-live.
@@ -70,7 +70,7 @@ mapped-ram in this scenario is portability since background-snapshot
depends on async dirty tracking (KVM_GET_DIRTY_LOG) which is not
supported outside of Linux.
-.. [#] While this same effect could be obtained with the usage of
+.. [#alternatives] While this same effect could be obtained with the usage of
snapshots or the ``file:`` migration alone, mapped-ram provides
a performance increase for VMs with larger RAM sizes (10s to
100s of GiBs), specially if the VM has been stopped beforehand.
diff --git a/docs/devel/migration/qatzip-compression.rst b/docs/devel/migration/qatzip-compression.rst
new file mode 100644
index 0000000..862b383
--- /dev/null
+++ b/docs/devel/migration/qatzip-compression.rst
@@ -0,0 +1,165 @@
+==================
+QATzip Compression
+==================
+In scenarios with limited network bandwidth, the ``QATzip`` solution can help
+users save a lot of host CPU resources by accelerating compression and
+decompression through the Intel QuickAssist Technology(``QAT``) hardware.
+
+
+The following test was conducted using 8 multifd channels and 10Gbps network
+bandwidth. The results show that, compared to zstd, ``QATzip`` significantly
+saves CPU resources on the sender and reduces migration time. Compared to the
+uncompressed solution, ``QATzip`` greatly improves the dirty page processing
+capability, indicated by the Pages per Second metric, and also reduces the
+total migration time.
+
+::
+
+ VM Configuration: 16 vCPU and 64G memory
+ VM Workload: all vCPUs are idle and 54G memory is filled with Silesia data.
+ QAT Devices: 4
+ |-----------|--------|---------|----------|----------|------|------|
+ |8 Channels |Total |down |throughput|pages per | send | recv |
+ | |time(ms)|time(ms) |(mbps) |second | cpu %| cpu% |
+ |-----------|--------|---------|----------|----------|------|------|
+ |qatzip | 16630| 28| 10467| 2940235| 160| 360|
+ |-----------|--------|---------|----------|----------|------|------|
+ |zstd | 20165| 24| 8579| 2391465| 810| 340|
+ |-----------|--------|---------|----------|----------|------|------|
+ |none | 46063| 40| 10848| 330240| 45| 85|
+ |-----------|--------|---------|----------|----------|------|------|
+
+
+QATzip Compression Framework
+============================
+
+``QATzip`` is a user space library which builds on top of the Intel QuickAssist
+Technology to provide extended accelerated compression and decompression
+services.
+
+For more ``QATzip`` introduction, please refer to `QATzip Introduction
+<https://github.com/intel/QATzip?tab=readme-ov-file#introductionl>`_
+
+::
+
+ +----------------+
+ | MultiFd Thread |
+ +-------+--------+
+ |
+ | compress/decompress
+ +-------+--------+
+ | QATzip library |
+ +-------+--------+
+ |
+ +-------+--------+
+ | QAT library |
+ +-------+--------+
+ | user space
+ --------+---------------------
+ | kernel space
+ +------+-------+
+ | QAT Driver |
+ +------+-------+
+ |
+ +------+-------+
+ | QAT Devices |
+ +--------------+
+
+
+QATzip Installation
+-------------------
+
+The ``QATzip`` installation package has been integrated into some Linux
+distributions and can be installed directly. For example, the Ubuntu Server
+24.04 LTS system can be installed using below command
+
+.. code-block:: shell
+
+ #apt search qatzip
+ libqatzip-dev/noble 1.2.0-0ubuntu3 amd64
+ Intel QuickAssist user space library development files
+
+ libqatzip3/noble 1.2.0-0ubuntu3 amd64
+ Intel QuickAssist user space library
+
+ qatzip/noble,now 1.2.0-0ubuntu3 amd64 [installed]
+ Compression user-space tool for Intel QuickAssist Technology
+
+ #sudo apt install libqatzip-dev libqatzip3 qatzip
+
+If your system does not support the ``QATzip`` installation package, you can
+use the source code to build and install, please refer to `QATzip source code installation
+<https://github.com/intel/QATzip?tab=readme-ov-file#build-intel-quickassist-technology-driver>`_
+
+QAT Hardware Deployment
+-----------------------
+
+``QAT`` supports physical functions(PFs) and virtual functions(VFs) for
+deployment, and users can configure ``QAT`` resources for migration according
+to actual needs. For more details about ``QAT`` deployment, please refer to
+`Intel QuickAssist Technology Documentation
+<https://intel.github.io/quickassist/index.html>`_
+
+For more ``QAT`` hardware introduction, please refer to `intel-quick-assist-technology-overview
+<https://www.intel.com/content/www/us/en/architecture-and-technology/intel-quick-assist-technology-overview.html>`_
+
+How To Use QATzip Compression
+=============================
+
+1 - Install ``QATzip`` library
+
+2 - Build ``QEMU`` with ``--enable-qatzip`` parameter
+
+ E.g. configure --target-list=x86_64-softmmu --enable-kvm ``--enable-qatzip``
+
+3 - Set ``migrate_set_parameter multifd-compression qatzip``
+
+4 - Set ``migrate_set_parameter multifd-qatzip-level comp_level``, the default
+comp_level value is 1, and it supports levels from 1 to 9
+
+QAT Memory Requirements
+=======================
+
+The user needs to reserve system memory for the QAT memory management to
+allocate DMA memory. The size of the reserved system memory depends on the
+number of devices used for migration and the number of multifd channels.
+
+Because memory usage depends on QAT configuration, please refer to `QAT Memory
+Driver Queries
+<https://intel.github.io/quickassist/PG/infrastructure_debugability.html?highlight=memory>`_
+for memory usage calculation.
+
+.. list-table:: An example of a PF used for migration
+ :header-rows: 1
+
+ * - Number of channels
+ - Sender memory usage
+ - Receiver memory usage
+ * - 2
+ - 10M
+ - 10M
+ * - 4
+ - 12M
+ - 14M
+ * - 8
+ - 16M
+ - 20M
+
+How To Choose Between QATzip and QPL
+====================================
+Starting from 4th Gen Intel Xeon Scalable processors, codenamed Sapphire Rapids
+processor(``SPR``), multiple built-in accelerators are supported including
+``QAT`` and ``IAA``. The former can accelerate ``QATzip`` and the latter is
+used to accelerate ``QPL``.
+
+Here are some suggestions:
+
+1 - If the live migration scenario is limited by network bandwidth and ``QAT``
+hardware resources exceed ``IAA``, use the ``QATzip`` method, which can save a
+lot of host CPU resources for compression.
+
+2 - If the system cannot support shared virtual memory (SVM) technology, use
+the ``QATzip`` method because ``QPL`` performance is not good without SVM
+support.
+
+3 - For other scenarios, use the ``QPL`` method first.
diff --git a/docs/devel/migration/uadk-compression.rst b/docs/devel/migration/uadk-compression.rst
index 3f73345..64cadeb 100644
--- a/docs/devel/migration/uadk-compression.rst
+++ b/docs/devel/migration/uadk-compression.rst
@@ -114,7 +114,7 @@ Make sure all these above kernel configurations are selected.
Accelerator dev node permissions
--------------------------------
-Harware accelerators(eg: HiSilicon Kunpeng Zip accelerator) gets registered to
+Hardware accelerators (eg: HiSilicon Kunpeng Zip accelerator) gets registered to
UADK and char devices are created in dev directory. In order to access resources
on hardware accelerator devices, write permission should be provided to user.
@@ -134,7 +134,7 @@ How To Use UADK Compression In QEMU Migration
Set ``migrate_set_parameter multifd-compression uadk``
Since UADK uses Shared Virtual Addressing(SVA) and device access virtual memory
-directly it is possible that SMMUv3 may enounter page faults while walking the
+directly it is possible that SMMUv3 may encounter page faults while walking the
IO page tables. This may impact the performance. In order to mitigate this,
please make sure to specify ``-mem-prealloc`` parameter to the destination VM
boot parameters.
diff --git a/docs/devel/multiple-iothreads.rst b/docs/devel/multiple-iothreads.rst
new file mode 100644
index 0000000..d1f3fc4
--- /dev/null
+++ b/docs/devel/multiple-iothreads.rst
@@ -0,0 +1,139 @@
+Using Multiple ``IOThread``\ s
+==============================
+
+..
+ Copyright (c) 2014-2017 Red Hat Inc.
+
+ This work is licensed under the terms of the GNU GPL, version 2 or later. See
+ the COPYING file in the top-level directory.
+
+
+This document explains the ``IOThread`` feature and how to write code that runs
+outside the BQL.
+
+The main loop and ``IOThread``\ s
+---------------------------------
+QEMU is an event-driven program that can do several things at once using an
+event loop. The VNC server and the QMP monitor are both processed from the
+same event loop, which monitors their file descriptors until they become
+readable and then invokes a callback.
+
+The default event loop is called the main loop (see ``main-loop.c``). It is
+possible to create additional event loop threads using
+``-object iothread,id=my-iothread``.
+
+Side note: The main loop and ``IOThread`` are both event loops but their code is
+not shared completely. Sometimes it is useful to remember that although they
+are conceptually similar they are currently not interchangeable.
+
+Why ``IOThread``\ s are useful
+------------------------------
+``IOThread``\ s allow the user to control the placement of work. The main loop is a
+scalability bottleneck on hosts with many CPUs. Work can be spread across
+several ``IOThread``\ s instead of just one main loop. When set up correctly this
+can improve I/O latency and reduce jitter seen by the guest.
+
+The main loop is also deeply associated with the BQL, which is a
+scalability bottleneck in itself. vCPU threads and the main loop use the BQL
+to serialize execution of QEMU code. This mutex is necessary because a lot of
+QEMU's code historically was not thread-safe.
+
+The fact that all I/O processing is done in a single main loop and that the
+BQL is contended by all vCPU threads and the main loop explain
+why it is desirable to place work into ``IOThread``\ s.
+
+The experimental ``virtio-blk`` data-plane implementation has been benchmarked and
+shows these effects:
+ftp://public.dhe.ibm.com/linux/pdfs/KVM_Virtualized_IO_Performance_Paper.pdf
+
+.. _how-to-program:
+
+How to program for ``IOThread``\ s
+----------------------------------
+The main difference between legacy code and new code that can run in an
+``IOThread`` is dealing explicitly with the event loop object, ``AioContext``
+(see ``include/block/aio.h``). Code that only works in the main loop
+implicitly uses the main loop's ``AioContext``. Code that supports running
+in ``IOThread``\ s must be aware of its ``AioContext``.
+
+AioContext supports the following services:
+ * File descriptor monitoring (read/write/error on POSIX hosts)
+ * Event notifiers (inter-thread signalling)
+ * Timers
+ * Bottom Halves (BH) deferred callbacks
+
+There are several old APIs that use the main loop AioContext:
+ * LEGACY ``qemu_aio_set_fd_handler()`` - monitor a file descriptor
+ * LEGACY ``qemu_aio_set_event_notifier()`` - monitor an event notifier
+ * LEGACY ``timer_new_ms()`` - create a timer
+ * LEGACY ``qemu_bh_new()`` - create a BH
+ * LEGACY ``qemu_bh_new_guarded()`` - create a BH with a device re-entrancy guard
+ * LEGACY ``qemu_aio_wait()`` - run an event loop iteration
+
+Since they implicitly work on the main loop they cannot be used in code that
+runs in an ``IOThread``. They might cause a crash or deadlock if called from an
+``IOThread`` since the BQL is not held.
+
+Instead, use the ``AioContext`` functions directly (see ``include/block/aio.h``):
+ * ``aio_set_fd_handler()`` - monitor a file descriptor
+ * ``aio_set_event_notifier()`` - monitor an event notifier
+ * ``aio_timer_new()`` - create a timer
+ * ``aio_bh_new()`` - create a BH
+ * ``aio_bh_new_guarded()`` - create a BH with a device re-entrancy guard
+ * ``aio_poll()`` - run an event loop iteration
+
+The ``qemu_bh_new_guarded``/``aio_bh_new_guarded`` APIs accept a
+``MemReentrancyGuard``
+argument, which is used to check for and prevent re-entrancy problems. For
+BHs associated with devices, the reentrancy-guard is contained in the
+corresponding ``DeviceState`` and named ``mem_reentrancy_guard``.
+
+The ``AioContext`` can be obtained from the ``IOThread`` using
+``iothread_get_aio_context()`` or for the main loop using
+``qemu_get_aio_context()``. Code that takes an ``AioContext`` argument
+works both in ``IOThread``\ s or the main loop, depending on which ``AioContext``
+instance the caller passes in.
+
+How to synchronize with an ``IOThread``
+---------------------------------------
+Variables that can be accessed by multiple threads require some form of
+synchronization such as ``qemu_mutex_lock()``, ``rcu_read_lock()``, etc.
+
+``AioContext`` functions like ``aio_set_fd_handler()``,
+``aio_set_event_notifier()``, ``aio_bh_new()``, and ``aio_timer_new()``
+are thread-safe. They can be used to trigger activity in an ``IOThread``.
+
+Side note: the best way to schedule a function call across threads is to call
+``aio_bh_schedule_oneshot()``.
+
+The main loop thread can wait synchronously for a condition using
+``AIO_WAIT_WHILE()``.
+
+``AioContext`` and the block layer
+----------------------------------
+The ``AioContext`` originates from the QEMU block layer, even though nowadays
+``AioContext`` is a generic event loop that can be used by any QEMU subsystem.
+
+The block layer has support for ``AioContext`` integrated. Each
+``BlockDriverState`` is associated with an ``AioContext`` using
+``bdrv_try_change_aio_context()`` and ``bdrv_get_aio_context()``.
+This allows block layer code to process I/O inside the
+right ``AioContext``. Other subsystems may wish to follow a similar approach.
+
+Block layer code must therefore expect to run in an ``IOThread`` and avoid using
+old APIs that implicitly use the main loop. See
+`How to program for IOThreads`_ for information on how to do that.
+
+Code running in the monitor typically needs to ensure that past
+requests from the guest are completed. When a block device is running
+in an ``IOThread``, the ``IOThread`` can also process requests from the guest
+(via ioeventfd). To achieve both objects, wrap the code between
+``bdrv_drained_begin()`` and ``bdrv_drained_end()``, thus creating a "drained
+section".
+
+Long-running jobs (usually in the form of coroutines) are often scheduled in
+the ``BlockDriverState``'s ``AioContext``. The functions
+``bdrv_add``/``remove_aio_context_notifier``, or alternatively
+``blk_add``/``remove_aio_context_notifier`` if you use ``BlockBackends``,
+can be used to get a notification whenever ``bdrv_try_change_aio_context()``
+moves a ``BlockDriverState`` to a different ``AioContext``.
diff --git a/docs/devel/multiple-iothreads.txt b/docs/devel/multiple-iothreads.txt
deleted file mode 100644
index de85767..0000000
--- a/docs/devel/multiple-iothreads.txt
+++ /dev/null
@@ -1,130 +0,0 @@
-Copyright (c) 2014-2017 Red Hat Inc.
-
-This work is licensed under the terms of the GNU GPL, version 2 or later. See
-the COPYING file in the top-level directory.
-
-
-This document explains the IOThread feature and how to write code that runs
-outside the BQL.
-
-The main loop and IOThreads
----------------------------
-QEMU is an event-driven program that can do several things at once using an
-event loop. The VNC server and the QMP monitor are both processed from the
-same event loop, which monitors their file descriptors until they become
-readable and then invokes a callback.
-
-The default event loop is called the main loop (see main-loop.c). It is
-possible to create additional event loop threads using -object
-iothread,id=my-iothread.
-
-Side note: The main loop and IOThread are both event loops but their code is
-not shared completely. Sometimes it is useful to remember that although they
-are conceptually similar they are currently not interchangeable.
-
-Why IOThreads are useful
-------------------------
-IOThreads allow the user to control the placement of work. The main loop is a
-scalability bottleneck on hosts with many CPUs. Work can be spread across
-several IOThreads instead of just one main loop. When set up correctly this
-can improve I/O latency and reduce jitter seen by the guest.
-
-The main loop is also deeply associated with the BQL, which is a
-scalability bottleneck in itself. vCPU threads and the main loop use the BQL
-to serialize execution of QEMU code. This mutex is necessary because a lot of
-QEMU's code historically was not thread-safe.
-
-The fact that all I/O processing is done in a single main loop and that the
-BQL is contended by all vCPU threads and the main loop explain
-why it is desirable to place work into IOThreads.
-
-The experimental virtio-blk data-plane implementation has been benchmarked and
-shows these effects:
-ftp://public.dhe.ibm.com/linux/pdfs/KVM_Virtualized_IO_Performance_Paper.pdf
-
-How to program for IOThreads
-----------------------------
-The main difference between legacy code and new code that can run in an
-IOThread is dealing explicitly with the event loop object, AioContext
-(see include/block/aio.h). Code that only works in the main loop
-implicitly uses the main loop's AioContext. Code that supports running
-in IOThreads must be aware of its AioContext.
-
-AioContext supports the following services:
- * File descriptor monitoring (read/write/error on POSIX hosts)
- * Event notifiers (inter-thread signalling)
- * Timers
- * Bottom Halves (BH) deferred callbacks
-
-There are several old APIs that use the main loop AioContext:
- * LEGACY qemu_aio_set_fd_handler() - monitor a file descriptor
- * LEGACY qemu_aio_set_event_notifier() - monitor an event notifier
- * LEGACY timer_new_ms() - create a timer
- * LEGACY qemu_bh_new() - create a BH
- * LEGACY qemu_bh_new_guarded() - create a BH with a device re-entrancy guard
- * LEGACY qemu_aio_wait() - run an event loop iteration
-
-Since they implicitly work on the main loop they cannot be used in code that
-runs in an IOThread. They might cause a crash or deadlock if called from an
-IOThread since the BQL is not held.
-
-Instead, use the AioContext functions directly (see include/block/aio.h):
- * aio_set_fd_handler() - monitor a file descriptor
- * aio_set_event_notifier() - monitor an event notifier
- * aio_timer_new() - create a timer
- * aio_bh_new() - create a BH
- * aio_bh_new_guarded() - create a BH with a device re-entrancy guard
- * aio_poll() - run an event loop iteration
-
-The qemu_bh_new_guarded/aio_bh_new_guarded APIs accept a "MemReentrancyGuard"
-argument, which is used to check for and prevent re-entrancy problems. For
-BHs associated with devices, the reentrancy-guard is contained in the
-corresponding DeviceState and named "mem_reentrancy_guard".
-
-The AioContext can be obtained from the IOThread using
-iothread_get_aio_context() or for the main loop using qemu_get_aio_context().
-Code that takes an AioContext argument works both in IOThreads or the main
-loop, depending on which AioContext instance the caller passes in.
-
-How to synchronize with an IOThread
------------------------------------
-Variables that can be accessed by multiple threads require some form of
-synchronization such as qemu_mutex_lock(), rcu_read_lock(), etc.
-
-AioContext functions like aio_set_fd_handler(), aio_set_event_notifier(),
-aio_bh_new(), and aio_timer_new() are thread-safe. They can be used to trigger
-activity in an IOThread.
-
-Side note: the best way to schedule a function call across threads is to call
-aio_bh_schedule_oneshot().
-
-The main loop thread can wait synchronously for a condition using
-AIO_WAIT_WHILE().
-
-AioContext and the block layer
-------------------------------
-The AioContext originates from the QEMU block layer, even though nowadays
-AioContext is a generic event loop that can be used by any QEMU subsystem.
-
-The block layer has support for AioContext integrated. Each BlockDriverState
-is associated with an AioContext using bdrv_try_change_aio_context() and
-bdrv_get_aio_context(). This allows block layer code to process I/O inside the
-right AioContext. Other subsystems may wish to follow a similar approach.
-
-Block layer code must therefore expect to run in an IOThread and avoid using
-old APIs that implicitly use the main loop. See the "How to program for
-IOThreads" above for information on how to do that.
-
-Code running in the monitor typically needs to ensure that past
-requests from the guest are completed. When a block device is running
-in an IOThread, the IOThread can also process requests from the guest
-(via ioeventfd). To achieve both objects, wrap the code between
-bdrv_drained_begin() and bdrv_drained_end(), thus creating a "drained
-section".
-
-Long-running jobs (usually in the form of coroutines) are often scheduled in
-the BlockDriverState's AioContext. The functions
-bdrv_add/remove_aio_context_notifier, or alternatively
-blk_add/remove_aio_context_notifier if you use BlockBackends, can be used to
-get a notification whenever bdrv_try_change_aio_context() moves a
-BlockDriverState to a different AioContext.
diff --git a/docs/devel/nested-papr.txt b/docs/devel/nested-papr.txt
deleted file mode 100644
index 9094365..0000000
--- a/docs/devel/nested-papr.txt
+++ /dev/null
@@ -1,119 +0,0 @@
-Nested PAPR API (aka KVM on PowerVM)
-====================================
-
-This API aims at providing support to enable nested virtualization with
-KVM on PowerVM. While the existing support for nested KVM on PowerNV was
-introduced with cap-nested-hv option, however, with a slight design change,
-to enable this on papr/pseries, a new cap-nested-papr option is added. eg:
-
- qemu-system-ppc64 -cpu POWER10 -machine pseries,cap-nested-papr=true ...
-
-Work by:
- Michael Neuling <mikey@neuling.org>
- Vaibhav Jain <vaibhav@linux.ibm.com>
- Jordan Niethe <jniethe5@gmail.com>
- Harsh Prateek Bora <harshpb@linux.ibm.com>
- Shivaprasad G Bhat <sbhat@linux.ibm.com>
- Kautuk Consul <kconsul@linux.vnet.ibm.com>
-
-Below taken from the kernel documentation:
-
-Introduction
-============
-
-This document explains how a guest operating system can act as a
-hypervisor and run nested guests through the use of hypercalls, if the
-hypervisor has implemented them. The terms L0, L1, and L2 are used to
-refer to different software entities. L0 is the hypervisor mode entity
-that would normally be called the "host" or "hypervisor". L1 is a
-guest virtual machine that is directly run under L0 and is initiated
-and controlled by L0. L2 is a guest virtual machine that is initiated
-and controlled by L1 acting as a hypervisor. A significant design change
-wrt existing API is that now the entire L2 state is maintained within L0.
-
-Existing Nested-HV API
-======================
-
-Linux/KVM has had support for Nesting as an L0 or L1 since 2018
-
-The L0 code was added::
-
- commit 8e3f5fc1045dc49fd175b978c5457f5f51e7a2ce
- Author: Paul Mackerras <paulus@ozlabs.org>
- Date: Mon Oct 8 16:31:03 2018 +1100
- KVM: PPC: Book3S HV: Framework and hcall stubs for nested virtualization
-
-The L1 code was added::
-
- commit 360cae313702cdd0b90f82c261a8302fecef030a
- Author: Paul Mackerras <paulus@ozlabs.org>
- Date: Mon Oct 8 16:31:04 2018 +1100
- KVM: PPC: Book3S HV: Nested guest entry via hypercall
-
-This API works primarily using a signal hcall h_enter_nested(). This
-call made by the L1 to tell the L0 to start an L2 vCPU with the given
-state. The L0 then starts this L2 and runs until an L2 exit condition
-is reached. Once the L2 exits, the state of the L2 is given back to
-the L1 by the L0. The full L2 vCPU state is always transferred from
-and to L1 when the L2 is run. The L0 doesn't keep any state on the L2
-vCPU (except in the short sequence in the L0 on L1 -> L2 entry and L2
--> L1 exit).
-
-The only state kept by the L0 is the partition table. The L1 registers
-it's partition table using the h_set_partition_table() hcall. All
-other state held by the L0 about the L2s is cached state (such as
-shadow page tables).
-
-The L1 may run any L2 or vCPU without first informing the L0. It
-simply starts the vCPU using h_enter_nested(). The creation of L2s and
-vCPUs is done implicitly whenever h_enter_nested() is called.
-
-In this document, we call this existing API the v1 API.
-
-New PAPR API
-===============
-
-The new PAPR API changes from the v1 API such that the creating L2 and
-associated vCPUs is explicit. In this document, we call this the v2
-API.
-
-h_enter_nested() is replaced with H_GUEST_VCPU_RUN(). Before this can
-be called the L1 must explicitly create the L2 using h_guest_create()
-and any associated vCPUs() created with h_guest_create_vCPU(). Getting
-and setting vCPU state can also be performed using h_guest_{g|s}et
-hcall.
-
-The basic execution flow is for an L1 to create an L2, run it, and
-delete it is:
-
-- L1 and L0 negotiate capabilities with H_GUEST_{G,S}ET_CAPABILITIES()
- (normally at L1 boot time).
-
-- L1 requests the L0 to create an L2 with H_GUEST_CREATE() and receives a token
-
-- L1 requests the L0 to create an L2 vCPU with H_GUEST_CREATE_VCPU()
-
-- L1 and L0 communicate the vCPU state using the H_GUEST_{G,S}ET() hcall
-
-- L1 requests the L0 to run the vCPU using H_GUEST_RUN_VCPU() hcall
-
-- L1 deletes L2 with H_GUEST_DELETE()
-
-For more details, please refer:
-
-[1] Linux Kernel documentation (upstream documentation commit):
-
-commit 476652297f94a2e5e5ef29e734b0da37ade94110
-Author: Michael Neuling <mikey@neuling.org>
-Date: Thu Sep 14 13:06:00 2023 +1000
-
- docs: powerpc: Document nested KVM on POWER
-
- Document support for nested KVM on POWER using the existing API as well
- as the new PAPR API. This includes the new HCALL interface and how it
- used by KVM.
-
- Signed-off-by: Michael Neuling <mikey@neuling.org>
- Signed-off-by: Jordan Niethe <jniethe5@gmail.com>
- Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
- Link: https://msgid.link/20230914030600.16993-12-jniethe5@gmail.com
diff --git a/docs/devel/rcu.txt b/docs/devel/rcu.rst
index 2e6cc60..dd07c1d 100644
--- a/docs/devel/rcu.txt
+++ b/docs/devel/rcu.rst
@@ -20,7 +20,7 @@ for the execution of all *currently running* critical sections before
proceeding, or before asynchronously executing a callback.
The key point here is that only the currently running critical sections
-are waited for; critical sections that are started _after_ the beginning
+are waited for; critical sections that are started **after** the beginning
of the wait do not extend the wait, despite running concurrently with
the updater. This is the reason why RCU is more scalable than,
for example, reader-writer locks. It is so much more scalable that
@@ -37,7 +37,7 @@ do not matter; as soon as all previous critical sections have finished,
there cannot be any readers who hold references to the data structure,
and these can now be safely reclaimed (e.g., freed or unref'ed).
-Here is a picture:
+Here is a picture::
thread 1 thread 2 thread 3
------------------- ------------------------ -------------------
@@ -58,43 +58,38 @@ that critical section.
RCU API
-=======
+-------
The core RCU API is small:
- void rcu_read_lock(void);
-
+``void rcu_read_lock(void);``
Used by a reader to inform the reclaimer that the reader is
entering an RCU read-side critical section.
- void rcu_read_unlock(void);
-
+``void rcu_read_unlock(void);``
Used by a reader to inform the reclaimer that the reader is
exiting an RCU read-side critical section. Note that RCU
read-side critical sections may be nested and/or overlapping.
- void synchronize_rcu(void);
-
+``void synchronize_rcu(void);``
Blocks until all pre-existing RCU read-side critical sections
on all threads have completed. This marks the end of the removal
phase and the beginning of reclamation phase.
Note that it would be valid for another update to come while
- synchronize_rcu is running. Because of this, it is better that
+ ``synchronize_rcu`` is running. Because of this, it is better that
the updater releases any locks it may hold before calling
- synchronize_rcu. If this is not possible (for example, because
- the updater is protected by the BQL), you can use call_rcu.
+ ``synchronize_rcu``. If this is not possible (for example, because
+ the updater is protected by the BQL), you can use ``call_rcu``.
- void call_rcu1(struct rcu_head * head,
- void (*func)(struct rcu_head *head));
-
- This function invokes func(head) after all pre-existing RCU
+``void call_rcu1(struct rcu_head * head, void (*func)(struct rcu_head *head));``
+ This function invokes ``func(head)`` after all pre-existing RCU
read-side critical sections on all threads have completed. This
marks the end of the removal phase, with func taking care
asynchronously of the reclamation phase.
- The foo struct needs to have an rcu_head structure added,
- perhaps as follows:
+ The ``foo`` struct needs to have an ``rcu_head`` structure added,
+ perhaps as follows::
struct foo {
struct rcu_head rcu;
@@ -103,8 +98,8 @@ The core RCU API is small:
long c;
};
- so that the reclaimer function can fetch the struct foo address
- and free it:
+ so that the reclaimer function can fetch the ``struct foo`` address
+ and free it::
call_rcu1(&foo.rcu, foo_reclaim);
@@ -114,29 +109,27 @@ The core RCU API is small:
g_free(fp);
}
- For the common case where the rcu_head member is the first of the
- struct, you can use the following macro.
+ ``call_rcu1`` is typically used via either the ``call_rcu`` or
+ ``g_free_rcu`` macros, which handle the common case where the
+ ``rcu_head`` member is the first of the struct.
- void call_rcu(T *p,
- void (*func)(T *p),
- field-name);
- void g_free_rcu(T *p,
- field-name);
+``void call_rcu(T *p, void (*func)(T *p), field-name);``
+ If the ``struct rcu_head`` is the first field in the struct, you can
+ use this macro instead of ``call_rcu1``.
- call_rcu1 is typically used through these macro, in the common case
- where the "struct rcu_head" is the first field in the struct. If
- the callback function is g_free, in particular, g_free_rcu can be
- used. In the above case, one could have written simply:
+``void g_free_rcu(T *p, field-name);``
+ This is a special-case version of ``call_rcu`` where the callback
+ function is ``g_free``.
+ In the example given in ``call_rcu1``, one could have written simply::
g_free_rcu(&foo, rcu);
- typeof(*p) qatomic_rcu_read(p);
-
- qatomic_rcu_read() is similar to qatomic_load_acquire(), but it makes
- some assumptions on the code that calls it. This allows a more
- optimized implementation.
+``typeof(*p) qatomic_rcu_read(p);``
+ ``qatomic_rcu_read()`` is similar to ``qatomic_load_acquire()``, but
+ it makes some assumptions on the code that calls it. This allows a
+ more optimized implementation.
- qatomic_rcu_read assumes that whenever a single RCU critical
+ ``qatomic_rcu_read`` assumes that whenever a single RCU critical
section reads multiple shared data, these reads are either
data-dependent or need no ordering. This is almost always the
case when using RCU, because read-side critical sections typically
@@ -144,7 +137,7 @@ The core RCU API is small:
every update) until reaching a data structure of interest,
and then read from there.
- RCU read-side critical sections must use qatomic_rcu_read() to
+ RCU read-side critical sections must use ``qatomic_rcu_read()`` to
read data, unless concurrent writes are prevented by another
synchronization mechanism.
@@ -152,18 +145,17 @@ The core RCU API is small:
data structure in a single direction, opposite to the direction
in which the updater initializes it.
- void qatomic_rcu_set(p, typeof(*p) v);
-
- qatomic_rcu_set() is similar to qatomic_store_release(), though it also
- makes assumptions on the code that calls it in order to allow a more
- optimized implementation.
+``void qatomic_rcu_set(p, typeof(*p) v);``
+ ``qatomic_rcu_set()`` is similar to ``qatomic_store_release()``,
+ though it also makes assumptions on the code that calls it in
+ order to allow a more optimized implementation.
- In particular, qatomic_rcu_set() suffices for synchronization
+ In particular, ``qatomic_rcu_set()`` suffices for synchronization
with readers, if the updater never mutates a field within a
data item that is already accessible to readers. This is the
case when initializing a new copy of the RCU-protected data
- structure; just ensure that initialization of *p is carried out
- before qatomic_rcu_set() makes the data item visible to readers.
+ structure; just ensure that initialization of ``*p`` is carried out
+ before ``qatomic_rcu_set()`` makes the data item visible to readers.
If this rule is observed, writes will happen in the opposite
order as reads in the RCU read-side critical sections (or if
there is just one update), and there will be no need for other
@@ -171,58 +163,54 @@ The core RCU API is small:
The following APIs must be used before RCU is used in a thread:
- void rcu_register_thread(void);
-
+``void rcu_register_thread(void);``
Mark a thread as taking part in the RCU mechanism. Such a thread
will have to report quiescent points regularly, either manually
- or through the QemuCond/QemuSemaphore/QemuEvent APIs.
-
- void rcu_unregister_thread(void);
+ or through the ``QemuCond``/``QemuSemaphore``/``QemuEvent`` APIs.
+``void rcu_unregister_thread(void);``
Mark a thread as not taking part anymore in the RCU mechanism.
It is not a problem if such a thread reports quiescent points,
- either manually or by using the QemuCond/QemuSemaphore/QemuEvent
- APIs.
+ either manually or by using the
+ ``QemuCond``/``QemuSemaphore``/``QemuEvent`` APIs.
-Note that these APIs are relatively heavyweight, and should _not_ be
+Note that these APIs are relatively heavyweight, and should **not** be
nested.
Convenience macros
-==================
+------------------
Two macros are provided that automatically release the read lock at the
end of the scope.
- RCU_READ_LOCK_GUARD()
-
+``RCU_READ_LOCK_GUARD()``
Takes the lock and will release it at the end of the block it's
used in.
- WITH_RCU_READ_LOCK_GUARD() { code }
-
+``WITH_RCU_READ_LOCK_GUARD() { code }``
Is used at the head of a block to protect the code within the block.
-Note that 'goto'ing out of the guarded block will also drop the lock.
+Note that a ``goto`` out of the guarded block will also drop the lock.
-DIFFERENCES WITH LINUX
-======================
+Differences with Linux
+----------------------
- Waiting on a mutex is possible, though discouraged, within an RCU critical
section. This is because spinlocks are rarely (if ever) used in userspace
programming; not allowing this would prevent upgrading an RCU read-side
critical section to become an updater.
-- qatomic_rcu_read and qatomic_rcu_set replace rcu_dereference and
- rcu_assign_pointer. They take a _pointer_ to the variable being accessed.
+- ``qatomic_rcu_read`` and ``qatomic_rcu_set`` replace ``rcu_dereference`` and
+ ``rcu_assign_pointer``. They take a **pointer** to the variable being accessed.
-- call_rcu is a macro that has an extra argument (the name of the first
- field in the struct, which must be a struct rcu_head), and expects the
+- ``call_rcu`` is a macro that has an extra argument (the name of the first
+ field in the struct, which must be a struct ``rcu_head``), and expects the
type of the callback's argument to be the type of the first argument.
- call_rcu1 is the same as Linux's call_rcu.
+ ``call_rcu1`` is the same as Linux's ``call_rcu``.
-RCU PATTERNS
-============
+RCU Patterns
+------------
Many patterns using read-writer locks translate directly to RCU, with
the advantages of higher scalability and deadlock immunity.
@@ -243,28 +231,28 @@ Here are some frequently-used RCU idioms that are worth noting.
RCU list processing
--------------------
+^^^^^^^^^^^^^^^^^^^
TBD (not yet used in QEMU)
RCU reference counting
-----------------------
+^^^^^^^^^^^^^^^^^^^^^^
Because grace periods are not allowed to complete while there is an RCU
read-side critical section in progress, the RCU read-side primitives
may be used as a restricted reference-counting mechanism. For example,
-consider the following code fragment:
+consider the following code fragment::
rcu_read_lock();
p = qatomic_rcu_read(&foo);
/* do something with p. */
rcu_read_unlock();
-The RCU read-side critical section ensures that the value of "p" remains
-valid until after the rcu_read_unlock(). In some sense, it is acquiring
-a reference to p that is later released when the critical section ends.
-The write side looks simply like this (with appropriate locking):
+The RCU read-side critical section ensures that the value of ``p`` remains
+valid until after the ``rcu_read_unlock()``. In some sense, it is acquiring
+a reference to ``p`` that is later released when the critical section ends.
+The write side looks simply like this (with appropriate locking)::
qemu_mutex_lock(&foo_mutex);
old = foo;
@@ -274,7 +262,7 @@ The write side looks simply like this (with appropriate locking):
free(old);
If the processing cannot be done purely within the critical section, it
-is possible to combine this idiom with a "real" reference count:
+is possible to combine this idiom with a "real" reference count::
rcu_read_lock();
p = qatomic_rcu_read(&foo);
@@ -283,7 +271,7 @@ is possible to combine this idiom with a "real" reference count:
/* do something with p. */
foo_unref(p);
-The write side can be like this:
+The write side can be like this::
qemu_mutex_lock(&foo_mutex);
old = foo;
@@ -292,7 +280,7 @@ The write side can be like this:
synchronize_rcu();
foo_unref(old);
-or with call_rcu:
+or with ``call_rcu``::
qemu_mutex_lock(&foo_mutex);
old = foo;
@@ -301,10 +289,10 @@ or with call_rcu:
call_rcu(foo_unref, old, rcu);
In both cases, the write side only performs removal. Reclamation
-happens when the last reference to a "foo" object is dropped.
-Using synchronize_rcu() is undesirably expensive, because the
+happens when the last reference to a ``foo`` object is dropped.
+Using ``synchronize_rcu()`` is undesirably expensive, because the
last reference may be dropped on the read side. Hence you can
-use call_rcu() instead:
+use ``call_rcu()`` instead::
foo_unref(struct foo *p) {
if (qatomic_fetch_dec(&p->refcount) == 1) {
@@ -314,7 +302,7 @@ use call_rcu() instead:
Note that the same idioms would be possible with reader/writer
-locks:
+locks::
read_lock(&foo_rwlock); write_mutex_lock(&foo_rwlock);
p = foo; p = foo;
@@ -334,15 +322,15 @@ locks:
foo_unref(p);
read_unlock(&foo_rwlock);
-foo_unref could use a mechanism such as bottom halves to move deallocation
+``foo_unref`` could use a mechanism such as bottom halves to move deallocation
out of the write-side critical section.
RCU resizable arrays
---------------------
+^^^^^^^^^^^^^^^^^^^^
Resizable arrays can be used with RCU. The expensive RCU synchronization
-(or call_rcu) only needs to take place when the array is resized.
+(or ``call_rcu``) only needs to take place when the array is resized.
The two items to take care of are:
- ensuring that the old version of the array is available between removal
@@ -351,10 +339,10 @@ The two items to take care of are:
- avoiding mismatches in the read side between the array data and the
array size.
-The first problem is avoided simply by not using realloc. Instead,
+The first problem is avoided simply by not using ``realloc``. Instead,
each resize will allocate a new array and copy the old data into it.
The second problem would arise if the size and the data pointers were
-two members of a larger struct:
+two members of a larger struct::
struct mystuff {
...
@@ -364,7 +352,7 @@ two members of a larger struct:
...
};
-Instead, we store the size of the array with the array itself:
+Instead, we store the size of the array with the array itself::
struct arr {
int size;
@@ -400,7 +388,7 @@ Instead, we store the size of the array with the array itself:
}
-SOURCES
-=======
+References
+----------
-* Documentation/RCU/ from the Linux kernel
+* The `Linux kernel RCU documentation <https://docs.kernel.org/RCU/>`__
diff --git a/docs/devel/replay.rst b/docs/devel/replay.rst
index effd856..40f58d9 100644
--- a/docs/devel/replay.rst
+++ b/docs/devel/replay.rst
@@ -202,6 +202,9 @@ into the log.
Saving/restoring the VM state
-----------------------------
+Record/replay relies on VM state save and restore being complete and
+deterministic.
+
All fields in the device state structure (including virtual timers)
should be restored by loadvm to the same values they had before savevm.
diff --git a/docs/devel/reset.rst b/docs/devel/reset.rst
index 9746a4e..74c7c01 100644
--- a/docs/devel/reset.rst
+++ b/docs/devel/reset.rst
@@ -44,6 +44,26 @@ The Resettable interface handles reset types with an enum ``ResetType``:
value on each cold reset, such as RNG seed information, and which they
must not reinitialize on a snapshot-load reset.
+``RESET_TYPE_WAKEUP``
+ If the machine supports waking up from a suspended state and needs to reset
+ its devices during wake-up (from the ``MachineClass::wakeup()`` method), this
+ reset type should be used for such a request. Devices can utilize this reset
+ type to differentiate the reset requested during machine wake-up from other
+ reset requests. For example, RAM content must not be lost during wake-up, and
+ memory devices like virtio-mem that provide additional RAM must not reset
+ such state during wake-ups, but might do so during cold resets. However, this
+ reset type should not be used for wake-up detection, as not every machine
+ type issues a device reset request during wake-up.
+
+``RESET_TYPE_S390_CPU_NORMAL``
+ This is only used for S390 CPU objects; it clears interrupts, stops
+ processing, and clears the TLB, but does not touch register contents.
+
+``RESET_TYPE_S390_CPU_INITIAL``
+ This is only used for S390 CPU objects; it does everything
+ ``RESET_TYPE_S390_CPU_NORMAL`` does and also clears the PSW, prefix,
+ FPC, timer and control registers. It does not touch gprs, fprs or acrs.
+
Devices which implement reset methods must treat any unknown ``ResetType``
as equivalent to ``RESET_TYPE_COLD``; this will reduce the amount of
existing code we need to change if we add more types in future.
diff --git a/docs/devel/tcg-plugins.rst b/docs/devel/tcg-plugins.rst
index f7d7b9e..9463692 100644
--- a/docs/devel/tcg-plugins.rst
+++ b/docs/devel/tcg-plugins.rst
@@ -8,38 +8,6 @@
QEMU TCG Plugins
================
-QEMU TCG plugins provide a way for users to run experiments taking
-advantage of the total system control emulation can have over a guest.
-It provides a mechanism for plugins to subscribe to events during
-translation and execution and optionally callback into the plugin
-during these events. TCG plugins are unable to change the system state
-only monitor it passively. However they can do this down to an
-individual instruction granularity including potentially subscribing
-to all load and store operations.
-
-Usage
------
-
-Any QEMU binary with TCG support has plugins enabled by default.
-Earlier releases needed to be explicitly enabled with::
-
- configure --enable-plugins
-
-Once built a program can be run with multiple plugins loaded each with
-their own arguments::
-
- $QEMU $OTHER_QEMU_ARGS \
- -plugin contrib/plugin/libhowvec.so,inline=on,count=hint \
- -plugin contrib/plugin/libhotblocks.so
-
-Arguments are plugin specific and can be used to modify their
-behaviour. In this case the howvec plugin is being asked to use inline
-ops to count and break down the hint instructions by type.
-
-Linux user-mode emulation also evaluates the environment variable
-``QEMU_PLUGIN``::
-
- QEMU_PLUGIN="file=contrib/plugins/libhowvec.so,inline=on,count=hint" $QEMU
Writing plugins
---------------
@@ -93,11 +61,14 @@ translation event the plugin has an option to enumerate the
instructions in a block of instructions and optionally register
callbacks to some or all instructions when they are executed.
-There is also a facility to add an inline event where code to
-increment a counter can be directly inlined with the translation.
-Currently only a simple increment is supported. This is not atomic so
-can miss counts. If you want absolute precision you should use a
-callback which can then ensure atomicity itself.
+There is also a facility to add inline instructions doing various operations,
+like adding or storing an immediate value. It is also possible to execute a
+callback conditionally, with condition being evaluated inline. All those inline
+operations are associated to a ``scoreboard``, which is a thread-local storage
+automatically expanded when new cores/threads are created and that can be
+accessed/modified in a thread-safe way without any lock needed. Combining inline
+operations and conditional callbacks offer a more efficient way to instrument
+binaries, compared to classic callbacks.
Finally when QEMU exits all the registered *atexit* callbacks are
invoked.
@@ -191,457 +162,6 @@ which means callbacks may still occur after the uninstall operation is
requested. The plugin isn't completely uninstalled until the safe work
has executed while all vCPUs are quiescent.
-Example Plugins
-===============
-
-There are a number of plugins included with QEMU and you are
-encouraged to contribute your own plugins plugins upstream. There is a
-``contrib/plugins`` directory where they can go. There are also some
-basic plugins that are used to test and exercise the API during the
-``make check-tcg`` target in ``tests\plugins``.
-
-- tests/plugins/empty.c
-
-Purely a test plugin for measuring the overhead of the plugins system
-itself. Does no instrumentation.
-
-- tests/plugins/bb.c
-
-A very basic plugin which will measure execution in course terms as
-each basic block is executed. By default the results are shown once
-execution finishes::
-
- $ qemu-aarch64 -plugin tests/plugin/libbb.so \
- -d plugin ./tests/tcg/aarch64-linux-user/sha1
- SHA1=15dd99a1991e0b3826fede3deffc1feba42278e6
- bb's: 2277338, insns: 158483046
-
-Behaviour can be tweaked with the following arguments:
-
- * inline=true|false
-
- Use faster inline addition of a single counter. Not per-cpu and not
- thread safe.
-
- * idle=true|false
-
- Dump the current execution stats whenever the guest vCPU idles
-
-- tests/plugins/insn.c
-
-This is a basic instruction level instrumentation which can count the
-number of instructions executed on each core/thread::
-
- $ qemu-aarch64 -plugin tests/plugin/libinsn.so \
- -d plugin ./tests/tcg/aarch64-linux-user/threadcount
- Created 10 threads
- Done
- cpu 0 insns: 46765
- cpu 1 insns: 3694
- cpu 2 insns: 3694
- cpu 3 insns: 2994
- cpu 4 insns: 1497
- cpu 5 insns: 1497
- cpu 6 insns: 1497
- cpu 7 insns: 1497
- total insns: 63135
-
-Behaviour can be tweaked with the following arguments:
-
- * inline=true|false
-
- Use faster inline addition of a single counter. Not per-cpu and not
- thread safe.
-
- * sizes=true|false
-
- Give a summary of the instruction sizes for the execution
-
- * match=<string>
-
- Only instrument instructions matching the string prefix. Will show
- some basic stats including how many instructions have executed since
- the last execution. For example::
-
- $ qemu-aarch64 -plugin tests/plugin/libinsn.so,match=bl \
- -d plugin ./tests/tcg/aarch64-linux-user/sha512-vector
- ...
- 0x40069c, 'bl #0x4002b0', 10 hits, 1093 match hits, Ī”+1257 since last match, 98 avg insns/match
- 0x4006ac, 'bl #0x403690', 10 hits, 1094 match hits, Ī”+47 since last match, 98 avg insns/match
- 0x4037fc, 'bl #0x4002b0', 18 hits, 1095 match hits, Ī”+22 since last match, 98 avg insns/match
- 0x400720, 'bl #0x403690', 10 hits, 1096 match hits, Ī”+58 since last match, 98 avg insns/match
- 0x4037fc, 'bl #0x4002b0', 19 hits, 1097 match hits, Ī”+22 since last match, 98 avg insns/match
- 0x400730, 'bl #0x403690', 10 hits, 1098 match hits, Ī”+33 since last match, 98 avg insns/match
- 0x4037ac, 'bl #0x4002b0', 12 hits, 1099 match hits, Ī”+20 since last match, 98 avg insns/match
- ...
-
-For more detailed execution tracing see the ``execlog`` plugin for
-other options.
-
-- tests/plugins/mem.c
-
-Basic instruction level memory instrumentation::
-
- $ qemu-aarch64 -plugin tests/plugin/libmem.so,inline=true \
- -d plugin ./tests/tcg/aarch64-linux-user/sha1
- SHA1=15dd99a1991e0b3826fede3deffc1feba42278e6
- inline mem accesses: 79525013
-
-Behaviour can be tweaked with the following arguments:
-
- * inline=true|false
-
- Use faster inline addition of a single counter. Not per-cpu and not
- thread safe.
-
- * callback=true|false
-
- Use callbacks on each memory instrumentation.
-
- * hwaddr=true|false
-
- Count IO accesses (only for system emulation)
-
-- tests/plugins/syscall.c
-
-A basic syscall tracing plugin. This only works for user-mode. By
-default it will give a summary of syscall stats at the end of the
-run::
-
- $ qemu-aarch64 -plugin tests/plugin/libsyscall \
- -d plugin ./tests/tcg/aarch64-linux-user/threadcount
- Created 10 threads
- Done
- syscall no. calls errors
- 226 12 0
- 99 11 11
- 115 11 0
- 222 11 0
- 93 10 0
- 220 10 0
- 233 10 0
- 215 8 0
- 214 4 0
- 134 2 0
- 64 2 0
- 96 1 0
- 94 1 0
- 80 1 0
- 261 1 0
- 78 1 0
- 160 1 0
- 135 1 0
-
-- contrib/plugins/hotblocks.c
-
-The hotblocks plugin allows you to examine the where hot paths of
-execution are in your program. Once the program has finished you will
-get a sorted list of blocks reporting the starting PC, translation
-count, number of instructions and execution count. This will work best
-with linux-user execution as system emulation tends to generate
-re-translations as blocks from different programs get swapped in and
-out of system memory.
-
-If your program is single-threaded you can use the ``inline`` option for
-slightly faster (but not thread safe) counters.
-
-Example::
-
- $ qemu-aarch64 \
- -plugin contrib/plugins/libhotblocks.so -d plugin \
- ./tests/tcg/aarch64-linux-user/sha1
- SHA1=15dd99a1991e0b3826fede3deffc1feba42278e6
- collected 903 entries in the hash table
- pc, tcount, icount, ecount
- 0x0000000041ed10, 1, 5, 66087
- 0x000000004002b0, 1, 4, 66087
- ...
-
-- contrib/plugins/hotpages.c
-
-Similar to hotblocks but this time tracks memory accesses::
-
- $ qemu-aarch64 \
- -plugin contrib/plugins/libhotpages.so -d plugin \
- ./tests/tcg/aarch64-linux-user/sha1
- SHA1=15dd99a1991e0b3826fede3deffc1feba42278e6
- Addr, RCPUs, Reads, WCPUs, Writes
- 0x000055007fe000, 0x0001, 31747952, 0x0001, 8835161
- 0x000055007ff000, 0x0001, 29001054, 0x0001, 8780625
- 0x00005500800000, 0x0001, 687465, 0x0001, 335857
- 0x0000000048b000, 0x0001, 130594, 0x0001, 355
- 0x0000000048a000, 0x0001, 1826, 0x0001, 11
-
-The hotpages plugin can be configured using the following arguments:
-
- * sortby=reads|writes|address
-
- Log the data sorted by either the number of reads, the number of writes, or
- memory address. (Default: entries are sorted by the sum of reads and writes)
-
- * io=on
-
- Track IO addresses. Only relevant to full system emulation. (Default: off)
-
- * pagesize=N
-
- The page size used. (Default: N = 4096)
-
-- contrib/plugins/howvec.c
-
-This is an instruction classifier so can be used to count different
-types of instructions. It has a number of options to refine which get
-counted. You can give a value to the ``count`` argument for a class of
-instructions to break it down fully, so for example to see all the system
-registers accesses::
-
- $ qemu-system-aarch64 $(QEMU_ARGS) \
- -append "root=/dev/sda2 systemd.unit=benchmark.service" \
- -smp 4 -plugin ./contrib/plugins/libhowvec.so,count=sreg -d plugin
-
-which will lead to a sorted list after the class breakdown::
-
- Instruction Classes:
- Class: UDEF not counted
- Class: SVE (68 hits)
- Class: PCrel addr (47789483 hits)
- Class: Add/Sub (imm) (192817388 hits)
- Class: Logical (imm) (93852565 hits)
- Class: Move Wide (imm) (76398116 hits)
- Class: Bitfield (44706084 hits)
- Class: Extract (5499257 hits)
- Class: Cond Branch (imm) (147202932 hits)
- Class: Exception Gen (193581 hits)
- Class: NOP not counted
- Class: Hints (6652291 hits)
- Class: Barriers (8001661 hits)
- Class: PSTATE (1801695 hits)
- Class: System Insn (6385349 hits)
- Class: System Reg counted individually
- Class: Branch (reg) (69497127 hits)
- Class: Branch (imm) (84393665 hits)
- Class: Cmp & Branch (110929659 hits)
- Class: Tst & Branch (44681442 hits)
- Class: AdvSimd ldstmult (736 hits)
- Class: ldst excl (9098783 hits)
- Class: Load Reg (lit) (87189424 hits)
- Class: ldst noalloc pair (3264433 hits)
- Class: ldst pair (412526434 hits)
- Class: ldst reg (imm) (314734576 hits)
- Class: Loads & Stores (2117774 hits)
- Class: Data Proc Reg (223519077 hits)
- Class: Scalar FP (31657954 hits)
- Individual Instructions:
- Instr: mrs x0, sp_el0 (2682661 hits) (op=0xd5384100/ System Reg)
- Instr: mrs x1, tpidr_el2 (1789339 hits) (op=0xd53cd041/ System Reg)
- Instr: mrs x2, tpidr_el2 (1513494 hits) (op=0xd53cd042/ System Reg)
- Instr: mrs x0, tpidr_el2 (1490823 hits) (op=0xd53cd040/ System Reg)
- Instr: mrs x1, sp_el0 (933793 hits) (op=0xd5384101/ System Reg)
- Instr: mrs x2, sp_el0 (699516 hits) (op=0xd5384102/ System Reg)
- Instr: mrs x4, tpidr_el2 (528437 hits) (op=0xd53cd044/ System Reg)
- Instr: mrs x30, ttbr1_el1 (480776 hits) (op=0xd538203e/ System Reg)
- Instr: msr ttbr1_el1, x30 (480713 hits) (op=0xd518203e/ System Reg)
- Instr: msr vbar_el1, x30 (480671 hits) (op=0xd518c01e/ System Reg)
- ...
-
-To find the argument shorthand for the class you need to examine the
-source code of the plugin at the moment, specifically the ``*opt``
-argument in the InsnClassExecCount tables.
-
-- contrib/plugins/lockstep.c
-
-This is a debugging tool for developers who want to find out when and
-where execution diverges after a subtle change to TCG code generation.
-It is not an exact science and results are likely to be mixed once
-asynchronous events are introduced. While the use of -icount can
-introduce determinism to the execution flow it doesn't always follow
-the translation sequence will be exactly the same. Typically this is
-caused by a timer firing to service the GUI causing a block to end
-early. However in some cases it has proved to be useful in pointing
-people at roughly where execution diverges. The only argument you need
-for the plugin is a path for the socket the two instances will
-communicate over::
-
-
- $ qemu-system-sparc -monitor none -parallel none \
- -net none -M SS-20 -m 256 -kernel day11/zImage.elf \
- -plugin ./contrib/plugins/liblockstep.so,sockpath=lockstep-sparc.sock \
- -d plugin,nochain
-
-which will eventually report::
-
- qemu-system-sparc: warning: nic lance.0 has no peer
- @ 0x000000ffd06678 vs 0x000000ffd001e0 (2/1 since last)
- @ 0x000000ffd07d9c vs 0x000000ffd06678 (3/1 since last)
- Ī” insn_count @ 0x000000ffd07d9c (809900609) vs 0x000000ffd06678 (809900612)
- previously @ 0x000000ffd06678/10 (809900609 insns)
- previously @ 0x000000ffd001e0/4 (809900599 insns)
- previously @ 0x000000ffd080ac/2 (809900595 insns)
- previously @ 0x000000ffd08098/5 (809900593 insns)
- previously @ 0x000000ffd080c0/1 (809900588 insns)
-
-- contrib/plugins/hwprofile.c
-
-The hwprofile tool can only be used with system emulation and allows
-the user to see what hardware is accessed how often. It has a number of options:
-
- * track=read or track=write
-
- By default the plugin tracks both reads and writes. You can use one
- of these options to limit the tracking to just one class of accesses.
-
- * source
-
- Will include a detailed break down of what the guest PC that made the
- access was. Not compatible with the pattern option. Example output::
-
- cirrus-low-memory @ 0xfffffd00000a0000
- pc:fffffc0000005cdc, 1, 256
- pc:fffffc0000005ce8, 1, 256
- pc:fffffc0000005cec, 1, 256
-
- * pattern
-
- Instead break down the accesses based on the offset into the HW
- region. This can be useful for seeing the most used registers of a
- device. Example output::
-
- pci0-conf @ 0xfffffd01fe000000
- off:00000004, 1, 1
- off:00000010, 1, 3
- off:00000014, 1, 3
- off:00000018, 1, 2
- off:0000001c, 1, 2
- off:00000020, 1, 2
- ...
-
-- contrib/plugins/execlog.c
-
-The execlog tool traces executed instructions with memory access. It can be used
-for debugging and security analysis purposes.
-Please be aware that this will generate a lot of output.
-
-The plugin needs default argument::
-
- $ qemu-system-arm $(QEMU_ARGS) \
- -plugin ./contrib/plugins/libexeclog.so -d plugin
-
-which will output an execution trace following this structure::
-
- # vCPU, vAddr, opcode, disassembly[, load/store, memory addr, device]...
- 0, 0xa12, 0xf8012400, "movs r4, #0"
- 0, 0xa14, 0xf87f42b4, "cmp r4, r6"
- 0, 0xa16, 0xd206, "bhs #0xa26"
- 0, 0xa18, 0xfff94803, "ldr r0, [pc, #0xc]", load, 0x00010a28, RAM
- 0, 0xa1a, 0xf989f000, "bl #0xd30"
- 0, 0xd30, 0xfff9b510, "push {r4, lr}", store, 0x20003ee0, RAM, store, 0x20003ee4, RAM
- 0, 0xd32, 0xf9893014, "adds r0, #0x14"
- 0, 0xd34, 0xf9c8f000, "bl #0x10c8"
- 0, 0x10c8, 0xfff96c43, "ldr r3, [r0, #0x44]", load, 0x200000e4, RAM
-
-Please note that you need to configure QEMU with Capstone support to get disassembly.
-
-The output can be filtered to only track certain instructions or
-addresses using the ``ifilter`` or ``afilter`` options. You can stack the
-arguments if required::
-
- $ qemu-system-arm $(QEMU_ARGS) \
- -plugin ./contrib/plugins/libexeclog.so,ifilter=st1w,afilter=0x40001808 -d plugin
-
-This plugin can also dump registers when they change value. Specify the name of the
-registers with multiple ``reg`` options. You can also use glob style matching if you wish::
-
- $ qemu-system-arm $(QEMU_ARGS) \
- -plugin ./contrib/plugins/libexeclog.so,reg=\*_el2,reg=sp -d plugin
-
-Be aware that each additional register to check will slow down
-execution quite considerably. You can optimise the number of register
-checks done by using the rdisas option. This will only instrument
-instructions that mention the registers in question in disassembly.
-This is not foolproof as some instructions implicitly change
-instructions. You can use the ifilter to catch these cases:
-
- $ qemu-system-arm $(QEMU_ARGS) \
- -plugin ./contrib/plugins/libexeclog.so,ifilter=msr,ifilter=blr,reg=x30,reg=\*_el1,rdisas=on
-
-- contrib/plugins/cache.c
-
-Cache modelling plugin that measures the performance of a given L1 cache
-configuration, and optionally a unified L2 per-core cache when a given working
-set is run::
-
- $ qemu-x86_64 -plugin ./contrib/plugins/libcache.so \
- -d plugin -D cache.log ./tests/tcg/x86_64-linux-user/float_convs
-
-will report the following::
-
- core #, data accesses, data misses, dmiss rate, insn accesses, insn misses, imiss rate
- 0 996695 508 0.0510% 2642799 18617 0.7044%
-
- address, data misses, instruction
- 0x424f1e (_int_malloc), 109, movq %rax, 8(%rcx)
- 0x41f395 (_IO_default_xsputn), 49, movb %dl, (%rdi, %rax)
- 0x42584d (ptmalloc_init.part.0), 33, movaps %xmm0, (%rax)
- 0x454d48 (__tunables_init), 20, cmpb $0, (%r8)
- ...
-
- address, fetch misses, instruction
- 0x4160a0 (__vfprintf_internal), 744, movl $1, %ebx
- 0x41f0a0 (_IO_setb), 744, endbr64
- 0x415882 (__vfprintf_internal), 744, movq %r12, %rdi
- 0x4268a0 (__malloc), 696, andq $0xfffffffffffffff0, %rax
- ...
-
-The plugin has a number of arguments, all of them are optional:
-
- * limit=N
-
- Print top N icache and dcache thrashing instructions along with their
- address, number of misses, and its disassembly. (default: 32)
-
- * icachesize=N
- * iblksize=B
- * iassoc=A
-
- Instruction cache configuration arguments. They specify the cache size, block
- size, and associativity of the instruction cache, respectively.
- (default: N = 16384, B = 64, A = 8)
-
- * dcachesize=N
- * dblksize=B
- * dassoc=A
-
- Data cache configuration arguments. They specify the cache size, block size,
- and associativity of the data cache, respectively.
- (default: N = 16384, B = 64, A = 8)
-
- * evict=POLICY
-
- Sets the eviction policy to POLICY. Available policies are: :code:`lru`,
- :code:`fifo`, and :code:`rand`. The plugin will use the specified policy for
- both instruction and data caches. (default: POLICY = :code:`lru`)
-
- * cores=N
-
- Sets the number of cores for which we maintain separate icache and dcache.
- (default: for linux-user, N = 1, for full system emulation: N = cores
- available to guest)
-
- * l2=on
-
- Simulates a unified L2 cache (stores blocks for both instructions and data)
- using the default L2 configuration (cache size = 2MB, associativity = 16-way,
- block size = 64B).
-
- * l2cachesize=N
- * l2blksize=B
- * l2assoc=A
-
- L2 cache configuration arguments. They specify the cache size, block size, and
- associativity of the L2 cache, respectively. Setting any of the L2
- configuration arguments implies ``l2=on``.
- (default: N = 2097152 (2MB), B = 64, A = 16)
-
Plugin API
==========
diff --git a/docs/devel/acpi-bits.rst b/docs/devel/testing/acpi-bits.rst
index 1ec394f..9a4d716 100644
--- a/docs/devel/acpi-bits.rst
+++ b/docs/devel/testing/acpi-bits.rst
@@ -1,6 +1,6 @@
-=============================================================================
-ACPI/SMBIOS avocado tests using biosbits
-=============================================================================
+==================================
+ACPI/SMBIOS testing using biosbits
+==================================
************
Introduction
************
@@ -30,26 +30,31 @@ OS modules are generally written using low level languages such as C and
low level assembly machine language. Writing test routines in a low level
language makes things more cumbersome. These and other reasons makes using
bios-bits very attractive for testing bioses. More details on the inspiration
-for developing biosbits and its real life uses can be found in [#a]_ and [#b]_.
+for developing biosbits and its real life uses were presented `at Plumbers
+in 2011 <Plumbers_>`__ and `at Linux.conf.au in 2012 <Linux.conf.au_>`__.
-For QEMU, we maintain a fork of bios bits in gitlab along with all the
-dependent submodules `here <https://gitlab.com/qemu-project/biosbits-bits>`__.
-This fork contains numerous fixes, a newer acpica and changes specific to
-running this avocado QEMU tests using bits. The author of this document
-is the sole maintainer of the QEMU fork of bios bits repository. For more
-information, please see author's `FOSDEM talk on this bios-bits based test
-framework <https://fosdem.org/2024/schedule/event/fosdem-2024-2262-exercising-qemu-generated-acpi-smbios-tables-using-biosbits-from-within-a-guest-vm-/>`__.
+For QEMU, we maintain a fork of bios bits in `gitlab`_, along with all
+the dependent submodules. This fork contains numerous fixes, a newer
+acpica and changes specific to running these functional QEMU tests using
+bits. The author of this document is the current maintainer of the QEMU
+fork of bios bits repository. For more information, please see `the
+author's FOSDEM presentation <FOSDEM_>`__ on this bios-bits based test framework.
+
+.. _Plumbers: https://blog.linuxplumbersconf.org/2011/ocw/system/presentations/867/original/bits.pdf
+.. _Linux.conf.au: https://www.youtube.com/watch?v=36QIepyUuhg
+.. _gitlab: https://gitlab.com/qemu-project/biosbits-bits
+.. _FOSDEM: https://fosdem.org/2024/schedule/event/fosdem-2024-2262-exercising-qemu-generated-acpi-smbios-tables-using-biosbits-from-within-a-guest-vm-/
*********************************
Description of the test framework
*********************************
-Under the directory ``tests/avocado/``, ``acpi-bits.py`` is a QEMU avocado
-test that drives all this.
+Under the directory ``tests/functional/``, ``test_acpi_bits.py`` is a QEMU
+functional test that drives all this.
A brief description of the various test files follows.
-Under ``tests/avocado/`` as the root we have:
+Under ``tests/functional/`` as the root we have:
::
@@ -60,12 +65,12 @@ Under ``tests/avocado/`` as the root we have:
ā”‚ ā”œā”€ā”€ smbios.py2
ā”‚ ā”œā”€ā”€ testacpi.py2
ā”‚ ā””ā”€ā”€ testcpuid.py2
- ā”œā”€ā”€ acpi-bits.py
+ ā”œā”€ā”€ test_acpi_bits.py
-* ``tests/avocado``:
+* ``tests/functional``:
- ``acpi-bits.py``:
- This is the main python avocado test script that generates a
+ ``test_acpi_bits.py``:
+ This is the main python functional test script that generates a
biosbits iso. It then spawns a QEMU VM with it, collects the log and reports
test failures. This is the script one would be interested in if they wanted
to add or change some component of the log parsing, add a new command line
@@ -79,35 +84,22 @@ Under ``tests/avocado/`` as the root we have:
you to inspect and run the specific commands manually.
In order to run this test, please perform the following steps from the QEMU
- build directory:
- ::
-
- $ make check-venv (needed only the first time to create the venv)
- $ ./pyvenv/bin/avocado run -t acpi tests/avocado
-
- The above will run all acpi avocado tests including this one.
- In order to run the individual tests, perform the following:
+ build directory (assuming that the sources are in ".."):
::
- $ ./pyvenv/bin/avocado run tests/avocado/acpi-bits.py --tap -
-
- The above will produce output in tap format. You can omit "--tap -" in the
- end and it will produce output like the following:
- ::
+ $ export PYTHONPATH=../python:../tests/functional
+ $ export QEMU_TEST_QEMU_BINARY=$PWD/qemu-system-x86_64
+ $ python3 ../tests/functional/test_acpi_bits.py
- $ ./pyvenv/bin/avocado run tests/avocado/acpi-bits.py
- Fetching asset from tests/avocado/acpi-bits.py:AcpiBitsTest.test_acpi_smbios_bits
- JOB ID : eab225724da7b64c012c65705dc2fa14ab1defef
- JOB LOG : /home/anisinha/avocado/job-results/job-2022-10-10T17.58-eab2257/job.log
- (1/1) tests/avocado/acpi-bits.py:AcpiBitsTest.test_acpi_smbios_bits: PASS (33.09 s)
- RESULTS : PASS 1 | ERROR 0 | FAIL 0 | SKIP 0 | WARN 0 | INTERRUPT 0 | CANCEL 0
- JOB TIME : 39.22 s
+ The above will run all acpi-bits functional tests (producing output in
+ tap format).
- You can inspect the log file for more information about the run or in order
- to diagnoze issues. If you pass V=1 in the environment, more diagnostic logs
- would be found in the test log.
+ You can inspect the log files in tests/functional/x86_64/test_acpi_bits.*/
+ for more information about the run or in order to diagnoze issues.
+ If you pass V=1 in the environment, more diagnostic logs will be put into
+ the test log.
-* ``tests/avocado/acpi-bits/bits-config``:
+* ``tests/functional/acpi-bits/bits-config``:
This location contains biosbits configuration files that determine how the
software runs the tests.
@@ -117,7 +109,7 @@ Under ``tests/avocado/`` as the root we have:
or actions are performed by bits. The description of the config options are
provided in the file itself.
-* ``tests/avocado/acpi-bits/bits-tests``:
+* ``tests/functional/acpi-bits/bits-tests``:
This directory contains biosbits python based tests that are run from within
the biosbits environment in the spawned VM. New additions of test cases can
@@ -155,13 +147,9 @@ Under ``tests/avocado/`` as the root we have:
(a) They are python2.7 based scripts and not python 3 scripts.
(b) They are run from within the bios bits VM and is not subjected to QEMU
build/test python script maintenance and dependency resolutions.
- (c) They need not be loaded by avocado framework when running tests.
+ (c) They need not be loaded by the test framework by accident when running
+ tests.
Author: Ani Sinha <anisinha@redhat.com>
-References:
------------
-.. [#a] https://blog.linuxplumbersconf.org/2011/ocw/system/presentations/867/original/bits.pdf
-.. [#b] https://www.youtube.com/watch?v=36QIepyUuhg
-.. [#c] https://fosdem.org/2024/schedule/event/fosdem-2024-2262-exercising-qemu-generated-acpi-smbios-tables-using-biosbits-from-within-a-guest-vm-/
diff --git a/docs/devel/testing/avocado.rst b/docs/devel/testing/avocado.rst
new file mode 100644
index 0000000..eda76fe
--- /dev/null
+++ b/docs/devel/testing/avocado.rst
@@ -0,0 +1,581 @@
+.. _checkavocado-ref:
+
+
+Integration testing with Avocado
+================================
+
+The ``tests/avocado`` directory hosts integration tests. They're usually
+higher level tests, and may interact with external resources and with
+various guest operating systems.
+
+These tests are written using the Avocado Testing Framework (which must be
+installed separately) in conjunction with a the ``avocado_qemu.QemuSystemTest``
+class, implemented at ``tests/avocado/avocado_qemu``.
+
+Tests based on ``avocado_qemu.QemuSystemTest`` can easily:
+
+ * Customize the command line arguments given to the convenience
+ ``self.vm`` attribute (a QEMUMachine instance)
+
+ * Interact with the QEMU monitor, send QMP commands and check
+ their results
+
+ * Interact with the guest OS, using the convenience console device
+ (which may be useful to assert the effectiveness and correctness of
+ command line arguments or QMP commands)
+
+ * Interact with external data files that accompany the test itself
+ (see ``self.get_data()``)
+
+ * Download (and cache) remote data files, such as firmware and kernel
+ images
+
+ * Have access to a library of guest OS images (by means of the
+ ``avocado.utils.vmimage`` library)
+
+ * Make use of various other test related utilities available at the
+ test class itself and at the utility library:
+
+ - http://avocado-framework.readthedocs.io/en/latest/api/test/avocado.html#avocado.Test
+ - http://avocado-framework.readthedocs.io/en/latest/api/utils/avocado.utils.html
+
+Running tests
+-------------
+
+You can run the avocado tests simply by executing:
+
+.. code::
+
+ make check-avocado
+
+This involves the automatic installation, from PyPI, of all the
+necessary avocado-framework dependencies into the QEMU venv within the
+build tree (at ``./pyvenv``). Test results are also saved within the
+build tree (at ``tests/results``).
+
+Note: the build environment must be using a Python 3 stack, and have
+the ``venv`` and ``pip`` packages installed. If necessary, make sure
+``configure`` is called with ``--python=`` and that those modules are
+available. On Debian and Ubuntu based systems, depending on the
+specific version, they may be on packages named ``python3-venv`` and
+``python3-pip``.
+
+It is also possible to run tests based on tags using the
+``make check-avocado`` command and the ``AVOCADO_TAGS`` environment
+variable:
+
+.. code::
+
+ make check-avocado AVOCADO_TAGS=quick
+
+Note that tags separated with commas have an AND behavior, while tags
+separated by spaces have an OR behavior. For more information on Avocado
+tags, see:
+
+ https://avocado-framework.readthedocs.io/en/latest/guides/user/chapters/tags.html
+
+To run a single test file, a couple of them, or a test within a file
+using the ``make check-avocado`` command, set the ``AVOCADO_TESTS``
+environment variable with the test files or test names. To run all
+tests from a single file, use:
+
+ .. code::
+
+ make check-avocado AVOCADO_TESTS=$FILEPATH
+
+The same is valid to run tests from multiple test files:
+
+ .. code::
+
+ make check-avocado AVOCADO_TESTS='$FILEPATH1 $FILEPATH2'
+
+To run a single test within a file, use:
+
+ .. code::
+
+ make check-avocado AVOCADO_TESTS=$FILEPATH:$TESTCLASS.$TESTNAME
+
+The same is valid to run single tests from multiple test files:
+
+ .. code::
+
+ make check-avocado AVOCADO_TESTS='$FILEPATH1:$TESTCLASS1.$TESTNAME1 $FILEPATH2:$TESTCLASS2.$TESTNAME2'
+
+The scripts installed inside the virtual environment may be used
+without an "activation". For instance, the Avocado test runner
+may be invoked by running:
+
+ .. code::
+
+ pyvenv/bin/avocado run $OPTION1 $OPTION2 tests/avocado/
+
+Note that if ``make check-avocado`` was not executed before, it is
+possible to create the Python virtual environment with the dependencies
+needed running:
+
+ .. code::
+
+ make check-venv
+
+It is also possible to run tests from a single file or a single test within
+a test file. To run tests from a single file within the build tree, use:
+
+ .. code::
+
+ pyvenv/bin/avocado run tests/avocado/$TESTFILE
+
+To run a single test within a test file, use:
+
+ .. code::
+
+ pyvenv/bin/avocado run tests/avocado/$TESTFILE:$TESTCLASS.$TESTNAME
+
+Valid test names are visible in the output from any previous execution
+of Avocado or ``make check-avocado``, and can also be queried using:
+
+ .. code::
+
+ pyvenv/bin/avocado list tests/avocado
+
+Manual Installation
+-------------------
+
+To manually install Avocado and its dependencies, run:
+
+.. code::
+
+ pip install --user avocado-framework
+
+Alternatively, follow the instructions on this link:
+
+ https://avocado-framework.readthedocs.io/en/latest/guides/user/chapters/installing.html
+
+Overview
+--------
+
+The ``tests/avocado/avocado_qemu`` directory provides the
+``avocado_qemu`` Python module, containing the ``avocado_qemu.QemuSystemTest``
+class. Here's a simple usage example:
+
+.. code::
+
+ from avocado_qemu import QemuSystemTest
+
+
+ class Version(QemuSystemTest):
+ """
+ :avocado: tags=quick
+ """
+ def test_qmp_human_info_version(self):
+ self.vm.launch()
+ res = self.vm.cmd('human-monitor-command',
+ command_line='info version')
+ self.assertRegex(res, r'^(\d+\.\d+\.\d)')
+
+To execute your test, run:
+
+.. code::
+
+ avocado run version.py
+
+Tests may be classified according to a convention by using docstring
+directives such as ``:avocado: tags=TAG1,TAG2``. To run all tests
+in the current directory, tagged as "quick", run:
+
+.. code::
+
+ avocado run -t quick .
+
+The ``avocado_qemu.QemuSystemTest`` base test class
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``avocado_qemu.QemuSystemTest`` class has a number of characteristics
+that are worth being mentioned right away.
+
+First of all, it attempts to give each test a ready to use QEMUMachine
+instance, available at ``self.vm``. Because many tests will tweak the
+QEMU command line, launching the QEMUMachine (by using ``self.vm.launch()``)
+is left to the test writer.
+
+The base test class has also support for tests with more than one
+QEMUMachine. The way to get machines is through the ``self.get_vm()``
+method which will return a QEMUMachine instance. The ``self.get_vm()``
+method accepts arguments that will be passed to the QEMUMachine creation
+and also an optional ``name`` attribute so you can identify a specific
+machine and get it more than once through the tests methods. A simple
+and hypothetical example follows:
+
+.. code::
+
+ from avocado_qemu import QemuSystemTest
+
+
+ class MultipleMachines(QemuSystemTest):
+ def test_multiple_machines(self):
+ first_machine = self.get_vm()
+ second_machine = self.get_vm()
+ self.get_vm(name='third_machine').launch()
+
+ first_machine.launch()
+ second_machine.launch()
+
+ first_res = first_machine.cmd(
+ 'human-monitor-command',
+ command_line='info version')
+
+ second_res = second_machine.cmd(
+ 'human-monitor-command',
+ command_line='info version')
+
+ third_res = self.get_vm(name='third_machine').cmd(
+ 'human-monitor-command',
+ command_line='info version')
+
+ self.assertEqual(first_res, second_res, third_res)
+
+At test "tear down", ``avocado_qemu.QemuSystemTest`` handles all the
+QEMUMachines shutdown.
+
+The ``avocado_qemu.LinuxTest`` base test class
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``avocado_qemu.LinuxTest`` is further specialization of the
+``avocado_qemu.QemuSystemTest`` class, so it contains all the characteristics
+of the later plus some extra features.
+
+First of all, this base class is intended for tests that need to
+interact with a fully booted and operational Linux guest. At this
+time, it uses a Fedora 31 guest image. The most basic example looks
+like this:
+
+.. code::
+
+ from avocado_qemu import LinuxTest
+
+
+ class SomeTest(LinuxTest):
+
+ def test(self):
+ self.launch_and_wait()
+ self.ssh_command('some_command_to_be_run_in_the_guest')
+
+Please refer to tests that use ``avocado_qemu.LinuxTest`` under
+``tests/avocado`` for more examples.
+
+QEMUMachine
+-----------
+
+The QEMUMachine API is already widely used in the Python iotests,
+device-crash-test and other Python scripts. It's a wrapper around the
+execution of a QEMU binary, giving its users:
+
+ * the ability to set command line arguments to be given to the QEMU
+ binary
+
+ * a ready to use QMP connection and interface, which can be used to
+ send commands and inspect its results, as well as asynchronous
+ events
+
+ * convenience methods to set commonly used command line arguments in
+ a more succinct and intuitive way
+
+QEMU binary selection
+^^^^^^^^^^^^^^^^^^^^^
+
+The QEMU binary used for the ``self.vm`` QEMUMachine instance will
+primarily depend on the value of the ``qemu_bin`` parameter. If it's
+not explicitly set, its default value will be the result of a dynamic
+probe in the same source tree. A suitable binary will be one that
+targets the architecture matching host machine.
+
+Based on this description, test writers will usually rely on one of
+the following approaches:
+
+1) Set ``qemu_bin``, and use the given binary
+
+2) Do not set ``qemu_bin``, and use a QEMU binary named like
+ "qemu-system-${arch}", either in the current
+ working directory, or in the current source tree.
+
+The resulting ``qemu_bin`` value will be preserved in the
+``avocado_qemu.QemuSystemTest`` as an attribute with the same name.
+
+Attribute reference
+-------------------
+
+Test
+^^^^
+
+Besides the attributes and methods that are part of the base
+``avocado.Test`` class, the following attributes are available on any
+``avocado_qemu.QemuSystemTest`` instance.
+
+vm
+""
+
+A QEMUMachine instance, initially configured according to the given
+``qemu_bin`` parameter.
+
+arch
+""""
+
+The architecture can be used on different levels of the stack, e.g. by
+the framework or by the test itself. At the framework level, it will
+currently influence the selection of a QEMU binary (when one is not
+explicitly given).
+
+Tests are also free to use this attribute value, for their own needs.
+A test may, for instance, use the same value when selecting the
+architecture of a kernel or disk image to boot a VM with.
+
+The ``arch`` attribute will be set to the test parameter of the same
+name. If one is not given explicitly, it will either be set to
+``None``, or, if the test is tagged with one (and only one)
+``:avocado: tags=arch:VALUE`` tag, it will be set to ``VALUE``.
+
+cpu
+"""
+
+The cpu model that will be set to all QEMUMachine instances created
+by the test.
+
+The ``cpu`` attribute will be set to the test parameter of the same
+name. If one is not given explicitly, it will either be set to
+``None ``, or, if the test is tagged with one (and only one)
+``:avocado: tags=cpu:VALUE`` tag, it will be set to ``VALUE``.
+
+machine
+"""""""
+
+The machine type that will be set to all QEMUMachine instances created
+by the test.
+
+The ``machine`` attribute will be set to the test parameter of the same
+name. If one is not given explicitly, it will either be set to
+``None``, or, if the test is tagged with one (and only one)
+``:avocado: tags=machine:VALUE`` tag, it will be set to ``VALUE``.
+
+qemu_bin
+""""""""
+
+The preserved value of the ``qemu_bin`` parameter or the result of the
+dynamic probe for a QEMU binary in the current working directory or
+source tree.
+
+LinuxTest
+^^^^^^^^^
+
+Besides the attributes present on the ``avocado_qemu.QemuSystemTest`` base
+class, the ``avocado_qemu.LinuxTest`` adds the following attributes:
+
+distro
+""""""
+
+The name of the Linux distribution used as the guest image for the
+test. The name should match the **Provider** column on the list
+of images supported by the avocado.utils.vmimage library:
+
+https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images
+
+distro_version
+""""""""""""""
+
+The version of the Linux distribution as the guest image for the
+test. The name should match the **Version** column on the list
+of images supported by the avocado.utils.vmimage library:
+
+https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images
+
+distro_checksum
+"""""""""""""""
+
+The sha256 hash of the guest image file used for the test.
+
+If this value is not set in the code or by a test parameter (with the
+same name), no validation on the integrity of the image will be
+performed.
+
+Parameter reference
+-------------------
+
+To understand how Avocado parameters are accessed by tests, and how
+they can be passed to tests, please refer to::
+
+ https://avocado-framework.readthedocs.io/en/latest/guides/writer/chapters/writing.html#accessing-test-parameters
+
+Parameter values can be easily seen in the log files, and will look
+like the following:
+
+.. code::
+
+ PARAMS (key=qemu_bin, path=*, default=./qemu-system-x86_64) => './qemu-system-x86_64
+
+Test
+^^^^
+
+arch
+""""
+
+The architecture that will influence the selection of a QEMU binary
+(when one is not explicitly given).
+
+Tests are also free to use this parameter value, for their own needs.
+A test may, for instance, use the same value when selecting the
+architecture of a kernel or disk image to boot a VM with.
+
+This parameter has a direct relation with the ``arch`` attribute. If
+not given, it will default to None.
+
+cpu
+"""
+
+The cpu model that will be set to all QEMUMachine instances created
+by the test.
+
+machine
+"""""""
+
+The machine type that will be set to all QEMUMachine instances created
+by the test.
+
+qemu_bin
+""""""""
+
+The exact QEMU binary to be used on QEMUMachine.
+
+LinuxTest
+^^^^^^^^^
+
+Besides the parameters present on the ``avocado_qemu.QemuSystemTest`` base
+class, the ``avocado_qemu.LinuxTest`` adds the following parameters:
+
+distro
+""""""
+
+The name of the Linux distribution used as the guest image for the
+test. The name should match the **Provider** column on the list
+of images supported by the avocado.utils.vmimage library:
+
+https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images
+
+distro_version
+""""""""""""""
+
+The version of the Linux distribution as the guest image for the
+test. The name should match the **Version** column on the list
+of images supported by the avocado.utils.vmimage library:
+
+https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images
+
+distro_checksum
+"""""""""""""""
+
+The sha256 hash of the guest image file used for the test.
+
+If this value is not set in the code or by this parameter no
+validation on the integrity of the image will be performed.
+
+Skipping tests
+--------------
+
+The Avocado framework provides Python decorators which allow for easily skip
+tests running under certain conditions. For example, on the lack of a binary
+on the test system or when the running environment is a CI system. For further
+information about those decorators, please refer to::
+
+ https://avocado-framework.readthedocs.io/en/latest/guides/writer/chapters/writing.html#skipping-tests
+
+While the conditions for skipping tests are often specifics of each one, there
+are recurring scenarios identified by the QEMU developers and the use of
+environment variables became a kind of standard way to enable/disable tests.
+
+Here is a list of the most used variables:
+
+AVOCADO_ALLOW_LARGE_STORAGE
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Tests which are going to fetch or produce assets considered *large* are not
+going to run unless that ``AVOCADO_ALLOW_LARGE_STORAGE=1`` is exported on
+the environment.
+
+The definition of *large* is a bit arbitrary here, but it usually means an
+asset which occupies at least 1GB of size on disk when uncompressed.
+
+SPEED
+^^^^^
+Tests which have a long runtime will not be run unless ``SPEED=slow`` is
+exported on the environment.
+
+The definition of *long* is a bit arbitrary here, and it depends on the
+usefulness of the test too. A unique test is worth spending more time on,
+small variations on existing tests perhaps less so. As a rough guide,
+a test or set of similar tests which take more than 100 seconds to
+complete.
+
+AVOCADO_ALLOW_UNTRUSTED_CODE
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+There are tests which will boot a kernel image or firmware that can be
+considered not safe to run on the developer's workstation, thus they are
+skipped by default. The definition of *not safe* is also arbitrary but
+usually it means a blob which either its source or build process aren't
+public available.
+
+You should export ``AVOCADO_ALLOW_UNTRUSTED_CODE=1`` on the environment in
+order to allow tests which make use of those kind of assets.
+
+AVOCADO_TIMEOUT_EXPECTED
+^^^^^^^^^^^^^^^^^^^^^^^^
+The Avocado framework has a timeout mechanism which interrupts tests to avoid the
+test suite of getting stuck. The timeout value can be set via test parameter or
+property defined in the test class, for further details::
+
+ https://avocado-framework.readthedocs.io/en/latest/guides/writer/chapters/writing.html#setting-a-test-timeout
+
+Even though the timeout can be set by the test developer, there are some tests
+that may not have a well-defined limit of time to finish under certain
+conditions. For example, tests that take longer to execute when QEMU is
+compiled with debug flags. Therefore, the ``AVOCADO_TIMEOUT_EXPECTED`` variable
+has been used to determine whether those tests should run or not.
+
+QEMU_TEST_FLAKY_TESTS
+^^^^^^^^^^^^^^^^^^^^^
+Some tests are not working reliably and thus are disabled by default.
+This includes tests that don't run reliably on GitLab's CI which
+usually expose real issues that are rarely seen on developer machines
+due to the constraints of the CI environment. If you encounter a
+similar situation then raise a bug and then mark the test as shown on
+the code snippet below:
+
+.. code::
+
+ # See https://gitlab.com/qemu-project/qemu/-/issues/nnnn
+ @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
+ def test(self):
+ do_something()
+
+You can also add ``:avocado: tags=flaky`` to the test meta-data so
+only the flaky tests can be run as a group:
+
+.. code::
+
+ env QEMU_TEST_FLAKY_TESTS=1 ./pyvenv/bin/avocado \
+ run tests/avocado -filter-by-tags=flaky
+
+Tests should not live in this state forever and should either be fixed
+or eventually removed.
+
+
+Uninstalling Avocado
+--------------------
+
+If you've followed the manual installation instructions above, you can
+easily uninstall Avocado. Start by listing the packages you have
+installed::
+
+ pip list --user
+
+And remove any package you want with::
+
+ pip uninstall <package_name>
+
+If you've used ``make check-avocado``, the Python virtual environment where
+Avocado is installed will be cleaned up as part of ``make check-clean``.
diff --git a/docs/devel/testing/blkdebug.rst b/docs/devel/testing/blkdebug.rst
new file mode 100644
index 0000000..63887c9
--- /dev/null
+++ b/docs/devel/testing/blkdebug.rst
@@ -0,0 +1,177 @@
+Block I/O error injection using ``blkdebug``
+============================================
+
+..
+ Copyright (C) 2014-2015 Red Hat Inc
+
+ This work is licensed under the terms of the GNU GPL, version 2 or later. See
+ the COPYING file in the top-level directory.
+
+The ``blkdebug`` block driver is a rule-based error injection engine. It can be
+used to exercise error code paths in block drivers including ``ENOSPC`` (out of
+space) and ``EIO``.
+
+This document gives an overview of the features available in ``blkdebug``.
+
+Background
+----------
+Block drivers have many error code paths that handle I/O errors. Image formats
+are especially complex since metadata I/O errors during cluster allocation or
+while updating tables happen halfway through request processing and require
+discipline to keep image files consistent.
+
+Error injection allows test cases to trigger I/O errors at specific points.
+This way, all error paths can be tested to make sure they are correct.
+
+Rules
+-----
+The ``blkdebug`` block driver takes a list of "rules" that tell the error injection
+engine when to fail an I/O request.
+
+Each I/O request is evaluated against the rules. If a rule matches the request
+then its "action" is executed.
+
+Rules can be placed in a configuration file; the configuration file
+follows the same .ini-like format used by QEMU's ``-readconfig`` option, and
+each section of the file represents a rule.
+
+The following configuration file defines a single rule::
+
+ $ cat blkdebug.conf
+ [inject-error]
+ event = "read_aio"
+ errno = "28"
+
+This rule fails all aio read requests with ``ENOSPC`` (28). Note that the errno
+value depends on the host. On Linux, see
+``/usr/include/asm-generic/errno-base.h`` for errno values.
+
+Invoke QEMU as follows::
+
+ $ qemu-system-x86_64
+ -drive if=none,cache=none,file=blkdebug:blkdebug.conf:test.img,id=drive0 \
+ -device virtio-blk-pci,drive=drive0,id=virtio-blk-pci0
+
+Rules support the following attributes:
+
+``event``
+ which type of operation to match (e.g. ``read_aio``, ``write_aio``,
+ ``flush_to_os``, ``flush_to_disk``). See `Events`_ for
+ information on events.
+
+``state``
+ (optional) the engine must be in this state number in order for this
+ rule to match. See `State transitions`_ for information
+ on states.
+
+``errno``
+ the numeric errno value to return when a request matches this rule.
+ The errno values depend on the host since the numeric values are not
+ standardized in the POSIX specification.
+
+``sector``
+ (optional) a sector number that the request must overlap in order to
+ match this rule
+
+``once``
+ (optional, default ``off``) only execute this action on the first
+ matching request
+
+``immediately``
+ (optional, default ``off``) return a NULL ``BlockAIOCB``
+ pointer and fail without an errno instead. This
+ exercises the code path where ``BlockAIOCB`` fails and the
+ caller's ``BlockCompletionFunc`` is not invoked.
+
+Events
+------
+Block drivers provide information about the type of I/O request they are about
+to make so rules can match specific types of requests. For example, the ``qcow2``
+block driver tells ``blkdebug`` when it accesses the L1 table so rules can match
+only L1 table accesses and not other metadata or guest data requests.
+
+The core events are:
+
+``read_aio``
+ guest data read
+
+``write_aio``
+ guest data write
+
+``flush_to_os``
+ write out unwritten block driver state (e.g. cached metadata)
+
+``flush_to_disk``
+ flush the host block device's disk cache
+
+See ``qapi/block-core.json:BlkdebugEvent`` for the full list of events.
+You may need to grep block driver source code to understand the
+meaning of specific events.
+
+State transitions
+-----------------
+There are cases where more power is needed to match a particular I/O request in
+a longer sequence of requests. For example::
+
+ write_aio
+ flush_to_disk
+ write_aio
+
+How do we match the 2nd ``write_aio`` but not the first? This is where state
+transitions come in.
+
+The error injection engine has an integer called the "state" that always starts
+initialized to 1. The state integer is internal to ``blkdebug`` and cannot be
+observed from outside but rules can interact with it for powerful matching
+behavior.
+
+Rules can be conditional on the current state and they can transition to a new
+state.
+
+When a rule's "state" attribute is non-zero then the current state must equal
+the attribute in order for the rule to match.
+
+For example, to match the 2nd write_aio::
+
+ [set-state]
+ event = "write_aio"
+ state = "1"
+ new_state = "2"
+
+ [inject-error]
+ event = "write_aio"
+ state = "2"
+ errno = "5"
+
+The first ``write_aio`` request matches the ``set-state`` rule and transitions from
+state 1 to state 2. Once state 2 has been entered, the ``set-state`` rule no
+longer matches since it requires state 1. But the ``inject-error`` rule now
+matches the next ``write_aio`` request and injects ``EIO`` (5).
+
+State transition rules support the following attributes:
+
+``event``
+ which type of operation to match (e.g. ``read_aio``, ``write_aio``,
+ ``flush_to_os`, ``flush_to_disk``). See `Events`_ for
+ information on events.
+
+``state``
+ (optional) the engine must be in this state number in order for this
+ rule to match
+
+``new_state``
+ transition to this state number
+
+Suspend and resume
+------------------
+Exercising code paths in block drivers may require specific ordering amongst
+concurrent requests. The "breakpoint" feature allows requests to be halted on
+a ``blkdebug`` event and resumed later. This makes it possible to achieve
+deterministic ordering when multiple requests are in flight.
+
+Breakpoints on ``blkdebug`` events are associated with a user-defined ``tag`` string.
+This tag serves as an identifier by which the request can be resumed at a later
+point.
+
+See the ``qemu-io(1)`` ``break``, ``resume``, ``remove_break``, and ``wait_break``
+commands for details.
diff --git a/docs/devel/blkverify.txt b/docs/devel/testing/blkverify.rst
index aca826c..2a71778 100644
--- a/docs/devel/blkverify.txt
+++ b/docs/devel/testing/blkverify.rst
@@ -1,8 +1,10 @@
-= Block driver correctness testing with blkverify =
+Block driver correctness testing with ``blkverify``
+===================================================
-== Introduction ==
+Introduction
+------------
-This document describes how to use the blkverify protocol to test that a block
+This document describes how to use the ``blkverify`` protocol to test that a block
driver is operating correctly.
It is difficult to test and debug block drivers against real guests. Often
@@ -11,12 +13,13 @@ of the executable. Other times obscure errors are raised by a program inside
the guest. These issues are extremely hard to trace back to bugs in the block
driver.
-Blkverify solves this problem by catching data corruption inside QEMU the first
+``blkverify`` solves this problem by catching data corruption inside QEMU the first
time bad data is read and reporting the disk sector that is corrupted.
-== How it works ==
+How it works
+------------
-The blkverify protocol has two child block devices, the "test" device and the
+The ``blkverify`` protocol has two child block devices, the "test" device and the
"raw" device. Read/write operations are mirrored to both devices so their
state should always be in sync.
@@ -25,13 +28,14 @@ contents to the "test" image. The idea is that the "raw" device will handle
read/write operations correctly and not corrupt data. It can be used as a
reference for comparison against the "test" device.
-After a mirrored read operation completes, blkverify will compare the data and
+After a mirrored read operation completes, ``blkverify`` will compare the data and
raise an error if it is not identical. This makes it possible to catch the
first instance where corrupt data is read.
-== Example ==
+Example
+-------
-Imagine raw.img has 0xcd repeated throughout its first sector:
+Imagine raw.img has 0xcd repeated throughout its first sector::
$ ./qemu-io -c 'read -v 0 512' raw.img
00000000: cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd ................
@@ -42,7 +46,7 @@ Imagine raw.img has 0xcd repeated throughout its first sector:
read 512/512 bytes at offset 0
512.000000 bytes, 1 ops; 0.0000 sec (97.656 MiB/sec and 200000.0000 ops/sec)
-And test.img is corrupt, its first sector is zeroed when it shouldn't be:
+And test.img is corrupt, its first sector is zeroed when it shouldn't be::
$ ./qemu-io -c 'read -v 0 512' test.img
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
@@ -53,17 +57,17 @@ And test.img is corrupt, its first sector is zeroed when it shouldn't be:
read 512/512 bytes at offset 0
512.000000 bytes, 1 ops; 0.0000 sec (81.380 MiB/sec and 166666.6667 ops/sec)
-This error is caught by blkverify:
+This error is caught by ``blkverify``::
$ ./qemu-io -c 'read 0 512' blkverify:a.img:b.img
blkverify: read sector_num=0 nb_sectors=4 contents mismatch in sector 0
-A more realistic scenario is verifying the installation of a guest OS:
+A more realistic scenario is verifying the installation of a guest OS::
$ ./qemu-img create raw.img 16G
$ ./qemu-img create -f qcow2 test.qcow2 16G
$ ./qemu-system-x86_64 -cdrom debian.iso \
-drive file=blkverify:raw.img:test.qcow2
-If the installation is aborted when blkverify detects corruption, use qemu-io
+If the installation is aborted when ``blkverify`` detects corruption, use ``qemu-io``
to explore the contents of the disk image at the sector in question.
diff --git a/docs/devel/ci-definitions.rst.inc b/docs/devel/testing/ci-definitions.rst.inc
index 6d5c6fd..6d5c6fd 100644
--- a/docs/devel/ci-definitions.rst.inc
+++ b/docs/devel/testing/ci-definitions.rst.inc
diff --git a/docs/devel/ci-jobs.rst.inc b/docs/devel/testing/ci-jobs.rst.inc
index 3756bbe..3756bbe 100644
--- a/docs/devel/ci-jobs.rst.inc
+++ b/docs/devel/testing/ci-jobs.rst.inc
diff --git a/docs/devel/ci-runners.rst.inc b/docs/devel/testing/ci-runners.rst.inc
index 67b23d3..67b23d3 100644
--- a/docs/devel/ci-runners.rst.inc
+++ b/docs/devel/testing/ci-runners.rst.inc
diff --git a/docs/devel/ci.rst b/docs/devel/testing/ci.rst
index ed88a20..ed88a20 100644
--- a/docs/devel/ci.rst
+++ b/docs/devel/testing/ci.rst
diff --git a/docs/devel/testing/functional.rst b/docs/devel/testing/functional.rst
new file mode 100644
index 0000000..bf6f1bb
--- /dev/null
+++ b/docs/devel/testing/functional.rst
@@ -0,0 +1,338 @@
+.. _checkfunctional-ref:
+
+Functional testing with Python
+==============================
+
+The ``tests/functional`` directory hosts functional tests written in
+Python. They are usually higher level tests, and may interact with
+external resources and with various guest operating systems.
+The functional tests have initially evolved from the Avocado tests, so there
+is a lot of similarity to those tests here (see :ref:`checkavocado-ref` for
+details about the Avocado tests).
+
+The tests should be written in the style of the Python `unittest`_ framework,
+using stdio for the TAP protocol. The folder ``tests/functional/qemu_test``
+provides classes (e.g. the ``QemuBaseTest``, ``QemuUserTest`` and the
+``QemuSystemTest`` classes) and utility functions that help to get your test
+into the right shape, e.g. by replacing the 'stdout' python object to redirect
+the normal output of your test to stderr instead.
+
+Note that if you don't use one of the QemuBaseTest based classes for your
+test, or if you spawn subprocesses from your test, you have to make sure
+that there is no TAP-incompatible output written to stdio, e.g. either by
+prefixing every line with a "# " to mark the output as a TAP comment, or
+e.g. by capturing the stdout output of subprocesses (redirecting it to
+stderr is OK).
+
+Tests based on ``qemu_test.QemuSystemTest`` can easily:
+
+ * Customize the command line arguments given to the convenience
+ ``self.vm`` attribute (a QEMUMachine instance)
+
+ * Interact with the QEMU monitor, send QMP commands and check
+ their results
+
+ * Interact with the guest OS, using the convenience console device
+ (which may be useful to assert the effectiveness and correctness of
+ command line arguments or QMP commands)
+
+ * Download (and cache) remote data files, such as firmware and kernel
+ images
+
+Running tests
+-------------
+
+You can run the functional tests simply by executing:
+
+.. code::
+
+ make check-functional
+
+It is also possible to run tests for a certain target only, for example
+the following line will only run the tests for the x86_64 target:
+
+.. code::
+
+ make check-functional-x86_64
+
+To run a single test file without the meson test runner, you can also
+execute the file directly by specifying two environment variables first,
+the PYTHONPATH that has to include the python folder and the tests/functional
+folder of the source tree, and QEMU_TEST_QEMU_BINARY that has to point
+to the QEMU binary that should be used for the test, for example::
+
+ $ export PYTHONPATH=../python:../tests/functional
+ $ export QEMU_TEST_QEMU_BINARY=$PWD/qemu-system-x86_64
+ $ python3 ../tests/functional/test_file.py
+
+Overview
+--------
+
+The ``tests/functional/qemu_test`` directory provides the ``qemu_test``
+Python module, containing the ``qemu_test.QemuSystemTest`` class.
+Here is a simple usage example:
+
+.. code::
+
+ #!/usr/bin/env python3
+
+ from qemu_test import QemuSystemTest
+
+ class Version(QemuSystemTest):
+
+ def test_qmp_human_info_version(self):
+ self.vm.launch()
+ res = self.vm.cmd('human-monitor-command',
+ command_line='info version')
+ self.assertRegex(res, r'^(\d+\.\d+\.\d)')
+
+ if __name__ == '__main__':
+ QemuSystemTest.main()
+
+By providing the "hash bang" line at the beginning of the script, marking
+the file as executable and by calling into QemuSystemTest.main(), the test
+can also be run stand-alone, without a test runner. OTOH when run via a test
+runner, the QemuSystemTest.main() function takes care of running the test
+functions in the right fassion (e.g. with TAP output that is required by the
+meson test runner).
+
+The ``qemu_test.QemuSystemTest`` base test class
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``qemu_test.QemuSystemTest`` class has a number of characteristics
+that are worth being mentioned.
+
+First of all, it attempts to give each test a ready to use QEMUMachine
+instance, available at ``self.vm``. Because many tests will tweak the
+QEMU command line, launching the QEMUMachine (by using ``self.vm.launch()``)
+is left to the test writer.
+
+The base test class has also support for tests with more than one
+QEMUMachine. The way to get machines is through the ``self.get_vm()``
+method which will return a QEMUMachine instance. The ``self.get_vm()``
+method accepts arguments that will be passed to the QEMUMachine creation
+and also an optional ``name`` attribute so you can identify a specific
+machine and get it more than once through the tests methods. A simple
+and hypothetical example follows:
+
+.. code::
+
+ from qemu_test import QemuSystemTest
+
+ class MultipleMachines(QemuSystemTest):
+ def test_multiple_machines(self):
+ first_machine = self.get_vm()
+ second_machine = self.get_vm()
+ self.get_vm(name='third_machine').launch()
+
+ first_machine.launch()
+ second_machine.launch()
+
+ first_res = first_machine.cmd(
+ 'human-monitor-command',
+ command_line='info version')
+
+ second_res = second_machine.cmd(
+ 'human-monitor-command',
+ command_line='info version')
+
+ third_res = self.get_vm(name='third_machine').cmd(
+ 'human-monitor-command',
+ command_line='info version')
+
+ self.assertEqual(first_res, second_res, third_res)
+
+At test "tear down", ``qemu_test.QemuSystemTest`` handles all the QEMUMachines
+shutdown.
+
+QEMUMachine
+-----------
+
+The QEMUMachine API is already widely used in the Python iotests,
+device-crash-test and other Python scripts. It's a wrapper around the
+execution of a QEMU binary, giving its users:
+
+ * the ability to set command line arguments to be given to the QEMU
+ binary
+
+ * a ready to use QMP connection and interface, which can be used to
+ send commands and inspect its results, as well as asynchronous
+ events
+
+ * convenience methods to set commonly used command line arguments in
+ a more succinct and intuitive way
+
+QEMU binary selection
+^^^^^^^^^^^^^^^^^^^^^
+
+The QEMU binary used for the ``self.vm`` QEMUMachine instance will
+primarily depend on the value of the ``qemu_bin`` class attribute.
+If it is not explicitly set by the test code, its default value will
+be the result the QEMU_TEST_QEMU_BINARY environment variable.
+
+Attribute reference
+-------------------
+
+QemuBaseTest
+^^^^^^^^^^^^
+
+The following attributes are available on any ``qemu_test.QemuBaseTest``
+instance.
+
+arch
+""""
+
+The target architecture of the QEMU binary.
+
+Tests are also free to use this attribute value, for their own needs.
+A test may, for instance, use this value when selecting the architecture
+of a kernel or disk image to boot a VM with.
+
+qemu_bin
+""""""""
+
+The preserved value of the ``QEMU_TEST_QEMU_BINARY`` environment
+variable.
+
+QemuUserTest
+^^^^^^^^^^^^
+
+The QemuUserTest class can be used for running an executable via the
+usermode emulation binaries.
+
+QemuSystemTest
+^^^^^^^^^^^^^^
+
+The QemuSystemTest class can be used for running tests via one of the
+qemu-system-* binaries.
+
+vm
+""
+
+A QEMUMachine instance, initially configured according to the given
+``qemu_bin`` parameter.
+
+cpu
+"""
+
+The cpu model that will be set to all QEMUMachine instances created
+by the test.
+
+machine
+"""""""
+
+The machine type that will be set to all QEMUMachine instances created
+by the test. By using the set_machine() function of the QemuSystemTest
+class to set this attribute, you can automatically check whether the
+machine is available to skip the test in case it is not built into the
+QEMU binary.
+
+Asset handling
+--------------
+
+Many functional tests download assets (e.g. Linux kernels, initrds,
+firmware images, etc.) from the internet to be able to run tests with
+them. This imposes additional challenges to the test framework.
+
+First there is the the problem that some people might not have an
+unconstrained internet connection, so such tests should not be run by
+default when running ``make check``. To accomplish this situation,
+the tests that download files should only be added to the "thorough"
+speed mode in the meson.build file, while the "quick" speed mode is
+fine for functional tests that can be run without downloading files.
+``make check`` then only runs the quick functional tests along with
+the other quick tests from the other test suites. If you choose to
+run only run ``make check-functional``, the "thorough" tests will be
+executed, too. And to run all functional tests along with the others,
+you can use something like::
+
+ make -j$(nproc) check SPEED=thorough
+
+The second problem with downloading files from the internet are time
+constraints. The time for downloading files should not be taken into
+account when the test is running and the timeout of the test is ticking
+(since downloading can be very slow, depending on the network bandwidth).
+This problem is solved by downloading the assets ahead of time, before
+the tests are run. This pre-caching is done with the qemu_test.Asset
+class. To use it in your test, declare an asset in your test class with
+its URL and SHA256 checksum like this::
+
+ ASSET_somename = (
+ ('https://www.qemu.org/assets/images/qemu_head_200.png'),
+ '34b74cad46ea28a2966c1d04e102510daf1fd73e6582b6b74523940d5da029dd')
+
+In your test function, you can then get the file name of the cached
+asset like this::
+
+ def test_function(self):
+ file_path = self.ASSET_somename.fetch()
+
+The pre-caching will be done automatically when running
+``make check-functional`` (but not when running e.g.
+``make check-functional-<target>``). In case you just want to download
+the assets without running the tests, you can do so by running::
+
+ make precache-functional
+
+The cache is populated in the ``~/.cache/qemu/download`` directory by
+default, but the location can be changed by setting the
+``QEMU_TEST_CACHE_DIR`` environment variable.
+
+Skipping tests
+--------------
+
+Since the test framework is based on the common Python unittest framework,
+you can use the usual Python decorators which allow for easily skipping
+tests running under certain conditions, for example, on the lack of a binary
+on the test system or when the running environment is a CI system. For further
+information about those decorators, please refer to:
+
+ https://docs.python.org/3/library/unittest.html#skipping-tests-and-expected-failures
+
+While the conditions for skipping tests are often specifics of each one, there
+are recurring scenarios identified by the QEMU developers and the use of
+environment variables became a kind of standard way to enable/disable tests.
+
+Here is a list of the most used variables:
+
+QEMU_TEST_ALLOW_LARGE_STORAGE
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Tests which are going to fetch or produce assets considered *large* are not
+going to run unless that ``QEMU_TEST_ALLOW_LARGE_STORAGE=1`` is exported on
+the environment.
+
+The definition of *large* is a bit arbitrary here, but it usually means an
+asset which occupies at least 1GB of size on disk when uncompressed.
+
+QEMU_TEST_ALLOW_UNTRUSTED_CODE
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+There are tests which will boot a kernel image or firmware that can be
+considered not safe to run on the developer's workstation, thus they are
+skipped by default. The definition of *not safe* is also arbitrary but
+usually it means a blob which either its source or build process aren't
+public available.
+
+You should export ``QEMU_TEST_ALLOW_UNTRUSTED_CODE=1`` on the environment in
+order to allow tests which make use of those kind of assets.
+
+QEMU_TEST_FLAKY_TESTS
+^^^^^^^^^^^^^^^^^^^^^
+Some tests are not working reliably and thus are disabled by default.
+This includes tests that don't run reliably on GitLab's CI which
+usually expose real issues that are rarely seen on developer machines
+due to the constraints of the CI environment. If you encounter a
+similar situation then raise a bug and then mark the test as shown on
+the code snippet below:
+
+.. code::
+
+ # See https://gitlab.com/qemu-project/qemu/-/issues/nnnn
+ @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
+ def test(self):
+ do_something()
+
+Tests should not live in this state forever and should either be fixed
+or eventually removed.
+
+
+.. _unittest: https://docs.python.org/3/library/unittest.html
diff --git a/docs/devel/fuzzing.rst b/docs/devel/testing/fuzzing.rst
index 3bfcb33..c3ac084 100644
--- a/docs/devel/fuzzing.rst
+++ b/docs/devel/testing/fuzzing.rst
@@ -21,11 +21,12 @@ Building the fuzzers
To build the fuzzers, install a recent version of clang:
Configure with (substitute the clang binaries with the version you installed).
-Here, enable-sanitizers, is optional but it allows us to reliably detect bugs
-such as out-of-bounds accesses, use-after-frees, double-frees etc.::
+Here, enable-asan and enable-ubsan are optional but they allow us to reliably
+detect bugs such as out-of-bounds accesses, uses-after-free, double-frees
+etc.::
- CC=clang-8 CXX=clang++-8 /path/to/configure --enable-fuzzing \
- --enable-sanitizers
+ CC=clang-8 CXX=clang++-8 /path/to/configure \
+ --enable-fuzzing --enable-asan --enable-ubsan
Fuzz targets are built similarly to system targets::
diff --git a/docs/devel/testing/index.rst b/docs/devel/testing/index.rst
new file mode 100644
index 0000000..1171f7d
--- /dev/null
+++ b/docs/devel/testing/index.rst
@@ -0,0 +1,18 @@
+Testing QEMU
+------------
+
+Details about how to test QEMU and how it is integrated into our CI
+testing infrastructure.
+
+.. toctree::
+ :maxdepth: 3
+
+ main
+ qtest
+ functional
+ avocado
+ acpi-bits
+ ci
+ fuzzing
+ blkdebug
+ blkverify
diff --git a/docs/devel/testing.rst b/docs/devel/testing/main.rst
index 23d3f44..91f4dc6 100644
--- a/docs/devel/testing.rst
+++ b/docs/devel/testing/main.rst
@@ -3,13 +3,28 @@
Testing in QEMU
===============
-This document describes the testing infrastructure in QEMU.
+QEMU's testing infrastructure is fairly complex as it covers
+everything from unit testing and exercising specific sub-systems all
+the way to full blown acceptance tests. To get an overview of the
+tests you can run ``make check-help`` from either the source or build
+tree.
+
+Most (but not all) tests are also integrated into the meson build
+system so can be run directly from the build tree, for example:
+
+.. code::
+
+ [./pyvenv/bin/]meson test --suite qemu:softfloat
+
+will run just the softfloat tests.
+
+The rest of this document will cover the details for specific test
+groups.
Testing with "make check"
-------------------------
-The "make check" testing family includes most of the C based tests in QEMU. For
-a quick help, run ``make check-help`` from the source tree.
+The "make check" testing family includes most of the C based tests in QEMU.
The usual way to run these tests is:
@@ -485,12 +500,6 @@ first to contribute the mapping to the ``libvirt-ci`` project:
`CI <https://www.qemu.org/docs/master/devel/ci.html>`__ documentation
page on how to trigger gitlab CI pipelines on your change.
- * Please also trigger gitlab container generation pipelines on your change
- for as many OS distros as practical to make sure that there are no
- obvious breakages when adding the new pre-requisite. Please see
- `CI <https://www.qemu.org/docs/master/devel/ci.html>`__ documentation
- page on how to trigger gitlab CI pipelines on your change.
-
For enterprise distros that default to old, end-of-life versions of the
Python runtime, QEMU uses a separate set of mappings that work with more
recent versions. These can be found in ``tests/lcitool/mappings.yml``.
@@ -619,20 +628,38 @@ Building and Testing with TSan
It is possible to build and test with TSan, with a few additional steps.
These steps are normally done automatically in the docker.
-There is a one time patch needed in clang-9 or clang-10 at this time:
+TSan is supported for clang and gcc.
+One particularity of sanitizers is that all the code, including shared objects
+dependencies, should be built with it.
+In the case of TSan, any synchronization primitive from glib (GMutex for
+instance) will not be recognized, and will lead to false positives.
+
+To build a tsan version of glib:
.. code::
- sed -i 's/^const/static const/g' \
- /usr/lib/llvm-10/lib/clang/10.0.0/include/sanitizer/tsan_interface.h
+ $ git clone --depth=1 --branch=2.81.0 https://github.com/GNOME/glib.git
+ $ cd glib
+ $ CFLAGS="-O2 -g -fsanitize=thread" meson build
+ $ ninja -C build
To configure the build for TSan:
.. code::
- ../configure --enable-tsan --cc=clang-10 --cxx=clang++-10 \
+ ../configure --enable-tsan \
--disable-werror --extra-cflags="-O0"
+When executing qemu, don't forget to point to tsan glib:
+
+.. code::
+
+ $ glib_dir=/path/to/glib
+ $ export LD_LIBRARY_PATH=$glib_dir/build/gio:$glib_dir/build/glib:$glib_dir/build/gmodule:$glib_dir/build/gobject:$glib_dir/build/gthread
+ # check correct version is used
+ $ ldd build/qemu-x86_64 | grep glib
+ $ qemu-system-x86_64 ...
+
The runtime behavior of TSAN is controlled by the TSAN_OPTIONS environment
variable.
@@ -847,46 +874,24 @@ supported. To start the fuzzer, run
Alternatively, some command different from ``qemu-img info`` can be tested, by
changing the ``-c`` option.
-Integration tests using the Avocado Framework
----------------------------------------------
-
-The ``tests/avocado`` directory hosts integration tests. They're usually
-higher level tests, and may interact with external resources and with
-various guest operating systems.
-
-These tests are written using the Avocado Testing Framework (which must
-be installed separately) in conjunction with a the ``avocado_qemu.Test``
-class, implemented at ``tests/avocado/avocado_qemu``.
-
-Tests based on ``avocado_qemu.Test`` can easily:
-
- * Customize the command line arguments given to the convenience
- ``self.vm`` attribute (a QEMUMachine instance)
-
- * Interact with the QEMU monitor, send QMP commands and check
- their results
-
- * Interact with the guest OS, using the convenience console device
- (which may be useful to assert the effectiveness and correctness of
- command line arguments or QMP commands)
+Functional tests using Python
+-----------------------------
- * Interact with external data files that accompany the test itself
- (see ``self.get_data()``)
+The ``tests/functional`` directory hosts functional tests written in
+Python. You can run the functional tests simply by executing:
- * Download (and cache) remote data files, such as firmware and kernel
- images
+.. code::
- * Have access to a library of guest OS images (by means of the
- ``avocado.utils.vmimage`` library)
+ make check-functional
- * Make use of various other test related utilities available at the
- test class itself and at the utility library:
+See :ref:`checkfunctional-ref` for more details.
- - http://avocado-framework.readthedocs.io/en/latest/api/test/avocado.html#avocado.Test
- - http://avocado-framework.readthedocs.io/en/latest/api/utils/avocado.utils.html
+Integration tests using the Avocado Framework
+---------------------------------------------
-Running tests
-~~~~~~~~~~~~~
+The ``tests/avocado`` directory hosts integration tests. They're usually
+higher level tests, and may interact with external resources and with
+various guest operating systems.
You can run the avocado tests simply by executing:
@@ -894,537 +899,8 @@ You can run the avocado tests simply by executing:
make check-avocado
-This involves the automatic installation, from PyPI, of all the
-necessary avocado-framework dependencies into the QEMU venv within the
-build tree (at ``./pyvenv``). Test results are also saved within the
-build tree (at ``tests/results``).
-
-Note: the build environment must be using a Python 3 stack, and have
-the ``venv`` and ``pip`` packages installed. If necessary, make sure
-``configure`` is called with ``--python=`` and that those modules are
-available. On Debian and Ubuntu based systems, depending on the
-specific version, they may be on packages named ``python3-venv`` and
-``python3-pip``.
-
-It is also possible to run tests based on tags using the
-``make check-avocado`` command and the ``AVOCADO_TAGS`` environment
-variable:
-
-.. code::
-
- make check-avocado AVOCADO_TAGS=quick
-
-Note that tags separated with commas have an AND behavior, while tags
-separated by spaces have an OR behavior. For more information on Avocado
-tags, see:
-
- https://avocado-framework.readthedocs.io/en/latest/guides/user/chapters/tags.html
-
-To run a single test file, a couple of them, or a test within a file
-using the ``make check-avocado`` command, set the ``AVOCADO_TESTS``
-environment variable with the test files or test names. To run all
-tests from a single file, use:
-
- .. code::
-
- make check-avocado AVOCADO_TESTS=$FILEPATH
-
-The same is valid to run tests from multiple test files:
-
- .. code::
-
- make check-avocado AVOCADO_TESTS='$FILEPATH1 $FILEPATH2'
-
-To run a single test within a file, use:
-
- .. code::
-
- make check-avocado AVOCADO_TESTS=$FILEPATH:$TESTCLASS.$TESTNAME
-
-The same is valid to run single tests from multiple test files:
-
- .. code::
-
- make check-avocado AVOCADO_TESTS='$FILEPATH1:$TESTCLASS1.$TESTNAME1 $FILEPATH2:$TESTCLASS2.$TESTNAME2'
-
-The scripts installed inside the virtual environment may be used
-without an "activation". For instance, the Avocado test runner
-may be invoked by running:
-
- .. code::
-
- pyvenv/bin/avocado run $OPTION1 $OPTION2 tests/avocado/
-
-Note that if ``make check-avocado`` was not executed before, it is
-possible to create the Python virtual environment with the dependencies
-needed running:
-
- .. code::
-
- make check-venv
-
-It is also possible to run tests from a single file or a single test within
-a test file. To run tests from a single file within the build tree, use:
-
- .. code::
-
- pyvenv/bin/avocado run tests/avocado/$TESTFILE
-
-To run a single test within a test file, use:
-
- .. code::
-
- pyvenv/bin/avocado run tests/avocado/$TESTFILE:$TESTCLASS.$TESTNAME
-
-Valid test names are visible in the output from any previous execution
-of Avocado or ``make check-avocado``, and can also be queried using:
-
- .. code::
-
- pyvenv/bin/avocado list tests/avocado
-
-Manual Installation
-~~~~~~~~~~~~~~~~~~~
-
-To manually install Avocado and its dependencies, run:
-
-.. code::
-
- pip install --user avocado-framework
-
-Alternatively, follow the instructions on this link:
-
- https://avocado-framework.readthedocs.io/en/latest/guides/user/chapters/installing.html
-
-Overview
-~~~~~~~~
-
-The ``tests/avocado/avocado_qemu`` directory provides the
-``avocado_qemu`` Python module, containing the ``avocado_qemu.Test``
-class. Here's a simple usage example:
-
-.. code::
-
- from avocado_qemu import QemuSystemTest
-
-
- class Version(QemuSystemTest):
- """
- :avocado: tags=quick
- """
- def test_qmp_human_info_version(self):
- self.vm.launch()
- res = self.vm.cmd('human-monitor-command',
- command_line='info version')
- self.assertRegex(res, r'^(\d+\.\d+\.\d)')
-
-To execute your test, run:
-
-.. code::
-
- avocado run version.py
-
-Tests may be classified according to a convention by using docstring
-directives such as ``:avocado: tags=TAG1,TAG2``. To run all tests
-in the current directory, tagged as "quick", run:
-
-.. code::
-
- avocado run -t quick .
-
-The ``avocado_qemu.Test`` base test class
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The ``avocado_qemu.Test`` class has a number of characteristics that
-are worth being mentioned right away.
-
-First of all, it attempts to give each test a ready to use QEMUMachine
-instance, available at ``self.vm``. Because many tests will tweak the
-QEMU command line, launching the QEMUMachine (by using ``self.vm.launch()``)
-is left to the test writer.
-
-The base test class has also support for tests with more than one
-QEMUMachine. The way to get machines is through the ``self.get_vm()``
-method which will return a QEMUMachine instance. The ``self.get_vm()``
-method accepts arguments that will be passed to the QEMUMachine creation
-and also an optional ``name`` attribute so you can identify a specific
-machine and get it more than once through the tests methods. A simple
-and hypothetical example follows:
-
-.. code::
-
- from avocado_qemu import QemuSystemTest
-
-
- class MultipleMachines(QemuSystemTest):
- def test_multiple_machines(self):
- first_machine = self.get_vm()
- second_machine = self.get_vm()
- self.get_vm(name='third_machine').launch()
-
- first_machine.launch()
- second_machine.launch()
-
- first_res = first_machine.cmd(
- 'human-monitor-command',
- command_line='info version')
-
- second_res = second_machine.cmd(
- 'human-monitor-command',
- command_line='info version')
-
- third_res = self.get_vm(name='third_machine').cmd(
- 'human-monitor-command',
- command_line='info version')
+See :ref:`checkavocado-ref` for more details.
- self.assertEqual(first_res, second_res, third_res)
-
-At test "tear down", ``avocado_qemu.Test`` handles all the QEMUMachines
-shutdown.
-
-The ``avocado_qemu.LinuxTest`` base test class
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The ``avocado_qemu.LinuxTest`` is further specialization of the
-``avocado_qemu.Test`` class, so it contains all the characteristics of
-the later plus some extra features.
-
-First of all, this base class is intended for tests that need to
-interact with a fully booted and operational Linux guest. At this
-time, it uses a Fedora 31 guest image. The most basic example looks
-like this:
-
-.. code::
-
- from avocado_qemu import LinuxTest
-
-
- class SomeTest(LinuxTest):
-
- def test(self):
- self.launch_and_wait()
- self.ssh_command('some_command_to_be_run_in_the_guest')
-
-Please refer to tests that use ``avocado_qemu.LinuxTest`` under
-``tests/avocado`` for more examples.
-
-QEMUMachine
-~~~~~~~~~~~
-
-The QEMUMachine API is already widely used in the Python iotests,
-device-crash-test and other Python scripts. It's a wrapper around the
-execution of a QEMU binary, giving its users:
-
- * the ability to set command line arguments to be given to the QEMU
- binary
-
- * a ready to use QMP connection and interface, which can be used to
- send commands and inspect its results, as well as asynchronous
- events
-
- * convenience methods to set commonly used command line arguments in
- a more succinct and intuitive way
-
-QEMU binary selection
-^^^^^^^^^^^^^^^^^^^^^
-
-The QEMU binary used for the ``self.vm`` QEMUMachine instance will
-primarily depend on the value of the ``qemu_bin`` parameter. If it's
-not explicitly set, its default value will be the result of a dynamic
-probe in the same source tree. A suitable binary will be one that
-targets the architecture matching host machine.
-
-Based on this description, test writers will usually rely on one of
-the following approaches:
-
-1) Set ``qemu_bin``, and use the given binary
-
-2) Do not set ``qemu_bin``, and use a QEMU binary named like
- "qemu-system-${arch}", either in the current
- working directory, or in the current source tree.
-
-The resulting ``qemu_bin`` value will be preserved in the
-``avocado_qemu.Test`` as an attribute with the same name.
-
-Attribute reference
-~~~~~~~~~~~~~~~~~~~
-
-Test
-^^^^
-
-Besides the attributes and methods that are part of the base
-``avocado.Test`` class, the following attributes are available on any
-``avocado_qemu.Test`` instance.
-
-vm
-''
-
-A QEMUMachine instance, initially configured according to the given
-``qemu_bin`` parameter.
-
-arch
-''''
-
-The architecture can be used on different levels of the stack, e.g. by
-the framework or by the test itself. At the framework level, it will
-currently influence the selection of a QEMU binary (when one is not
-explicitly given).
-
-Tests are also free to use this attribute value, for their own needs.
-A test may, for instance, use the same value when selecting the
-architecture of a kernel or disk image to boot a VM with.
-
-The ``arch`` attribute will be set to the test parameter of the same
-name. If one is not given explicitly, it will either be set to
-``None``, or, if the test is tagged with one (and only one)
-``:avocado: tags=arch:VALUE`` tag, it will be set to ``VALUE``.
-
-cpu
-'''
-
-The cpu model that will be set to all QEMUMachine instances created
-by the test.
-
-The ``cpu`` attribute will be set to the test parameter of the same
-name. If one is not given explicitly, it will either be set to
-``None ``, or, if the test is tagged with one (and only one)
-``:avocado: tags=cpu:VALUE`` tag, it will be set to ``VALUE``.
-
-machine
-'''''''
-
-The machine type that will be set to all QEMUMachine instances created
-by the test.
-
-The ``machine`` attribute will be set to the test parameter of the same
-name. If one is not given explicitly, it will either be set to
-``None``, or, if the test is tagged with one (and only one)
-``:avocado: tags=machine:VALUE`` tag, it will be set to ``VALUE``.
-
-qemu_bin
-''''''''
-
-The preserved value of the ``qemu_bin`` parameter or the result of the
-dynamic probe for a QEMU binary in the current working directory or
-source tree.
-
-LinuxTest
-^^^^^^^^^
-
-Besides the attributes present on the ``avocado_qemu.Test`` base
-class, the ``avocado_qemu.LinuxTest`` adds the following attributes:
-
-distro
-''''''
-
-The name of the Linux distribution used as the guest image for the
-test. The name should match the **Provider** column on the list
-of images supported by the avocado.utils.vmimage library:
-
-https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images
-
-distro_version
-''''''''''''''
-
-The version of the Linux distribution as the guest image for the
-test. The name should match the **Version** column on the list
-of images supported by the avocado.utils.vmimage library:
-
-https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images
-
-distro_checksum
-'''''''''''''''
-
-The sha256 hash of the guest image file used for the test.
-
-If this value is not set in the code or by a test parameter (with the
-same name), no validation on the integrity of the image will be
-performed.
-
-Parameter reference
-~~~~~~~~~~~~~~~~~~~
-
-To understand how Avocado parameters are accessed by tests, and how
-they can be passed to tests, please refer to::
-
- https://avocado-framework.readthedocs.io/en/latest/guides/writer/chapters/writing.html#accessing-test-parameters
-
-Parameter values can be easily seen in the log files, and will look
-like the following:
-
-.. code::
-
- PARAMS (key=qemu_bin, path=*, default=./qemu-system-x86_64) => './qemu-system-x86_64
-
-Test
-^^^^
-
-arch
-''''
-
-The architecture that will influence the selection of a QEMU binary
-(when one is not explicitly given).
-
-Tests are also free to use this parameter value, for their own needs.
-A test may, for instance, use the same value when selecting the
-architecture of a kernel or disk image to boot a VM with.
-
-This parameter has a direct relation with the ``arch`` attribute. If
-not given, it will default to None.
-
-cpu
-'''
-
-The cpu model that will be set to all QEMUMachine instances created
-by the test.
-
-machine
-'''''''
-
-The machine type that will be set to all QEMUMachine instances created
-by the test.
-
-qemu_bin
-''''''''
-
-The exact QEMU binary to be used on QEMUMachine.
-
-LinuxTest
-^^^^^^^^^
-
-Besides the parameters present on the ``avocado_qemu.Test`` base
-class, the ``avocado_qemu.LinuxTest`` adds the following parameters:
-
-distro
-''''''
-
-The name of the Linux distribution used as the guest image for the
-test. The name should match the **Provider** column on the list
-of images supported by the avocado.utils.vmimage library:
-
-https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images
-
-distro_version
-''''''''''''''
-
-The version of the Linux distribution as the guest image for the
-test. The name should match the **Version** column on the list
-of images supported by the avocado.utils.vmimage library:
-
-https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images
-
-distro_checksum
-'''''''''''''''
-
-The sha256 hash of the guest image file used for the test.
-
-If this value is not set in the code or by this parameter no
-validation on the integrity of the image will be performed.
-
-Skipping tests
-~~~~~~~~~~~~~~
-
-The Avocado framework provides Python decorators which allow for easily skip
-tests running under certain conditions. For example, on the lack of a binary
-on the test system or when the running environment is a CI system. For further
-information about those decorators, please refer to::
-
- https://avocado-framework.readthedocs.io/en/latest/guides/writer/chapters/writing.html#skipping-tests
-
-While the conditions for skipping tests are often specifics of each one, there
-are recurring scenarios identified by the QEMU developers and the use of
-environment variables became a kind of standard way to enable/disable tests.
-
-Here is a list of the most used variables:
-
-AVOCADO_ALLOW_LARGE_STORAGE
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Tests which are going to fetch or produce assets considered *large* are not
-going to run unless that ``AVOCADO_ALLOW_LARGE_STORAGE=1`` is exported on
-the environment.
-
-The definition of *large* is a bit arbitrary here, but it usually means an
-asset which occupies at least 1GB of size on disk when uncompressed.
-
-SPEED
-^^^^^
-Tests which have a long runtime will not be run unless ``SPEED=slow`` is
-exported on the environment.
-
-The definition of *long* is a bit arbitrary here, and it depends on the
-usefulness of the test too. A unique test is worth spending more time on,
-small variations on existing tests perhaps less so. As a rough guide,
-a test or set of similar tests which take more than 100 seconds to
-complete.
-
-AVOCADO_ALLOW_UNTRUSTED_CODE
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-There are tests which will boot a kernel image or firmware that can be
-considered not safe to run on the developer's workstation, thus they are
-skipped by default. The definition of *not safe* is also arbitrary but
-usually it means a blob which either its source or build process aren't
-public available.
-
-You should export ``AVOCADO_ALLOW_UNTRUSTED_CODE=1`` on the environment in
-order to allow tests which make use of those kind of assets.
-
-AVOCADO_TIMEOUT_EXPECTED
-^^^^^^^^^^^^^^^^^^^^^^^^
-The Avocado framework has a timeout mechanism which interrupts tests to avoid the
-test suite of getting stuck. The timeout value can be set via test parameter or
-property defined in the test class, for further details::
-
- https://avocado-framework.readthedocs.io/en/latest/guides/writer/chapters/writing.html#setting-a-test-timeout
-
-Even though the timeout can be set by the test developer, there are some tests
-that may not have a well-defined limit of time to finish under certain
-conditions. For example, tests that take longer to execute when QEMU is
-compiled with debug flags. Therefore, the ``AVOCADO_TIMEOUT_EXPECTED`` variable
-has been used to determine whether those tests should run or not.
-
-QEMU_TEST_FLAKY_TESTS
-^^^^^^^^^^^^^^^^^^^^^
-Some tests are not working reliably and thus are disabled by default.
-This includes tests that don't run reliably on GitLab's CI which
-usually expose real issues that are rarely seen on developer machines
-due to the constraints of the CI environment. If you encounter a
-similar situation then raise a bug and then mark the test as shown on
-the code snippet below:
-
-.. code::
-
- # See https://gitlab.com/qemu-project/qemu/-/issues/nnnn
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
- def test(self):
- do_something()
-
-You can also add ``:avocado: tags=flaky`` to the test meta-data so
-only the flaky tests can be run as a group:
-
-.. code::
-
- env QEMU_TEST_FLAKY_TESTS=1 ./pyvenv/bin/avocado \
- run tests/avocado -filter-by-tags=flaky
-
-Tests should not live in this state forever and should either be fixed
-or eventually removed.
-
-
-Uninstalling Avocado
-~~~~~~~~~~~~~~~~~~~~
-
-If you've followed the manual installation instructions above, you can
-easily uninstall Avocado. Start by listing the packages you have
-installed::
-
- pip list --user
-
-And remove any package you want with::
-
- pip uninstall <package_name>
-
-If you've used ``make check-avocado``, the Python virtual environment where
-Avocado is installed will be cleaned up as part of ``make check-clean``.
.. _checktcg-ref:
@@ -1475,6 +951,19 @@ And run with::
Adding ``V=1`` to the invocation will show the details of how to
invoke QEMU for the test which is useful for debugging tests.
+Running individual tests
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Tests can also be run directly from the test build directory. If you
+run ``make help`` from the test build directory you will get a list of
+all the tests that can be run. Please note that same binaries are used
+in multiple tests, for example::
+
+ make run-plugin-test-mmap-with-libinline.so
+
+will run the mmap test with the ``libinline.so`` TCG plugin. The
+gdbstub tests also re-use the test binaries but while exercising gdb.
+
TCG test dependencies
~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/devel/qgraph.rst b/docs/devel/testing/qgraph.rst
index 43342d9..43342d9 100644
--- a/docs/devel/qgraph.rst
+++ b/docs/devel/testing/qgraph.rst
diff --git a/docs/devel/qtest.rst b/docs/devel/testing/qtest.rst
index c5b8546..c5b8546 100644
--- a/docs/devel/qtest.rst
+++ b/docs/devel/testing/qtest.rst
diff --git a/docs/interop/firmware.json b/docs/interop/firmware.json
index 54a1fc6..57f55f6 100644
--- a/docs/interop/firmware.json
+++ b/docs/interop/firmware.json
@@ -14,8 +14,10 @@
# = Firmware
##
-{ 'include' : 'machine.json' }
-{ 'include' : 'block-core.json' }
+{ 'pragma': {
+ 'member-name-exceptions': [
+ 'FirmwareArchitecture' # x86_64
+ ] } }
##
# @FirmwareOSInterface:
@@ -61,6 +63,27 @@
'data' : [ 'flash', 'kernel', 'memory' ] }
##
+# @FirmwareArchitecture:
+#
+# Enumeration of architectures for which Qemu uses additional
+# firmware files.
+#
+# @aarch64: 64-bit Arm.
+#
+# @arm: 32-bit Arm.
+#
+# @i386: 32-bit x86.
+#
+# @loongarch64: 64-bit LoongArch. (since: 7.1)
+#
+# @x86_64: 64-bit x86.
+#
+# Since: 3.0
+##
+{ 'enum' : 'FirmwareArchitecture',
+ 'data' : [ 'aarch64', 'arm', 'i386', 'loongarch64', 'x86_64' ] }
+
+##
# @FirmwareTarget:
#
# Defines the machine types that firmware may execute on.
@@ -81,7 +104,7 @@
# Since: 3.0
##
{ 'struct' : 'FirmwareTarget',
- 'data' : { 'architecture' : 'SysEmuTarget',
+ 'data' : { 'architecture' : 'FirmwareArchitecture',
'machines' : [ 'str' ] } }
##
@@ -201,6 +224,20 @@
'verbose-dynamic', 'verbose-static' ] }
##
+# @FirmwareFormat:
+#
+# Formats that are supported for firmware images.
+#
+# @raw: Raw disk image format.
+#
+# @qcow2: The QCOW2 image format.
+#
+# Since: 3.0
+##
+{ 'enum': 'FirmwareFormat',
+ 'data': [ 'raw', 'qcow2' ] }
+
+##
# @FirmwareFlashFile:
#
# Defines common properties that are necessary for loading a firmware
@@ -219,7 +256,7 @@
##
{ 'struct' : 'FirmwareFlashFile',
'data' : { 'filename' : 'str',
- 'format' : 'BlockdevDriver' } }
+ 'format' : 'FirmwareFormat' } }
##
@@ -433,7 +470,7 @@
#
# Since: 3.0
#
-# Examples:
+# .. qmp-example::
#
# {
# "description": "SeaBIOS",
diff --git a/docs/interop/index.rst b/docs/interop/index.rst
index ed65395..999e44e 100644
--- a/docs/interop/index.rst
+++ b/docs/interop/index.rst
@@ -14,6 +14,9 @@ are useful for making QEMU interoperate with other software.
dbus-vmstate
dbus-display
live-block-operations
+ nbd
+ parallels
+ prl-xml
pr-helper
qmp-spec
qemu-ga
diff --git a/docs/interop/live-block-operations.rst b/docs/interop/live-block-operations.rst
index 691429c..6b549ed 100644
--- a/docs/interop/live-block-operations.rst
+++ b/docs/interop/live-block-operations.rst
@@ -931,8 +931,8 @@ Shutdown the guest, by issuing the ``quit`` QMP command::
}
-Live disk backup --- ``blockdev-backup`` and the deprecated``drive-backup``
----------------------------------------------------------------------------
+Live disk backup --- ``blockdev-backup`` and the deprecated ``drive-backup``
+----------------------------------------------------------------------------
The ``blockdev-backup`` (and the deprecated ``drive-backup``) allows
you to create a point-in-time snapshot.
diff --git a/docs/interop/nbd.rst b/docs/interop/nbd.rst
new file mode 100644
index 0000000..de079d3
--- /dev/null
+++ b/docs/interop/nbd.rst
@@ -0,0 +1,89 @@
+QEMU NBD protocol support
+=========================
+
+QEMU supports the NBD protocol, and has an internal NBD client (see
+``block/nbd.c``), an internal NBD server (see ``blockdev-nbd.c``), and an
+external NBD server tool (see ``qemu-nbd.c``). The common code is placed
+in ``nbd/*``.
+
+The NBD protocol is specified here:
+https://github.com/NetworkBlockDevice/nbd/blob/master/doc/proto.md
+
+The following paragraphs describe some specific properties of NBD
+protocol realization in QEMU.
+
+Metadata namespaces
+-------------------
+
+QEMU supports the ``base:allocation`` metadata context as defined in the
+NBD protocol specification, and also defines an additional metadata
+namespace ``qemu``.
+
+``qemu`` namespace
+------------------
+
+The ``qemu`` namespace currently contains two available metadata context
+types. The first is related to exposing the contents of a dirty
+bitmap alongside the associated disk contents. That metadata context
+is named with the following form::
+
+ qemu:dirty-bitmap:<dirty-bitmap-export-name>
+
+Each dirty-bitmap metadata context defines only one flag for extents
+in reply for ``NBD_CMD_BLOCK_STATUS``:
+
+bit 0:
+ ``NBD_STATE_DIRTY``, set when the extent is "dirty"
+
+The second is related to exposing the source of various extents within
+the image, with a single metadata context named::
+
+ qemu:allocation-depth
+
+In the allocation depth context, the entire 32-bit value represents a
+depth of which layer in a thin-provisioned backing chain provided the
+data (0 for unallocated, 1 for the active layer, 2 for the first
+backing layer, and so forth).
+
+For ``NBD_OPT_LIST_META_CONTEXT`` the following queries are supported
+in addition to the specific ``qemu:allocation-depth`` and
+``qemu:dirty-bitmap:<dirty-bitmap-export-name>``:
+
+``qemu:``
+ returns list of all available metadata contexts in the namespace
+``qemu:dirty-bitmap:``
+ returns list of all available dirty-bitmap metadata contexts
+
+Features by version
+-------------------
+
+The following list documents which qemu version first implemented
+various features (both as a server exposing the feature, and as a
+client taking advantage of the feature when present), to make it
+easier to plan for cross-version interoperability. Note that in
+several cases, the initial release containing a feature may require
+additional patches from the corresponding stable branch to fix bugs in
+the operation of that feature.
+
+2.6
+ ``NBD_OPT_STARTTLS`` with TLS X.509 Certificates
+2.8
+ ``NBD_CMD_WRITE_ZEROES``
+2.10
+ ``NBD_OPT_GO``, ``NBD_INFO_BLOCK``
+2.11
+ ``NBD_OPT_STRUCTURED_REPLY``
+2.12
+ ``NBD_CMD_BLOCK_STATUS`` for ``base:allocation``
+3.0
+ ``NBD_OPT_STARTTLS`` with TLS Pre-Shared Keys (PSK),
+ ``NBD_CMD_BLOCK_STATUS`` for ``qemu:dirty-bitmap:``, ``NBD_CMD_CACHE``
+4.2
+ ``NBD_FLAG_CAN_MULTI_CONN`` for shareable read-only exports,
+ ``NBD_CMD_FLAG_FAST_ZERO``
+5.2
+ ``NBD_CMD_BLOCK_STATUS`` for ``qemu:allocation-depth``
+7.1
+ ``NBD_FLAG_CAN_MULTI_CONN`` for shareable writable exports
+8.2
+ ``NBD_OPT_EXTENDED_HEADERS``, ``NBD_FLAG_BLOCK_STATUS_PAYLOAD``
diff --git a/docs/interop/nbd.txt b/docs/interop/nbd.txt
deleted file mode 100644
index 18efb25..0000000
--- a/docs/interop/nbd.txt
+++ /dev/null
@@ -1,72 +0,0 @@
-QEMU supports the NBD protocol, and has an internal NBD client (see
-block/nbd.c), an internal NBD server (see blockdev-nbd.c), and an
-external NBD server tool (see qemu-nbd.c). The common code is placed
-in nbd/*.
-
-The NBD protocol is specified here:
-https://github.com/NetworkBlockDevice/nbd/blob/master/doc/proto.md
-
-The following paragraphs describe some specific properties of NBD
-protocol realization in QEMU.
-
-= Metadata namespaces =
-
-QEMU supports the "base:allocation" metadata context as defined in the
-NBD protocol specification, and also defines an additional metadata
-namespace "qemu".
-
-== "qemu" namespace ==
-
-The "qemu" namespace currently contains two available metadata context
-types. The first is related to exposing the contents of a dirty
-bitmap alongside the associated disk contents. That metadata context
-is named with the following form:
-
- qemu:dirty-bitmap:<dirty-bitmap-export-name>
-
-Each dirty-bitmap metadata context defines only one flag for extents
-in reply for NBD_CMD_BLOCK_STATUS:
-
- bit 0: NBD_STATE_DIRTY, set when the extent is "dirty"
-
-The second is related to exposing the source of various extents within
-the image, with a single metadata context named:
-
- qemu:allocation-depth
-
-In the allocation depth context, the entire 32-bit value represents a
-depth of which layer in a thin-provisioned backing chain provided the
-data (0 for unallocated, 1 for the active layer, 2 for the first
-backing layer, and so forth).
-
-For NBD_OPT_LIST_META_CONTEXT the following queries are supported
-in addition to the specific "qemu:allocation-depth" and
-"qemu:dirty-bitmap:<dirty-bitmap-export-name>":
-
-* "qemu:" - returns list of all available metadata contexts in the
- namespace.
-* "qemu:dirty-bitmap:" - returns list of all available dirty-bitmap
- metadata contexts.
-
-= Features by version =
-
-The following list documents which qemu version first implemented
-various features (both as a server exposing the feature, and as a
-client taking advantage of the feature when present), to make it
-easier to plan for cross-version interoperability. Note that in
-several cases, the initial release containing a feature may require
-additional patches from the corresponding stable branch to fix bugs in
-the operation of that feature.
-
-* 2.6: NBD_OPT_STARTTLS with TLS X.509 Certificates
-* 2.8: NBD_CMD_WRITE_ZEROES
-* 2.10: NBD_OPT_GO, NBD_INFO_BLOCK
-* 2.11: NBD_OPT_STRUCTURED_REPLY
-* 2.12: NBD_CMD_BLOCK_STATUS for "base:allocation"
-* 3.0: NBD_OPT_STARTTLS with TLS Pre-Shared Keys (PSK),
-NBD_CMD_BLOCK_STATUS for "qemu:dirty-bitmap:", NBD_CMD_CACHE
-* 4.2: NBD_FLAG_CAN_MULTI_CONN for shareable read-only exports,
-NBD_CMD_FLAG_FAST_ZERO
-* 5.2: NBD_CMD_BLOCK_STATUS for "qemu:allocation-depth"
-* 7.1: NBD_FLAG_CAN_MULTI_CONN for shareable writable exports
-* 8.2: NBD_OPT_EXTENDED_HEADERS, NBD_FLAG_BLOCK_STATUS_PAYLOAD
diff --git a/docs/interop/parallels.txt b/docs/interop/parallels.rst
index bb3fadf..7b328a4 100644
--- a/docs/interop/parallels.txt
+++ b/docs/interop/parallels.rst
@@ -1,41 +1,46 @@
-= License =
+Parallels Expandable Image File Format
+======================================
-Copyright (c) 2015 Denis Lunev
-Copyright (c) 2015 Vladimir Sementsov-Ogievskiy
+..
+ Copyright (c) 2015 Denis Lunev
+ Copyright (c) 2015 Vladimir Sementsov-Ogievskiy
-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 work is licensed under the terms of the GNU GPL, version 2 or later.
+ See the COPYING file in the top-level directory.
-= Parallels Expandable Image File Format =
A Parallels expandable image file consists of three consecutive parts:
- * header
- * BAT
- * data area
+
+* header
+* BAT
+* data area
All numbers in a Parallels expandable image are stored in little-endian byte
order.
-== Definitions ==
-
- Sector A 512-byte data chunk.
+Definitions
+-----------
- Cluster A data chunk of the size specified in the image header.
- Currently, the default size is 1MiB (2048 sectors). In previous
- versions, cluster sizes of 63 sectors, 256 and 252 kilobytes were
- used.
+Sector
+ A 512-byte data chunk.
- BAT Block Allocation Table, an entity that contains information for
- guest-to-host I/O data address translation.
+Cluster
+ A data chunk of the size specified in the image header.
+ Currently, the default size is 1MiB (2048 sectors). In previous
+ versions, cluster sizes of 63 sectors, 256 and 252 kilobytes were used.
+BAT
+ Block Allocation Table, an entity that contains information for
+ guest-to-host I/O data address translation.
-== Header ==
+Header
+------
The header is placed at the start of an image and contains the following
-fields:
+fields::
-Bytes:
+ Bytes:
0 - 15: magic
Must contain "WithoutFreeSpace" or "WithouFreSpacExt".
@@ -103,44 +108,46 @@ Bytes:
ext_off must meet the same requirements as cluster offsets
defined by BAT entries (see below).
-
-== BAT ==
+BAT
+---
BAT is placed immediately after the image header. In the file, BAT is a
contiguous array of 32-bit unsigned little-endian integers with
-(bat_entries * 4) bytes size.
+``(bat_entries * 4)`` bytes size.
Each BAT entry contains an offset from the start of the file to the
-corresponding cluster. The offset set in clusters for "WithouFreSpacExt" images
-and in sectors for "WithoutFreeSpace" images.
+corresponding cluster. The offset set in clusters for ``WithouFreSpacExt``
+images and in sectors for ``WithoutFreeSpace`` images.
If a BAT entry is zero, the corresponding cluster is not allocated and should
be considered as filled with zeroes.
Cluster offsets specified by BAT entries must meet the following requirements:
- - the value must not be lower than data offset (provided by header.data_off
- or calculated as specified above),
- - the value must be lower than the desired file size,
- - the value must be unique among all BAT entries,
- - the result of (cluster offset - data offset) must be aligned to cluster
- size.
+- the value must not be lower than data offset (provided by ``header.data_off``
+ or calculated as specified above)
+- the value must be lower than the desired file size
+- the value must be unique among all BAT entries
+- the result of ``(cluster offset - data offset)`` must be aligned to
+ cluster size
-== Data Area ==
+Data Area
+---------
-The data area is an area from the data offset (provided by header.data_off or
-calculated as specified above) to the end of the file. It represents a
+The data area is an area from the data offset (provided by ``header.data_off``
+or calculated as specified above) to the end of the file. It represents a
contiguous array of clusters. Most of them are allocated by the BAT, some may
-be allocated by the ext_off field in the header while other may be allocated by
-extensions. All clusters allocated by ext_off and extensions should meet the
-same requirements as clusters specified by BAT entries.
+be allocated by the ``ext_off`` field in the header while other may be
+allocated by extensions. All clusters allocated by ``ext_off`` and extensions
+should meet the same requirements as clusters specified by BAT entries.
-== Format Extension ==
+Format Extension
+----------------
The Format Extension is an area 1 cluster in size that provides additional
format features. This cluster is addressed by the ext_off field in the header.
-The format of the Format Extension area is the following:
+The format of the Format Extension area is the following::
0 - 7: magic
Must be 0xAB234CEF23DCEA87
@@ -149,10 +156,10 @@ The format of the Format Extension area is the following:
The MD5 checksum of the entire Header Extension cluster except
the first 24 bytes.
- The above are followed by feature sections or "extensions". The last
- extension must be "End of features" (see below).
+The above are followed by feature sections or "extensions". The last
+extension must be "End of features" (see below).
-Each feature section has the following format:
+Each feature section has the following format::
0 - 7: magic
The identifier of the feature:
@@ -183,16 +190,17 @@ Each feature section has the following format:
variable: data (data_size bytes)
- The above is followed by padding to the next 8 bytes boundary, then the
- next extension starts.
+The above is followed by padding to the next 8 bytes boundary, then the
+next extension starts.
- The last extension must be "End of features" with all the fields set to 0.
+The last extension must be "End of features" with all the fields set to 0.
-=== Dirty bitmaps feature ===
+Dirty bitmaps feature
+---------------------
This feature provides a way of storing dirty bitmaps in the image. The fields
-of its data area are:
+of its data area are::
0 - 7: size
The bitmap size, should be equal to disk size in sectors.
@@ -215,7 +223,7 @@ clusters inside the Parallels image file. The offsets of these clusters are
saved in the L1 offset table specified by the feature extension. Each L1 table
entry is a 64 bit integer as described below:
-Given an offset in bytes into the bitmap data, corresponding L1 entry is
+Given an offset in bytes into the bitmap data, corresponding L1 entry is::
l1_table[offset / cluster_size]
@@ -227,6 +235,6 @@ are assumed to be 1.
If an L1 table entry is not 0 or 1, it contains the corresponding cluster
offset (in 512b sectors). Given an offset in bytes into the bitmap data the
-offset in bytes into the image file can be obtained as follows:
+offset in bytes into the image file can be obtained as follows::
offset = l1_table[offset / cluster_size] * 512 + (offset % cluster_size)
diff --git a/docs/interop/prl-xml.rst b/docs/interop/prl-xml.rst
new file mode 100644
index 0000000..5bb63bb
--- /dev/null
+++ b/docs/interop/prl-xml.rst
@@ -0,0 +1,192 @@
+Parallels Disk Format
+=====================
+
+..
+ Copyright (c) 2015-2017, Virtuozzo, Inc.
+ Authors:
+ 2015 Denis Lunev <den@openvz.org>
+ 2015 Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
+ 2016-2017 Klim Kireev <klim.kireev@virtuozzo.com>
+ 2016-2017 Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.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.
+
+This specification contains minimal information about Parallels Disk Format,
+which is enough to properly work with QEMU. Nevertheless, Parallels Cloud Server
+and Parallels Desktop are able to add some unspecified nodes to the xml and use
+them, but they are for internal work and don't affect functionality. Also it
+uses auxiliary xml ``Snapshot.xml``, which allows storage of optional snapshot
+information, but this doesn't influence open/read/write functionality. QEMU and
+other software should not use fields not covered in this document or the
+``Snapshot.xml`` file, and must leave them as is.
+
+A Parallels disk consists of two parts: the set of snapshots and the disk
+descriptor file, which stores information about all files and snapshots.
+
+Definitions
+-----------
+
+Snapshot
+ a record of the contents captured at a particular time, capable
+ of storing current state. A snapshot has a UUID and a parent UUID.
+
+Snapshot image
+ an overlay representing the difference between this
+ snapshot and some earlier snapshot.
+
+Overlay
+ an image storing the different sectors between two captured states.
+
+Root image
+ a snapshot image with no parent, the root of the snapshot tree.
+
+Storage
+ the backing storage for a subset of the virtual disk. When
+ there is more than one storage in a Parallels disk then that
+ is referred to as a split image. In this case every storage
+ covers a specific address space area of the disk and has its
+ particular root image. Split images are not considered here
+ and are not supported. Each storage consists of disk
+ parameters and a list of images. The list of images always
+ contains a root image and may also contain overlays. The
+ root image can be an expandable Parallels image file or
+ plain. Overlays must be expandable.
+
+Description file
+ ``DiskDescriptor.xml`` stores information about disk parameters,
+ snapshots, and storages.
+
+Top Snapshot
+ The overlay between actual state and some previous snapshot.
+ It is not a snapshot in the classical sense because it
+ serves as the active image that the guest writes to.
+
+Sector
+ a 512-byte data chunk.
+
+Description file
+----------------
+
+All information is placed in a single XML element
+``Parallels_disk_image``.
+The element has only one attribute, ``Version``, which must be ``1.0``.
+
+The schema of ``DiskDescriptor.xml``::
+
+ <Parallels_disk_image Version="1.0">
+ <Disk_Parameters>
+ ...
+ </Disk_Parameters>
+ <StorageData>
+ ...
+ </StorageData>
+ <Snapshots>
+ ...
+ </Snapshots>
+ </Parallels_disk_image>
+
+``Disk_Parameters`` element
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``Disk_Parameters`` element describes the physical layout of the
+virtual disk and some general settings.
+
+The ``Disk_Parameters`` element MUST contain the following child elements:
+
+* ``Disk_size`` - number of sectors in the disk,
+ desired size of the disk.
+* ``Cylinders`` - number of the disk cylinders.
+* ``Heads`` - number of the disk heads.
+* ``Sectors`` - number of the disk sectors per cylinder
+ (sector size is 512 bytes)
+ Limitation: The product of the ``Heads``, ``Sectors`` and ``Cylinders``
+ values MUST be equal to the value of the Disk_size parameter.
+* ``Padding`` - must be 0. Parallels Cloud Server and Parallels Desktop may
+ use padding set to 1; however this case is not covered
+ by this specification. QEMU and other software should not open
+ such disks and should not create them.
+
+``StorageData`` element
+^^^^^^^^^^^^^^^^^^^^^^^
+
+This element of the file describes the root image and all snapshot images.
+
+The ``StorageData`` element consists of the ``Storage`` child element,
+as shown below::
+
+ <StorageData>
+ <Storage>
+ ...
+ </Storage>
+ </StorageData>
+
+A ``Storage`` element has the following child elements:
+
+* ``Start`` - start sector of the storage, in case of non split storage
+ equals to 0.
+* ``End`` - number of sector following the last sector, in case of non
+ split storage equals to ``Disk_size``.
+* ``Blocksize`` - storage cluster size, number of sectors per one cluster.
+ The cluster size for each "Compressed" (see below) image in
+ a parallels disk must be equal to this field. Note: the cluster
+ size for a Parallels Expandable Image is in the ``tracks`` field of
+ its header (see :doc:`parallels`).
+* Several ``Image`` child elements.
+
+Each ``Image`` element has the following child elements:
+
+* ``GUID`` - image identifier, UUID in curly brackets.
+ For instance, ``{12345678-9abc-def1-2345-6789abcdef12}.``
+ The GUID is used by the Snapshots element to reference images
+ (see below)
+* ``Type`` - image type of the element. It can be:
+
+ * ``Plain`` for raw files.
+ * ``Compressed`` for expanding disks.
+
+* ``File`` - path to image file. The path can be relative to
+ ``DiskDescriptor.xml`` or absolute.
+
+``Snapshots`` element
+^^^^^^^^^^^^^^^^^^^^^
+
+The ``Snapshots`` element describes the snapshot relations with the snapshot tree.
+
+The element contains the set of ``Shot`` child elements, as shown below::
+
+ <Snapshots>
+ <TopGUID> ... </TopGUID> /* Optional child element */
+ <Shot>
+ ...
+ </Shot>
+ <Shot>
+ ...
+ </Shot>
+ ...
+ </Snapshots>
+
+Each ``Shot`` element contains the following child elements:
+
+* ``GUID`` - an image GUID.
+* ``ParentGUID`` - GUID of the image of the parent snapshot.
+
+The software may traverse snapshots from child to parent using the
+``<ParentGUID>`` field as reference. The ``ParentGUID`` of the root
+snapshot is ``{00000000-0000-0000-0000-000000000000}``.
+There should be only one root snapshot.
+
+The Top snapshot could be
+described via two ways: via the ``TopGUID`` child
+element of the ``Snapshots`` element, or via the predefined GUID
+``{5fbaabe3-6958-40ff-92a7-860e329aab41}``. If ``TopGUID`` is defined,
+the predefined GUID is interpreted as a normal GUID. All snapshot images
+(except the Top Snapshot) should be
+opened read-only.
+
+There is another predefined GUID,
+``BackupID = {704718e1-2314-44c8-9087-d78ed36b0f4e}``, which is used by
+original and some third-party software for backup. QEMU and other
+software may operate with images with ``GUID = BackupID`` as usual.
+However, it is not recommended to use this
+GUID for new disks. The Top snapshot cannot have this GUID.
diff --git a/docs/interop/prl-xml.txt b/docs/interop/prl-xml.txt
deleted file mode 100644
index cf9b3fb..0000000
--- a/docs/interop/prl-xml.txt
+++ /dev/null
@@ -1,158 +0,0 @@
-= License =
-
-Copyright (c) 2015-2017, Virtuozzo, Inc.
-Authors:
- 2015 Denis Lunev <den@openvz.org>
- 2015 Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
- 2016-2017 Klim Kireev <klim.kireev@virtuozzo.com>
- 2016-2017 Edgar Kaziakhmedov <edgar.kaziakhmedov@virtuozzo.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.
-
-This specification contains minimal information about Parallels Disk Format,
-which is enough to proper work with QEMU. Nevertheless, Parallels Cloud Server
-and Parallels Desktop are able to add some unspecified nodes to xml and use
-them, but they are for internal work and don't affect functionality. Also it
-uses auxiliary xml "Snapshot.xml", which allows to store optional snapshot
-information, but it doesn't influence open/read/write functionality. QEMU and
-other software should not use fields not covered in this document and
-Snapshot.xml file and must leave them as is.
-
-= Parallels Disk Format =
-
-Parallels disk consists of two parts: the set of snapshots and the disk
-descriptor file, which stores information about all files and snapshots.
-
-== Definitions ==
- Snapshot a record of the contents captured at a particular time,
- capable of storing current state. A snapshot has UUID and
- parent UUID.
-
- Snapshot image an overlay representing the difference between this
- snapshot and some earlier snapshot.
-
- Overlay an image storing the different sectors between two captured
- states.
-
- Root image snapshot image with no parent, the root of snapshot tree.
-
- Storage the backing storage for a subset of the virtual disk. When
- there is more than one storage in a Parallels disk then that
- is referred to as a split image. In this case every storage
- covers specific address space area of the disk and has its
- particular root image. Split images are not considered here
- and are not supported. Each storage consists of disk
- parameters and a list of images. The list of images always
- contains a root image and may also contain overlays. The
- root image can be an expandable Parallels image file or
- plain. Overlays must be expandable.
-
- Description DiskDescriptor.xml stores information about disk parameters,
- file snapshots, storages.
-
- Top The overlay between actual state and some previous snapshot.
- Snapshot It is not a snapshot in the classical sense because it
- serves as the active image that the guest writes to.
-
- Sector a 512-byte data chunk.
-
-== Description file ==
-All information is placed in a single XML element Parallels_disk_image.
-The element has only one attribute "Version", that must be 1.0.
-Schema of DiskDescriptor.xml:
-
-<Parallels_disk_image Version="1.0">
- <Disk_Parameters>
- ...
- </Disk_Parameters>
- <StorageData>
- ...
- </StorageData>
- <Snapshots>
- ...
- </Snapshots>
-</Parallels_disk_image>
-
-== Disk_Parameters element ==
-The Disk_Parameters element describes the physical layout of the virtual disk
-and some general settings.
-
-The Disk_Parameters element MUST contain the following child elements:
- * Disk_size - number of sectors in the disk,
- desired size of the disk.
- * Cylinders - number of the disk cylinders.
- * Heads - number of the disk heads.
- * Sectors - number of the disk sectors per cylinder
- (sector size is 512 bytes)
- Limitation: Product of the Heads, Sectors and Cylinders
- values MUST be equal to the value of the Disk_size parameter.
- * Padding - must be 0. Parallels Cloud Server and Parallels Desktop may
- use padding set to 1, however this case is not covered
- by this spec, QEMU and other software should not open
- such disks and should not create them.
-
-== StorageData element ==
-This element of the file describes the root image and all snapshot images.
-
-The StorageData element consists of the Storage child element, as shown below:
-<StorageData>
- <Storage>
- ...
- </Storage>
-</StorageData>
-
-A Storage element has following child elements:
- * Start - start sector of the storage, in case of non split storage
- equals to 0.
- * End - number of sector following the last sector, in case of non
- split storage equals to Disk_size.
- * Blocksize - storage cluster size, number of sectors per one cluster.
- Cluster size for each "Compressed" (see below) image in
- parallels disk must be equal to this field. Note: cluster
- size for Parallels Expandable Image is in 'tracks' field of
- its header (see docs/interop/parallels.txt).
- * Several Image child elements.
-
-Each Image element has following child elements:
- * GUID - image identifier, UUID in curly brackets.
- For instance, {12345678-9abc-def1-2345-6789abcdef12}.
- The GUID is used by the Snapshots element to reference images
- (see below)
- * Type - image type of the element. It can be:
- "Plain" for raw files.
- "Compressed" for expanding disks.
- * File - path to image file. Path can be relative to DiskDescriptor.xml or
- absolute.
-
-== Snapshots element ==
-The Snapshots element describes the snapshot relations with the snapshot tree.
-
-The element contains the set of Shot child elements, as shown below:
-<Snapshots>
- <TopGUID> ... </TopGUID> /* Optional child element */
- <Shot>
- ...
- </Shot>
- <Shot>
- ...
- </Shot>
- ...
-</Snapshots>
-
-Each Shot element contains the following child elements:
- * GUID - an image GUID.
- * ParentGUID - GUID of the image of the parent snapshot.
-
-The software may traverse snapshots from child to parent using <ParentGUID>
-field as reference. ParentGUID of root snapshot is
-{00000000-0000-0000-0000-000000000000}. There should be only one root
-snapshot. Top snapshot could be described via two ways: via TopGUID child
-element of the Snapshots element or via predefined GUID
-{5fbaabe3-6958-40ff-92a7-860e329aab41}. If TopGUID is defined, predefined GUID is
-interpreted as usual GUID. All snapshot images (except Top Snapshot) should be
-opened read-only. There is another predefined GUID,
-BackupID = {704718e1-2314-44c8-9087-d78ed36b0f4e}, which is used by original and
-some third-party software for backup, QEMU and other software may operate with
-images with GUID = BackupID as usual, however, it is not recommended to use this
-GUID for new disks. Top snapshot cannot have this GUID.
diff --git a/docs/interop/qemu-ga.rst b/docs/interop/qemu-ga.rst
index 72fb75a..11f7bae 100644
--- a/docs/interop/qemu-ga.rst
+++ b/docs/interop/qemu-ga.rst
@@ -28,11 +28,30 @@ configuration options on the command line. For the same key, the last
option wins, but the lists accumulate (see below for configuration
file format).
+If an allowed RPCs list is defined in the configuration, then all
+RPCs will be blocked by default, except for the allowed list.
+
+If a blocked RPCs list is defined in the configuration, then all
+RPCs will be allowed by default, except for the blocked list.
+
+If both allowed and blocked RPCs lists are defined in the configuration,
+then all RPCs will be blocked by default, then the allowed list will
+be applied, followed by the blocked list.
+
+While filesystems are frozen, all except for a designated safe set
+of RPCs will blocked, regardless of what the general configuration
+declares.
+
Options
-------
.. program:: qemu-ga
+.. option:: -c, --config=PATH
+
+ Configuration file path (the default is |CONFDIR|\ ``/qemu-ga.conf``,
+ unless overridden by the QGA_CONF environment variable)
+
.. option:: -m, --method=METHOD
Transport method: one of ``unix-listen``, ``virtio-serial``, or
@@ -131,6 +150,7 @@ fsfreeze-hook string
statedir string
verbose boolean
block-rpcs string list
+allow-rpcs string list
============= ===========
See also
diff --git a/docs/meson.build b/docs/meson.build
index 9040f86..3676f81 100644
--- a/docs/meson.build
+++ b/docs/meson.build
@@ -54,7 +54,6 @@ if build_docs
'qemu-pr-helper.8': (have_tools ? 'man8' : ''),
'qemu-storage-daemon.1': (have_tools ? 'man1' : ''),
'qemu-trace-stap.1': (stap.found() ? 'man1' : ''),
- 'virtfs-proxy-helper.1': (have_virtfs_proxy_helper ? 'man1' : ''),
'qemu.1': 'man1',
'qemu-block-drivers.7': 'man7',
'qemu-cpu-models.7': 'man7'
@@ -99,3 +98,8 @@ if build_docs
alias_target('html', sphinxdocs)
alias_target('man', sphinxmans)
endif
+
+test('QAPI firmware.json regression tests', qapi_gen,
+ args: ['-o', meson.current_build_dir() / 'qapi',
+ meson.current_source_dir() / 'interop/firmware.json'],
+ suite: ['qapi-schema', 'qapi-interop'])
diff --git a/docs/pcie_sriov.txt b/docs/pcie_sriov.txt
index ab21428..a47aad0 100644
--- a/docs/pcie_sriov.txt
+++ b/docs/pcie_sriov.txt
@@ -52,11 +52,9 @@ setting up a BAR for a VF.
...
/* Add and initialize the SR/IOV capability */
- if (!pcie_sriov_pf_init(d, 0x200, "your_virtual_dev",
- vf_devid, initial_vfs, total_vfs,
- fun_offset, stride, errp)) {
- return;
- }
+ pcie_sriov_pf_init(d, 0x200, "your_virtual_dev",
+ vf_devid, initial_vfs, total_vfs,
+ fun_offset, stride);
/* Set up individual VF BARs (parameters as for normal BARs) */
pcie_sriov_pf_init_vf_bar( ... )
diff --git a/docs/specs/acpi_hw_reduced_hotplug.rst b/docs/specs/acpi_hw_reduced_hotplug.rst
index 0bd3f93..3acd6fc 100644
--- a/docs/specs/acpi_hw_reduced_hotplug.rst
+++ b/docs/specs/acpi_hw_reduced_hotplug.rst
@@ -64,7 +64,8 @@ GED IO interface (4 byte access)
0: Memory hotplug event
1: System power down event
2: NVDIMM hotplug event
- 3-31: Reserved
+ 3: CPU hotplug event
+ 4-31: Reserved
**write_access:**
diff --git a/docs/specs/fw_cfg.rst b/docs/specs/fw_cfg.rst
index 5ad47a9..31ae315 100644
--- a/docs/specs/fw_cfg.rst
+++ b/docs/specs/fw_cfg.rst
@@ -54,11 +54,11 @@ Data Register
-------------
* Read/Write (writes ignored as of QEMU v2.4, but see the DMA interface)
-* Location: platform dependent (IOport [#]_ or MMIO)
+* Location: platform dependent (IOport\ [#placement]_ or MMIO)
* Width: 8-bit (if IOport), 8/16/32/64-bit (if MMIO)
* Endianness: string-preserving
-.. [#]
+.. [#placement]
On platforms where the data register is exposed as an IOport, its
port number will always be one greater than the port number of the
selector register. In other words, the two ports overlap, and can not
diff --git a/docs/specs/index.rst b/docs/specs/index.rst
index 1484e3e..6495ed5 100644
--- a/docs/specs/index.rst
+++ b/docs/specs/index.rst
@@ -29,7 +29,10 @@ guest hardware that is specific to QEMU.
edu
ivshmem-spec
pvpanic
+ spdm
standard-vga
virt-ctlr
vmcoreinfo
vmgenid
+ rapl-msr
+ rocker
diff --git a/docs/specs/pci-ids.rst b/docs/specs/pci-ids.rst
index c0a3dec..328ab31 100644
--- a/docs/specs/pci-ids.rst
+++ b/docs/specs/pci-ids.rst
@@ -77,13 +77,17 @@ PCI devices (other than virtio):
1b36:0008
PCIe host bridge
1b36:0009
- PCI Expander Bridge (-device pxb)
+ PCI Expander Bridge (``-device pxb``)
1b36:000a
PCI-PCI bridge (multiseat)
1b36:000b
- PCIe Expander Bridge (-device pxb-pcie)
+ PCIe Expander Bridge (``-device pxb-pcie``)
+1b36:000c
+ PCIe Root Port (``-device pcie-root-port``)
1b36:000d
PCI xhci usb host adapter
+1b36:000e
+ PCIe-to-PCI bridge (``-device pcie-pci-bridge``)
1b36:000f
mdpy (mdev sample device), ``linux/samples/vfio-mdev/mdpy.c``
1b36:0010
diff --git a/docs/specs/rapl-msr.rst b/docs/specs/rapl-msr.rst
new file mode 100644
index 0000000..aaf0db9
--- /dev/null
+++ b/docs/specs/rapl-msr.rst
@@ -0,0 +1,154 @@
+================
+RAPL MSR support
+================
+
+The RAPL interface (Running Average Power Limit) is advertising the accumulated
+energy consumption of various power domains (e.g. CPU packages, DRAM, etc.).
+
+The consumption is reported via MSRs (model specific registers) like
+MSR_PKG_ENERGY_STATUS for the CPU package power domain. These MSRs are 64 bits
+registers that represent the accumulated energy consumption in micro Joules.
+
+Thanks to KVM's `MSR filtering <msr-filter-patch_>`__ functionality,
+not all MSRs are handled by KVM. Some of them can now be handled by the
+userspace (QEMU); a list of MSRs is given at VM creation time to KVM, and
+a userspace exit occurs when they are accessed.
+
+.. _msr-filter-patch: https://patchwork.kernel.org/project/kvm/patch/20200916202951.23760-7-graf@amazon.com/
+
+At the moment the following MSRs are involved:
+
+.. code:: C
+
+ #define MSR_RAPL_POWER_UNIT 0x00000606
+ #define MSR_PKG_POWER_LIMIT 0x00000610
+ #define MSR_PKG_ENERGY_STATUS 0x00000611
+ #define MSR_PKG_POWER_INFO 0x00000614
+
+The ``*_POWER_UNIT``, ``*_POWER_LIMIT``, ``*_POWER INFO`` are part of the RAPL
+spec and specify the power limit of the package, provide range of parameter(min
+power, max power,..) and also the information of the multiplier for the energy
+counter to calculate the power. Those MSRs are populated once at the beginning
+by reading the host CPU MSRs and are given back to the guest 1:1 when
+requested.
+
+The MSR_PKG_ENERGY_STATUS is a counter; it represents the total amount of
+energy consumed since the last time the register was cleared. If you multiply
+it with the UNIT provided above you'll get the power in micro-joules. This
+counter is always increasing and it increases more or less faster depending on
+the consumption of the package. This counter is supposed to overflow at some
+point.
+
+Each core belonging to the same Package reading the MSR_PKG_ENERGY_STATUS (i.e
+"rdmsr 0x611") will retrieve the same value. The value represents the energy
+for the whole package. Whatever Core reading it will get the same value and a
+core that belongs to PKG-0 will not be able to get the value of PKG-1 and
+vice-versa.
+
+High level implementation
+-------------------------
+
+In order to update the value of the virtual MSR, a QEMU thread is created.
+The thread is basically just an infinity loop that does:
+
+1. Snapshot of the time metrics of all QEMU threads (Time spent scheduled in
+ Userspace and System)
+
+2. Snapshot of the actual MSR_PKG_ENERGY_STATUS counter of all packages where
+ the QEMU threads are running on.
+
+3. Sleep for 1 second - During this pause the vcpu and other non-vcpu threads
+ will do what they have to do and so the energy counter will increase.
+
+4. Repeat 2. and 3. and calculate the delta of every metrics representing the
+ time spent scheduled for each QEMU thread *and* the energy spent by the
+ packages during the pause.
+
+5. Filter the vcpu threads and the non-vcpu threads.
+
+6. Retrieve the topology of the Virtual Machine. This helps identify which
+ vCPU is running on which virtual package.
+
+7. The total energy spent by the non-vcpu threads is divided by the number
+ of vcpu threads so that each vcpu thread will get an equal part of the
+ energy spent by the QEMU workers.
+
+8. Calculate the ratio of energy spent per vcpu threads.
+
+9. Calculate the energy for each virtual package.
+
+10. The virtual MSRs are updated for each virtual package. Each vCPU that
+ belongs to the same package will return the same value when accessing the
+ the MSR.
+
+11. Loop back to 1.
+
+Ratio calculation
+-----------------
+
+In Linux, a process has an execution time associated with it. The scheduler is
+dividing the time in clock ticks. The number of clock ticks per second can be
+found by the sysconf system call. A typical value of clock ticks per second is
+100. So a core can run a process at the maximum of 100 ticks per second. If a
+package has 4 cores, 400 ticks maximum can be scheduled on all the cores
+of the package for a period of 1 second.
+
+`/proc/[pid]/stat <stat_>`__ is a procfs file that can give the executed
+time of a process with the [pid] as the process ID. It gives the amount
+of ticks the process has been scheduled in userspace (utime) and kernel
+space (stime).
+
+.. _stat: https://man7.org/linux/man-pages/man5/proc.5.html
+
+By reading those metrics for a thread, one can calculate the ratio of time the
+package has spent executing the thread.
+
+Example:
+
+A 4 cores package can schedule a maximum of 400 ticks per second with 100 ticks
+per second per core. If a thread was scheduled for 100 ticks between a second
+on this package, that means my thread has been scheduled for 1/4 of the whole
+package. With that, the calculation of the energy spent by the thread on this
+package during this whole second is 1/4 of the total energy spent by the
+package.
+
+Usage
+-----
+
+Currently this feature is only working on an Intel CPU that has the RAPL driver
+mounted and available in the sysfs. if not, QEMU fails at start-up.
+
+This feature is activated with -accel
+kvm,rapl=true,rapl-helper-socket=/path/sock.sock
+
+It is important that the socket path is the same as the one
+:program:`qemu-vmsr-helper` is listening to.
+
+qemu-vmsr-helper
+----------------
+
+The qemu-vmsr-helper is working very much like the qemu-pr-helper. Instead of
+making persistent reservation, qemu-vmsr-helper is here to overcome the
+CVE-2020-8694 which remove user access to the rapl msr attributes.
+
+A socket communication is established between QEMU processes that has the RAPL
+MSR support activated and the qemu-vmsr-helper. A systemd service and socket
+activation is provided in contrib/systemd/qemu-vmsr-helper.(service/socket).
+
+The systemd socket uses 600, like contrib/systemd/qemu-pr-helper.socket. The
+socket can be passed via SCM_RIGHTS by libvirt, or its permissions can be
+changed (e.g. 660 and root:kvm for a Debian system for example). Libvirt could
+also start a separate helper if needed. All in all, the policy is left to the
+user.
+
+See the qemu-pr-helper documentation or manpage for further details.
+
+Current Limitations
+-------------------
+
+- Works only on Intel host CPUs because AMD CPUs are using different MSR
+ addresses.
+
+- Only the Package Power-Plane (MSR_PKG_ENERGY_STATUS) is reported at the
+ moment.
+
diff --git a/docs/specs/rocker.txt b/docs/specs/rocker.rst
index 1857b31..3a7fc6a 100644
--- a/docs/specs/rocker.txt
+++ b/docs/specs/rocker.rst
@@ -1,23 +1,23 @@
Rocker Network Switch Register Programming Guide
-Copyright (c) Scott Feldman <sfeldma@gmail.com>
-Copyright (c) Neil Horman <nhorman@tuxdriver.com>
-Version 0.11, 12/29/2014
+************************************************
-LICENSE
-=======
+..
+ Copyright (c) Scott Feldman <sfeldma@gmail.com>
+ Copyright (c) Neil Horman <nhorman@tuxdriver.com>
+ Version 0.11, 12/29/2014
-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 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.
+ 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.
-SECTION 1: Introduction
-=======================
+Introduction
+============
Overview
--------
@@ -29,25 +29,25 @@ software.
Notations and Conventions
-------------------------
-o In register descriptions, [n:m] indicates a range from bit n to bit m,
-inclusive.
-o Use of leading 0x indicates a hexadecimal number.
-o Use of leading 0b indicates a binary number.
-o The use of RSVD or Reserved indicates that a bit or field is reserved for
-future use.
-o Field width is in bytes, unless otherwise noted.
-o Register are (R) read-only, (R/W) read/write, (W) write-only, or (COR) clear
-on read
-o TLV values in network-byte-order are designated with (N).
+* In register descriptions, [n:m] indicates a range from bit n to bit m,
+ inclusive.
+* Use of leading 0x indicates a hexadecimal number.
+* Use of leading 0b indicates a binary number.
+* The use of RSVD or Reserved indicates that a bit or field is reserved for
+ future use.
+* Field width is in bytes, unless otherwise noted.
+* Register are (R) read-only, (R/W) read/write, (W) write-only, or (COR) clear
+ on read
+* TLV values in network-byte-order are designated with (N).
-SECTION 2: PCI Configuration Registers
-======================================
+PCI Configuration Registers
+===========================
PCI Configuration Space
-----------------------
-Each switch instance registers as a PCI device with PCI configuration space:
+Each switch instance registers as a PCI device with PCI configuration space::
offset width description value
---------------------------------------------
@@ -74,11 +74,10 @@ Each switch instance registers as a PCI device with PCI configuration space:
0x41 1 Retry count
0x42 2 Reserved
+ * Assigned by sub-system implementation
-* Assigned by sub-system implementation
-
-SECTION 3: Memory-Mapped Register Space
-=======================================
+Memory-Mapped Register Space
+============================
There are two memory-mapped BARs. BAR0 maps device register space and is
0x2000 in size. BAR1 maps MSI-X vector and PBA tables and is also 0x2000 in
@@ -89,7 +88,7 @@ byte registers with one 4-byte access, and 8 byte registers with either two
4-byte accesses or a single 8-byte access. In the case of two 4-byte accesses,
access must be lower and then upper 4-bytes, in that order.
-BAR0 device register space is organized as follows:
+BAR0 device register space is organized as follows::
offset description
------------------------------------------------------
@@ -105,7 +104,7 @@ Reads to reserved registers read back as 0.
No fancy stuff like write-combining is enabled on any of the registers.
-BAR1 MSI-X register space is organized as follows:
+BAR1 MSI-X register space is organized as follows::
offset description
------------------------------------------------------
@@ -113,8 +112,8 @@ BAR1 MSI-X register space is organized as follows:
0x1000-0x1fff MSI-X PBA table
-SECTION 4: Interrupts, DMA, and Endianness
-==========================================
+Interrupts, DMA, and Endianness
+===============================
PCI Interrupts
--------------
@@ -122,7 +121,7 @@ PCI Interrupts
The device supports only MSI-X interrupts. BAR1 memory-mapped region contains
the MSI-X vector and PBA tables, with support for up to 256 MSI-X vectors.
-The vector assignment is:
+The vector assignment is::
vector description
-----------------------------------------------------
@@ -134,7 +133,7 @@ The vector assignment is:
Tx vector is even
Rx vector is odd
-A MSI-X vector table entry is 16 bytes:
+A MSI-X vector table entry is 16 bytes::
field offset width description
-------------------------------------------------------------
@@ -170,7 +169,7 @@ ring, and hardware will set this bit when the descriptor is complete.
Descriptor ring sizes must be a power of 2 and range from 2 to 64K entries.
Descriptor rings' base address must be 8-byte aligned. Descriptors must be
packed within ring. Each descriptor in each ring must also be aligned on an 8
-byte boundary. Each descriptor ring will have these registers:
+byte boundary. Each descriptor ring will have these registers::
DMA_DESC_xxx_BASE_ADDR, offset 0x1000 + (x * 32), 64-bit, (R/W)
DMA_DESC_xxx_SIZE, offset 0x1008 + (x * 32), 32-bit, (R/W)
@@ -180,7 +179,7 @@ byte boundary. Each descriptor ring will have these registers:
DMA_DESC_xxx_CREDITS, offset 0x1018 + (x * 32), 32-bit, (R/W)
DMA_DESC_xxx_RSVD1, offset 0x101c + (x * 32), 32-bit, (R/W)
-Where x is descriptor ring index:
+Where x is descriptor ring index::
index ring
--------------------
@@ -203,14 +202,14 @@ written past TAIL. To do so would wrap the ring. An empty ring is when HEAD
== TAIL. A full ring is when HEAD is one position behind TAIL. Both HEAD and
TAIL increment and modulo wrap at the ring size.
-CTRL register bits:
+CTRL register bits::
bit name description
------------------------------------------------------------------------
[0] CTRL_RESET Reset the descriptor ring
[1:31] Reserved
-All descriptor types share some common fields:
+All descriptor types share some common fields::
field width description
-------------------------------------------------------------------
@@ -234,7 +233,7 @@ filled in by the switch. Likewise, the switch will ignore unknown fields
filled in by software.
Descriptor payload buffer is 8-byte aligned and TLVs are 8-byte aligned. The
-value within a TLV is also 8-byte aligned. The (packed, 8 byte) TLV header is:
+value within a TLV is also 8-byte aligned. The (packed, 8 byte) TLV header is::
field width description
-----------------------------
@@ -246,7 +245,7 @@ The alignment requirements for descriptors and TLVs are to avoid unaligned
access exceptions in software. Note that the payload for each TLV is also
8 byte aligned.
-Figure 1 shows an example descriptor buffer with two TLVs.
+Figure 1 shows an example descriptor buffer with two TLVs::
<------- 8 bytes ------->
@@ -316,11 +315,11 @@ network packet data. All non-network-packet TLV multi-byte values will be LE.
TLV values in network-byte-order are designated with (N).
-SECTION 5: Test Registers
-=========================
+Test Registers
+==============
Rocker has several test registers to support troubleshooting register access,
-interrupt generation, and DMA operations:
+interrupt generation, and DMA operations::
TEST_REG, offset 0x0010, 32-bit (R/W)
TEST_REG64, offset 0x0018, 64-bit (R/W)
@@ -338,7 +337,7 @@ for that vector.
To test basic DMA operations, allocate a DMA-able host buffer and put the
buffer address into TEST_DMA_ADDR and size into TEST_DMA_SIZE. Then, write to
-TEST_DMA_CTRL to manipulate the buffer contents. TEST_DMA_CTRL operations are:
+TEST_DMA_CTRL to manipulate the buffer contents. TEST_DMA_CTRL operations are::
operation value description
-----------------------------------------------------------
@@ -351,14 +350,14 @@ issue exists. In particular, buffers that start on odd-8-byte boundary and/or
span multiple PAGE sizes should be tested.
-SECTION 6: Ports
-================
+Ports
+=====
Physical and Logical Ports
------------------------------------
The switch supports up to 62 physical (front-panel) ports. Register
-PORT_PHYS_COUNT returns the actual number of physical ports available:
+PORT_PHYS_COUNT returns the actual number of physical ports available::
PORT_PHYS_COUNT, offset 0x0304, 32-bit, (R)
@@ -369,7 +368,7 @@ Front-panel ports and logical tunnel ports are mapped into a single 32-bit port
space. A special CPU port is assigned port 0. The front-panel ports are
mapped to ports 1-62. A special loopback port is assigned port 63. Logical
tunnel ports are assigned ports 0x0001000-0x0001ffff.
-To summarize the port assignments:
+To summarize the port assignments::
port mapping
-------------------------------------------------------
@@ -391,14 +390,14 @@ set/get the mode for front-panel ports, see port settings, below.
Port Settings
-------------
-Link status for all front-panel ports is available via PORT_PHYS_LINK_STATUS:
+Link status for all front-panel ports is available via PORT_PHYS_LINK_STATUS::
PORT_PHYS_LINK_STATUS, offset 0x0310, 64-bit, (R)
Value is port bitmap. Bits 0 and 63 always read 0. Bits 1-62
read 1 for link UP and 0 for link DOWN for respective front-panel ports.
-Other properties for front-panel ports are available via DMA CMD descriptors:
+Other properties for front-panel ports are available via DMA CMD descriptors::
Get PORT_SETTINGS descriptor:
@@ -438,7 +437,7 @@ Port Enable
-----------
Front-panel ports are initially disabled, which means port ingress and egress
-packets will be dropped. To enable or disable a port, use PORT_PHYS_ENABLE:
+packets will be dropped. To enable or disable a port, use PORT_PHYS_ENABLE::
PORT_PHYS_ENABLE: offset 0x0318, 64-bit, (R/W)
@@ -447,15 +446,15 @@ packets will be dropped. To enable or disable a port, use PORT_PHYS_ENABLE:
Default is 0.
-SECTION 7: Switch Control
-=========================
+Switch Control
+==============
This section covers switch-wide register settings.
Control
-------
-This register is used for low level control of the switch.
+This register is used for low level control of the switch::
CONTROL: offset 0x0300, 32-bit, (W)
@@ -468,18 +467,18 @@ Switch ID
---------
The switch has a SWITCH_ID to be used by software to uniquely identify the
-switch:
+switch::
SWITCH_ID: offset 0x0320, 64-bit, (R)
Value is opaque to switch software and no special encoding is implied.
-SECTION 8: Events
-=================
+Events
+======
Non-I/O asynchronous events from the device are notified to the host using the
-event ring. The TLV structure for events is:
+event ring. The TLV structure for events is::
field width description
---------------------------------------------------
@@ -491,7 +490,7 @@ event ring. The TLV structure for events is:
Link Changed Event
------------------
-When link status changes on a physical port, this event is generated.
+When link status changes on a physical port, this event is generated::
field width description
---------------------------------------------------
@@ -510,6 +509,8 @@ driver should install to the device the MAC/VLAN on the port into the bridge
table. Once installed, the MAC/VLAN is known on the port and this event will
no longer be generated.
+::
+
field width description
---------------------------------------------------
INFO <nest>
@@ -518,8 +519,8 @@ no longer be generated.
VLAN 2 VLAN ID
-SECTION 9: CPU Packet Processing
-================================
+CPU Packet Processing
+=====================
Ingress packets directed to the host CPU for further processing are delivered
in the DMA RX ring. Likewise, host CPU originating packets destined to egress
@@ -540,7 +541,7 @@ software that Tx is complete and software resources (e.g. skb) backing packet
can be released.
Figure 2 shows an example 3-fragment packet queued with one Tx descriptor. A
-TLV is used for each packet fragment.
+TLV is used for each packet fragment::
pkt frag 1
+ā€“ā€“ā€“ā€“ā€“ā€“ā€“+ +ā€“+
@@ -570,7 +571,7 @@ TLV is used for each packet fragment.
fig 2.
-The TLVs for Tx descriptor buffer are:
+The TLVs for Tx descriptor buffer are::
field width description
---------------------------------------------------------------------
@@ -600,7 +601,7 @@ The TLVs for Tx descriptor buffer are:
TX_FRAG_ADDR 8 DMA address of packet fragment
TX_FRAG_LEN 2 Packet fragment length
-Possible status return codes in descriptor on completion are:
+Possible status return codes in descriptor on completion are::
DESC_COMP_ERR reason
--------------------------------------------------------------------
@@ -623,7 +624,7 @@ worst-case packet size. A single Rx descriptor will contain the entire Rx
packet data in one RX_FRAG. Other Rx TLVs describe and hardware offloads
performed on the packet, such as checksum validation.
-The TLVs for Rx descriptor buffer are:
+The TLVs for Rx descriptor buffer are::
field width description
---------------------------------------------------
@@ -649,7 +650,7 @@ The TLVs for Rx descriptor buffer are:
Offload forward RX_FLAG indicates the device has already forwarded the packet
so the host CPU should not also forward the packet.
-Possible status return codes in descriptor on completion are:
+Possible status return codes in descriptor on completion are::
DESC_COMP_ERR reason
--------------------------------------------------------------------
@@ -660,14 +661,14 @@ Possible status return codes in descriptor on completion are:
packet data TLV and other TLVs.
-SECTION 10: OF-DPA Mode
-======================
+OF-DPA Mode
+===========
OF-DPA mode allows the switch to offload flow packet processing functions to
hardware. An OpenFlow controller would communicate with an OpenFlow agent
installed on the switch. The OpenFlow agent would (directly or indirectly)
communicate with the Rocker switch driver, which in turn would program switch
-hardware with flow functionality, as defined in OF-DPA. The block diagram is:
+hardware with flow functionality, as defined in OF-DPA. The block diagram is::
+ā€“ā€“ā€“ā€“ā€“ā€“ā€“ā€“ā€“ā€“ā€“ā€“ā€“ā€“ā€“----ā€“ā€“ā€“+
| OF |
@@ -696,14 +697,14 @@ OF-DPA Flow Table Interface
There are commands to add, modify, delete, and get stats of flow table entries.
The commands are issued using the DMA CMD descriptor ring. The following
-commands are defined:
+commands are defined::
CMD_ADD: add an entry to flow table
CMD_MOD: modify an entry in flow table
CMD_DEL: delete an entry from flow table
CMD_GET_STATS: get stats for flow entry
-TLVs for add and modify commands are:
+TLVs for add and modify commands are::
field width description
----------------------------------------------------
@@ -723,14 +724,14 @@ TLVs for add and modify commands are:
Additional TLVs based on flow table ID:
-Table ID 0: ingress port
+Table ID 0: ingress port::
field width description
----------------------------------------------------
OF_DPA_IN_PPORT 4 ingress physical port number
OF_DPA_GOTO_TBL 2 goto table ID; zero to drop
-Table ID 10: vlan
+Table ID 10: vlan::
field width description
----------------------------------------------------
@@ -740,7 +741,7 @@ Table ID 10: vlan
OF_DPA_GOTO_TBL 2 goto table ID; zero to drop
OF_DPA_NEW_VLAN_ID 2 (N) new vlan ID
-Table ID 20: termination mac
+Table ID 20: termination mac::
field width description
----------------------------------------------------
@@ -757,7 +758,7 @@ Table ID 20: termination mac
OF_DPA_OUT_PPORT 2 if specified, must be
controller, set zero otherwise
-Table ID 30: unicast routing
+Table ID 30: unicast routing::
field width description
----------------------------------------------------
@@ -772,7 +773,7 @@ Table ID 30: unicast routing
OF_DPA_GROUP_ID 4 data for GROUP action must
be an L3 Unicast group entry
-Table ID 40: multicast routing
+Table ID 40: multicast routing::
field width description
----------------------------------------------------
@@ -797,7 +798,7 @@ Table ID 40: multicast routing
OF_DPA_GROUP_ID 4 data for GROUP action must
be an L3 multicast group entry
-Table ID 50: bridging
+Table ID 50: bridging::
field width description
----------------------------------------------------
@@ -818,7 +819,7 @@ Table ID 50: bridging
restricted to CONTROLLER,
set to 0 otherwise
-Table ID 60: acl policy
+Table ID 60: acl policy::
field width description
----------------------------------------------------
@@ -890,7 +891,7 @@ Table ID 60: acl policy
dropped (all other instructions
ignored)
-TLVs for flow delete and get stats command are:
+TLVs for flow delete and get stats command are::
field width description
---------------------------------------------------
@@ -898,7 +899,7 @@ TLVs for flow delete and get stats command are:
OF_DPA_COOKIE 8 Cookie
On completion of get stats command, the descriptor buffer is written back with
-the following TLVs:
+the following TLVs::
field width description
---------------------------------------------------
@@ -906,7 +907,7 @@ the following TLVs:
OF_DPA_STAT_RX_PKTS 8 Received packets
OF_DPA_STAT_TX_PKTS 8 Transmit packets
-Possible status return codes in descriptor on completion are:
+Possible status return codes in descriptor on completion are::
DESC_COMP_ERR command reason
--------------------------------------------------------------------
@@ -928,14 +929,14 @@ Group Table Interface
There are commands to add, modify, delete, and get stats of group table
entries. The commands are issued using the DMA CMD descriptor ring. The
-following commands are defined:
+following commands are defined::
CMD_ADD: add an entry to group table
CMD_MOD: modify an entry in group table
CMD_DEL: delete an entry from group table
CMD_GET_STATS: get stats for group entry
-TLVs for add and modify commands are:
+TLVs for add and modify commands are::
field width description
-----------------------------------------------------------
@@ -969,7 +970,7 @@ TLVs for add and modify commands are:
FLOW_SRC_MAC 6 (types 1, 2, 5)
FLOW_DST_MAC 6 (types 1, 2)
-TLVs for flow delete and get stats command are:
+TLVs for flow delete and get stats command are::
field width description
-----------------------------------------------------------
@@ -977,7 +978,7 @@ TLVs for flow delete and get stats command are:
FLOW_GROUP_ID 2 Flow group ID
On completion of get stats command, the descriptor buffer is written back with
-the following TLVs:
+the following TLVs::
field width description
---------------------------------------------------
@@ -986,7 +987,7 @@ the following TLVs:
FLOW_STAT_REF_COUNT 4 Flow reference count
FLOW_STAT_BUCKET_COUNT 4 Flow bucket count
-Possible status return codes in descriptor on completion are:
+Possible status return codes in descriptor on completion are::
DESC_COMP_ERR command reason
--------------------------------------------------------------------
diff --git a/docs/specs/spdm.rst b/docs/specs/spdm.rst
new file mode 100644
index 0000000..f7de080
--- /dev/null
+++ b/docs/specs/spdm.rst
@@ -0,0 +1,134 @@
+======================================================
+QEMU Security Protocols and Data Models (SPDM) Support
+======================================================
+
+SPDM enables authentication, attestation and key exchange to assist in
+providing infrastructure security enablement. It's a standard published
+by the `DMTF`_.
+
+QEMU supports connecting to a SPDM responder implementation. This allows an
+external application to emulate the SPDM responder logic for an SPDM device.
+
+Setting up a SPDM server
+========================
+
+When using QEMU with SPDM devices QEMU will connect to a server which
+implements the SPDM functionality.
+
+SPDM-Utils
+----------
+
+You can use `SPDM Utils`_ to emulate a responder. This is the simplest method.
+
+SPDM-Utils is a Linux applications to manage, test and develop devices
+supporting DMTF Security Protocol and Data Model (SPDM). It is written in Rust
+and utilises libspdm.
+
+To use SPDM-Utils you will need to do the following steps. Details are included
+in the SPDM-Utils README.
+
+ 1. `Build libspdm`_
+ 2. `Build SPDM Utils`_
+ 3. `Run it as a server`_
+
+spdm-emu
+--------
+
+You can use `spdm emu`_ to model the
+SPDM responder.
+
+.. code-block:: shell
+
+ $ cd spdm-emu
+ $ git submodule init; git submodule update --recursive
+ $ mkdir build; cd build
+ $ cmake -DARCH=x64 -DTOOLCHAIN=GCC -DTARGET=Debug -DCRYPTO=openssl ..
+ $ make -j32
+ $ make copy_sample_key # Build certificates, required for SPDM authentication.
+
+It is worth noting that the certificates should be in compliance with
+PCIe r6.1 sec 6.31.3. This means you will need to add the following to
+openssl.cnf
+
+.. code-block::
+
+ subjectAltName = otherName:2.23.147;UTF8:Vendor=1b36:Device=0010:CC=010802:REV=02:SSVID=1af4:SSID=1100
+ 2.23.147 = ASN1:OID:2.23.147
+
+and then manually regenerate some certificates with:
+
+.. code-block:: shell
+
+ $ openssl req -nodes -newkey ec:param.pem -keyout end_responder.key \
+ -out end_responder.req -sha384 -batch \
+ -subj "/CN=DMTF libspdm ECP384 responder cert"
+
+ $ openssl x509 -req -in end_responder.req -out end_responder.cert \
+ -CA inter.cert -CAkey inter.key -sha384 -days 3650 -set_serial 3 \
+ -extensions v3_end -extfile ../openssl.cnf
+
+ $ openssl asn1parse -in end_responder.cert -out end_responder.cert.der
+
+ $ cat ca.cert.der inter.cert.der end_responder.cert.der > bundle_responder.certchain.der
+
+You can use SPDM-Utils instead as it will generate the correct certificates
+automatically.
+
+The responder can then be launched with
+
+.. code-block:: shell
+
+ $ cd bin
+ $ ./spdm_responder_emu --trans PCI_DOE
+
+Connecting an SPDM NVMe device
+==============================
+
+Once a SPDM server is running we can start QEMU and connect to the server.
+
+For an NVMe device first let's setup a block we can use
+
+.. code-block:: shell
+
+ $ cd qemu-spdm/linux/image
+ $ dd if=/dev/zero of=blknvme bs=1M count=2096 # 2GB NNMe Drive
+
+Then you can add this to your QEMU command line:
+
+.. code-block:: shell
+
+ -drive file=blknvme,if=none,id=mynvme,format=raw \
+ -device nvme,drive=mynvme,serial=deadbeef,spdm_port=2323
+
+At which point QEMU will try to connect to the SPDM server.
+
+Note that if using x64-64 you will want to use the q35 machine instead
+of the default. So the entire QEMU command might look like this
+
+.. code-block:: shell
+
+ qemu-system-x86_64 -M q35 \
+ --kernel bzImage \
+ -drive file=rootfs.ext2,if=virtio,format=raw \
+ -append "root=/dev/vda console=ttyS0" \
+ -net none -nographic \
+ -drive file=blknvme,if=none,id=mynvme,format=raw \
+ -device nvme,drive=mynvme,serial=deadbeef,spdm_port=2323
+
+.. _DMTF:
+ https://www.dmtf.org/standards/SPDM
+
+.. _SPDM Utils:
+ https://github.com/westerndigitalcorporation/spdm-utils
+
+.. _spdm emu:
+ https://github.com/dmtf/spdm-emu
+
+.. _Build libspdm:
+ https://github.com/westerndigitalcorporation/spdm-utils?tab=readme-ov-file#build-libspdm
+
+.. _Build SPDM Utils:
+ https://github.com/westerndigitalcorporation/spdm-utils?tab=readme-ov-file#build-the-binary
+
+.. _Run it as a server:
+ https://github.com/westerndigitalcorporation/spdm-utils#qemu-spdm-device-emulation
diff --git a/docs/sphinx/depfile.py b/docs/sphinx/depfile.py
index afdcbce..e74be6a 100644
--- a/docs/sphinx/depfile.py
+++ b/docs/sphinx/depfile.py
@@ -19,7 +19,7 @@ __version__ = '1.0'
def get_infiles(env):
for x in env.found_docs:
- yield env.doc2path(x)
+ yield str(env.doc2path(x))
yield from ((os.path.join(env.srcdir, dep)
for dep in env.dependencies[x]))
for mod in sys.modules.values():
diff --git a/docs/sphinx/qapidoc.py b/docs/sphinx/qapidoc.py
index 738b245..5f96b46 100644
--- a/docs/sphinx/qapidoc.py
+++ b/docs/sphinx/qapidoc.py
@@ -388,6 +388,7 @@ class QAPISchemaGenRSTVisitor(QAPISchemaVisitor):
self._active_headings[level - 1] += snode
self._active_headings = self._active_headings[:level]
self._active_headings.append(snode)
+ return snode
def _add_node_to_current_heading(self, node):
"""Add the node to whatever the current active heading is"""
@@ -417,13 +418,11 @@ class QAPISchemaGenRSTVisitor(QAPISchemaVisitor):
# the first line of the block)
(heading, _, text) = text.partition('\n')
(leader, _, heading) = heading.partition(' ')
- self._start_new_heading(heading, len(leader))
+ node = self._start_new_heading(heading, len(leader))
if text == '':
return
- node = self._make_section(None)
self._parse_text_into_node(text, node)
- self._add_node_to_current_heading(node)
self._cur_doc = None
def _parse_text_into_node(self, doctext, node):
diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst
index cd9559e..6733ffd 100644
--- a/docs/system/arm/aspeed.rst
+++ b/docs/system/arm/aspeed.rst
@@ -123,6 +123,8 @@ To boot the machine from the flash image, use an MTD drive :
Options specific to Aspeed machines are :
+ * ``boot-emmc`` to set or unset boot from eMMC (AST2600).
+
* ``execute-in-place`` which emulates the boot from the CE0 flash
device by using the FMC controller to load the instructions, and
not simply from RAM. This takes a little longer.
diff --git a/docs/system/arm/cubieboard.rst b/docs/system/arm/cubieboard.rst
index 58c4a2d..90d24c7 100644
--- a/docs/system/arm/cubieboard.rst
+++ b/docs/system/arm/cubieboard.rst
@@ -15,4 +15,5 @@ Emulated devices:
- USB controller
- SATA controller
- TWI (I2C) controller
+- SPI controller
- Watchdog timer
diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst
index 3ab6e72..35f52a5 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -45,6 +45,7 @@ the following architecture extensions:
- FEAT_DotProd (Advanced SIMD dot product instructions)
- FEAT_DoubleFault (Double Fault Extension)
- FEAT_E0PD (Preventing EL0 access to halves of address maps)
+- FEAT_EBF16 (AArch64 Extended BFloat16 instructions)
- FEAT_ECV (Enhanced Counter Virtualization)
- FEAT_EL0 (Support for execution at EL0)
- FEAT_EL1 (Support for execution at EL1)
diff --git a/docs/system/arm/gumstix.rst b/docs/system/arm/gumstix.rst
deleted file mode 100644
index cb37313..0000000
--- a/docs/system/arm/gumstix.rst
+++ /dev/null
@@ -1,21 +0,0 @@
-Gumstix Connex and Verdex (``connex``, ``verdex``)
-==================================================
-
-These machines model the Gumstix Connex and Verdex boards.
-The Connex has a PXA255 CPU and the Verdex has a PXA270.
-
-Implemented devices:
-
- * NOR flash
- * SMC91C111 ethernet
- * Interrupt controller
- * DMA
- * Timer
- * GPIO
- * MMC/SD card
- * Fast infra-red communications port (FIR)
- * LCD controller
- * Synchronous serial ports (SPI)
- * PCMCIA interface
- * I2C
- * I2S
diff --git a/docs/system/arm/mainstone.rst b/docs/system/arm/mainstone.rst
deleted file mode 100644
index 05310f4..0000000
--- a/docs/system/arm/mainstone.rst
+++ /dev/null
@@ -1,25 +0,0 @@
-Intel Mainstone II board (``mainstone``)
-========================================
-
-The ``mainstone`` board emulates the Intel Mainstone II development
-board, which uses a PXA270 CPU.
-
-Emulated devices:
-
-- Flash memory
-- Keypad
-- MMC controller
-- 91C111 ethernet
-- PIC
-- Timer
-- DMA
-- GPIO
-- FIR
-- Serial
-- LCD controller
-- SSP
-- USB controller
-- RTC
-- PCMCIA
-- I2C
-- I2S
diff --git a/docs/system/arm/nseries.rst b/docs/system/arm/nseries.rst
deleted file mode 100644
index cd9edf5..0000000
--- a/docs/system/arm/nseries.rst
+++ /dev/null
@@ -1,33 +0,0 @@
-Nokia N800 and N810 tablets (``n800``, ``n810``)
-================================================
-
-Nokia N800 and N810 internet tablets (known also as RX-34 and RX-44 /
-48) emulation supports the following elements:
-
-- Texas Instruments OMAP2420 System-on-chip (ARM1136 core)
-
-- RAM and non-volatile OneNAND Flash memories
-
-- Display connected to EPSON remote framebuffer chip and OMAP on-chip
- display controller and a LS041y3 MIPI DBI-C controller
-
-- TI TSC2301 (in N800) and TI TSC2005 (in N810) touchscreen
- controllers driven through SPI bus
-
-- National Semiconductor LM8323-controlled qwerty keyboard driven
- through |I2C| bus
-
-- Secure Digital card connected to OMAP MMC/SD host
-
-- Three OMAP on-chip UARTs and on-chip STI debugging console
-
-- Mentor Graphics \"Inventra\" dual-role USB controller embedded in a
- TI TUSB6010 chip - only USB host mode is supported
-
-- TI TMP105 temperature sensor driven through |I2C| bus
-
-- TI TWL92230C power management companion with an RTC on
- |I2C| bus
-
-- Nokia RETU and TAHVO multi-purpose chips with an RTC, connected
- through CBUS
diff --git a/docs/system/arm/palm.rst b/docs/system/arm/palm.rst
deleted file mode 100644
index 61bc8d3..0000000
--- a/docs/system/arm/palm.rst
+++ /dev/null
@@ -1,23 +0,0 @@
-Palm Tungsten|E PDA (``cheetah``)
-=================================
-
-The Palm Tungsten|E PDA (codename \"Cheetah\") emulation includes the
-following elements:
-
-- Texas Instruments OMAP310 System-on-chip (ARM925T core)
-
-- ROM and RAM memories (ROM firmware image can be loaded with
- -option-rom)
-
-- On-chip LCD controller
-
-- On-chip Real Time Clock
-
-- TI TSC2102i touchscreen controller / analog-digital converter /
- Audio CODEC, connected through MicroWire and |I2S| buses
-
-- GPIO-connected matrix keypad
-
-- Secure Digital card connected to OMAP MMC/SD host
-
-- Three on-chip UARTs
diff --git a/docs/system/arm/stm32.rst b/docs/system/arm/stm32.rst
index 3b640f3..ca7a558 100644
--- a/docs/system/arm/stm32.rst
+++ b/docs/system/arm/stm32.rst
@@ -36,6 +36,7 @@ Supported devices
* SPI controller
* System configuration (SYSCFG)
* Timer controller (TIMER)
+ * Reset and Clock Controller (RCC) (STM32F4 only, reset and enable only)
Missing devices
---------------
@@ -53,7 +54,7 @@ Missing devices
* Power supply configuration (PWR)
* Random Number Generator (RNG)
* Real-Time Clock (RTC) controller
- * Reset and Clock Controller (RCC)
+ * Reset and Clock Controller (RCC) (other features than reset and enable)
* Secure Digital Input/Output (SDIO) interface
* USB OTG
* Watchdog controller (IWDG, WWDG)
diff --git a/docs/system/arm/xscale.rst b/docs/system/arm/xscale.rst
deleted file mode 100644
index e239136..0000000
--- a/docs/system/arm/xscale.rst
+++ /dev/null
@@ -1,35 +0,0 @@
-Sharp XScale-based PDA models (``akita``, ``borzoi``, ``spitz``, ``terrier``, ``tosa``)
-=======================================================================================
-
-The Sharp Zaurus are PDAs based on XScale, able to run Linux ('SL series').
-
-The SL-6000 (\"Tosa\"), released in 2005, uses a PXA255 System-on-chip.
-
-The SL-C3000 (\"Spitz\"), SL-C1000 (\"Akita\"), SL-C3100 (\"Borzoi\") and
-SL-C3200 (\"Terrier\") use a PXA270.
-
-The clamshell PDA models emulation includes the following peripherals:
-
-- Intel PXA255/PXA270 System-on-chip (ARMv5TE core)
-
-- NAND Flash memory - not in \"Tosa\"
-
-- IBM/Hitachi DSCM microdrive in a PXA PCMCIA slot - not in \"Akita\"
-
-- On-chip OHCI USB controller - not in \"Tosa\"
-
-- On-chip LCD controller
-
-- On-chip Real Time Clock
-
-- TI ADS7846 touchscreen controller on SSP bus
-
-- Maxim MAX1111 analog-digital converter on |I2C| bus
-
-- GPIO-connected keyboard controller and LEDs
-
-- Secure Digital card connected to PXA MMC/SD host
-
-- Three on-chip UARTs
-
-- WM8750 audio CODEC on |I2C| and |I2S| buses
diff --git a/docs/system/bootindex.rst b/docs/system/bootindex.rst
index 8b057f8..988f7b3 100644
--- a/docs/system/bootindex.rst
+++ b/docs/system/bootindex.rst
@@ -49,10 +49,11 @@ Limitations
-----------
Some firmware has limitations on which devices can be considered for
-booting. For instance, the PC BIOS boot specification allows only one
-disk to be bootable. If boot from disk fails for some reason, the BIOS
+booting. For instance, the x86 PC BIOS boot specification allows only one
+disk to be bootable. If boot from disk fails for some reason, the x86 BIOS
won't retry booting from other disk. It can still try to boot from
-floppy or net, though.
+floppy or net, though. In the case of s390x BIOS, the BIOS will try up to
+8 total devices, any number of which may be disks.
Sometimes, firmware cannot map the device path QEMU wants firmware to
boot from to a boot method. It doesn't happen for devices the firmware
diff --git a/docs/system/devices/virtio-gpu.rst b/docs/system/devices/virtio-gpu.rst
index cb73dd7..b7eb0fc 100644
--- a/docs/system/devices/virtio-gpu.rst
+++ b/docs/system/devices/virtio-gpu.rst
@@ -71,6 +71,17 @@ representation back to OpenGL API calls.
.. _Gallium3D: https://www.freedesktop.org/wiki/Software/gallium/
.. _virglrenderer: https://gitlab.freedesktop.org/virgl/virglrenderer/
+Translation of Vulkan API calls is supported since release of `virglrenderer`_
+v1.0.0 using `venus`_ protocol. ``Venus`` virtio-gpu capability set ("capset")
+requires host blob support (``hostmem`` and ``blob`` fields) and should
+be enabled using ``venus`` field. The ``hostmem`` field specifies the size
+of virtio-gpu host memory window. This is typically between 256M and 8G.
+
+.. parsed-literal::
+ -device virtio-gpu-gl,hostmem=8G,blob=true,venus=true
+
+.. _venus: https://gitlab.freedesktop.org/virgl/venus-protocol/
+
virtio-gpu rutabaga
-------------------
diff --git a/docs/system/i386/hyperv.rst b/docs/system/i386/hyperv.rst
index 2505dc4..1c1de77 100644
--- a/docs/system/i386/hyperv.rst
+++ b/docs/system/i386/hyperv.rst
@@ -262,14 +262,19 @@ Supplementary features
``hv-passthrough``
In some cases (e.g. during development) it may make sense to use QEMU in
'pass-through' mode and give Windows guests all enlightenments currently
- supported by KVM. This pass-through mode is enabled by "hv-passthrough" CPU
- flag.
+ supported by KVM.
Note: ``hv-passthrough`` flag only enables enlightenments which are known to QEMU
(have corresponding 'hv-' flag) and copies ``hv-spinlocks`` and ``hv-vendor-id``
values from KVM to QEMU. ``hv-passthrough`` overrides all other 'hv-' settings on
- the command line. Also, enabling this flag effectively prevents migration as the
- list of enabled enlightenments may differ between target and destination hosts.
+ the command line.
+
+ Note: ``hv-passthrough`` does not enable ``hv-syndbg`` which can prevent certain
+ Windows guests from booting when used without proper configuration. If needed,
+ ``hv-syndbg`` can be enabled additionally.
+
+ Note: ``hv-passthrough`` effectively prevents migration as the list of enabled
+ enlightenments may differ between target and destination hosts.
``hv-enforce-cpuid``
By default, KVM allows the guest to use all currently supported Hyper-V
@@ -278,6 +283,36 @@ Supplementary features
feature alters this behavior and only allows the guest to use exposed Hyper-V
enlightenments.
+Recommendations
+---------------
+
+To achieve the best performance of Windows and Hyper-V guests and unless there
+are any specific requirements (e.g. migration to older QEMU/KVM versions,
+emulating specific Hyper-V version, ...), it is recommended to enable all
+currently implemented Hyper-V enlightenments with the following exceptions:
+
+- ``hv-syndbg``, ``hv-passthrough``, ``hv-enforce-cpuid`` should not be enabled
+ in production configurations as these are debugging/development features.
+- ``hv-reset`` can be avoided as modern Hyper-V versions don't expose it.
+- ``hv-evmcs`` can (and should) be enabled on Intel CPUs only. While the feature
+ is only used in nested configurations (Hyper-V, WSL2), enabling it for regular
+ Windows guests should not have any negative effects.
+- ``hv-no-nonarch-coresharing`` must only be enabled if vCPUs are properly pinned
+ so no non-architectural core sharing is possible.
+- ``hv-vendor-id``, ``hv-version-id-build``, ``hv-version-id-major``,
+ ``hv-version-id-minor``, ``hv-version-id-spack``, ``hv-version-id-sbranch``,
+ ``hv-version-id-snumber`` can be left unchanged, guests are not supposed to
+ behave differently when different Hyper-V version is presented to them.
+- ``hv-crash`` must only be enabled if the crash information is consumed via
+ QAPI by higher levels of the virtualization stack. Enabling this feature
+ effectively prevents Windows from creating dumps upon crashes.
+- ``hv-reenlightenment`` can only be used on hardware which supports TSC
+ scaling or when guest migration is not needed.
+- ``hv-spinlocks`` should be set to e.g. 0xfff when host CPUs are overcommited
+ (meaning there are other scheduled tasks or guests) and can be left unchanged
+ from the default value (0xffffffff) otherwise.
+- ``hv-avic``/``hv-apicv`` should not be enabled if the hardware does not
+ support APIC virtualization (Intel APICv, AMD AVIC).
Useful links
------------
diff --git a/docs/system/i386/xenpvh.rst b/docs/system/i386/xenpvh.rst
new file mode 100644
index 0000000..354250f
--- /dev/null
+++ b/docs/system/i386/xenpvh.rst
@@ -0,0 +1,49 @@
+Xen PVH machine (``xenpvh``)
+=========================================
+
+Xen supports a spectrum of types of guests that vary in how they depend
+on HW virtualization features, emulation models and paravirtualization.
+PVH is a mode that uses HW virtualization features (like HVM) but tries
+to avoid emulation models and instead use passthrough or
+paravirtualized devices.
+
+QEMU can be used to provide PV virtio devices on an emulated PCIe controller.
+That is the purpose of this minimal machine.
+
+Supported devices
+-----------------
+
+The x86 Xen PVH QEMU machine provide the following devices:
+
+- RAM
+- GPEX host bridge
+- virtio-pci devices
+
+The idea is to only connect virtio-pci devices but in theory any compatible
+PCI device model will work depending on Xen and guest support.
+
+Running
+-------
+
+The Xen tools will typically construct a command-line and launch QEMU
+for you when needed. But here's an example of what it can look like in
+case you need to construct one manually:
+
+.. code-block:: console
+
+ qemu-system-i386 -xen-domid 3 -no-shutdown \
+ -chardev socket,id=libxl-cmd,path=/var/run/xen/qmp-libxl-3,server=on,wait=off \
+ -mon chardev=libxl-cmd,mode=control \
+ -chardev socket,id=libxenstat-cmd,path=/var/run/xen/qmp-libxenstat-3,server=on,wait=off \
+ -mon chardev=libxenstat-cmd,mode=control \
+ -nodefaults \
+ -no-user-config \
+ -xen-attach -name g0 \
+ -vnc none \
+ -display none \
+ -device virtio-net-pci,id=nic0,netdev=net0,mac=00:16:3e:5c:81:78 \
+ -netdev type=tap,id=net0,ifname=vif3.0-emu,br=xenbr0,script=no,downscript=no \
+ -smp 4,maxcpus=4 \
+ -nographic \
+ -machine xenpvh,ram-low-base=0,ram-low-size=2147483648,ram-high-base=4294967296,ram-high-size=2147483648,pci-ecam-base=824633720832,pci-ecam-size=268435456,pci-mmio-base=4026531840,pci-mmio-size=33554432,pci-mmio-high-base=824902156288,pci-mmio-high-size=68719476736 \
+ -m 4096
diff --git a/docs/system/loongarch/virt.rst b/docs/system/loongarch/virt.rst
index 06d034b..172fba0 100644
--- a/docs/system/loongarch/virt.rst
+++ b/docs/system/loongarch/virt.rst
@@ -64,7 +64,7 @@ Note: You need get the latest cross-tools at https://github.com/loongson/build-t
(3) Build BIOS:
- See: https://github.com/tianocore/edk2-platforms/tree/master/Platform/Loongson/LoongArchQemuPkg#readme
+ See: https://github.com/tianocore/edk2/tree/master/OvmfPkg/LoongArchVirt#readme
Note: To build the release version of the bios, set --buildtarget=RELEASE,
the bios file path: Build/LoongArchQemu/RELEASE_GCC5/FV/QEMU_EFI.fd
diff --git a/docs/system/ppc/powermac.rst b/docs/system/ppc/powermac.rst
index 04334ba..3eac81c 100644
--- a/docs/system/ppc/powermac.rst
+++ b/docs/system/ppc/powermac.rst
@@ -4,8 +4,8 @@ PowerMac family boards (``g3beige``, ``mac99``)
Use the executable ``qemu-system-ppc`` to simulate a complete PowerMac
PowerPC system.
-- ``g3beige`` Heathrow based PowerMAC
-- ``mac99`` Mac99 based PowerMAC
+- ``g3beige`` Heathrow based PowerMac
+- ``mac99`` Mac99 based PowerMac
Supported devices
-----------------
diff --git a/docs/system/ppc/powernv.rst b/docs/system/ppc/powernv.rst
index 09f3965..de7a807 100644
--- a/docs/system/ppc/powernv.rst
+++ b/docs/system/ppc/powernv.rst
@@ -181,7 +181,7 @@ connected to a remote QEMU machine acting as BMC, using these options
.. code-block:: bash
- -chardev socket,id=ipmi0,host=localhost,port=9002,reconnect=10 \
+ -chardev socket,id=ipmi0,host=localhost,port=9002,reconnect-ms=10000 \
-device ipmi-bmc-extern,id=bmc0,chardev=ipmi0 \
-device isa-ipmi-bt,bmc=bmc0,irq=10 \
-nodefaults
diff --git a/docs/system/s390x/bootdevices.rst b/docs/system/s390x/bootdevices.rst
index 1a7a18b..1a1a764 100644
--- a/docs/system/s390x/bootdevices.rst
+++ b/docs/system/s390x/bootdevices.rst
@@ -6,9 +6,7 @@ Booting with bootindex parameter
For classical mainframe guests (i.e. LPAR or z/VM installations), you always
have to explicitly specify the disk where you want to boot from (or "IPL" from,
-in s390x-speak -- IPL means "Initial Program Load"). In particular, there can
-also be only one boot device according to the architecture specification, thus
-specifying multiple boot devices is not possible (yet).
+in s390x-speak -- IPL means "Initial Program Load").
So for booting an s390x guest in QEMU, you should always mark the
device where you want to boot from with the ``bootindex`` property, for
@@ -17,6 +15,11 @@ example::
qemu-system-s390x -drive if=none,id=dr1,file=guest.qcow2 \
-device virtio-blk,drive=dr1,bootindex=1
+Multiple devices may have a bootindex. The lowest bootindex is assigned to the
+device to IPL first. If the IPL fails for the first, the device with the second
+lowest bootindex will be tried and so on until IPL is successful or there are no
+remaining boot devices to try.
+
For booting from a CD-ROM ISO image (which needs to include El-Torito boot
information in order to be bootable), it is recommended to specify a ``scsi-cd``
device, for example like this::
@@ -82,23 +85,17 @@ Note that ``0`` can be used to boot the default entry.
Booting from a network device
-----------------------------
-Beside the normal guest firmware (which is loaded from the file ``s390-ccw.img``
-in the data directory of QEMU, or via the ``-bios`` option), QEMU ships with
-a small TFTP network bootloader firmware for virtio-net-ccw devices, too. This
-firmware is loaded from a file called ``s390-netboot.img`` in the QEMU data
-directory. In case you want to load it from a different filename instead,
-you can specify it via the ``-global s390-ipl.netboot_fw=filename``
-command line option.
-
-The ``bootindex`` property is especially important for booting via the network.
-If you don't specify the ``bootindex`` property here, the network bootloader
-firmware code won't get loaded into the guest memory so that the network boot
-will fail. For a successful network boot, try something like this::
+The firmware that ships with QEMU includes a small TFTP network bootloader
+for virtio-net-ccw devices. The ``bootindex`` property is especially
+important for booting via the network. If you don't specify the ``bootindex``
+property here, the network bootloader won't be taken into consideration and
+the network boot will fail. For a successful network boot, try something
+like this::
qemu-system-s390x -netdev user,id=n1,tftp=...,bootfile=... \
-device virtio-net-ccw,netdev=n1,bootindex=1
-The network bootloader firmware also has basic support for pxelinux.cfg-style
+The network bootloader also has basic support for pxelinux.cfg-style
configuration files. See the `PXELINUX Configuration page
<https://wiki.syslinux.org/wiki/index.php?title=PXELINUX#Configuration>`__
for details how to set up the configuration file on your TFTP server.
diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst
index 7b99272..3c0a584 100644
--- a/docs/system/target-arm.rst
+++ b/docs/system/target-arm.rst
@@ -91,17 +91,12 @@ undocumented; you can get a complete list by running
arm/cubieboard
arm/emcraft-sf2
arm/musicpal
- arm/gumstix
- arm/mainstone
arm/kzm
- arm/nseries
arm/nrf
arm/nuvoton
arm/imx25-pdk
arm/orangepi
- arm/palm
arm/raspi
- arm/xscale
arm/collie
arm/sx1
arm/stellaris
diff --git a/docs/system/target-i386.rst b/docs/system/target-i386.rst
index 1b8a1f2..23e84e3 100644
--- a/docs/system/target-i386.rst
+++ b/docs/system/target-i386.rst
@@ -26,6 +26,7 @@ Architectural features
i386/cpu
i386/hyperv
i386/xen
+ i386/xenpvh
i386/kvm-pv
i386/sgx
i386/amd-memory-encryption
diff --git a/docs/tools/index.rst b/docs/tools/index.rst
index 8e65ce0..1e88ae4 100644
--- a/docs/tools/index.rst
+++ b/docs/tools/index.rst
@@ -15,4 +15,4 @@ command line utilities and other standalone programs.
qemu-nbd
qemu-pr-helper
qemu-trace-stap
- virtfs-proxy-helper
+ qemu-vmsr-helper
diff --git a/docs/tools/qemu-vmsr-helper.rst b/docs/tools/qemu-vmsr-helper.rst
new file mode 100644
index 0000000..9ce10b9
--- /dev/null
+++ b/docs/tools/qemu-vmsr-helper.rst
@@ -0,0 +1,89 @@
+==================================
+QEMU virtual RAPL MSR helper
+==================================
+
+Synopsis
+--------
+
+**qemu-vmsr-helper** [*OPTION*]
+
+Description
+-----------
+
+Implements the virtual RAPL MSR helper for QEMU.
+
+Accessing the RAPL (Running Average Power Limit) MSR enables the RAPL powercap
+driver to advertise and monitor the power consumption or accumulated energy
+consumption of different power domains, such as CPU packages, DRAM, and other
+components when available.
+
+However those registers are accessible under privileged access (CAP_SYS_RAWIO).
+QEMU can use an external helper to access those privileged registers.
+
+:program:`qemu-vmsr-helper` is that external helper; it creates a listener
+socket which will accept incoming connections for communication with QEMU.
+
+If you want to run VMs in a setup like this, this helper should be started as a
+system service, and you should read the QEMU manual section on "RAPL MSR
+support" to find out how to configure QEMU to connect to the socket created by
+:program:`qemu-vmsr-helper`.
+
+After connecting to the socket, :program:`qemu-vmsr-helper` can
+optionally drop root privileges, except for those capabilities that
+are needed for its operation.
+
+:program:`qemu-vmsr-helper` can also use the systemd socket activation
+protocol. In this case, the systemd socket unit should specify a
+Unix stream socket, like this::
+
+ [Socket]
+ ListenStream=/var/run/qemu-vmsr-helper.sock
+
+Options
+-------
+
+.. program:: qemu-vmsr-helper
+
+.. option:: -d, --daemon
+
+ run in the background (and create a PID file)
+
+.. option:: -q, --quiet
+
+ decrease verbosity
+
+.. option:: -v, --verbose
+
+ increase verbosity
+
+.. option:: -f, --pidfile=PATH
+
+ PID file when running as a daemon. By default the PID file
+ is created in the system runtime state directory, for example
+ :file:`/var/run/qemu-vmsr-helper.pid`.
+
+.. option:: -k, --socket=PATH
+
+ path to the socket. By default the socket is created in
+ the system runtime state directory, for example
+ :file:`/var/run/qemu-vmsr-helper.sock`.
+
+.. option:: -T, --trace [[enable=]PATTERN][,events=FILE][,file=FILE]
+
+ .. include:: ../qemu-option-trace.rst.inc
+
+.. option:: -u, --user=USER
+
+ user to drop privileges to
+
+.. option:: -g, --group=GROUP
+
+ group to drop privileges to
+
+.. option:: -h, --help
+
+ Display a help message and exit.
+
+.. option:: -V, --version
+
+ Display version information and exit.
diff --git a/docs/tools/virtfs-proxy-helper.rst b/docs/tools/virtfs-proxy-helper.rst
deleted file mode 100644
index bd310eb..0000000
--- a/docs/tools/virtfs-proxy-helper.rst
+++ /dev/null
@@ -1,75 +0,0 @@
-QEMU 9p virtfs proxy filesystem helper
-======================================
-
-Synopsis
---------
-
-**virtfs-proxy-helper** [*OPTIONS*]
-
-Description
------------
-
-NOTE: The 9p 'proxy' backend is deprecated (since QEMU 8.1) and will be
-removed, along with this daemon, in a future version of QEMU!
-
-Pass-through security model in QEMU 9p server needs root privilege to do
-few file operations (like chown, chmod to any mode/uid:gid). There are two
-issues in pass-through security model:
-
-- TOCTTOU vulnerability: Following symbolic links in the server could
- provide access to files beyond 9p export path.
-
-- Running QEMU with root privilege could be a security issue.
-
-To overcome above issues, following approach is used: A new filesystem
-type 'proxy' is introduced. Proxy FS uses chroot + socket combination
-for securing the vulnerability known with following symbolic links.
-Intention of adding a new filesystem type is to allow qemu to run
-in non-root mode, but doing privileged operations using socket IO.
-
-Proxy helper (a stand alone binary part of qemu) is invoked with
-root privileges. Proxy helper chroots into 9p export path and creates
-a socket pair or a named socket based on the command line parameter.
-QEMU and proxy helper communicate using this socket. QEMU proxy fs
-driver sends filesystem request to proxy helper and receives the
-response from it.
-
-The proxy helper is designed so that it can drop root privileges except
-for the capabilities needed for doing filesystem operations.
-
-Options
--------
-
-The following options are supported:
-
-.. program:: virtfs-proxy-helper
-
-.. option:: -h
-
- Display help and exit
-
-.. option:: -p, --path PATH
-
- Path to export for proxy filesystem driver
-
-.. option:: -f, --fd SOCKET_ID
-
- Use given file descriptor as socket descriptor for communicating with
- qemu proxy fs drier. Usually a helper like libvirt will create
- socketpair and pass one of the fds as parameter to this option.
-
-.. option:: -s, --socket SOCKET_FILE
-
- Creates named socket file for communicating with qemu proxy fs driver
-
-.. option:: -u, --uid UID
-
- uid to give access to named socket file; used in combination with -g.
-
-.. option:: -g, --gid GID
-
- gid to give access to named socket file; used in combination with -u.
-
-.. option:: -n, --nodaemon
-
- Run as a normal program. By default program will run in daemon mode
diff --git a/docs/user/main.rst b/docs/user/main.rst
index e04bc2c..7a126ee 100644
--- a/docs/user/main.rst
+++ b/docs/user/main.rst
@@ -130,10 +130,6 @@ Other binaries
The binary format is detected automatically.
-- user mode (Cris)
-
- * ``qemu-cris`` TODO.
-
- user mode (i386)
* ``qemu-i386`` TODO.
diff --git a/dump/dump.c b/dump/dump.c
index 84064d8..45e8442 100644
--- a/dump/dump.c
+++ b/dump/dump.c
@@ -30,6 +30,7 @@
#include "migration/blocker.h"
#include "hw/core/cpu.h"
#include "win_dump.h"
+#include "qemu/range.h"
#include <zlib.h>
#ifdef CONFIG_LZO
@@ -574,8 +575,10 @@ static void get_offset_range(hwaddr phys_addr,
QTAILQ_FOREACH(block, &s->guest_phys_blocks.head, next) {
if (dump_has_filter(s)) {
- if (block->target_start >= s->filter_area_begin + s->filter_area_length ||
- block->target_end <= s->filter_area_begin) {
+ if (!ranges_overlap(block->target_start,
+ block->target_end - block->target_start,
+ s->filter_area_begin,
+ s->filter_area_length)) {
/* This block is out of the range */
continue;
}
@@ -734,8 +737,9 @@ int64_t dump_filtered_memblock_start(GuestPhysBlock *block,
{
if (filter_area_length) {
/* return -1 if the block is not within filter area */
- if (block->target_start >= filter_area_start + filter_area_length ||
- block->target_end <= filter_area_start) {
+ if (!ranges_overlap(block->target_start,
+ block->target_end - block->target_start,
+ filter_area_start, filter_area_length)) {
return -1;
}
diff --git a/ebpf/ebpf_rss-stub.c b/ebpf/ebpf_rss-stub.c
index 8d7fae2..d0e7f99 100644
--- a/ebpf/ebpf_rss-stub.c
+++ b/ebpf/ebpf_rss-stub.c
@@ -23,19 +23,21 @@ bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx)
return false;
}
-bool ebpf_rss_load(struct EBPFRSSContext *ctx)
+bool ebpf_rss_load(struct EBPFRSSContext *ctx, Error **errp)
{
return false;
}
bool ebpf_rss_load_fds(struct EBPFRSSContext *ctx, int program_fd,
- int config_fd, int toeplitz_fd, int table_fd)
+ int config_fd, int toeplitz_fd, int table_fd,
+ Error **errp)
{
return false;
}
bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
- uint16_t *indirections_table, uint8_t *toeplitz_key)
+ uint16_t *indirections_table, uint8_t *toeplitz_key,
+ Error **errp)
{
return false;
}
diff --git a/ebpf/ebpf_rss.c b/ebpf/ebpf_rss.c
index 87f0714..e793786 100644
--- a/ebpf/ebpf_rss.c
+++ b/ebpf/ebpf_rss.c
@@ -47,34 +47,37 @@ bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx)
return ctx != NULL && (ctx->obj != NULL || ctx->program_fd != -1);
}
-static bool ebpf_rss_mmap(struct EBPFRSSContext *ctx)
+static bool ebpf_rss_mmap(struct EBPFRSSContext *ctx, Error **errp)
{
- if (!ebpf_rss_is_loaded(ctx)) {
- return false;
- }
-
ctx->mmap_configuration = mmap(NULL, qemu_real_host_page_size(),
PROT_READ | PROT_WRITE, MAP_SHARED,
ctx->map_configuration, 0);
if (ctx->mmap_configuration == MAP_FAILED) {
- trace_ebpf_error("eBPF RSS", "can not mmap eBPF configuration array");
+ trace_ebpf_rss_mmap_error(ctx, "configuration");
+ error_setg(errp, "Unable to map eBPF configuration array");
return false;
}
ctx->mmap_toeplitz_key = mmap(NULL, qemu_real_host_page_size(),
PROT_READ | PROT_WRITE, MAP_SHARED,
ctx->map_toeplitz_key, 0);
if (ctx->mmap_toeplitz_key == MAP_FAILED) {
- trace_ebpf_error("eBPF RSS", "can not mmap eBPF toeplitz key");
+ trace_ebpf_rss_mmap_error(ctx, "toeplitz key");
+ error_setg(errp, "Unable to map eBPF toeplitz array");
goto toeplitz_fail;
}
ctx->mmap_indirections_table = mmap(NULL, qemu_real_host_page_size(),
PROT_READ | PROT_WRITE, MAP_SHARED,
ctx->map_indirections_table, 0);
if (ctx->mmap_indirections_table == MAP_FAILED) {
- trace_ebpf_error("eBPF RSS", "can not mmap eBPF indirection table");
+ trace_ebpf_rss_mmap_error(ctx, "indirections table");
+ error_setg(errp, "Unable to map eBPF indirection array");
goto indirection_fail;
}
+ trace_ebpf_rss_mmap(ctx,
+ ctx->mmap_configuration,
+ ctx->mmap_toeplitz_key,
+ ctx->mmap_indirections_table);
return true;
indirection_fail:
@@ -90,10 +93,6 @@ toeplitz_fail:
static void ebpf_rss_munmap(struct EBPFRSSContext *ctx)
{
- if (!ebpf_rss_is_loaded(ctx)) {
- return;
- }
-
munmap(ctx->mmap_indirections_table, qemu_real_host_page_size());
munmap(ctx->mmap_toeplitz_key, qemu_real_host_page_size());
munmap(ctx->mmap_configuration, qemu_real_host_page_size());
@@ -103,7 +102,7 @@ static void ebpf_rss_munmap(struct EBPFRSSContext *ctx)
ctx->mmap_indirections_table = NULL;
}
-bool ebpf_rss_load(struct EBPFRSSContext *ctx)
+bool ebpf_rss_load(struct EBPFRSSContext *ctx, Error **errp)
{
struct rss_bpf *rss_bpf_ctx;
@@ -113,14 +112,16 @@ bool ebpf_rss_load(struct EBPFRSSContext *ctx)
rss_bpf_ctx = rss_bpf__open();
if (rss_bpf_ctx == NULL) {
- trace_ebpf_error("eBPF RSS", "can not open eBPF RSS object");
+ trace_ebpf_rss_open_error(ctx);
+ error_setg(errp, "Unable to open eBPF RSS object");
goto error;
}
bpf_program__set_type(rss_bpf_ctx->progs.tun_rss_steering_prog, BPF_PROG_TYPE_SOCKET_FILTER);
if (rss_bpf__load(rss_bpf_ctx)) {
- trace_ebpf_error("eBPF RSS", "can not load RSS program");
+ trace_ebpf_rss_load_error(ctx);
+ error_setg(errp, "Unable to load eBPF program");
goto error;
}
@@ -134,7 +135,12 @@ bool ebpf_rss_load(struct EBPFRSSContext *ctx)
ctx->map_toeplitz_key = bpf_map__fd(
rss_bpf_ctx->maps.tap_rss_map_toeplitz_key);
- if (!ebpf_rss_mmap(ctx)) {
+ trace_ebpf_rss_load(ctx,
+ ctx->program_fd,
+ ctx->map_configuration,
+ ctx->map_indirections_table,
+ ctx->map_toeplitz_key);
+ if (!ebpf_rss_mmap(ctx, errp)) {
goto error;
}
@@ -151,13 +157,28 @@ error:
}
bool ebpf_rss_load_fds(struct EBPFRSSContext *ctx, int program_fd,
- int config_fd, int toeplitz_fd, int table_fd)
+ int config_fd, int toeplitz_fd, int table_fd,
+ Error **errp)
{
if (ebpf_rss_is_loaded(ctx)) {
+ error_setg(errp, "eBPF program is already loaded");
return false;
}
- if (program_fd < 0 || config_fd < 0 || toeplitz_fd < 0 || table_fd < 0) {
+ if (program_fd < 0) {
+ error_setg(errp, "eBPF program FD is not open");
+ return false;
+ }
+ if (config_fd < 0) {
+ error_setg(errp, "eBPF config FD is not open");
+ return false;
+ }
+ if (toeplitz_fd < 0) {
+ error_setg(errp, "eBPF toeplitz FD is not open");
+ return false;
+ }
+ if (table_fd < 0) {
+ error_setg(errp, "eBPF indirection FD is not open");
return false;
}
@@ -166,7 +187,13 @@ bool ebpf_rss_load_fds(struct EBPFRSSContext *ctx, int program_fd,
ctx->map_toeplitz_key = toeplitz_fd;
ctx->map_indirections_table = table_fd;
- if (!ebpf_rss_mmap(ctx)) {
+ trace_ebpf_rss_load(ctx,
+ ctx->program_fd,
+ ctx->map_configuration,
+ ctx->map_indirections_table,
+ ctx->map_toeplitz_key);
+
+ if (!ebpf_rss_mmap(ctx, errp)) {
ctx->program_fd = -1;
ctx->map_configuration = -1;
ctx->map_toeplitz_key = -1;
@@ -177,25 +204,22 @@ bool ebpf_rss_load_fds(struct EBPFRSSContext *ctx, int program_fd,
return true;
}
-static bool ebpf_rss_set_config(struct EBPFRSSContext *ctx,
+static void ebpf_rss_set_config(struct EBPFRSSContext *ctx,
struct EBPFRSSConfig *config)
{
- if (!ebpf_rss_is_loaded(ctx)) {
- return false;
- }
-
memcpy(ctx->mmap_configuration, config, sizeof(*config));
- return true;
}
static bool ebpf_rss_set_indirections_table(struct EBPFRSSContext *ctx,
uint16_t *indirections_table,
- size_t len)
+ size_t len,
+ Error **errp)
{
char *cursor = ctx->mmap_indirections_table;
- if (!ebpf_rss_is_loaded(ctx) || indirections_table == NULL ||
- len > VIRTIO_NET_RSS_MAX_TABLE_LEN) {
+ if (len > VIRTIO_NET_RSS_MAX_TABLE_LEN) {
+ error_setg(errp, "Indirections table length %zu exceeds limit %d",
+ len, VIRTIO_NET_RSS_MAX_TABLE_LEN);
return false;
}
@@ -207,43 +231,51 @@ static bool ebpf_rss_set_indirections_table(struct EBPFRSSContext *ctx,
return true;
}
-static bool ebpf_rss_set_toepliz_key(struct EBPFRSSContext *ctx,
+static void ebpf_rss_set_toepliz_key(struct EBPFRSSContext *ctx,
uint8_t *toeplitz_key)
{
/* prepare toeplitz key */
uint8_t toe[VIRTIO_NET_RSS_MAX_KEY_SIZE] = {};
- if (!ebpf_rss_is_loaded(ctx) || toeplitz_key == NULL) {
- return false;
- }
memcpy(toe, toeplitz_key, VIRTIO_NET_RSS_MAX_KEY_SIZE);
*(uint32_t *)toe = ntohl(*(uint32_t *)toe);
memcpy(ctx->mmap_toeplitz_key, toe, VIRTIO_NET_RSS_MAX_KEY_SIZE);
- return true;
}
bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
- uint16_t *indirections_table, uint8_t *toeplitz_key)
+ uint16_t *indirections_table, uint8_t *toeplitz_key,
+ Error **errp)
{
- if (!ebpf_rss_is_loaded(ctx) || config == NULL ||
- indirections_table == NULL || toeplitz_key == NULL) {
+ if (!ebpf_rss_is_loaded(ctx)) {
+ error_setg(errp, "eBPF program is not loaded");
return false;
}
-
- if (!ebpf_rss_set_config(ctx, config)) {
+ if (config == NULL) {
+ error_setg(errp, "eBPF config table is NULL");
return false;
}
-
- if (!ebpf_rss_set_indirections_table(ctx, indirections_table,
- config->indirections_len)) {
+ if (indirections_table == NULL) {
+ error_setg(errp, "eBPF indirections table is NULL");
+ return false;
+ }
+ if (toeplitz_key == NULL) {
+ error_setg(errp, "eBPF toeplitz key is NULL");
return false;
}
- if (!ebpf_rss_set_toepliz_key(ctx, toeplitz_key)) {
+ ebpf_rss_set_config(ctx, config);
+
+ if (!ebpf_rss_set_indirections_table(ctx, indirections_table,
+ config->indirections_len,
+ errp)) {
return false;
}
+ ebpf_rss_set_toepliz_key(ctx, toeplitz_key);
+
+ trace_ebpf_rss_set_data(ctx, config, indirections_table, toeplitz_key);
+
return true;
}
@@ -253,6 +285,8 @@ void ebpf_rss_unload(struct EBPFRSSContext *ctx)
return;
}
+ trace_ebpf_rss_unload(ctx);
+
ebpf_rss_munmap(ctx);
if (ctx->obj) {
@@ -271,4 +305,4 @@ void ebpf_rss_unload(struct EBPFRSSContext *ctx)
ctx->map_indirections_table = -1;
}
-ebpf_binary_init(EBPF_PROGRAMID_RSS, rss_bpf__elf_bytes)
+ebpf_binary_init(EBPF_PROGRAM_ID_RSS, rss_bpf__elf_bytes)
diff --git a/ebpf/ebpf_rss.h b/ebpf/ebpf_rss.h
index 239242b..86a5787 100644
--- a/ebpf/ebpf_rss.h
+++ b/ebpf/ebpf_rss.h
@@ -14,6 +14,8 @@
#ifndef QEMU_EBPF_RSS_H
#define QEMU_EBPF_RSS_H
+#include "qapi/error.h"
+
#define EBPF_RSS_MAX_FDS 4
struct EBPFRSSContext {
@@ -41,13 +43,15 @@ void ebpf_rss_init(struct EBPFRSSContext *ctx);
bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx);
-bool ebpf_rss_load(struct EBPFRSSContext *ctx);
+bool ebpf_rss_load(struct EBPFRSSContext *ctx, Error **errp);
bool ebpf_rss_load_fds(struct EBPFRSSContext *ctx, int program_fd,
- int config_fd, int toeplitz_fd, int table_fd);
+ int config_fd, int toeplitz_fd, int table_fd,
+ Error **errp);
bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
- uint16_t *indirections_table, uint8_t *toeplitz_key);
+ uint16_t *indirections_table, uint8_t *toeplitz_key,
+ Error **errp);
void ebpf_rss_unload(struct EBPFRSSContext *ctx);
diff --git a/ebpf/trace-events b/ebpf/trace-events
index b3ad1a3..bf3d9b6 100644
--- a/ebpf/trace-events
+++ b/ebpf/trace-events
@@ -1,4 +1,10 @@
# See docs/devel/tracing.rst for syntax documentation.
# ebpf-rss.c
-ebpf_error(const char *s1, const char *s2) "error in %s: %s"
+ebpf_rss_load(void *ctx, int progfd, int cfgfd, int toepfd, int indirfd) "ctx=%p program-fd=%d config-fd=%d toeplitz-fd=%d indirection-fd=%d"
+ebpf_rss_load_error(void *ctx) "ctx=%p"
+ebpf_rss_mmap(void *ctx, void *cfgptr, void *toepptr, void *indirptr) "ctx=%p config-ptr=%p toeplitz-ptr=%p indirection-ptr=%p"
+ebpf_rss_mmap_error(void *ctx, const char *object) "ctx=%p object=%s"
+ebpf_rss_open_error(void *ctx) "ctx=%p"
+ebpf_rss_set_data(void *ctx, void *cfgptr, void *toepptr, void *indirptr) "ctx=%p config-ptr=%p toeplitz-ptr=%p indirection-ptr=%p"
+ebpf_rss_unload(void *ctx) "rss unload ctx=%p"
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
index a44649f..cc6e06b 100644
--- a/fpu/softfloat-parts.c.inc
+++ b/fpu/softfloat-parts.c.inc
@@ -1373,7 +1373,6 @@ static FloatPartsN *partsN(minmax)(FloatPartsN *a, FloatPartsN *b,
break;
default:
g_assert_not_reached();
- break;
}
switch (b->cls) {
case float_class_normal:
@@ -1386,7 +1385,6 @@ static FloatPartsN *partsN(minmax)(FloatPartsN *a, FloatPartsN *b,
break;
default:
g_assert_not_reached();
- break;
}
}
diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc
index 8f3b97d..4e279b9 100644
--- a/fpu/softfloat-specialize.c.inc
+++ b/fpu/softfloat-specialize.c.inc
@@ -151,8 +151,8 @@ static void parts64_default_nan(FloatParts64 *p, float_status *status)
#else
/*
* This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V,
- * S390, SH4, TriCore, and Xtensa. Our other supported targets,
- * such CRIS, do not have floating-point.
+ * S390, SH4, TriCore, and Xtensa. Our other supported targets
+ * do not have floating-point.
*/
if (snan_bit_is_one(status)) {
/* set all bits other than msb */
diff --git a/fsdev/9p-iov-marshal.c b/fsdev/9p-iov-marshal.c
index a1c9bed..0c5a1a0 100644
--- a/fsdev/9p-iov-marshal.c
+++ b/fsdev/9p-iov-marshal.c
@@ -84,9 +84,12 @@ ssize_t v9fs_iov_vunmarshal(struct iovec *out_sg, int out_num, size_t offset,
break;
}
case 'w': {
- uint16_t val, *valp;
+ uint16_t val = 0, *valp;
valp = va_arg(ap, uint16_t *);
copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
+ if (copied <= 0) {
+ break;
+ }
if (bswap) {
*valp = le16_to_cpu(val);
} else {
@@ -95,9 +98,12 @@ ssize_t v9fs_iov_vunmarshal(struct iovec *out_sg, int out_num, size_t offset,
break;
}
case 'd': {
- uint32_t val, *valp;
+ uint32_t val = 0, *valp;
valp = va_arg(ap, uint32_t *);
copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
+ if (copied <= 0) {
+ break;
+ }
if (bswap) {
*valp = le32_to_cpu(val);
} else {
@@ -106,9 +112,12 @@ ssize_t v9fs_iov_vunmarshal(struct iovec *out_sg, int out_num, size_t offset,
break;
}
case 'q': {
- uint64_t val, *valp;
+ uint64_t val = 0, *valp;
valp = va_arg(ap, uint64_t *);
copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
+ if (copied <= 0) {
+ break;
+ }
if (bswap) {
*valp = le64_to_cpu(val);
} else {
diff --git a/fsdev/meson.build b/fsdev/meson.build
index e20d725..c751d8c 100644
--- a/fsdev/meson.build
+++ b/fsdev/meson.build
@@ -8,11 +8,3 @@ fsdev_ss.add(when: ['CONFIG_FSDEV_9P'], if_true: files(
if host_os in ['linux', 'darwin']
system_ss.add_all(fsdev_ss)
endif
-
-if have_virtfs_proxy_helper
- executable('virtfs-proxy-helper',
- files('virtfs-proxy-helper.c', '9p-marshal.c', '9p-iov-marshal.c'),
- dependencies: [qemuutil, libattr, libcap_ng],
- install: true,
- install_dir: get_option('libexecdir'))
-endif
diff --git a/fsdev/qemu-fsdev.c b/fsdev/qemu-fsdev.c
index f5c953a..57877da 100644
--- a/fsdev/qemu-fsdev.c
+++ b/fsdev/qemu-fsdev.c
@@ -89,17 +89,6 @@ static FsDriverTable FsDrivers[] = {
NULL
},
},
- {
- .name = "proxy",
- .ops = &proxy_ops,
- .opts = (const char * []) {
- COMMON_FS_DRIVER_OPTIONS,
- "socket",
- "sock_fd",
- "writeout",
- NULL
- },
- },
};
static int validate_opt(void *opaque, const char *name, const char *value,
@@ -133,14 +122,6 @@ int qemu_fsdev_add(QemuOpts *opts, Error **errp)
}
if (fsdriver) {
- if (strncmp(fsdriver, "proxy", 5) == 0) {
- warn_report(
- "'-fsdev proxy' and '-virtfs proxy' are deprecated, use "
- "'local' instead of 'proxy, or consider deploying virtiofsd "
- "as alternative to 9p"
- );
- }
-
for (i = 0; i < ARRAY_SIZE(FsDrivers); i++) {
if (strcmp(FsDrivers[i].name, fsdriver) == 0) {
break;
diff --git a/fsdev/qemu-fsdev.h b/fsdev/qemu-fsdev.h
index 52a5397..731f140 100644
--- a/fsdev/qemu-fsdev.h
+++ b/fsdev/qemu-fsdev.h
@@ -18,5 +18,4 @@ int qemu_fsdev_add(QemuOpts *opts, Error **errp);
FsDriverEntry *get_fsdev_fsentry(char *id);
extern FileOperations local_ops;
extern FileOperations synth_ops;
-extern FileOperations proxy_ops;
#endif
diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
deleted file mode 100644
index 144aaf5..0000000
--- a/fsdev/virtfs-proxy-helper.c
+++ /dev/null
@@ -1,1193 +0,0 @@
-/*
- * Helper for QEMU Proxy FS Driver
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- * M. Mohan Kumar <mohan@in.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- */
-
-/*
- * NOTE: The 9p 'proxy' backend is deprecated (since QEMU 8.1) and will be
- * removed in a future version of QEMU!
- */
-
-#include "qemu/osdep.h"
-#include <glib/gstdio.h>
-#include <sys/resource.h>
-#include <getopt.h>
-#include <syslog.h>
-#include <sys/fsuid.h>
-#include <sys/vfs.h>
-#include <sys/ioctl.h>
-#include <linux/fs.h>
-#ifdef CONFIG_LINUX_MAGIC_H
-#include <linux/magic.h>
-#endif
-#include <cap-ng.h>
-#include "qemu/sockets.h"
-#include "qemu/xattr.h"
-#include "9p-iov-marshal.h"
-#include "hw/9pfs/9p-proxy.h"
-#include "hw/9pfs/9p-util.h"
-#include "fsdev/9p-iov-marshal.h"
-
-#define PROGNAME "virtfs-proxy-helper"
-
-#ifndef XFS_SUPER_MAGIC
-#define XFS_SUPER_MAGIC 0x58465342
-#endif
-#ifndef EXT2_SUPER_MAGIC
-#define EXT2_SUPER_MAGIC 0xEF53
-#endif
-#ifndef REISERFS_SUPER_MAGIC
-#define REISERFS_SUPER_MAGIC 0x52654973
-#endif
-#ifndef BTRFS_SUPER_MAGIC
-#define BTRFS_SUPER_MAGIC 0x9123683E
-#endif
-
-static const struct option helper_opts[] = {
- {"fd", required_argument, NULL, 'f'},
- {"path", required_argument, NULL, 'p'},
- {"nodaemon", no_argument, NULL, 'n'},
- {"socket", required_argument, NULL, 's'},
- {"uid", required_argument, NULL, 'u'},
- {"gid", required_argument, NULL, 'g'},
- {},
-};
-
-static bool is_daemon;
-static bool get_version; /* IOC getversion IOCTL supported */
-static char *prog_name;
-
-static void G_GNUC_PRINTF(2, 3) do_log(int loglevel, const char *format, ...)
-{
- va_list ap;
-
- va_start(ap, format);
- if (is_daemon) {
- vsyslog(LOG_CRIT, format, ap);
- } else {
- vfprintf(stderr, format, ap);
- }
- va_end(ap);
-}
-
-static void do_perror(const char *string)
-{
- if (is_daemon) {
- syslog(LOG_CRIT, "%s:%s", string, strerror(errno));
- } else {
- fprintf(stderr, "%s:%s\n", string, strerror(errno));
- }
-}
-
-static int init_capabilities(void)
-{
- /* helper needs following capabilities only */
- int cap_list[] = {
- CAP_CHOWN,
- CAP_DAC_OVERRIDE,
- CAP_FOWNER,
- CAP_FSETID,
- CAP_SETGID,
- CAP_MKNOD,
- CAP_SETUID,
- };
- int i;
-
- capng_clear(CAPNG_SELECT_BOTH);
- for (i = 0; i < ARRAY_SIZE(cap_list); i++) {
- if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
- cap_list[i]) < 0) {
- do_perror("capng_update");
- return -1;
- }
- }
- if (capng_apply(CAPNG_SELECT_BOTH) < 0) {
- do_perror("capng_apply");
- return -1;
- }
-
- /* Prepare effective set for setugid. */
- for (i = 0; i < ARRAY_SIZE(cap_list); i++) {
- if (cap_list[i] == CAP_DAC_OVERRIDE) {
- continue;
- }
-
- if (capng_update(CAPNG_DROP, CAPNG_EFFECTIVE,
- cap_list[i]) < 0) {
- do_perror("capng_update");
- return -1;
- }
- }
- return 0;
-}
-
-static int socket_read(int sockfd, void *buff, ssize_t size)
-{
- ssize_t retval, total = 0;
-
- while (size) {
- retval = read(sockfd, buff, size);
- if (retval == 0) {
- return -EIO;
- }
- if (retval < 0) {
- if (errno == EINTR) {
- continue;
- }
- return -errno;
- }
- size -= retval;
- buff += retval;
- total += retval;
- }
- return total;
-}
-
-static int socket_write(int sockfd, void *buff, ssize_t size)
-{
- ssize_t retval, total = 0;
-
- while (size) {
- retval = write(sockfd, buff, size);
- if (retval < 0) {
- if (errno == EINTR) {
- continue;
- }
- return -errno;
- }
- size -= retval;
- buff += retval;
- total += retval;
- }
- return total;
-}
-
-static int read_request(int sockfd, struct iovec *iovec, ProxyHeader *header)
-{
- int retval;
-
- /*
- * read the request header.
- */
- iovec->iov_len = 0;
- retval = socket_read(sockfd, iovec->iov_base, PROXY_HDR_SZ);
- if (retval < 0) {
- return retval;
- }
- iovec->iov_len = PROXY_HDR_SZ;
- retval = proxy_unmarshal(iovec, 0, "dd", &header->type, &header->size);
- if (retval < 0) {
- return retval;
- }
- /*
- * We can't process message.size > PROXY_MAX_IO_SZ.
- * Treat it as fatal error
- */
- if (header->size > PROXY_MAX_IO_SZ) {
- return -ENOBUFS;
- }
- retval = socket_read(sockfd, iovec->iov_base + PROXY_HDR_SZ, header->size);
- if (retval < 0) {
- return retval;
- }
- iovec->iov_len += header->size;
- return 0;
-}
-
-static int send_fd(int sockfd, int fd)
-{
- struct msghdr msg;
- struct iovec iov;
- int retval, data;
- struct cmsghdr *cmsg;
- union MsgControl msg_control;
-
- iov.iov_base = &data;
- iov.iov_len = sizeof(data);
-
- memset(&msg, 0, sizeof(msg));
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- /* No ancillary data on error */
- if (fd < 0) {
- /* fd is really negative errno if the request failed */
- data = fd;
- } else {
- data = V9FS_FD_VALID;
- msg.msg_control = &msg_control;
- msg.msg_controllen = sizeof(msg_control);
-
- cmsg = &msg_control.cmsg;
- cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
- }
-
- do {
- retval = sendmsg(sockfd, &msg, 0);
- } while (retval < 0 && errno == EINTR);
- if (fd >= 0) {
- close(fd);
- }
- if (retval < 0) {
- return retval;
- }
- return 0;
-}
-
-static int send_status(int sockfd, struct iovec *iovec, int status)
-{
- ProxyHeader header;
- int retval, msg_size;
-
- if (status < 0) {
- header.type = T_ERROR;
- } else {
- header.type = T_SUCCESS;
- }
- header.size = sizeof(status);
- /*
- * marshal the return status. We don't check error.
- * because we are sure we have enough space for the status
- */
- msg_size = proxy_marshal(iovec, 0, "ddd", header.type,
- header.size, status);
- if (msg_size < 0) {
- return msg_size;
- }
- retval = socket_write(sockfd, iovec->iov_base, msg_size);
- if (retval < 0) {
- return retval;
- }
- return 0;
-}
-
-/*
- * from man 7 capabilities, section
- * Effect of User ID Changes on Capabilities:
- * If the effective user ID is changed from nonzero to 0, then the permitted
- * set is copied to the effective set. If the effective user ID is changed
- * from 0 to nonzero, then all capabilities are are cleared from the effective
- * set.
- *
- * The setfsuid/setfsgid man pages warn that changing the effective user ID may
- * expose the program to unwanted signals, but this is not true anymore: for an
- * unprivileged (without CAP_KILL) program to send a signal, the real or
- * effective user ID of the sending process must equal the real or saved user
- * ID of the target process. Even when dropping privileges, it is enough to
- * keep the saved UID to a "privileged" value and virtfs-proxy-helper won't
- * be exposed to signals. So just use setresuid/setresgid.
- */
-static int setugid(int uid, int gid, int *suid, int *sgid)
-{
- int retval;
-
- *suid = geteuid();
- *sgid = getegid();
-
- if (setresgid(-1, gid, *sgid) == -1) {
- return -errno;
- }
-
- if (setresuid(-1, uid, *suid) == -1) {
- retval = -errno;
- goto err_sgid;
- }
-
- if (uid == 0 && gid == 0) {
- /* Linux has already copied the permitted set to the effective set. */
- return 0;
- }
-
- /*
- * All capabilities have been cleared from the effective set. However
- * we still need DAC_OVERRIDE because we don't change supplementary
- * group ids, and hence may be subject to DAC rules. init_capabilities
- * left the set of capabilities that we want in libcap-ng's state.
- */
- if (capng_apply(CAPNG_SELECT_CAPS) < 0) {
- retval = -errno;
- do_perror("capng_apply");
- goto err_suid;
- }
- return 0;
-
-err_suid:
- if (setresuid(-1, *suid, *suid) == -1) {
- abort();
- }
-err_sgid:
- if (setresgid(-1, *sgid, *sgid) == -1) {
- abort();
- }
- return retval;
-}
-
-/*
- * This is used to reset the ugid back with the saved values
- * There is nothing much we can do checking error values here.
- */
-static void resetugid(int suid, int sgid)
-{
- if (setresgid(-1, sgid, sgid) == -1) {
- abort();
- }
- if (setresuid(-1, suid, suid) == -1) {
- abort();
- }
-}
-
-/*
- * Open regular file or directory. Attempts to open any special file are
- * rejected.
- *
- * returns file descriptor or -1 on error
- */
-static int open_regular(const char *pathname, int flags, mode_t mode)
-{
- int fd;
-
- fd = open(pathname, flags, mode);
- if (fd < 0) {
- return fd;
- }
-
- if (close_if_special_file(fd) < 0) {
- return -1;
- }
-
- return fd;
-}
-
-/*
- * send response in two parts
- * 1) ProxyHeader
- * 2) Response or error status
- * This function should be called with marshaled response
- * send_response constructs header part and error part only.
- * send response sends {ProxyHeader,Response} if the request was success
- * otherwise sends {ProxyHeader,error status}
- */
-static int send_response(int sock, struct iovec *iovec, int size)
-{
- int retval;
- ProxyHeader header;
-
- /*
- * If response size exceeds available iovec->iov_len,
- * we return ENOBUFS
- */
- if (size > PROXY_MAX_IO_SZ) {
- size = -ENOBUFS;
- }
-
- if (size < 0) {
- /*
- * In case of error we would not have got the error encoded
- * already so encode the error here.
- */
- header.type = T_ERROR;
- header.size = sizeof(size);
- proxy_marshal(iovec, PROXY_HDR_SZ, "d", size);
- } else {
- header.type = T_SUCCESS;
- header.size = size;
- }
- proxy_marshal(iovec, 0, "dd", header.type, header.size);
- retval = socket_write(sock, iovec->iov_base, header.size + PROXY_HDR_SZ);
- if (retval < 0) {
- return retval;
- }
- return 0;
-}
-
-/*
- * gets generation number
- * returns -errno on failure and sizeof(generation number) on success
- */
-static int do_getversion(struct iovec *iovec, struct iovec *out_iovec)
-{
- uint64_t version;
- int retval = -ENOTTY;
-#ifdef FS_IOC_GETVERSION
- int fd;
- V9fsString path;
-#endif
-
-
- /* no need to issue ioctl */
- if (!get_version) {
- version = 0;
- retval = proxy_marshal(out_iovec, PROXY_HDR_SZ, "q", version);
- return retval;
- }
-#ifdef FS_IOC_GETVERSION
- retval = proxy_unmarshal(iovec, PROXY_HDR_SZ, "s", &path);
- if (retval < 0) {
- return retval;
- }
-
- fd = open(path.data, O_RDONLY);
- if (fd < 0) {
- retval = -errno;
- goto err_out;
- }
- if (ioctl(fd, FS_IOC_GETVERSION, &version) < 0) {
- retval = -errno;
- } else {
- retval = proxy_marshal(out_iovec, PROXY_HDR_SZ, "q", version);
- }
- close(fd);
-err_out:
- v9fs_string_free(&path);
-#endif
- return retval;
-}
-
-static int do_getxattr(int type, struct iovec *iovec, struct iovec *out_iovec)
-{
- int size = 0, offset, retval;
- V9fsString path, name, xattr;
-
- v9fs_string_init(&xattr);
- v9fs_string_init(&path);
- retval = proxy_unmarshal(iovec, PROXY_HDR_SZ, "ds", &size, &path);
- if (retval < 0) {
- return retval;
- }
- offset = PROXY_HDR_SZ + retval;
-
- if (size) {
- xattr.data = g_malloc(size);
- xattr.size = size;
- }
- switch (type) {
- case T_LGETXATTR:
- v9fs_string_init(&name);
- retval = proxy_unmarshal(iovec, offset, "s", &name);
- if (retval > 0) {
- retval = lgetxattr(path.data, name.data, xattr.data, size);
- if (retval < 0) {
- retval = -errno;
- } else {
- xattr.size = retval;
- }
- }
- v9fs_string_free(&name);
- break;
- case T_LLISTXATTR:
- retval = llistxattr(path.data, xattr.data, size);
- if (retval < 0) {
- retval = -errno;
- } else {
- xattr.size = retval;
- }
- break;
- }
- if (retval < 0) {
- goto err_out;
- }
-
- if (!size) {
- proxy_marshal(out_iovec, PROXY_HDR_SZ, "d", retval);
- retval = sizeof(retval);
- } else {
- retval = proxy_marshal(out_iovec, PROXY_HDR_SZ, "s", &xattr);
- }
-err_out:
- v9fs_string_free(&xattr);
- v9fs_string_free(&path);
- return retval;
-}
-
-static void stat_to_prstat(ProxyStat *pr_stat, struct stat *stat)
-{
- memset(pr_stat, 0, sizeof(*pr_stat));
- pr_stat->st_dev = stat->st_dev;
- pr_stat->st_ino = stat->st_ino;
- pr_stat->st_nlink = stat->st_nlink;
- pr_stat->st_mode = stat->st_mode;
- pr_stat->st_uid = stat->st_uid;
- pr_stat->st_gid = stat->st_gid;
- pr_stat->st_rdev = stat->st_rdev;
- pr_stat->st_size = stat->st_size;
- pr_stat->st_blksize = stat->st_blksize;
- pr_stat->st_blocks = stat->st_blocks;
- pr_stat->st_atim_sec = stat->st_atim.tv_sec;
- pr_stat->st_atim_nsec = stat->st_atim.tv_nsec;
- pr_stat->st_mtim_sec = stat->st_mtim.tv_sec;
- pr_stat->st_mtim_nsec = stat->st_mtim.tv_nsec;
- pr_stat->st_ctim_sec = stat->st_ctim.tv_sec;
- pr_stat->st_ctim_nsec = stat->st_ctim.tv_nsec;
-}
-
-static void statfs_to_prstatfs(ProxyStatFS *pr_stfs, struct statfs *stfs)
-{
- memset(pr_stfs, 0, sizeof(*pr_stfs));
- pr_stfs->f_type = stfs->f_type;
- pr_stfs->f_bsize = stfs->f_bsize;
- pr_stfs->f_blocks = stfs->f_blocks;
- pr_stfs->f_bfree = stfs->f_bfree;
- pr_stfs->f_bavail = stfs->f_bavail;
- pr_stfs->f_files = stfs->f_files;
- pr_stfs->f_ffree = stfs->f_ffree;
- pr_stfs->f_fsid[0] = stfs->f_fsid.__val[0];
- pr_stfs->f_fsid[1] = stfs->f_fsid.__val[1];
- pr_stfs->f_namelen = stfs->f_namelen;
- pr_stfs->f_frsize = stfs->f_frsize;
-}
-
-/*
- * Gets stat/statfs information and packs in out_iovec structure
- * on success returns number of bytes packed in out_iovec structure
- * otherwise returns -errno
- */
-static int do_stat(int type, struct iovec *iovec, struct iovec *out_iovec)
-{
- int retval;
- V9fsString path;
- ProxyStat pr_stat;
- ProxyStatFS pr_stfs;
- struct stat st_buf;
- struct statfs stfs_buf;
-
- v9fs_string_init(&path);
- retval = proxy_unmarshal(iovec, PROXY_HDR_SZ, "s", &path);
- if (retval < 0) {
- return retval;
- }
-
- switch (type) {
- case T_LSTAT:
- retval = lstat(path.data, &st_buf);
- if (retval < 0) {
- retval = -errno;
- } else {
- stat_to_prstat(&pr_stat, &st_buf);
- retval = proxy_marshal(out_iovec, PROXY_HDR_SZ,
- "qqqdddqqqqqqqqqq", pr_stat.st_dev,
- pr_stat.st_ino, pr_stat.st_nlink,
- pr_stat.st_mode, pr_stat.st_uid,
- pr_stat.st_gid, pr_stat.st_rdev,
- pr_stat.st_size, pr_stat.st_blksize,
- pr_stat.st_blocks,
- pr_stat.st_atim_sec, pr_stat.st_atim_nsec,
- pr_stat.st_mtim_sec, pr_stat.st_mtim_nsec,
- pr_stat.st_ctim_sec, pr_stat.st_ctim_nsec);
- }
- break;
- case T_STATFS:
- retval = statfs(path.data, &stfs_buf);
- if (retval < 0) {
- retval = -errno;
- } else {
- statfs_to_prstatfs(&pr_stfs, &stfs_buf);
- retval = proxy_marshal(out_iovec, PROXY_HDR_SZ,
- "qqqqqqqqqqq", pr_stfs.f_type,
- pr_stfs.f_bsize, pr_stfs.f_blocks,
- pr_stfs.f_bfree, pr_stfs.f_bavail,
- pr_stfs.f_files, pr_stfs.f_ffree,
- pr_stfs.f_fsid[0], pr_stfs.f_fsid[1],
- pr_stfs.f_namelen, pr_stfs.f_frsize);
- }
- break;
- }
- v9fs_string_free(&path);
- return retval;
-}
-
-static int do_readlink(struct iovec *iovec, struct iovec *out_iovec)
-{
- char *buffer;
- int size, retval;
- V9fsString target, path;
-
- v9fs_string_init(&path);
- retval = proxy_unmarshal(iovec, PROXY_HDR_SZ, "sd", &path, &size);
- if (retval < 0) {
- v9fs_string_free(&path);
- return retval;
- }
- buffer = g_malloc(size);
- v9fs_string_init(&target);
- retval = readlink(path.data, buffer, size - 1);
- if (retval > 0) {
- buffer[retval] = '\0';
- v9fs_string_sprintf(&target, "%s", buffer);
- retval = proxy_marshal(out_iovec, PROXY_HDR_SZ, "s", &target);
- } else {
- retval = -errno;
- }
- g_free(buffer);
- v9fs_string_free(&target);
- v9fs_string_free(&path);
- return retval;
-}
-
-/*
- * create other filesystem objects and send 0 on success
- * return -errno on error
- */
-static int do_create_others(int type, struct iovec *iovec)
-{
- dev_t rdev;
- int retval = 0;
- int offset = PROXY_HDR_SZ;
- V9fsString oldpath, path;
- int mode, uid, gid, cur_uid, cur_gid;
-
- v9fs_string_init(&path);
- v9fs_string_init(&oldpath);
-
- retval = proxy_unmarshal(iovec, offset, "dd", &uid, &gid);
- if (retval < 0) {
- return retval;
- }
- offset += retval;
- retval = setugid(uid, gid, &cur_uid, &cur_gid);
- if (retval < 0) {
- goto unmarshal_err_out;
- }
- switch (type) {
- case T_MKNOD:
- retval = proxy_unmarshal(iovec, offset, "sdq", &path, &mode, &rdev);
- if (retval < 0) {
- goto err_out;
- }
- retval = mknod(path.data, mode, rdev);
- break;
- case T_MKDIR:
- retval = proxy_unmarshal(iovec, offset, "sd", &path, &mode);
- if (retval < 0) {
- goto err_out;
- }
- retval = g_mkdir(path.data, mode);
- break;
- case T_SYMLINK:
- retval = proxy_unmarshal(iovec, offset, "ss", &oldpath, &path);
- if (retval < 0) {
- goto err_out;
- }
- retval = symlink(oldpath.data, path.data);
- break;
- }
- if (retval < 0) {
- retval = -errno;
- }
-
-err_out:
- resetugid(cur_uid, cur_gid);
-unmarshal_err_out:
- v9fs_string_free(&path);
- v9fs_string_free(&oldpath);
- return retval;
-}
-
-/*
- * create a file and send fd on success
- * return -errno on error
- */
-static int do_create(struct iovec *iovec)
-{
- int ret;
- V9fsString path;
- int flags, mode, uid, gid, cur_uid, cur_gid;
-
- v9fs_string_init(&path);
- ret = proxy_unmarshal(iovec, PROXY_HDR_SZ, "sdddd",
- &path, &flags, &mode, &uid, &gid);
- if (ret < 0) {
- goto unmarshal_err_out;
- }
- ret = setugid(uid, gid, &cur_uid, &cur_gid);
- if (ret < 0) {
- goto unmarshal_err_out;
- }
- ret = open_regular(path.data, flags, mode);
- if (ret < 0) {
- ret = -errno;
- }
-
- resetugid(cur_uid, cur_gid);
-unmarshal_err_out:
- v9fs_string_free(&path);
- return ret;
-}
-
-/*
- * open a file and send fd on success
- * return -errno on error
- */
-static int do_open(struct iovec *iovec)
-{
- int flags, ret;
- V9fsString path;
-
- v9fs_string_init(&path);
- ret = proxy_unmarshal(iovec, PROXY_HDR_SZ, "sd", &path, &flags);
- if (ret < 0) {
- goto err_out;
- }
- ret = open_regular(path.data, flags, 0);
- if (ret < 0) {
- ret = -errno;
- }
-err_out:
- v9fs_string_free(&path);
- return ret;
-}
-
-/* create unix domain socket and return the descriptor */
-static int proxy_socket(const char *path, uid_t uid, gid_t gid)
-{
- int sock, client;
- struct sockaddr_un proxy, qemu;
- socklen_t size;
-
- /* requested socket already exists, refuse to start */
- if (!access(path, F_OK)) {
- do_log(LOG_CRIT, "socket already exists\n");
- return -1;
- }
-
- if (strlen(path) >= sizeof(proxy.sun_path)) {
- do_log(LOG_CRIT, "UNIX domain socket path exceeds %zu characters\n",
- sizeof(proxy.sun_path));
- return -1;
- }
-
- sock = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sock < 0) {
- do_perror("socket");
- return -1;
- }
-
- /* mask other part of mode bits */
- umask(7);
-
- proxy.sun_family = AF_UNIX;
- strcpy(proxy.sun_path, path);
- if (bind(sock, (struct sockaddr *)&proxy,
- sizeof(struct sockaddr_un)) < 0) {
- do_perror("bind");
- goto error;
- }
- if (chown(proxy.sun_path, uid, gid) < 0) {
- do_perror("chown");
- goto error;
- }
- if (listen(sock, 1) < 0) {
- do_perror("listen");
- goto error;
- }
-
- size = sizeof(qemu);
- client = accept(sock, (struct sockaddr *)&qemu, &size);
- if (client < 0) {
- do_perror("accept");
- goto error;
- }
- close(sock);
- return client;
-
-error:
- close(sock);
- return -1;
-}
-
-static void usage(void)
-{
- fprintf(stderr, "usage: %s\n"
- " -p|--path <path> 9p path to export\n"
- " {-f|--fd <socket-descriptor>} socket file descriptor to be used\n"
- " {-s|--socket <socketname> socket file used for communication\n"
- " \t-u|--uid <uid> -g|--gid <gid>} - uid:gid combination to give "
- " access to this socket\n"
- " \tNote: -s & -f can not be used together\n"
- " [-n|--nodaemon] Run as a normal program\n",
- prog_name);
-}
-
-static int process_reply(int sock, int type,
- struct iovec *out_iovec, int retval)
-{
- switch (type) {
- case T_OPEN:
- case T_CREATE:
- if (send_fd(sock, retval) < 0) {
- return -1;
- }
- break;
- case T_MKNOD:
- case T_MKDIR:
- case T_SYMLINK:
- case T_LINK:
- case T_CHMOD:
- case T_CHOWN:
- case T_TRUNCATE:
- case T_UTIME:
- case T_RENAME:
- case T_REMOVE:
- case T_LSETXATTR:
- case T_LREMOVEXATTR:
- if (send_status(sock, out_iovec, retval) < 0) {
- return -1;
- }
- break;
- case T_LSTAT:
- case T_STATFS:
- case T_READLINK:
- case T_LGETXATTR:
- case T_LLISTXATTR:
- case T_GETVERSION:
- if (send_response(sock, out_iovec, retval) < 0) {
- return -1;
- }
- break;
- default:
- return -1;
- break;
- }
- return 0;
-}
-
-static int process_requests(int sock)
-{
- int flags;
- int size = 0;
- int retval = 0;
- uint64_t offset;
- ProxyHeader header;
- int mode, uid, gid;
- V9fsString name, value;
- struct timespec spec[2];
- V9fsString oldpath, path;
- struct iovec in_iovec, out_iovec;
-
- in_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ);
- in_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ;
- out_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ);
- out_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ;
-
- while (1) {
- /*
- * initialize the header type, so that we send
- * response to proper request type.
- */
- header.type = 0;
- retval = read_request(sock, &in_iovec, &header);
- if (retval < 0) {
- goto err_out;
- }
-
- switch (header.type) {
- case T_OPEN:
- retval = do_open(&in_iovec);
- break;
- case T_CREATE:
- retval = do_create(&in_iovec);
- break;
- case T_MKNOD:
- case T_MKDIR:
- case T_SYMLINK:
- retval = do_create_others(header.type, &in_iovec);
- break;
- case T_LINK:
- v9fs_string_init(&path);
- v9fs_string_init(&oldpath);
- retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ,
- "ss", &oldpath, &path);
- if (retval > 0) {
- retval = link(oldpath.data, path.data);
- if (retval < 0) {
- retval = -errno;
- }
- }
- v9fs_string_free(&oldpath);
- v9fs_string_free(&path);
- break;
- case T_LSTAT:
- case T_STATFS:
- retval = do_stat(header.type, &in_iovec, &out_iovec);
- break;
- case T_READLINK:
- retval = do_readlink(&in_iovec, &out_iovec);
- break;
- case T_CHMOD:
- v9fs_string_init(&path);
- retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ,
- "sd", &path, &mode);
- if (retval > 0) {
- retval = chmod(path.data, mode);
- if (retval < 0) {
- retval = -errno;
- }
- }
- v9fs_string_free(&path);
- break;
- case T_CHOWN:
- v9fs_string_init(&path);
- retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "sdd", &path,
- &uid, &gid);
- if (retval > 0) {
- retval = lchown(path.data, uid, gid);
- if (retval < 0) {
- retval = -errno;
- }
- }
- v9fs_string_free(&path);
- break;
- case T_TRUNCATE:
- v9fs_string_init(&path);
- retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "sq",
- &path, &offset);
- if (retval > 0) {
- retval = truncate(path.data, offset);
- if (retval < 0) {
- retval = -errno;
- }
- }
- v9fs_string_free(&path);
- break;
- case T_UTIME:
- v9fs_string_init(&path);
- retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "sqqqq", &path,
- &spec[0].tv_sec, &spec[0].tv_nsec,
- &spec[1].tv_sec, &spec[1].tv_nsec);
- if (retval > 0) {
- retval = utimensat(AT_FDCWD, path.data, spec,
- AT_SYMLINK_NOFOLLOW);
- if (retval < 0) {
- retval = -errno;
- }
- }
- v9fs_string_free(&path);
- break;
- case T_RENAME:
- v9fs_string_init(&path);
- v9fs_string_init(&oldpath);
- retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ,
- "ss", &oldpath, &path);
- if (retval > 0) {
- retval = rename(oldpath.data, path.data);
- if (retval < 0) {
- retval = -errno;
- }
- }
- v9fs_string_free(&oldpath);
- v9fs_string_free(&path);
- break;
- case T_REMOVE:
- v9fs_string_init(&path);
- retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "s", &path);
- if (retval > 0) {
- retval = remove(path.data);
- if (retval < 0) {
- retval = -errno;
- }
- }
- v9fs_string_free(&path);
- break;
- case T_LGETXATTR:
- case T_LLISTXATTR:
- retval = do_getxattr(header.type, &in_iovec, &out_iovec);
- break;
- case T_LSETXATTR:
- v9fs_string_init(&path);
- v9fs_string_init(&name);
- v9fs_string_init(&value);
- retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "sssdd", &path,
- &name, &value, &size, &flags);
- if (retval > 0) {
- retval = lsetxattr(path.data,
- name.data, value.data, size, flags);
- if (retval < 0) {
- retval = -errno;
- }
- }
- v9fs_string_free(&path);
- v9fs_string_free(&name);
- v9fs_string_free(&value);
- break;
- case T_LREMOVEXATTR:
- v9fs_string_init(&path);
- v9fs_string_init(&name);
- retval = proxy_unmarshal(&in_iovec,
- PROXY_HDR_SZ, "ss", &path, &name);
- if (retval > 0) {
- retval = lremovexattr(path.data, name.data);
- if (retval < 0) {
- retval = -errno;
- }
- }
- v9fs_string_free(&path);
- v9fs_string_free(&name);
- break;
- case T_GETVERSION:
- retval = do_getversion(&in_iovec, &out_iovec);
- break;
- default:
- goto err_out;
- break;
- }
-
- if (process_reply(sock, header.type, &out_iovec, retval) < 0) {
- goto err_out;
- }
- }
-err_out:
- g_free(in_iovec.iov_base);
- g_free(out_iovec.iov_base);
- return -1;
-}
-
-int main(int argc, char **argv)
-{
- int sock;
- uid_t own_u;
- gid_t own_g;
- char *rpath = NULL;
- char *sock_name = NULL;
- struct stat stbuf;
- int c, option_index;
-#ifdef FS_IOC_GETVERSION
- int retval;
- struct statfs st_fs;
-#endif
-
- fprintf(stderr, "NOTE: The 9p 'proxy' backend is deprecated (since "
- "QEMU 8.1) and will be removed in a future version of "
- "QEMU!\n");
-
- prog_name = g_path_get_basename(argv[0]);
-
- is_daemon = true;
- sock = -1;
- own_u = own_g = -1;
- while (1) {
- option_index = 0;
- c = getopt_long(argc, argv, "p:nh?f:s:u:g:", helper_opts,
- &option_index);
- if (c == -1) {
- break;
- }
- switch (c) {
- case 'p':
- rpath = g_strdup(optarg);
- break;
- case 'n':
- is_daemon = false;
- break;
- case 'f':
- sock = atoi(optarg);
- break;
- case 's':
- sock_name = g_strdup(optarg);
- break;
- case 'u':
- own_u = atoi(optarg);
- break;
- case 'g':
- own_g = atoi(optarg);
- break;
- case '?':
- case 'h':
- default:
- usage();
- exit(EXIT_FAILURE);
- }
- }
-
- /* Parameter validation */
- if ((sock_name == NULL && sock == -1) || rpath == NULL) {
- fprintf(stderr, "socket, socket descriptor or path not specified\n");
- usage();
- return -1;
- }
-
- if (sock_name && sock != -1) {
- fprintf(stderr, "both named socket and socket descriptor specified\n");
- usage();
- exit(EXIT_FAILURE);
- }
-
- if (sock_name && (own_u == -1 || own_g == -1)) {
- fprintf(stderr, "owner uid:gid not specified, ");
- fprintf(stderr,
- "owner uid:gid specifies who can access the socket file\n");
- usage();
- exit(EXIT_FAILURE);
- }
-
- if (lstat(rpath, &stbuf) < 0) {
- fprintf(stderr, "invalid path \"%s\" specified, %s\n",
- rpath, strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- if (!S_ISDIR(stbuf.st_mode)) {
- fprintf(stderr, "specified path \"%s\" is not directory\n", rpath);
- exit(EXIT_FAILURE);
- }
-
- if (is_daemon) {
- if (daemon(0, 0) < 0) {
- fprintf(stderr, "daemon call failed\n");
- exit(EXIT_FAILURE);
- }
- openlog(PROGNAME, LOG_PID, LOG_DAEMON);
- }
-
- do_log(LOG_INFO, "Started\n");
- if (sock_name) {
- sock = proxy_socket(sock_name, own_u, own_g);
- if (sock < 0) {
- goto error;
- }
- }
-
- if (chroot(rpath) < 0) {
- do_perror("chroot");
- goto error;
- }
- if (chdir("/") < 0) {
- do_perror("chdir");
- goto error;
- }
-
- get_version = false;
-#ifdef FS_IOC_GETVERSION
- /* check whether underlying FS support IOC_GETVERSION */
- retval = statfs("/", &st_fs);
- if (!retval) {
- switch (st_fs.f_type) {
- case EXT2_SUPER_MAGIC:
- case BTRFS_SUPER_MAGIC:
- case REISERFS_SUPER_MAGIC:
- case XFS_SUPER_MAGIC:
- get_version = true;
- break;
- }
- }
-#endif
-
- umask(0);
- if (init_capabilities() < 0) {
- goto error;
- }
-
- process_requests(sock);
-error:
- g_free(rpath);
- g_free(sock_name);
- do_log(LOG_INFO, "Done\n");
- closelog();
- return 0;
-}
diff --git a/gdb-xml/hexagon-core.xml b/gdb-xml/hexagon-core.xml
index e181163..b943781 100644
--- a/gdb-xml/hexagon-core.xml
+++ b/gdb-xml/hexagon-core.xml
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!--
- Copyright(c) 2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ Copyright(c) 2023-2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
This work is licensed under the terms of the GNU GPL, version 2 or
(at your option) any later version. See the COPYING file in the
@@ -80,5 +80,9 @@
<reg name="c29" bitsize="32" offset="244" encoding="uint" format="hex" group="Thread Registers" dwarf_regnum="61"/>
<reg name="utimerlo" bitsize="32" offset="248" encoding="uint" format="hex" group="Thread Registers" dwarf_regnum="62"/>
<reg name="utimerhi" bitsize="32" offset="252" encoding="uint" format="hex" group="Thread Registers" dwarf_regnum="63"/>
+ <reg name="p0" bitsize="8" offset="256" encoding="uint" format="hex" group="Predicate Registers" dwarf_regnum="64"/>
+ <reg name="p1" bitsize="8" offset="257" encoding="uint" format="hex" group="Predicate Registers" dwarf_regnum="65"/>
+ <reg name="p2" bitsize="8" offset="258" encoding="uint" format="hex" group="Predicate Registers" dwarf_regnum="66"/>
+ <reg name="p3" bitsize="8" offset="259" encoding="uint" format="hex" group="Predicate Registers" dwarf_regnum="67"/>
</feature>
diff --git a/gdb-xml/i386-32bit-linux.xml b/gdb-xml/i386-32bit-linux.xml
new file mode 100644
index 0000000..5ffe561
--- /dev/null
+++ b/gdb-xml/i386-32bit-linux.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010-2024 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.linux">
+ <reg name="orig_eax" bitsize="32" type="int"/>
+</feature>
diff --git a/gdb-xml/i386-64bit-linux.xml b/gdb-xml/i386-64bit-linux.xml
new file mode 100644
index 0000000..0f26990
--- /dev/null
+++ b/gdb-xml/i386-64bit-linux.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010-2024 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.linux">
+ <reg name="orig_rax" bitsize="64" type="int"/>
+</feature>
diff --git a/gdb-xml/loongarch-lasx.xml b/gdb-xml/loongarch-lasx.xml
new file mode 100644
index 0000000..753b982
--- /dev/null
+++ b/gdb-xml/loongarch-lasx.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2022-2024 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.loongarch.lasx">
+ <vector id="v8f32" type="ieee_single" count="8"/>
+ <vector id="v4f64" type="ieee_double" count="4"/>
+ <vector id="v32i8" type="int8" count="32"/>
+ <vector id="v16i16" type="int16" count="16"/>
+ <vector id="v8i32" type="int32" count="8"/>
+ <vector id="v4i64" type="int64" count="4"/>
+ <vector id="v2ui128" type="uint128" count="2"/>
+
+ <union id="lasxv">
+ <field name="v8_float" type="v8f32"/>
+ <field name="v4_double" type="v4f64"/>
+ <field name="v32_int8" type="v32i8"/>
+ <field name="v16_int16" type="v16i16"/>
+ <field name="v8_int32" type="v8i32"/>
+ <field name="v4_int64" type="v4i64"/>
+ <field name="v2_uint128" type="v2ui128"/>
+ </union>
+
+ <reg name="xr0" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr1" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr2" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr3" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr4" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr5" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr6" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr7" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr8" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr9" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr10" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr11" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr12" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr13" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr14" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr15" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr16" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr17" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr18" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr19" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr20" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr21" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr22" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr23" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr24" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr25" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr26" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr27" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr28" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr29" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr30" bitsize="256" type="lasxv" group="lasx"/>
+ <reg name="xr31" bitsize="256" type="lasxv" group="lasx"/>
+</feature>
diff --git a/gdb-xml/loongarch-lsx.xml b/gdb-xml/loongarch-lsx.xml
new file mode 100644
index 0000000..51af1c6
--- /dev/null
+++ b/gdb-xml/loongarch-lsx.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2022-2024 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.loongarch.lsx">
+ <vector id="v4f32" type="ieee_single" count="4"/>
+ <vector id="v2f64" type="ieee_double" count="2"/>
+ <vector id="v16i8" type="int8" count="16"/>
+ <vector id="v8i16" type="int16" count="8"/>
+ <vector id="v4i32" type="int32" count="4"/>
+ <vector id="v2i64" type="int64" count="2"/>
+
+ <union id="lsxv">
+ <field name="v4_float" type="v4f32"/>
+ <field name="v2_double" type="v2f64"/>
+ <field name="v16_int8" type="v16i8"/>
+ <field name="v8_int16" type="v8i16"/>
+ <field name="v4_int32" type="v4i32"/>
+ <field name="v2_int64" type="v2i64"/>
+ <field name="uint128" type="uint128"/>
+ </union>
+
+ <reg name="vr0" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr1" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr2" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr3" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr4" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr5" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr6" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr7" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr8" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr9" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr10" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr11" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr12" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr13" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr14" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr15" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr16" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr17" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr18" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr19" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr20" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr21" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr22" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr23" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr26" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr25" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr26" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr27" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr28" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr29" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr30" bitsize="128" type="lsxv" group="lsx"/>
+ <reg name="vr31" bitsize="128" type="lsxv" group="lsx"/>
+</feature>
diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c
index b9ad0a0..b1def7e 100644
--- a/gdbstub/gdbstub.c
+++ b/gdbstub/gdbstub.c
@@ -20,7 +20,7 @@
* 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/>.
*
- * SPDX-License-Identifier: LGPL-2.0+
+ * SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "qemu/osdep.h"
@@ -618,6 +618,19 @@ void gdb_register_coprocessor(CPUState *cpu,
}
}
+void gdb_unregister_coprocessor_all(CPUState *cpu)
+{
+ /*
+ * Safe to nuke everything. GDBRegisterState::xml is static const char so
+ * it won't be freed
+ */
+ g_array_free(cpu->gdb_regs, true);
+
+ cpu->gdb_regs = NULL;
+ cpu->gdb_num_regs = 0;
+ cpu->gdb_num_g_regs = 0;
+}
+
static void gdb_process_breakpoint_remove_all(GDBProcess *p)
{
CPUState *cpu = gdb_get_first_cpu_in_process(p);
@@ -1614,18 +1627,21 @@ static void handle_query_thread_extra(GArray *params, void *user_ctx)
gdb_put_strbuf();
}
-static char *extended_qsupported_features;
-void gdb_extend_qsupported_features(char *qsupported_features)
-{
- /*
- * We don't support different sets of CPU gdb features on different CPUs yet
- * so assert the feature strings are the same on all CPUs, or is set only
- * once (1 CPU).
- */
- g_assert(extended_qsupported_features == NULL ||
- g_strcmp0(extended_qsupported_features, qsupported_features) == 0);
- extended_qsupported_features = qsupported_features;
+static char **extra_query_flags;
+
+void gdb_extend_qsupported_features(char *qflags)
+{
+ if (!extra_query_flags) {
+ extra_query_flags = g_new0(char *, 2);
+ extra_query_flags[0] = g_strdup(qflags);
+ } else if (!g_strv_contains((const gchar * const *) extra_query_flags,
+ qflags)) {
+ int len = g_strv_length(extra_query_flags);
+ extra_query_flags = g_realloc_n(extra_query_flags, len + 2,
+ sizeof(char *));
+ extra_query_flags[len] = g_strdup(qflags);
+ }
}
static void handle_query_supported(GArray *params, void *user_ctx)
@@ -1668,8 +1684,11 @@ static void handle_query_supported(GArray *params, void *user_ctx)
g_string_append(gdbserver_state.str_buf, ";vContSupported+;multiprocess+");
- if (extended_qsupported_features) {
- g_string_append(gdbserver_state.str_buf, extended_qsupported_features);
+ if (extra_query_flags) {
+ int extras = g_strv_length(extra_query_flags);
+ for (int i = 0; i < extras; i++) {
+ g_string_append(gdbserver_state.str_buf, extra_query_flags[i]);
+ }
}
gdb_put_strbuf();
@@ -1753,39 +1772,58 @@ static const GdbCmdParseEntry gdb_gen_query_set_common_table[] = {
},
};
-/* Compares if a set of command parsers is equal to another set of parsers. */
-static bool cmp_cmds(GdbCmdParseEntry *c, GdbCmdParseEntry *d, int size)
+/**
+ * extend_table() - extend one of the command tables
+ * @table: the command table to extend (or NULL)
+ * @extensions: a list of GdbCmdParseEntry pointers
+ *
+ * The entries themselves should be pointers to static const
+ * GdbCmdParseEntry entries. If the entry is already in the table we
+ * skip adding it again.
+ *
+ * Returns (a potentially freshly allocated) GPtrArray of GdbCmdParseEntry
+ */
+static GPtrArray *extend_table(GPtrArray *table, GPtrArray *extensions)
{
- for (int i = 0; i < size; i++) {
- if (!(c[i].handler == d[i].handler &&
- g_strcmp0(c[i].cmd, d[i].cmd) == 0 &&
- c[i].cmd_startswith == d[i].cmd_startswith &&
- g_strcmp0(c[i].schema, d[i].schema) == 0)) {
+ if (!table) {
+ table = g_ptr_array_new();
+ }
- /* Sets are different. */
- return false;
+ for (int i = 0; i < extensions->len; i++) {
+ gpointer entry = g_ptr_array_index(extensions, i);
+ if (!g_ptr_array_find(table, entry, NULL)) {
+ g_ptr_array_add(table, entry);
}
}
- /* Sets are equal, i.e. contain the same command parsers. */
- return true;
+ return table;
}
-static GdbCmdParseEntry *extended_query_table;
-static int extended_query_table_size;
-void gdb_extend_query_table(GdbCmdParseEntry *table, int size)
+/**
+ * process_extended_table() - run through an extended command table
+ * @table: the command table to check
+ * @data: parameters
+ *
+ * returns true if the command was found and executed
+ */
+static bool process_extended_table(GPtrArray *table, const char *data)
{
- /*
- * We don't support different sets of CPU gdb features on different CPUs yet
- * so assert query table is the same on all CPUs, or is set only once
- * (1 CPU).
- */
- g_assert(extended_query_table == NULL ||
- (extended_query_table_size == size &&
- cmp_cmds(extended_query_table, table, size)));
+ for (int i = 0; i < table->len; i++) {
+ const GdbCmdParseEntry *entry = g_ptr_array_index(table, i);
+ if (process_string_cmd(data, entry, 1)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/* Ptr to GdbCmdParseEntry */
+static GPtrArray *extended_query_table;
- extended_query_table = table;
- extended_query_table_size = size;
+void gdb_extend_query_table(GPtrArray *new_queries)
+{
+ extended_query_table = extend_table(extended_query_table, new_queries);
}
static const GdbCmdParseEntry gdb_gen_query_table[] = {
@@ -1880,20 +1918,12 @@ static const GdbCmdParseEntry gdb_gen_query_table[] = {
#endif
};
-static GdbCmdParseEntry *extended_set_table;
-static int extended_set_table_size;
-void gdb_extend_set_table(GdbCmdParseEntry *table, int size)
-{
- /*
- * We don't support different sets of CPU gdb features on different CPUs yet
- * so assert set table is the same on all CPUs, or is set only once (1 CPU).
- */
- g_assert(extended_set_table == NULL ||
- (extended_set_table_size == size &&
- cmp_cmds(extended_set_table, table, size)));
+/* Ptr to GdbCmdParseEntry */
+static GPtrArray *extended_set_table;
- extended_set_table = table;
- extended_set_table_size = size;
+void gdb_extend_set_table(GPtrArray *new_set)
+{
+ extended_set_table = extend_table(extended_set_table, new_set);
}
static const GdbCmdParseEntry gdb_gen_set_table[] = {
@@ -1924,26 +1954,28 @@ static const GdbCmdParseEntry gdb_gen_set_table[] = {
static void handle_gen_query(GArray *params, void *user_ctx)
{
+ const char *data;
+
if (!params->len) {
return;
}
- if (process_string_cmd(gdb_get_cmd_param(params, 0)->data,
+ data = gdb_get_cmd_param(params, 0)->data;
+
+ if (process_string_cmd(data,
gdb_gen_query_set_common_table,
ARRAY_SIZE(gdb_gen_query_set_common_table))) {
return;
}
- if (process_string_cmd(gdb_get_cmd_param(params, 0)->data,
+ if (process_string_cmd(data,
gdb_gen_query_table,
ARRAY_SIZE(gdb_gen_query_table))) {
return;
}
if (extended_query_table &&
- process_string_cmd(gdb_get_cmd_param(params, 0)->data,
- extended_query_table,
- extended_query_table_size)) {
+ process_extended_table(extended_query_table, data)) {
return;
}
@@ -1953,26 +1985,28 @@ static void handle_gen_query(GArray *params, void *user_ctx)
static void handle_gen_set(GArray *params, void *user_ctx)
{
+ const char *data;
+
if (!params->len) {
return;
}
- if (process_string_cmd(gdb_get_cmd_param(params, 0)->data,
+ data = gdb_get_cmd_param(params, 0)->data;
+
+ if (process_string_cmd(data,
gdb_gen_query_set_common_table,
ARRAY_SIZE(gdb_gen_query_set_common_table))) {
return;
}
- if (process_string_cmd(gdb_get_cmd_param(params, 0)->data,
+ if (process_string_cmd(data,
gdb_gen_set_table,
ARRAY_SIZE(gdb_gen_set_table))) {
return;
}
if (extended_set_table &&
- process_string_cmd(gdb_get_cmd_param(params, 0)->data,
- extended_set_table,
- extended_set_table_size)) {
+ process_extended_table(extended_set_table, data)) {
return;
}
diff --git a/gdbstub/syscalls.c b/gdbstub/syscalls.c
index 4e1295b..4ddd5ca 100644
--- a/gdbstub/syscalls.c
+++ b/gdbstub/syscalls.c
@@ -7,7 +7,7 @@
* Copyright (c) 2003-2005 Fabrice Bellard
* Copyright (c) 2023 Linaro Ltd
*
- * SPDX-License-Identifier: LGPL-2.0+
+ * SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "qemu/osdep.h"
diff --git a/gdbstub/system.c b/gdbstub/system.c
index 1ad87fe..c9f236e 100644
--- a/gdbstub/system.c
+++ b/gdbstub/system.c
@@ -7,7 +7,7 @@
* Copyright (c) 2003-2005 Fabrice Bellard
* Copyright (c) 2022 Linaro Ltd
*
- * SPDX-License-Identifier: LGPL-2.0+
+ * SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "qemu/osdep.h"
diff --git a/gdbstub/user-target.c b/gdbstub/user-target.c
index b5e01fd..22bf400 100644
--- a/gdbstub/user-target.c
+++ b/gdbstub/user-target.c
@@ -4,7 +4,7 @@
* Copyright (c) 2003-2005 Fabrice Bellard
* Copyright (c) 2022 Linaro Ltd
*
- * SPDX-License-Identifier: LGPL-2.0+
+ * SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "qemu/osdep.h"
diff --git a/gdbstub/user.c b/gdbstub/user.c
index b36033b..0b4bfa9 100644
--- a/gdbstub/user.c
+++ b/gdbstub/user.c
@@ -6,7 +6,7 @@
* Copyright (c) 2003-2005 Fabrice Bellard
* Copyright (c) 2022 Linaro Ltd
*
- * SPDX-License-Identifier: LGPL-2.0+
+ * SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "qemu/osdep.h"
diff --git a/host/include/riscv/host/cpuinfo.h b/host/include/riscv/host/cpuinfo.h
index 2b00660..cdc784e 100644
--- a/host/include/riscv/host/cpuinfo.h
+++ b/host/include/riscv/host/cpuinfo.h
@@ -10,9 +10,11 @@
#define CPUINFO_ZBA (1u << 1)
#define CPUINFO_ZBB (1u << 2)
#define CPUINFO_ZICOND (1u << 3)
+#define CPUINFO_ZVE64X (1u << 4)
/* Initialized with a constructor. */
extern unsigned cpuinfo;
+extern unsigned riscv_lg2_vlenb;
/*
* We cannot rely on constructor ordering, so other constructors must
diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c
deleted file mode 100644
index 7aac49a..0000000
--- a/hw/9pfs/9p-proxy.c
+++ /dev/null
@@ -1,1279 +0,0 @@
-/*
- * 9p Proxy callback
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- * M. Mohan Kumar <mohan@in.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- */
-
-/*
- * Not so fast! You might want to read the 9p developer docs first:
- * https://wiki.qemu.org/Documentation/9p
- */
-
-/*
- * NOTE: The 9p 'proxy' backend is deprecated (since QEMU 8.1) and will be
- * removed in a future version of QEMU!
- */
-
-#include "qemu/osdep.h"
-#include <sys/socket.h>
-#include <sys/un.h>
-#include "9p.h"
-#include "qapi/error.h"
-#include "qemu/cutils.h"
-#include "qemu/error-report.h"
-#include "qemu/option.h"
-#include "fsdev/qemu-fsdev.h"
-#include "9p-proxy.h"
-
-typedef struct V9fsProxy {
- int sockfd;
- QemuMutex mutex;
- struct iovec in_iovec;
- struct iovec out_iovec;
-} V9fsProxy;
-
-/*
- * Return received file descriptor on success in *status.
- * errno is also returned on *status (which will be < 0)
- * return < 0 on transport error.
- */
-static int v9fs_receivefd(int sockfd, int *status)
-{
- struct iovec iov;
- struct msghdr msg;
- struct cmsghdr *cmsg;
- int retval, data, fd;
- union MsgControl msg_control;
-
- iov.iov_base = &data;
- iov.iov_len = sizeof(data);
-
- memset(&msg, 0, sizeof(msg));
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = &msg_control;
- msg.msg_controllen = sizeof(msg_control);
-
- do {
- retval = recvmsg(sockfd, &msg, 0);
- } while (retval < 0 && errno == EINTR);
- if (retval <= 0) {
- return retval;
- }
- /*
- * data is set to V9FS_FD_VALID, if ancillary data is sent. If this
- * request doesn't need ancillary data (fd) or an error occurred,
- * data is set to negative errno value.
- */
- if (data != V9FS_FD_VALID) {
- *status = data;
- return 0;
- }
- /*
- * File descriptor (fd) is sent in the ancillary data. Check if we
- * indeed received it. One of the reasons to fail to receive it is if
- * we exceeded the maximum number of file descriptors!
- */
- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
- if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
- cmsg->cmsg_level != SOL_SOCKET ||
- cmsg->cmsg_type != SCM_RIGHTS) {
- continue;
- }
- fd = *((int *)CMSG_DATA(cmsg));
- *status = fd;
- return 0;
- }
- *status = -ENFILE; /* Ancillary data sent but not received */
- return 0;
-}
-
-static ssize_t socket_read(int sockfd, void *buff, size_t size)
-{
- ssize_t retval, total = 0;
-
- while (size) {
- retval = read(sockfd, buff, size);
- if (retval == 0) {
- return -EIO;
- }
- if (retval < 0) {
- if (errno == EINTR) {
- continue;
- }
- return -errno;
- }
- size -= retval;
- buff += retval;
- total += retval;
- }
- return total;
-}
-
-/* Converts proxy_statfs to VFS statfs structure */
-static void prstatfs_to_statfs(struct statfs *stfs, ProxyStatFS *prstfs)
-{
- memset(stfs, 0, sizeof(*stfs));
- stfs->f_type = prstfs->f_type;
- stfs->f_bsize = prstfs->f_bsize;
- stfs->f_blocks = prstfs->f_blocks;
- stfs->f_bfree = prstfs->f_bfree;
- stfs->f_bavail = prstfs->f_bavail;
- stfs->f_files = prstfs->f_files;
- stfs->f_ffree = prstfs->f_ffree;
-#ifdef CONFIG_DARWIN
- /* f_namelen and f_frsize do not exist on Darwin */
- stfs->f_fsid.val[0] = prstfs->f_fsid[0] & 0xFFFFFFFFU;
- stfs->f_fsid.val[1] = prstfs->f_fsid[1] >> 32 & 0xFFFFFFFFU;
-#else
- stfs->f_fsid.__val[0] = prstfs->f_fsid[0] & 0xFFFFFFFFU;
- stfs->f_fsid.__val[1] = prstfs->f_fsid[1] >> 32 & 0xFFFFFFFFU;
- stfs->f_namelen = prstfs->f_namelen;
- stfs->f_frsize = prstfs->f_frsize;
-#endif
-}
-
-/* Converts proxy_stat structure to VFS stat structure */
-static void prstat_to_stat(struct stat *stbuf, ProxyStat *prstat)
-{
- memset(stbuf, 0, sizeof(*stbuf));
- stbuf->st_dev = prstat->st_dev;
- stbuf->st_ino = prstat->st_ino;
- stbuf->st_nlink = prstat->st_nlink;
- stbuf->st_mode = prstat->st_mode;
- stbuf->st_uid = prstat->st_uid;
- stbuf->st_gid = prstat->st_gid;
- stbuf->st_rdev = prstat->st_rdev;
- stbuf->st_size = prstat->st_size;
- stbuf->st_blksize = prstat->st_blksize;
- stbuf->st_blocks = prstat->st_blocks;
- stbuf->st_atime = prstat->st_atim_sec;
- stbuf->st_mtime = prstat->st_mtim_sec;
- stbuf->st_ctime = prstat->st_ctim_sec;
-#ifdef CONFIG_DARWIN
- stbuf->st_atimespec.tv_sec = prstat->st_atim_sec;
- stbuf->st_mtimespec.tv_sec = prstat->st_mtim_sec;
- stbuf->st_ctimespec.tv_sec = prstat->st_ctim_sec;
- stbuf->st_atimespec.tv_nsec = prstat->st_atim_nsec;
- stbuf->st_mtimespec.tv_nsec = prstat->st_mtim_nsec;
- stbuf->st_ctimespec.tv_nsec = prstat->st_ctim_nsec;
-#else
- stbuf->st_atim.tv_sec = prstat->st_atim_sec;
- stbuf->st_mtim.tv_sec = prstat->st_mtim_sec;
- stbuf->st_ctim.tv_sec = prstat->st_ctim_sec;
- stbuf->st_atim.tv_nsec = prstat->st_atim_nsec;
- stbuf->st_mtim.tv_nsec = prstat->st_mtim_nsec;
- stbuf->st_ctim.tv_nsec = prstat->st_ctim_nsec;
-#endif
-}
-
-/*
- * Response contains two parts
- * {header, data}
- * header.type == T_ERROR, data -> -errno
- * header.type == T_SUCCESS, data -> response
- * size of errno/response is given by header.size
- * returns < 0, on transport error. response is
- * valid only if status >= 0.
- */
-static int v9fs_receive_response(V9fsProxy *proxy, int type,
- int *status, void *response)
-{
- int retval;
- ProxyHeader header;
- struct iovec *reply = &proxy->in_iovec;
-
- *status = 0;
- reply->iov_len = 0;
- retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ);
- if (retval < 0) {
- return retval;
- }
- reply->iov_len = PROXY_HDR_SZ;
- retval = proxy_unmarshal(reply, 0, "dd", &header.type, &header.size);
- assert(retval == 4 * 2);
- /*
- * if response size > PROXY_MAX_IO_SZ, read the response but ignore it and
- * return -ENOBUFS
- */
- if (header.size > PROXY_MAX_IO_SZ) {
- int count;
- while (header.size > 0) {
- count = MIN(PROXY_MAX_IO_SZ, header.size);
- count = socket_read(proxy->sockfd, reply->iov_base, count);
- if (count < 0) {
- return count;
- }
- header.size -= count;
- }
- *status = -ENOBUFS;
- return 0;
- }
-
- retval = socket_read(proxy->sockfd,
- reply->iov_base + PROXY_HDR_SZ, header.size);
- if (retval < 0) {
- return retval;
- }
- reply->iov_len += header.size;
- /* there was an error during processing request */
- if (header.type == T_ERROR) {
- int ret;
- ret = proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status);
- assert(ret == 4);
- return 0;
- }
-
- switch (type) {
- case T_LSTAT: {
- ProxyStat prstat;
- retval = proxy_unmarshal(reply, PROXY_HDR_SZ,
- "qqqdddqqqqqqqqqq", &prstat.st_dev,
- &prstat.st_ino, &prstat.st_nlink,
- &prstat.st_mode, &prstat.st_uid,
- &prstat.st_gid, &prstat.st_rdev,
- &prstat.st_size, &prstat.st_blksize,
- &prstat.st_blocks,
- &prstat.st_atim_sec, &prstat.st_atim_nsec,
- &prstat.st_mtim_sec, &prstat.st_mtim_nsec,
- &prstat.st_ctim_sec, &prstat.st_ctim_nsec);
- assert(retval == 8 * 3 + 4 * 3 + 8 * 10);
- prstat_to_stat(response, &prstat);
- break;
- }
- case T_STATFS: {
- ProxyStatFS prstfs;
- retval = proxy_unmarshal(reply, PROXY_HDR_SZ,
- "qqqqqqqqqqq", &prstfs.f_type,
- &prstfs.f_bsize, &prstfs.f_blocks,
- &prstfs.f_bfree, &prstfs.f_bavail,
- &prstfs.f_files, &prstfs.f_ffree,
- &prstfs.f_fsid[0], &prstfs.f_fsid[1],
- &prstfs.f_namelen, &prstfs.f_frsize);
- assert(retval == 8 * 11);
- prstatfs_to_statfs(response, &prstfs);
- break;
- }
- case T_READLINK: {
- V9fsString target;
- v9fs_string_init(&target);
- retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &target);
- strcpy(response, target.data);
- v9fs_string_free(&target);
- break;
- }
- case T_LGETXATTR:
- case T_LLISTXATTR: {
- V9fsString xattr;
- v9fs_string_init(&xattr);
- retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &xattr);
- memcpy(response, xattr.data, xattr.size);
- v9fs_string_free(&xattr);
- break;
- }
- case T_GETVERSION:
- retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "q", response);
- assert(retval == 8);
- break;
- default:
- return -1;
- }
- if (retval < 0) {
- *status = retval;
- }
- return 0;
-}
-
-/*
- * return < 0 on transport error.
- * *status is valid only if return >= 0
- */
-static int v9fs_receive_status(V9fsProxy *proxy,
- struct iovec *reply, int *status)
-{
- int retval;
- ProxyHeader header;
-
- *status = 0;
- reply->iov_len = 0;
- retval = socket_read(proxy->sockfd, reply->iov_base, PROXY_HDR_SZ);
- if (retval < 0) {
- return retval;
- }
- reply->iov_len = PROXY_HDR_SZ;
- retval = proxy_unmarshal(reply, 0, "dd", &header.type, &header.size);
- assert(retval == 4 * 2);
- retval = socket_read(proxy->sockfd,
- reply->iov_base + PROXY_HDR_SZ, header.size);
- if (retval < 0) {
- return retval;
- }
- reply->iov_len += header.size;
- retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status);
- assert(retval == 4);
- return 0;
-}
-
-/*
- * Proxy->header and proxy->request written to socket by QEMU process.
- * This request read by proxy helper process
- * returns 0 on success and -errno on error
- */
-static int v9fs_request(V9fsProxy *proxy, int type, void *response, ...)
-{
- dev_t rdev;
- va_list ap;
- int size = 0;
- int retval = 0;
- uint64_t offset;
- ProxyHeader header = { 0, 0};
- struct timespec spec[2];
- int flags, mode, uid, gid;
- V9fsString *name, *value;
- V9fsString *path, *oldpath;
- struct iovec *iovec = NULL, *reply = NULL;
-
- qemu_mutex_lock(&proxy->mutex);
-
- if (proxy->sockfd == -1) {
- retval = -EIO;
- goto err_out;
- }
- iovec = &proxy->out_iovec;
- reply = &proxy->in_iovec;
- va_start(ap, response);
- switch (type) {
- case T_OPEN:
- path = va_arg(ap, V9fsString *);
- flags = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, flags);
- if (retval > 0) {
- header.size = retval;
- header.type = T_OPEN;
- }
- break;
- case T_CREATE:
- path = va_arg(ap, V9fsString *);
- flags = va_arg(ap, int);
- mode = va_arg(ap, int);
- uid = va_arg(ap, int);
- gid = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sdddd", path,
- flags, mode, uid, gid);
- if (retval > 0) {
- header.size = retval;
- header.type = T_CREATE;
- }
- break;
- case T_MKNOD:
- path = va_arg(ap, V9fsString *);
- mode = va_arg(ap, int);
- rdev = va_arg(ap, long int);
- uid = va_arg(ap, int);
- gid = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddsdq",
- uid, gid, path, mode, rdev);
- if (retval > 0) {
- header.size = retval;
- header.type = T_MKNOD;
- }
- break;
- case T_MKDIR:
- path = va_arg(ap, V9fsString *);
- mode = va_arg(ap, int);
- uid = va_arg(ap, int);
- gid = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddsd",
- uid, gid, path, mode);
- if (retval > 0) {
- header.size = retval;
- header.type = T_MKDIR;
- }
- break;
- case T_SYMLINK:
- oldpath = va_arg(ap, V9fsString *);
- path = va_arg(ap, V9fsString *);
- uid = va_arg(ap, int);
- gid = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ddss",
- uid, gid, oldpath, path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_SYMLINK;
- }
- break;
- case T_LINK:
- oldpath = va_arg(ap, V9fsString *);
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss",
- oldpath, path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LINK;
- }
- break;
- case T_LSTAT:
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LSTAT;
- }
- break;
- case T_READLINK:
- path = va_arg(ap, V9fsString *);
- size = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, size);
- if (retval > 0) {
- header.size = retval;
- header.type = T_READLINK;
- }
- break;
- case T_STATFS:
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_STATFS;
- }
- break;
- case T_CHMOD:
- path = va_arg(ap, V9fsString *);
- mode = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sd", path, mode);
- if (retval > 0) {
- header.size = retval;
- header.type = T_CHMOD;
- }
- break;
- case T_CHOWN:
- path = va_arg(ap, V9fsString *);
- uid = va_arg(ap, int);
- gid = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sdd", path, uid, gid);
- if (retval > 0) {
- header.size = retval;
- header.type = T_CHOWN;
- }
- break;
- case T_TRUNCATE:
- path = va_arg(ap, V9fsString *);
- offset = va_arg(ap, uint64_t);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sq", path, offset);
- if (retval > 0) {
- header.size = retval;
- header.type = T_TRUNCATE;
- }
- break;
- case T_UTIME:
- path = va_arg(ap, V9fsString *);
- spec[0].tv_sec = va_arg(ap, long);
- spec[0].tv_nsec = va_arg(ap, long);
- spec[1].tv_sec = va_arg(ap, long);
- spec[1].tv_nsec = va_arg(ap, long);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sqqqq", path,
- spec[0].tv_sec, spec[1].tv_nsec,
- spec[1].tv_sec, spec[1].tv_nsec);
- if (retval > 0) {
- header.size = retval;
- header.type = T_UTIME;
- }
- break;
- case T_RENAME:
- oldpath = va_arg(ap, V9fsString *);
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", oldpath, path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_RENAME;
- }
- break;
- case T_REMOVE:
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_REMOVE;
- }
- break;
- case T_LGETXATTR:
- size = va_arg(ap, int);
- path = va_arg(ap, V9fsString *);
- name = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ,
- "dss", size, path, name);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LGETXATTR;
- }
- break;
- case T_LLISTXATTR:
- size = va_arg(ap, int);
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ds", size, path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LLISTXATTR;
- }
- break;
- case T_LSETXATTR:
- path = va_arg(ap, V9fsString *);
- name = va_arg(ap, V9fsString *);
- value = va_arg(ap, V9fsString *);
- size = va_arg(ap, int);
- flags = va_arg(ap, int);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sssdd",
- path, name, value, size, flags);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LSETXATTR;
- }
- break;
- case T_LREMOVEXATTR:
- path = va_arg(ap, V9fsString *);
- name = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", path, name);
- if (retval > 0) {
- header.size = retval;
- header.type = T_LREMOVEXATTR;
- }
- break;
- case T_GETVERSION:
- path = va_arg(ap, V9fsString *);
- retval = proxy_marshal(iovec, PROXY_HDR_SZ, "s", path);
- if (retval > 0) {
- header.size = retval;
- header.type = T_GETVERSION;
- }
- break;
- default:
- error_report("Invalid type %d", type);
- retval = -EINVAL;
- break;
- }
- va_end(ap);
-
- if (retval < 0) {
- goto err_out;
- }
-
- /* marshal the header details */
- retval = proxy_marshal(iovec, 0, "dd", header.type, header.size);
- assert(retval == 4 * 2);
- header.size += PROXY_HDR_SZ;
-
- retval = qemu_write_full(proxy->sockfd, iovec->iov_base, header.size);
- if (retval != header.size) {
- goto close_error;
- }
-
- switch (type) {
- case T_OPEN:
- case T_CREATE:
- /*
- * A file descriptor is returned as response for
- * T_OPEN,T_CREATE on success
- */
- if (v9fs_receivefd(proxy->sockfd, &retval) < 0) {
- goto close_error;
- }
- break;
- case T_MKNOD:
- case T_MKDIR:
- case T_SYMLINK:
- case T_LINK:
- case T_CHMOD:
- case T_CHOWN:
- case T_RENAME:
- case T_TRUNCATE:
- case T_UTIME:
- case T_REMOVE:
- case T_LSETXATTR:
- case T_LREMOVEXATTR:
- if (v9fs_receive_status(proxy, reply, &retval) < 0) {
- goto close_error;
- }
- break;
- case T_LSTAT:
- case T_READLINK:
- case T_STATFS:
- case T_GETVERSION:
- if (v9fs_receive_response(proxy, type, &retval, response) < 0) {
- goto close_error;
- }
- break;
- case T_LGETXATTR:
- case T_LLISTXATTR:
- if (!size) {
- if (v9fs_receive_status(proxy, reply, &retval) < 0) {
- goto close_error;
- }
- } else {
- if (v9fs_receive_response(proxy, type, &retval, response) < 0) {
- goto close_error;
- }
- }
- break;
- }
-
-err_out:
- qemu_mutex_unlock(&proxy->mutex);
- return retval;
-
-close_error:
- close(proxy->sockfd);
- proxy->sockfd = -1;
- qemu_mutex_unlock(&proxy->mutex);
- return -EIO;
-}
-
-static int proxy_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
-{
- int retval;
- retval = v9fs_request(fs_ctx->private, T_LSTAT, stbuf, fs_path);
- if (retval < 0) {
- errno = -retval;
- return -1;
- }
- return retval;
-}
-
-static ssize_t proxy_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
- char *buf, size_t bufsz)
-{
- int retval;
- retval = v9fs_request(fs_ctx->private, T_READLINK, buf, fs_path, bufsz);
- if (retval < 0) {
- errno = -retval;
- return -1;
- }
- return strlen(buf);
-}
-
-static int proxy_close(FsContext *ctx, V9fsFidOpenState *fs)
-{
- return close(fs->fd);
-}
-
-static int proxy_closedir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- return closedir(fs->dir.stream);
-}
-
-static int proxy_open(FsContext *ctx, V9fsPath *fs_path,
- int flags, V9fsFidOpenState *fs)
-{
- fs->fd = v9fs_request(ctx->private, T_OPEN, NULL, fs_path, flags);
- if (fs->fd < 0) {
- errno = -fs->fd;
- fs->fd = -1;
- }
- return fs->fd;
-}
-
-static int proxy_opendir(FsContext *ctx,
- V9fsPath *fs_path, V9fsFidOpenState *fs)
-{
- int serrno, fd;
-
- fs->dir.stream = NULL;
- fd = v9fs_request(ctx->private, T_OPEN, NULL, fs_path, O_DIRECTORY);
- if (fd < 0) {
- errno = -fd;
- return -1;
- }
- fs->dir.stream = fdopendir(fd);
- if (!fs->dir.stream) {
- serrno = errno;
- close(fd);
- errno = serrno;
- return -1;
- }
- return 0;
-}
-
-static void proxy_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- rewinddir(fs->dir.stream);
-}
-
-static off_t proxy_telldir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- return telldir(fs->dir.stream);
-}
-
-static struct dirent *proxy_readdir(FsContext *ctx, V9fsFidOpenState *fs)
-{
- struct dirent *entry;
- entry = readdir(fs->dir.stream);
-#ifdef CONFIG_DARWIN
- if (!entry) {
- return NULL;
- }
- int td;
- td = telldir(fs->dir.stream);
- /* If telldir fails, fail the entire readdir call */
- if (td < 0) {
- return NULL;
- }
- entry->d_seekoff = td;
-#endif
- return entry;
-}
-
-static void proxy_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
-{
- seekdir(fs->dir.stream, off);
-}
-
-static ssize_t proxy_preadv(FsContext *ctx, V9fsFidOpenState *fs,
- const struct iovec *iov,
- int iovcnt, off_t offset)
-{
- ssize_t ret;
-#ifdef CONFIG_PREADV
- ret = preadv(fs->fd, iov, iovcnt, offset);
-#else
- ret = lseek(fs->fd, offset, SEEK_SET);
- if (ret >= 0) {
- ret = readv(fs->fd, iov, iovcnt);
- }
-#endif
- return ret;
-}
-
-static ssize_t proxy_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
- const struct iovec *iov,
- int iovcnt, off_t offset)
-{
- ssize_t ret;
-
-#ifdef CONFIG_PREADV
- ret = pwritev(fs->fd, iov, iovcnt, offset);
-#else
- ret = lseek(fs->fd, offset, SEEK_SET);
- if (ret >= 0) {
- ret = writev(fs->fd, iov, iovcnt);
- }
-#endif
-#ifdef CONFIG_SYNC_FILE_RANGE
- if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) {
- /*
- * Initiate a writeback. This is not a data integrity sync.
- * We want to ensure that we don't leave dirty pages in the cache
- * after write when writeout=immediate is specified.
- */
- sync_file_range(fs->fd, offset, ret,
- SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
- }
-#endif
- return ret;
-}
-
-static int proxy_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
-{
- int retval;
- retval = v9fs_request(fs_ctx->private, T_CHMOD, NULL, fs_path,
- credp->fc_mode);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
- const char *name, FsCred *credp)
-{
- int retval;
- V9fsString fullname;
-
- v9fs_string_init(&fullname);
- v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
-
- retval = v9fs_request(fs_ctx->private, T_MKNOD, NULL, &fullname,
- credp->fc_mode, credp->fc_rdev,
- credp->fc_uid, credp->fc_gid);
- v9fs_string_free(&fullname);
- if (retval < 0) {
- errno = -retval;
- retval = -1;
- }
- return retval;
-}
-
-static int proxy_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
- const char *name, FsCred *credp)
-{
- int retval;
- V9fsString fullname;
-
- v9fs_string_init(&fullname);
- v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
-
- retval = v9fs_request(fs_ctx->private, T_MKDIR, NULL, &fullname,
- credp->fc_mode, credp->fc_uid, credp->fc_gid);
- v9fs_string_free(&fullname);
- if (retval < 0) {
- errno = -retval;
- retval = -1;
- }
- return retval;
-}
-
-static int proxy_fstat(FsContext *fs_ctx, int fid_type,
- V9fsFidOpenState *fs, struct stat *stbuf)
-{
- int fd;
-
- if (fid_type == P9_FID_DIR) {
- fd = dirfd(fs->dir.stream);
- } else {
- fd = fs->fd;
- }
- return fstat(fd, stbuf);
-}
-
-static int proxy_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
- int flags, FsCred *credp, V9fsFidOpenState *fs)
-{
- V9fsString fullname;
-
- v9fs_string_init(&fullname);
- v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
-
- fs->fd = v9fs_request(fs_ctx->private, T_CREATE, NULL, &fullname, flags,
- credp->fc_mode, credp->fc_uid, credp->fc_gid);
- v9fs_string_free(&fullname);
- if (fs->fd < 0) {
- errno = -fs->fd;
- fs->fd = -1;
- }
- return fs->fd;
-}
-
-static int proxy_symlink(FsContext *fs_ctx, const char *oldpath,
- V9fsPath *dir_path, const char *name, FsCred *credp)
-{
- int retval;
- V9fsString fullname, target;
-
- v9fs_string_init(&fullname);
- v9fs_string_init(&target);
-
- v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
- v9fs_string_sprintf(&target, "%s", oldpath);
-
- retval = v9fs_request(fs_ctx->private, T_SYMLINK, NULL, &target, &fullname,
- credp->fc_uid, credp->fc_gid);
- v9fs_string_free(&fullname);
- v9fs_string_free(&target);
- if (retval < 0) {
- errno = -retval;
- retval = -1;
- }
- return retval;
-}
-
-static int proxy_link(FsContext *ctx, V9fsPath *oldpath,
- V9fsPath *dirpath, const char *name)
-{
- int retval;
- V9fsString newpath;
-
- v9fs_string_init(&newpath);
- v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
-
- retval = v9fs_request(ctx->private, T_LINK, NULL, oldpath, &newpath);
- v9fs_string_free(&newpath);
- if (retval < 0) {
- errno = -retval;
- retval = -1;
- }
- return retval;
-}
-
-static int proxy_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
-{
- int retval;
-
- retval = v9fs_request(ctx->private, T_TRUNCATE, NULL, fs_path, size);
- if (retval < 0) {
- errno = -retval;
- return -1;
- }
- return 0;
-}
-
-static int proxy_rename(FsContext *ctx, const char *oldpath,
- const char *newpath)
-{
- int retval;
- V9fsString oldname, newname;
-
- v9fs_string_init(&oldname);
- v9fs_string_init(&newname);
-
- v9fs_string_sprintf(&oldname, "%s", oldpath);
- v9fs_string_sprintf(&newname, "%s", newpath);
- retval = v9fs_request(ctx->private, T_RENAME, NULL, &oldname, &newname);
- v9fs_string_free(&oldname);
- v9fs_string_free(&newname);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
-{
- int retval;
- retval = v9fs_request(fs_ctx->private, T_CHOWN, NULL, fs_path,
- credp->fc_uid, credp->fc_gid);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_utimensat(FsContext *s, V9fsPath *fs_path,
- const struct timespec *buf)
-{
- int retval;
- retval = v9fs_request(s->private, T_UTIME, NULL, fs_path,
- buf[0].tv_sec, buf[0].tv_nsec,
- buf[1].tv_sec, buf[1].tv_nsec);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_remove(FsContext *ctx, const char *path)
-{
- int retval;
- V9fsString name;
- v9fs_string_init(&name);
- v9fs_string_sprintf(&name, "%s", path);
- retval = v9fs_request(ctx->private, T_REMOVE, NULL, &name);
- v9fs_string_free(&name);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_fsync(FsContext *ctx, int fid_type,
- V9fsFidOpenState *fs, int datasync)
-{
- int fd;
-
- if (fid_type == P9_FID_DIR) {
- fd = dirfd(fs->dir.stream);
- } else {
- fd = fs->fd;
- }
-
- if (datasync) {
- return qemu_fdatasync(fd);
- } else {
- return fsync(fd);
- }
-}
-
-static int proxy_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
-{
- int retval;
- retval = v9fs_request(s->private, T_STATFS, stbuf, fs_path);
- if (retval < 0) {
- errno = -retval;
- return -1;
- }
- return retval;
-}
-
-static ssize_t proxy_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
- const char *name, void *value, size_t size)
-{
- int retval;
- V9fsString xname;
-
- v9fs_string_init(&xname);
- v9fs_string_sprintf(&xname, "%s", name);
- retval = v9fs_request(ctx->private, T_LGETXATTR, value, size, fs_path,
- &xname);
- v9fs_string_free(&xname);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static ssize_t proxy_llistxattr(FsContext *ctx, V9fsPath *fs_path,
- void *value, size_t size)
-{
- int retval;
- retval = v9fs_request(ctx->private, T_LLISTXATTR, value, size, fs_path);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name,
- void *value, size_t size, int flags)
-{
- int retval;
- V9fsString xname, xvalue;
-
- v9fs_string_init(&xname);
- v9fs_string_sprintf(&xname, "%s", name);
-
- v9fs_string_init(&xvalue);
- xvalue.size = size;
- xvalue.data = g_malloc(size);
- memcpy(xvalue.data, value, size);
-
- retval = v9fs_request(ctx->private, T_LSETXATTR, value, fs_path, &xname,
- &xvalue, size, flags);
- v9fs_string_free(&xname);
- v9fs_string_free(&xvalue);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_lremovexattr(FsContext *ctx, V9fsPath *fs_path,
- const char *name)
-{
- int retval;
- V9fsString xname;
-
- v9fs_string_init(&xname);
- v9fs_string_sprintf(&xname, "%s", name);
- retval = v9fs_request(ctx->private, T_LREMOVEXATTR, NULL, fs_path, &xname);
- v9fs_string_free(&xname);
- if (retval < 0) {
- errno = -retval;
- }
- return retval;
-}
-
-static int proxy_name_to_path(FsContext *ctx, V9fsPath *dir_path,
- const char *name, V9fsPath *target)
-{
- if (dir_path) {
- v9fs_path_sprintf(target, "%s/%s", dir_path->data, name);
- } else {
- v9fs_path_sprintf(target, "%s", name);
- }
- return 0;
-}
-
-static int proxy_renameat(FsContext *ctx, V9fsPath *olddir,
- const char *old_name, V9fsPath *newdir,
- const char *new_name)
-{
- int ret;
- V9fsString old_full_name, new_full_name;
-
- v9fs_string_init(&old_full_name);
- v9fs_string_init(&new_full_name);
-
- v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name);
- v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name);
-
- ret = proxy_rename(ctx, old_full_name.data, new_full_name.data);
- v9fs_string_free(&old_full_name);
- v9fs_string_free(&new_full_name);
- return ret;
-}
-
-static int proxy_unlinkat(FsContext *ctx, V9fsPath *dir,
- const char *name, int flags)
-{
- int ret;
- V9fsString fullname;
- v9fs_string_init(&fullname);
-
- v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
- ret = proxy_remove(ctx, fullname.data);
- v9fs_string_free(&fullname);
-
- return ret;
-}
-
-static int proxy_ioc_getversion(FsContext *fs_ctx, V9fsPath *path,
- mode_t st_mode, uint64_t *st_gen)
-{
- int err;
-
- /* Do not try to open special files like device nodes, fifos etc
- * we can get fd for regular files and directories only
- */
- if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
- errno = ENOTTY;
- return -1;
- }
- err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, path);
- if (err < 0) {
- errno = -err;
- err = -1;
- }
- return err;
-}
-
-static int connect_namedsocket(const char *path, Error **errp)
-{
- int sockfd;
- struct sockaddr_un helper;
-
- if (strlen(path) >= sizeof(helper.sun_path)) {
- error_setg(errp, "socket name too long");
- return -1;
- }
- sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sockfd < 0) {
- error_setg_errno(errp, errno, "failed to create client socket");
- return -1;
- }
- strcpy(helper.sun_path, path);
- helper.sun_family = AF_UNIX;
- if (connect(sockfd, (struct sockaddr *)&helper, sizeof(helper)) < 0) {
- error_setg_errno(errp, errno, "failed to connect to '%s'", path);
- close(sockfd);
- return -1;
- }
-
- /* remove the socket for security reasons */
- unlink(path);
- return sockfd;
-}
-
-static void error_append_socket_sockfd_hint(Error *const *errp)
-{
- error_append_hint(errp, "Either specify socket=/some/path where /some/path"
- " points to a listening AF_UNIX socket or sock_fd=fd"
- " where fd is a file descriptor to a connected AF_UNIX"
- " socket\n");
-}
-
-static int proxy_parse_opts(QemuOpts *opts, FsDriverEntry *fs, Error **errp)
-{
- const char *socket = qemu_opt_get(opts, "socket");
- const char *sock_fd = qemu_opt_get(opts, "sock_fd");
-
- if (!socket && !sock_fd) {
- error_setg(errp, "both socket and sock_fd properties are missing");
- error_append_socket_sockfd_hint(errp);
- return -1;
- }
- if (socket && sock_fd) {
- error_setg(errp, "both socket and sock_fd properties are set");
- error_append_socket_sockfd_hint(errp);
- return -1;
- }
- if (socket) {
- fs->path = g_strdup(socket);
- fs->export_flags |= V9FS_PROXY_SOCK_NAME;
- } else {
- fs->path = g_strdup(sock_fd);
- fs->export_flags |= V9FS_PROXY_SOCK_FD;
- }
- return 0;
-}
-
-static int proxy_init(FsContext *ctx, Error **errp)
-{
- V9fsProxy *proxy = g_new(V9fsProxy, 1);
- int sock_id;
-
- if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) {
- sock_id = connect_namedsocket(ctx->fs_root, errp);
- } else {
- sock_id = atoi(ctx->fs_root);
- if (sock_id < 0) {
- error_setg(errp, "socket descriptor not initialized");
- }
- }
- if (sock_id < 0) {
- g_free(proxy);
- return -1;
- }
- g_free(ctx->fs_root);
- ctx->fs_root = NULL;
-
- proxy->in_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ);
- proxy->in_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ;
- proxy->out_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ);
- proxy->out_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ;
-
- ctx->private = proxy;
- proxy->sockfd = sock_id;
- qemu_mutex_init(&proxy->mutex);
-
- ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
- ctx->exops.get_st_gen = proxy_ioc_getversion;
- return 0;
-}
-
-static void proxy_cleanup(FsContext *ctx)
-{
- V9fsProxy *proxy = ctx->private;
-
- if (!proxy) {
- return;
- }
-
- g_free(proxy->out_iovec.iov_base);
- g_free(proxy->in_iovec.iov_base);
- if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) {
- close(proxy->sockfd);
- }
- g_free(proxy);
-}
-
-FileOperations proxy_ops = {
- .parse_opts = proxy_parse_opts,
- .init = proxy_init,
- .cleanup = proxy_cleanup,
- .lstat = proxy_lstat,
- .readlink = proxy_readlink,
- .close = proxy_close,
- .closedir = proxy_closedir,
- .open = proxy_open,
- .opendir = proxy_opendir,
- .rewinddir = proxy_rewinddir,
- .telldir = proxy_telldir,
- .readdir = proxy_readdir,
- .seekdir = proxy_seekdir,
- .preadv = proxy_preadv,
- .pwritev = proxy_pwritev,
- .chmod = proxy_chmod,
- .mknod = proxy_mknod,
- .mkdir = proxy_mkdir,
- .fstat = proxy_fstat,
- .open2 = proxy_open2,
- .symlink = proxy_symlink,
- .link = proxy_link,
- .truncate = proxy_truncate,
- .rename = proxy_rename,
- .chown = proxy_chown,
- .utimensat = proxy_utimensat,
- .remove = proxy_remove,
- .fsync = proxy_fsync,
- .statfs = proxy_statfs,
- .lgetxattr = proxy_lgetxattr,
- .llistxattr = proxy_llistxattr,
- .lsetxattr = proxy_lsetxattr,
- .lremovexattr = proxy_lremovexattr,
- .name_to_path = proxy_name_to_path,
- .renameat = proxy_renameat,
- .unlinkat = proxy_unlinkat,
-};
diff --git a/hw/9pfs/9p-proxy.h b/hw/9pfs/9p-proxy.h
deleted file mode 100644
index 9be4718..0000000
--- a/hw/9pfs/9p-proxy.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 9p Proxy callback
- *
- * Copyright IBM, Corp. 2011
- *
- * Authors:
- * M. Mohan Kumar <mohan@in.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- */
-
-/*
- * NOTE: The 9p 'proxy' backend is deprecated (since QEMU 8.1) and will be
- * removed in a future version of QEMU!
- */
-
-#ifndef QEMU_9P_PROXY_H
-#define QEMU_9P_PROXY_H
-
-#define PROXY_MAX_IO_SZ (64 * 1024)
-#define V9FS_FD_VALID INT_MAX
-
-/*
- * proxy iovec only support one element and
- * marsha/unmarshal doesn't do little endian conversion.
- */
-#define proxy_unmarshal(in_sg, offset, fmt, args...) \
- v9fs_iov_unmarshal(in_sg, 1, offset, 0, fmt, ##args)
-#define proxy_marshal(out_sg, offset, fmt, args...) \
- v9fs_iov_marshal(out_sg, 1, offset, 0, fmt, ##args)
-
-union MsgControl {
- struct cmsghdr cmsg;
- char control[CMSG_SPACE(sizeof(int))];
-};
-
-typedef struct {
- uint32_t type;
- uint32_t size;
-} ProxyHeader;
-
-#define PROXY_HDR_SZ (sizeof(ProxyHeader))
-
-enum {
- T_SUCCESS = 0,
- T_ERROR,
- T_OPEN,
- T_CREATE,
- T_MKNOD,
- T_MKDIR,
- T_SYMLINK,
- T_LINK,
- T_LSTAT,
- T_READLINK,
- T_STATFS,
- T_CHMOD,
- T_CHOWN,
- T_TRUNCATE,
- T_UTIME,
- T_RENAME,
- T_REMOVE,
- T_LGETXATTR,
- T_LLISTXATTR,
- T_LSETXATTR,
- T_LREMOVEXATTR,
- T_GETVERSION,
-};
-
-typedef struct {
- uint64_t st_dev;
- uint64_t st_ino;
- uint64_t st_nlink;
- uint32_t st_mode;
- uint32_t st_uid;
- uint32_t st_gid;
- uint64_t st_rdev;
- uint64_t st_size;
- uint64_t st_blksize;
- uint64_t st_blocks;
- uint64_t st_atim_sec;
- uint64_t st_atim_nsec;
- uint64_t st_mtim_sec;
- uint64_t st_mtim_nsec;
- uint64_t st_ctim_sec;
- uint64_t st_ctim_nsec;
-} ProxyStat;
-
-typedef struct {
- uint64_t f_type;
- uint64_t f_bsize;
- uint64_t f_blocks;
- uint64_t f_bfree;
- uint64_t f_bavail;
- uint64_t f_files;
- uint64_t f_ffree;
- uint64_t f_fsid[2];
- uint64_t f_namelen;
- uint64_t f_frsize;
-} ProxyStatFS;
-#endif
diff --git a/hw/9pfs/meson.build b/hw/9pfs/meson.build
index f1b62fa..eceffdb 100644
--- a/hw/9pfs/meson.build
+++ b/hw/9pfs/meson.build
@@ -2,7 +2,6 @@ fs_ss = ss.source_set()
fs_ss.add(files(
'9p-local.c',
'9p-posix-acl.c',
- '9p-proxy.c',
'9p-synth.c',
'9p-xattr-user.c',
'9p-xattr.c',
diff --git a/hw/Kconfig b/hw/Kconfig
index f7866e7..1b4e9bb 100644
--- a/hw/Kconfig
+++ b/hw/Kconfig
@@ -27,7 +27,6 @@ source nvme/Kconfig
source nvram/Kconfig
source pci-bridge/Kconfig
source pci-host/Kconfig
-source pcmcia/Kconfig
source pci/Kconfig
source remote/Kconfig
source rtc/Kconfig
@@ -50,7 +49,6 @@ source arm/Kconfig
source cpu/Kconfig
source alpha/Kconfig
source avr/Kconfig
-source cris/Kconfig
source hppa/Kconfig
source i386/Kconfig
source loongarch/Kconfig
diff --git a/hw/acpi/acpi-cpu-hotplug-stub.c b/hw/acpi/acpi-cpu-hotplug-stub.c
index 3fc4b14..c6c61bb 100644
--- a/hw/acpi/acpi-cpu-hotplug-stub.c
+++ b/hw/acpi/acpi-cpu-hotplug-stub.c
@@ -19,6 +19,12 @@ void legacy_acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner,
return;
}
+void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner,
+ CPUHotplugState *state, hwaddr base_addr)
+{
+ return;
+}
+
void acpi_cpu_ospm_status(CPUHotplugState *cpu_st, ACPIOSTInfoList ***list)
{
return;
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 6d4517c..34e0ddb 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -534,8 +534,7 @@ void aml_append(Aml *parent_ctx, Aml *child)
case AML_NO_OPCODE:
break;
default:
- assert(0);
- break;
+ g_assert_not_reached();
}
build_append_array(parent_ctx->buf, buf);
build_free_array(buf);
diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c
index 2d81c1e..5cb60ca 100644
--- a/hw/acpi/cpu.c
+++ b/hw/acpi/cpu.c
@@ -7,7 +7,6 @@
#include "trace.h"
#include "sysemu/numa.h"
-#define ACPI_CPU_HOTPLUG_REG_LEN 12
#define ACPI_CPU_SELECTOR_OFFSET_WR 0
#define ACPI_CPU_FLAGS_OFFSET_RW 4
#define ACPI_CPU_CMD_OFFSET_WR 5
@@ -339,9 +338,10 @@ const VMStateDescription vmstate_cpu_hotplug = {
#define CPU_FW_EJECT_EVENT "CEJF"
void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
- build_madt_cpu_fn build_madt_cpu, hwaddr io_base,
+ build_madt_cpu_fn build_madt_cpu, hwaddr base_addr,
const char *res_root,
- const char *event_handler_method)
+ const char *event_handler_method,
+ AmlRegionSpace rs)
{
Aml *ifctx;
Aml *field;
@@ -365,14 +365,22 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
aml_name_decl("_UID", aml_string("CPU Hotplug resources")));
aml_append(cpu_ctrl_dev, aml_mutex(CPU_LOCK, 0));
+ assert((rs == AML_SYSTEM_IO) || (rs == AML_SYSTEM_MEMORY));
+
crs = aml_resource_template();
- aml_append(crs, aml_io(AML_DECODE16, io_base, io_base, 1,
+ if (rs == AML_SYSTEM_IO) {
+ aml_append(crs, aml_io(AML_DECODE16, base_addr, base_addr, 1,
ACPI_CPU_HOTPLUG_REG_LEN));
+ } else if (rs == AML_SYSTEM_MEMORY) {
+ aml_append(crs, aml_memory32_fixed(base_addr,
+ ACPI_CPU_HOTPLUG_REG_LEN, AML_READ_WRITE));
+ }
+
aml_append(cpu_ctrl_dev, aml_name_decl("_CRS", crs));
/* declare CPU hotplug MMIO region with related access fields */
aml_append(cpu_ctrl_dev,
- aml_operation_region("PRST", AML_SYSTEM_IO, aml_int(io_base),
+ aml_operation_region("PRST", rs, aml_int(base_addr),
ACPI_CPU_HOTPLUG_REG_LEN));
field = aml_field("PRST", AML_BYTE_ACC, AML_NOLOCK,
diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c
index b2f1b13..a108cfe 100644
--- a/hw/acpi/erst.c
+++ b/hw/acpi/erst.c
@@ -1030,7 +1030,7 @@ static void erst_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_REDHAT_ACPI_ERST;
k->revision = 0x00;
k->class_id = PCI_CLASS_OTHERS;
- dc->reset = erst_reset;
+ device_class_set_legacy_reset(dc, erst_reset);
dc->vmsd = &erst_vmstate;
dc->user_creatable = true;
dc->hotpluggable = false;
diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c
index 2d6e91b..d00f5a6 100644
--- a/hw/acpi/generic_event_device.c
+++ b/hw/acpi/generic_event_device.c
@@ -25,6 +25,7 @@ static const uint32_t ged_supported_events[] = {
ACPI_GED_MEM_HOTPLUG_EVT,
ACPI_GED_PWR_DOWN_EVT,
ACPI_GED_NVDIMM_HOTPLUG_EVT,
+ ACPI_GED_CPU_HOTPLUG_EVT,
};
/*
@@ -107,6 +108,9 @@ void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev,
aml_append(if_ctx, aml_call0(MEMORY_DEVICES_CONTAINER "."
MEMORY_SLOT_SCAN_METHOD));
break;
+ case ACPI_GED_CPU_HOTPLUG_EVT:
+ aml_append(if_ctx, aml_call0(AML_GED_EVT_CPU_SCAN_METHOD));
+ break;
case ACPI_GED_PWR_DOWN_EVT:
aml_append(if_ctx,
aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE),
@@ -197,9 +201,9 @@ static void ged_regs_write(void *opaque, hwaddr addr, uint64_t data,
switch (addr) {
case ACPI_GED_REG_SLEEP_CTL:
- slp_typ = (data >> 2) & 0x07;
- slp_en = (data >> 5) & 0x01;
- if (slp_en && slp_typ == 5) {
+ slp_typ = (data >> ACPI_GED_SLP_TYP_POS) & ACPI_GED_SLP_TYP_MASK;
+ slp_en = !!(data & ACPI_GED_SLP_EN);
+ if (slp_en && slp_typ == ACPI_GED_SLP_TYP_S5) {
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
}
return;
@@ -234,6 +238,8 @@ static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev,
} else {
acpi_memory_plug_cb(hotplug_dev, &s->memhp_state, dev, errp);
}
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
+ acpi_cpu_plug_cb(hotplug_dev, &s->cpuhp_state, dev, errp);
} else {
error_setg(errp, "virt: device plug request for unsupported device"
" type: %s", object_get_typename(OBJECT(dev)));
@@ -248,6 +254,8 @@ static void acpi_ged_unplug_request_cb(HotplugHandler *hotplug_dev,
if ((object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) &&
!(object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)))) {
acpi_memory_unplug_request_cb(hotplug_dev, &s->memhp_state, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
+ acpi_cpu_unplug_request_cb(hotplug_dev, &s->cpuhp_state, dev, errp);
} else {
error_setg(errp, "acpi: device unplug request for unsupported device"
" type: %s", object_get_typename(OBJECT(dev)));
@@ -261,6 +269,8 @@ static void acpi_ged_unplug_cb(HotplugHandler *hotplug_dev,
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
acpi_memory_unplug_cb(&s->memhp_state, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
+ acpi_cpu_unplug_cb(&s->cpuhp_state, dev, errp);
} else {
error_setg(errp, "acpi: device unplug for unsupported device"
" type: %s", object_get_typename(OBJECT(dev)));
@@ -272,6 +282,7 @@ static void acpi_ged_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list)
AcpiGedState *s = ACPI_GED(adev);
acpi_memory_ospm_status(&s->memhp_state, list);
+ acpi_cpu_ospm_status(&s->cpuhp_state, list);
}
static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
@@ -286,6 +297,8 @@ static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
sel = ACPI_GED_PWR_DOWN_EVT;
} else if (ev & ACPI_NVDIMM_HOTPLUG_STATUS) {
sel = ACPI_GED_NVDIMM_HOTPLUG_EVT;
+ } else if (ev & ACPI_CPU_HOTPLUG_STATUS) {
+ sel = ACPI_GED_CPU_HOTPLUG_EVT;
} else {
/* Unknown event. Return without generating interrupt. */
warn_report("GED: Unsupported event %d. No irq injected", ev);
@@ -371,6 +384,42 @@ static const VMStateDescription vmstate_acpi_ged = {
}
};
+static void acpi_ged_realize(DeviceState *dev, Error **errp)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ AcpiGedState *s = ACPI_GED(dev);
+ uint32_t ged_events;
+ int i;
+
+ ged_events = ctpop32(s->ged_event_bitmap);
+
+ for (i = 0; i < ARRAY_SIZE(ged_supported_events) && ged_events; i++) {
+ uint32_t event = s->ged_event_bitmap & ged_supported_events[i];
+
+ if (!event) {
+ continue;
+ }
+
+ switch (event) {
+ case ACPI_GED_CPU_HOTPLUG_EVT:
+ /* initialize CPU Hotplug related regions */
+ memory_region_init(&s->container_cpuhp, OBJECT(dev),
+ "cpuhp container",
+ ACPI_CPU_HOTPLUG_REG_LEN);
+ sysbus_init_mmio(sbd, &s->container_cpuhp);
+ cpu_hotplug_hw_init(&s->container_cpuhp, OBJECT(dev),
+ &s->cpuhp_state, 0);
+ break;
+ }
+ ged_events--;
+ }
+
+ if (ged_events) {
+ error_report("Unsupported events specified");
+ abort();
+ }
+}
+
static void acpi_ged_initfn(Object *obj)
{
DeviceState *dev = DEVICE(obj);
@@ -411,6 +460,7 @@ static void acpi_ged_class_init(ObjectClass *class, void *data)
dc->desc = "ACPI Generic Event Device";
device_class_set_props(dc, acpi_ged_properties);
dc->vmsd = &vmstate_acpi_ged;
+ dc->realize = acpi_ged_realize;
hc->plug = acpi_ged_device_plug_cb;
hc->unplug_request = acpi_ged_unplug_request_cb;
diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c
index 02d8546..c15e5b8 100644
--- a/hw/acpi/ich9.c
+++ b/hw/acpi/ich9.c
@@ -35,6 +35,7 @@
#include "sysemu/runstate.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/ich9_tco.h"
+#include "hw/acpi/ich9_timer.h"
#include "hw/southbridge/ich9.h"
#include "hw/mem/pc-dimm.h"
@@ -108,6 +109,18 @@ static void ich9_smi_writel(void *opaque, hwaddr addr, uint64_t val,
}
pm->smi_en &= ~pm->smi_en_wmask;
pm->smi_en |= (val & pm->smi_en_wmask);
+ if (pm->swsmi_timer_enabled) {
+ ich9_pm_update_swsmi_timer(pm, pm->smi_en &
+ ICH9_PMIO_SMI_EN_SWSMI_EN);
+ }
+ if (pm->periodic_timer_enabled) {
+ ich9_pm_update_periodic_timer(pm, pm->smi_en &
+ ICH9_PMIO_SMI_EN_PERIODIC_EN);
+ }
+ break;
+ case 4:
+ pm->smi_sts &= ~pm->smi_sts_wmask;
+ pm->smi_sts |= (val & pm->smi_sts_wmask);
break;
}
}
@@ -286,6 +299,8 @@ static void pm_powerdown_req(Notifier *n, void *opaque)
void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, qemu_irq sci_irq)
{
+ pm->smi_sts_wmask = 0;
+
memory_region_init(&pm->io, OBJECT(lpc_pci), "ich9-pm", ICH9_PMIO_SIZE);
memory_region_set_enabled(&pm->io, false);
memory_region_add_subregion(pci_address_space_io(lpc_pci),
@@ -305,6 +320,14 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, qemu_irq sci_irq)
"acpi-smi", 8);
memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi);
+ if (pm->swsmi_timer_enabled) {
+ ich9_pm_swsmi_timer_init(pm);
+ }
+
+ if (pm->periodic_timer_enabled) {
+ ich9_pm_periodic_timer_init(pm);
+ }
+
if (pm->enable_tco) {
acpi_pm_tco_init(&pm->tco_regs, &pm->io);
}
diff --git a/hw/acpi/ich9_timer.c b/hw/acpi/ich9_timer.c
new file mode 100644
index 0000000..5b1c910
--- /dev/null
+++ b/hw/acpi/ich9_timer.c
@@ -0,0 +1,93 @@
+/*
+ * QEMU ICH9 Timer emulation
+ *
+ * Copyright (c) 2024 Dominic Prinz <git@dprinz.de>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/core/cpu.h"
+#include "hw/pci/pci.h"
+#include "hw/southbridge/ich9.h"
+#include "qemu/timer.h"
+
+#include "hw/acpi/ich9_timer.h"
+
+void ich9_pm_update_swsmi_timer(ICH9LPCPMRegs *pm, bool enable)
+{
+ uint16_t swsmi_rate_sel;
+ int64_t expire_time;
+ ICH9LPCState *lpc;
+
+ if (enable) {
+ lpc = container_of(pm, ICH9LPCState, pm);
+ swsmi_rate_sel =
+ (pci_get_word(lpc->d.config + ICH9_LPC_GEN_PMCON_3) & 0xc0) >> 6;
+
+ if (swsmi_rate_sel == 0) {
+ expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 1500000LL;
+ } else {
+ expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+ 8 * (1 << swsmi_rate_sel) * 1000000LL;
+ }
+
+ timer_mod(pm->swsmi_timer, expire_time);
+ } else {
+ timer_del(pm->swsmi_timer);
+ }
+}
+
+static void ich9_pm_swsmi_timer_expired(void *opaque)
+{
+ ICH9LPCPMRegs *pm = opaque;
+
+ pm->smi_sts |= ICH9_PMIO_SMI_STS_SWSMI_STS;
+ ich9_generate_smi();
+
+ ich9_pm_update_swsmi_timer(pm, pm->smi_en & ICH9_PMIO_SMI_EN_SWSMI_EN);
+}
+
+void ich9_pm_swsmi_timer_init(ICH9LPCPMRegs *pm)
+{
+ pm->smi_sts_wmask |= ICH9_PMIO_SMI_STS_SWSMI_STS;
+ pm->swsmi_timer =
+ timer_new_ns(QEMU_CLOCK_VIRTUAL, ich9_pm_swsmi_timer_expired, pm);
+}
+
+void ich9_pm_update_periodic_timer(ICH9LPCPMRegs *pm, bool enable)
+{
+ uint16_t per_smi_sel;
+ int64_t expire_time;
+ ICH9LPCState *lpc;
+
+ if (enable) {
+ lpc = container_of(pm, ICH9LPCState, pm);
+ per_smi_sel = pci_get_word(lpc->d.config + ICH9_LPC_GEN_PMCON_1) & 3;
+ expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+ 8 * (1 << (3 - per_smi_sel)) * NANOSECONDS_PER_SECOND;
+
+ timer_mod(pm->periodic_timer, expire_time);
+ } else {
+ timer_del(pm->periodic_timer);
+ }
+}
+
+static void ich9_pm_periodic_timer_expired(void *opaque)
+{
+ ICH9LPCPMRegs *pm = opaque;
+
+ pm->smi_sts = ICH9_PMIO_SMI_STS_PERIODIC_STS;
+ ich9_generate_smi();
+
+ ich9_pm_update_periodic_timer(pm,
+ pm->smi_en & ICH9_PMIO_SMI_EN_PERIODIC_EN);
+}
+
+void ich9_pm_periodic_timer_init(ICH9LPCPMRegs *pm)
+{
+ pm->smi_sts_wmask |= ICH9_PMIO_SMI_STS_PERIODIC_STS;
+ pm->periodic_timer =
+ timer_new_ns(QEMU_CLOCK_VIRTUAL, ich9_pm_periodic_timer_expired, pm);
+}
diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build
index fa5c07d..7f8ccc9 100644
--- a/hw/acpi/meson.build
+++ b/hw/acpi/meson.build
@@ -24,7 +24,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_PCI_BRIDGE', if_true: files('pci-bridge.c'))
acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_true: files('pcihp.c'))
acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_false: files('acpi-pci-hotplug-stub.c'))
acpi_ss.add(when: 'CONFIG_ACPI_VIOT', if_true: files('viot.c'))
-acpi_ss.add(when: 'CONFIG_ACPI_ICH9', if_true: files('ich9.c', 'ich9_tco.c'))
+acpi_ss.add(when: 'CONFIG_ACPI_ICH9', if_true: files('ich9.c', 'ich9_tco.c', 'ich9_timer.c'))
acpi_ss.add(when: 'CONFIG_ACPI_ERST', if_true: files('erst.c'))
acpi_ss.add(when: 'CONFIG_IPMI', if_true: files('ipmi.c'), if_false: files('ipmi-stub.c'))
acpi_ss.add(when: 'CONFIG_PC', if_false: files('acpi-x86-stub.c'))
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index debe1ad..1de3fe3 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -633,7 +633,7 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_INTEL_82371AB_3;
k->revision = 0x03;
k->class_id = PCI_CLASS_BRIDGE_OTHER;
- dc->reset = piix4_pm_reset;
+ device_class_set_legacy_reset(dc, piix4_pm_reset);
dc->desc = "PM";
dc->vmsd = &vmstate_acpi;
device_class_set_props(dc, piix4_pm_properties);
diff --git a/hw/adc/Kconfig b/hw/adc/Kconfig
index a825bd3..25d2229 100644
--- a/hw/adc/Kconfig
+++ b/hw/adc/Kconfig
@@ -1,5 +1,2 @@
config STM32F2XX_ADC
bool
-
-config MAX111X
- bool
diff --git a/hw/adc/aspeed_adc.c b/hw/adc/aspeed_adc.c
index 68bdbc7..598f2bd 100644
--- a/hw/adc/aspeed_adc.c
+++ b/hw/adc/aspeed_adc.c
@@ -297,7 +297,7 @@ static void aspeed_adc_engine_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_adc_engine_realize;
- dc->reset = aspeed_adc_engine_reset;
+ device_class_set_legacy_reset(dc, aspeed_adc_engine_reset);
device_class_set_props(dc, aspeed_adc_engine_properties);
dc->desc = "Aspeed Analog-to-Digital Engine";
dc->vmsd = &vmstate_aspeed_adc_engine;
@@ -398,6 +398,15 @@ static void aspeed_1030_adc_class_init(ObjectClass *klass, void *data)
aac->nr_engines = 2;
}
+static void aspeed_2700_adc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
+
+ dc->desc = "ASPEED 2700 ADC Controller";
+ aac->nr_engines = 2;
+}
+
static const TypeInfo aspeed_adc_info = {
.name = TYPE_ASPEED_ADC,
.parent = TYPE_SYS_BUS_DEVICE,
@@ -430,6 +439,12 @@ static const TypeInfo aspeed_1030_adc_info = {
.class_init = aspeed_1030_adc_class_init, /* No change since AST2600 */
};
+static const TypeInfo aspeed_2700_adc_info = {
+ .name = TYPE_ASPEED_2700_ADC,
+ .parent = TYPE_ASPEED_ADC,
+ .class_init = aspeed_2700_adc_class_init,
+};
+
static void aspeed_adc_register_types(void)
{
type_register_static(&aspeed_adc_engine_info);
@@ -438,6 +453,7 @@ static void aspeed_adc_register_types(void)
type_register_static(&aspeed_2500_adc_info);
type_register_static(&aspeed_2600_adc_info);
type_register_static(&aspeed_1030_adc_info);
+ type_register_static(&aspeed_2700_adc_info);
}
type_init(aspeed_adc_register_types);
diff --git a/hw/adc/max111x.c b/hw/adc/max111x.c
deleted file mode 100644
index 957d177..0000000
--- a/hw/adc/max111x.c
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Maxim MAX1110/1111 ADC chip emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPLv2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/adc/max111x.h"
-#include "hw/irq.h"
-#include "migration/vmstate.h"
-#include "qemu/module.h"
-#include "hw/qdev-properties.h"
-
-/* Control-byte bitfields */
-#define CB_PD0 (1 << 0)
-#define CB_PD1 (1 << 1)
-#define CB_SGL (1 << 2)
-#define CB_UNI (1 << 3)
-#define CB_SEL0 (1 << 4)
-#define CB_SEL1 (1 << 5)
-#define CB_SEL2 (1 << 6)
-#define CB_START (1 << 7)
-
-#define CHANNEL_NUM(v, b0, b1, b2) \
- ((((v) >> (2 + (b0))) & 4) | \
- (((v) >> (3 + (b1))) & 2) | \
- (((v) >> (4 + (b2))) & 1))
-
-static uint32_t max111x_read(MAX111xState *s)
-{
- if (!s->tb1)
- return 0;
-
- switch (s->cycle ++) {
- case 1:
- return s->rb2;
- case 2:
- return s->rb3;
- }
-
- return 0;
-}
-
-/* Interpret a control-byte */
-static void max111x_write(MAX111xState *s, uint32_t value)
-{
- int measure, chan;
-
- /* Ignore the value if START bit is zero */
- if (!(value & CB_START))
- return;
-
- s->cycle = 0;
-
- if (!(value & CB_PD1)) {
- s->tb1 = 0;
- return;
- }
-
- s->tb1 = value;
-
- if (s->inputs == 8)
- chan = CHANNEL_NUM(value, 1, 0, 2);
- else
- chan = CHANNEL_NUM(value & ~CB_SEL0, 0, 1, 2);
-
- if (value & CB_SGL)
- measure = s->input[chan] - s->com;
- else
- measure = s->input[chan] - s->input[chan ^ 1];
-
- if (!(value & CB_UNI))
- measure ^= 0x80;
-
- s->rb2 = (measure >> 2) & 0x3f;
- s->rb3 = (measure << 6) & 0xc0;
-
- /* FIXME: When should the IRQ be lowered? */
- qemu_irq_raise(s->interrupt);
-}
-
-static uint32_t max111x_transfer(SSIPeripheral *dev, uint32_t value)
-{
- MAX111xState *s = MAX_111X(dev);
- max111x_write(s, value);
- return max111x_read(s);
-}
-
-static const VMStateDescription vmstate_max111x = {
- .name = "max111x",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
- VMSTATE_SSI_PERIPHERAL(parent_obj, MAX111xState),
- VMSTATE_UINT8(tb1, MAX111xState),
- VMSTATE_UINT8(rb2, MAX111xState),
- VMSTATE_UINT8(rb3, MAX111xState),
- VMSTATE_INT32_EQUAL(inputs, MAX111xState, NULL),
- VMSTATE_INT32(com, MAX111xState),
- VMSTATE_ARRAY_INT32_UNSAFE(input, MAX111xState, inputs,
- vmstate_info_uint8, uint8_t),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void max111x_input_set(void *opaque, int line, int value)
-{
- MAX111xState *s = MAX_111X(opaque);
-
- assert(line >= 0 && line < s->inputs);
- s->input[line] = value;
-}
-
-static int max111x_init(SSIPeripheral *d, int inputs)
-{
- DeviceState *dev = DEVICE(d);
- MAX111xState *s = MAX_111X(dev);
-
- qdev_init_gpio_out(dev, &s->interrupt, 1);
- qdev_init_gpio_in(dev, max111x_input_set, inputs);
-
- s->inputs = inputs;
-
- return 0;
-}
-
-static void max1110_realize(SSIPeripheral *dev, Error **errp)
-{
- max111x_init(dev, 8);
-}
-
-static void max1111_realize(SSIPeripheral *dev, Error **errp)
-{
- max111x_init(dev, 4);
-}
-
-static void max111x_reset(DeviceState *dev)
-{
- MAX111xState *s = MAX_111X(dev);
- int i;
-
- for (i = 0; i < s->inputs; i++) {
- s->input[i] = s->reset_input[i];
- }
- s->com = 0;
- s->tb1 = 0;
- s->rb2 = 0;
- s->rb3 = 0;
- s->cycle = 0;
-}
-
-static Property max1110_properties[] = {
- /* Reset values for ADC inputs */
- DEFINE_PROP_UINT8("input0", MAX111xState, reset_input[0], 0xf0),
- DEFINE_PROP_UINT8("input1", MAX111xState, reset_input[1], 0xe0),
- DEFINE_PROP_UINT8("input2", MAX111xState, reset_input[2], 0xd0),
- DEFINE_PROP_UINT8("input3", MAX111xState, reset_input[3], 0xc0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static Property max1111_properties[] = {
- /* Reset values for ADC inputs */
- DEFINE_PROP_UINT8("input0", MAX111xState, reset_input[0], 0xf0),
- DEFINE_PROP_UINT8("input1", MAX111xState, reset_input[1], 0xe0),
- DEFINE_PROP_UINT8("input2", MAX111xState, reset_input[2], 0xd0),
- DEFINE_PROP_UINT8("input3", MAX111xState, reset_input[3], 0xc0),
- DEFINE_PROP_UINT8("input4", MAX111xState, reset_input[4], 0xb0),
- DEFINE_PROP_UINT8("input5", MAX111xState, reset_input[5], 0xa0),
- DEFINE_PROP_UINT8("input6", MAX111xState, reset_input[6], 0x90),
- DEFINE_PROP_UINT8("input7", MAX111xState, reset_input[7], 0x80),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void max111x_class_init(ObjectClass *klass, void *data)
-{
- SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->transfer = max111x_transfer;
- dc->reset = max111x_reset;
- dc->vmsd = &vmstate_max111x;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
-}
-
-static const TypeInfo max111x_info = {
- .name = TYPE_MAX_111X,
- .parent = TYPE_SSI_PERIPHERAL,
- .instance_size = sizeof(MAX111xState),
- .class_init = max111x_class_init,
- .abstract = true,
-};
-
-static void max1110_class_init(ObjectClass *klass, void *data)
-{
- SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->realize = max1110_realize;
- device_class_set_props(dc, max1110_properties);
-}
-
-static const TypeInfo max1110_info = {
- .name = TYPE_MAX_1110,
- .parent = TYPE_MAX_111X,
- .class_init = max1110_class_init,
-};
-
-static void max1111_class_init(ObjectClass *klass, void *data)
-{
- SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- k->realize = max1111_realize;
- device_class_set_props(dc, max1111_properties);
-}
-
-static const TypeInfo max1111_info = {
- .name = TYPE_MAX_1111,
- .parent = TYPE_MAX_111X,
- .class_init = max1111_class_init,
-};
-
-static void max111x_register_types(void)
-{
- type_register_static(&max111x_info);
- type_register_static(&max1110_info);
- type_register_static(&max1111_info);
-}
-
-type_init(max111x_register_types)
diff --git a/hw/adc/meson.build b/hw/adc/meson.build
index a4f85b7..7f7acc1 100644
--- a/hw/adc/meson.build
+++ b/hw/adc/meson.build
@@ -2,4 +2,3 @@ system_ss.add(when: 'CONFIG_STM32F2XX_ADC', if_true: files('stm32f2xx_adc.c'))
system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_adc.c'))
system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_adc.c'))
system_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq-xadc.c'))
-system_ss.add(when: 'CONFIG_MAX111X', if_true: files('max111x.c'))
diff --git a/hw/adc/stm32f2xx_adc.c b/hw/adc/stm32f2xx_adc.c
index e9df6ea..e3b21f9 100644
--- a/hw/adc/stm32f2xx_adc.c
+++ b/hw/adc/stm32f2xx_adc.c
@@ -288,7 +288,7 @@ static void stm32f2xx_adc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = stm32f2xx_adc_reset;
+ device_class_set_legacy_reset(dc, stm32f2xx_adc_reset);
dc->vmsd = &vmstate_stm32f2xx_adc;
}
diff --git a/hw/adc/zynq-xadc.c b/hw/adc/zynq-xadc.c
index 3426831..26d9a7b 100644
--- a/hw/adc/zynq-xadc.c
+++ b/hw/adc/zynq-xadc.c
@@ -286,7 +286,7 @@ static void zynq_xadc_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_zynq_xadc;
- dc->reset = zynq_xadc_reset;
+ device_class_set_legacy_reset(dc, zynq_xadc_reset);
}
static const TypeInfo zynq_xadc_info = {
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 1ad60da..e7fd933 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -20,7 +20,8 @@ config ARM_VIRT
select PCI_EXPRESS
select PCI_EXPRESS_GENERIC_BRIDGE
select PFLASH_CFI01
- select PL011 # UART
+ select PL011 if !HAVE_RUST # UART
+ select X_PL011_RUST if HAVE_RUST # UART
select PL031 # RTC
select PL061 # GPIO
select GPIO_PWR
@@ -37,13 +38,6 @@ config ARM_VIRT
select ACPI_CXL
select ACPI_HMAT
-config CHEETAH
- bool
- default y
- depends on TCG && ARM
- select OMAP
- select TSC210X
-
config CUBIEBOARD
bool
default y
@@ -80,7 +74,8 @@ config HIGHBANK
select AHCI
select ARM_TIMER # sp804
select ARM_V7M
- select PL011 # UART
+ select PL011 if !HAVE_RUST # UART
+ select X_PL011_RUST if HAVE_RUST # UART
select PL022 # SPI
select PL031 # RTC
select PL061 # GPIO
@@ -93,7 +88,8 @@ config INTEGRATOR
depends on TCG && ARM
select ARM_TIMER
select INTEGRATOR_DEBUG
- select PL011 # UART
+ select PL011 if !HAVE_RUST # UART
+ select X_PL011_RUST if HAVE_RUST # UART
select PL031 # RTC
select PL041 # audio
select PL050 # keyboard/mouse
@@ -101,14 +97,6 @@ config INTEGRATOR
select PL181 # display
select SMC91C111
-config MAINSTONE
- bool
- default y
- depends on TCG && ARM
- select PXA2XX
- select PFLASH_CFI01
- select SMC91C111
-
config MPS3R
bool
default y
@@ -119,7 +107,8 @@ config MUSCA
default y
depends on TCG && ARM
select ARMSSE
- select PL011
+ select PL011 if !HAVE_RUST # UART
+ select X_PL011_RUST if HAVE_RUST # UART
select PL031
select SPLIT_IRQ
select UNIMP
@@ -136,7 +125,7 @@ config MUSICPAL
select MARVELL_88W8618
select PTIMER
select PFLASH_CFI02
- select SERIAL
+ select SERIAL_MM
select WM8750
config NETDUINO2
@@ -157,79 +146,14 @@ config OLIMEX_STM32_H405
depends on TCG && ARM
select STM32F405_SOC
-config NSERIES
- bool
- default y
- depends on TCG && ARM
- select OMAP
- select TMP105 # temperature sensor
- select BLIZZARD # LCD/TV controller
- select ONENAND
- select TSC210X # touchscreen/sensors/audio
- select TSC2005 # touchscreen/sensors/keypad
- select LM832X # GPIO keyboard chip
- select TWL92230 # energy-management
- select TUSB6010
-
config OMAP
bool
select FRAMEBUFFER
select I2C
- select ECC
select NAND
select PFLASH_CFI01
select SD
- select SERIAL
-
-config PXA2XX
- bool
- select FRAMEBUFFER
- select I2C
- select SERIAL
- select SD
- select SSI
- select USB_OHCI_SYSBUS
- select PCMCIA
-
-config GUMSTIX
- bool
- default y
- depends on TCG && ARM
- select PFLASH_CFI01
- select SMC91C111
- select PXA2XX
-
-config TOSA
- bool
- default y
- depends on TCG && ARM
- select ZAURUS # scoop
- select MICRODRIVE
- select PXA2XX
- select LED
-
-config SPITZ
- bool
- default y
- depends on TCG && ARM
- select ADS7846 # touch-screen controller
- select MAX111X # A/D converter
- select WM8750 # audio codec
- select MAX7310 # GPIO expander
- select ZAURUS # scoop
- select NAND # memory
- select ECC # Error-correcting for NAND
- select MICRODRIVE
- select PXA2XX
-
-config Z2
- bool
- default y
- depends on TCG && ARM
- select PFLASH_CFI01
- select WM8750
- select PL011 # UART
- select PXA2XX
+ select SERIAL_MM
config REALVIEW
bool
@@ -248,7 +172,8 @@ config REALVIEW
select WM8750 # audio codec
select LSI_SCSI_PCI
select PCI
- select PL011 # UART
+ select PL011 if !HAVE_RUST # UART
+ select X_PL011_RUST if HAVE_RUST # UART
select PL031 # RTC
select PL041 # audio codec
select PL050 # keyboard/mouse
@@ -273,7 +198,8 @@ config SBSA_REF
select PCI_EXPRESS
select PCI_EXPRESS_GENERIC_BRIDGE
select PFLASH_CFI01
- select PL011 # UART
+ select PL011 if !HAVE_RUST # UART
+ select X_PL011_RUST if HAVE_RUST # UART
select PL031 # RTC
select PL061 # GPIO
select USB_XHCI_SYSBUS
@@ -297,7 +223,8 @@ config STELLARIS
select ARM_V7M
select CMSDK_APB_WATCHDOG
select I2C
- select PL011 # UART
+ select PL011 if !HAVE_RUST # UART
+ select X_PL011_RUST if HAVE_RUST # UART
select PL022 # SPI
select PL061 # GPIO
select SSD0303 # OLED display
@@ -316,14 +243,15 @@ config STM32VLDISCOVERY
config STRONGARM
bool
- select PXA2XX
+ select PXA2XX_TIMER
+ select SSI
config COLLIE
bool
default y
depends on TCG && ARM
select PFLASH_CFI01
- select ZAURUS # scoop
+ select ZAURUS_SCOOP
select STRONGARM
config SX1
@@ -356,7 +284,8 @@ config VEXPRESS
select ARM_TIMER # sp804
select LAN9118
select PFLASH_CFI01
- select PL011 # UART
+ select PL011 if !HAVE_RUST # UART
+ select X_PL011_RUST if HAVE_RUST # UART
select PL041 # audio codec
select PL181 # display
select REALVIEW
@@ -398,8 +327,9 @@ config ALLWINNER_A10
select ALLWINNER_WDT
select ALLWINNER_EMAC
select ALLWINNER_I2C
+ select ALLWINNER_A10_SPI
select AXP2XX_PMU
- select SERIAL
+ select SERIAL_MM
select UNIMP
select USB_OHCI_SYSBUS
@@ -411,7 +341,7 @@ config ALLWINNER_H3
select ALLWINNER_SUN8I_EMAC
select ALLWINNER_I2C
select ALLWINNER_WDT
- select SERIAL
+ select SERIAL_MM
select ARM_TIMER
select ARM_GIC
select UNIMP
@@ -427,7 +357,7 @@ config ALLWINNER_R40
select ALLWINNER_A10_PIT
select ALLWINNER_WDT
select AXP2XX_PMU
- select SERIAL
+ select SERIAL_MM
select ARM_TIMER
select ARM_GIC
select UNIMP
@@ -440,7 +370,8 @@ config RASPI
default y
depends on TCG && ARM
select FRAMEBUFFER
- select PL011 # UART
+ select PL011 if !HAVE_RUST # UART
+ select X_PL011_RUST if HAVE_RUST # UART
select SDHCI
select USB_DWC2
select BCM2835_SPI
@@ -466,6 +397,7 @@ config STM32F405_SOC
bool
select ARM_V7M
select OR_IRQ
+ select STM32_RCC
select STM32F4XX_SYSCFG
select STM32F4XX_EXTI
@@ -515,7 +447,8 @@ config XLNX_VERSAL
select ARM_GIC
select CPU_CLUSTER
select DEVICE_TREE
- select PL011
+ select PL011 if !HAVE_RUST # UART
+ select X_PL011_RUST if HAVE_RUST # UART
select CADENCE
select VIRTIO_MMIO
select UNIMP
@@ -542,7 +475,7 @@ config NPCM7XX
select ISL_PMBUS_VR
select PL310 # cache controller
select PMBUS
- select SERIAL
+ select SERIAL_MM
select SSI
select UNIMP
select PCA954X
@@ -564,7 +497,7 @@ config FSL_IMX31
default y
depends on TCG && ARM
imply I2C_DEVICES
- select SERIAL
+ select SERIAL_MM
select IMX
select IMX_I2C
select WDT_IMX2
@@ -593,7 +526,7 @@ config ASPEED_SOC
select I2C
select DPS310
select PCA9552
- select SERIAL
+ select SERIAL_MM
select SMBUS_EEPROM
select PCA954X
select SSI
@@ -681,15 +614,10 @@ config MSF2
bool
select ARM_V7M
select PTIMER
- select SERIAL
+ select SERIAL_MM
select SSI
select UNIMP
-config ZAURUS
- bool
- select NAND
- select ECC
-
config ARMSSE
bool
select ARM_V7M
diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c
index 57d5d80..52327d9 100644
--- a/hw/arm/allwinner-a10.c
+++ b/hw/arm/allwinner-a10.c
@@ -17,8 +17,9 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
+#include "qemu/error-report.h"
#include "qemu/module.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/sysbus.h"
#include "hw/arm/allwinner-a10.h"
#include "hw/misc/unimp.h"
@@ -35,6 +36,7 @@
#define AW_A10_PIC_REG_BASE 0x01c20400
#define AW_A10_PIT_REG_BASE 0x01c20c00
#define AW_A10_UART0_REG_BASE 0x01c28000
+#define AW_A10_SPI0_BASE 0x01c05000
#define AW_A10_EMAC_BASE 0x01c0b000
#define AW_A10_EHCI_BASE 0x01c14000
#define AW_A10_OHCI_BASE 0x01c14400
@@ -49,9 +51,8 @@ void allwinner_a10_bootrom_setup(AwA10State *s, BlockBackend *blk)
g_autofree uint8_t *buffer = g_new0(uint8_t, rom_size);
if (blk_pread(blk, 8 * KiB, rom_size, buffer, 0) < 0) {
- error_setg(&error_fatal, "%s: failed to read BlockBackend data",
- __func__);
- return;
+ error_report("%s: failed to read BlockBackend data", __func__);
+ exit(1);
}
rom_add_blob("allwinner-a10.bootrom", buffer, rom_size,
@@ -80,6 +81,8 @@ static void aw_a10_init(Object *obj)
object_initialize_child(obj, "i2c0", &s->i2c0, TYPE_AW_I2C);
+ object_initialize_child(obj, "spi0", &s->spi0, TYPE_AW_A10_SPI);
+
for (size_t i = 0; i < AW_A10_NUM_USB; i++) {
object_initialize_child(obj, "ehci[*]", &s->ehci[i],
TYPE_PLATFORM_EHCI);
@@ -195,6 +198,11 @@ static void aw_a10_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c0), 0, AW_A10_I2C0_BASE);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c0), 0, qdev_get_gpio_in(dev, 7));
+ /* SPI */
+ sysbus_realize(SYS_BUS_DEVICE(&s->spi0), &error_fatal);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi0), 0, AW_A10_SPI0_BASE);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi0), 0, qdev_get_gpio_in(dev, 10));
+
/* WDT */
sysbus_realize(SYS_BUS_DEVICE(&s->wdt), &error_fatal);
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->wdt), 0, AW_A10_WDT_BASE, 1);
diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
index 6870c3f..fd7638d 100644
--- a/hw/arm/allwinner-h3.c
+++ b/hw/arm/allwinner-h3.c
@@ -24,7 +24,7 @@
#include "qemu/units.h"
#include "hw/qdev-core.h"
#include "hw/sysbus.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/misc/unimp.h"
#include "hw/usb/hcd-ehci.h"
#include "hw/loader.h"
@@ -182,9 +182,8 @@ void allwinner_h3_bootrom_setup(AwH3State *s, BlockBackend *blk)
g_autofree uint8_t *buffer = g_new0(uint8_t, rom_size);
if (blk_pread(blk, 8 * KiB, rom_size, buffer, 0) < 0) {
- error_setg(&error_fatal, "%s: failed to read BlockBackend data",
- __func__);
- return;
+ error_report("%s: failed to read BlockBackend data", __func__);
+ exit(1);
}
rom_add_blob("allwinner-h3.bootrom", buffer, rom_size,
diff --git a/hw/arm/allwinner-r40.c b/hw/arm/allwinner-r40.c
index b8c7202..c6f7cab 100644
--- a/hw/arm/allwinner-r40.c
+++ b/hw/arm/allwinner-r40.c
@@ -26,7 +26,7 @@
#include "hw/boards.h"
#include "hw/qdev-core.h"
#include "hw/sysbus.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/misc/unimp.h"
#include "hw/usb/hcd-ehci.h"
#include "hw/loader.h"
@@ -231,9 +231,8 @@ bool allwinner_r40_bootrom_setup(AwR40State *s, BlockBackend *blk, int unit)
struct boot_file_head *head = (struct boot_file_head *)buffer;
if (blk_pread(blk, 8 * KiB, rom_size, buffer, 0) < 0) {
- error_setg(&error_fatal, "%s: failed to read BlockBackend data",
- __func__);
- return false;
+ error_report("%s: failed to read BlockBackend data", __func__);
+ exit(1);
}
/* we only check the magic string here. */
diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c
index 91502d1..255346a 100644
--- a/hw/arm/armsse.c
+++ b/hw/arm/armsse.c
@@ -1700,7 +1700,7 @@ static void armsse_class_init(ObjectClass *klass, void *data)
dc->realize = armsse_realize;
dc->vmsd = &armsse_vmstate;
device_class_set_props(dc, info->props);
- dc->reset = armsse_reset;
+ device_class_set_legacy_reset(dc, armsse_reset);
iic->check = armsse_idau_check;
asc->info = info;
}
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index 53a4f66..b4b1ce9 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -46,6 +46,7 @@ struct AspeedMachineState {
uint32_t uart_chosen;
char *fmc_model;
char *spi_model;
+ uint32_t hw_strap1;
};
/* On 32-bit hosts, lower RAM to 1G because of the 2047 MB limit */
@@ -189,7 +190,7 @@ struct AspeedMachineState {
#define TACOMA_BMC_HW_STRAP2 0x00000040
/* Rainier hardware value: (QEMU prototype) */
-#define RAINIER_BMC_HW_STRAP1 0x00422016
+#define RAINIER_BMC_HW_STRAP1 (0x00422016 | SCU_AST2600_HW_STRAP_BOOT_SRC_EMMC)
#define RAINIER_BMC_HW_STRAP2 0x80000848
/* Fuji hardware value */
@@ -265,7 +266,8 @@ static void write_boot_rom(BlockBackend *blk, hwaddr addr, size_t rom_size,
g_autofree void *storage = NULL;
int64_t size;
- /* The block backend size should have already been 'validated' by
+ /*
+ * The block backend size should have already been 'validated' by
* the creation of the m25p80 object.
*/
size = blk_getlength(blk);
@@ -327,14 +329,20 @@ void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype,
}
}
-static void sdhci_attach_drive(SDHCIState *sdhci, DriveInfo *dinfo)
+static void sdhci_attach_drive(SDHCIState *sdhci, DriveInfo *dinfo, bool emmc,
+ bool boot_emmc)
{
DeviceState *card;
if (!dinfo) {
return;
}
- card = qdev_new(TYPE_SD_CARD);
+ card = qdev_new(emmc ? TYPE_EMMC : TYPE_SD_CARD);
+ if (emmc) {
+ qdev_prop_set_uint64(card, "boot-partition-size", 1 * MiB);
+ qdev_prop_set_uint8(card, "boot-config",
+ boot_emmc ? 0x1 << 3 : 0x0);
+ }
qdev_prop_set_drive_err(card, "drive", blk_by_legacy_dinfo(dinfo),
&error_fatal);
qdev_realize_and_unref(card,
@@ -364,6 +372,8 @@ static void aspeed_machine_init(MachineState *machine)
AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(machine);
AspeedSoCClass *sc;
int i;
+ DriveInfo *emmc0 = NULL;
+ bool boot_emmc;
bmc->soc = ASPEED_SOC(object_new(amc->soc_name));
object_property_add_child(OBJECT(machine), "soc", OBJECT(bmc->soc));
@@ -385,7 +395,7 @@ static void aspeed_machine_init(MachineState *machine)
}
}
- object_property_set_int(OBJECT(bmc->soc), "hw-strap1", amc->hw_strap1,
+ object_property_set_int(OBJECT(bmc->soc), "hw-strap1", bmc->hw_strap1,
&error_abort);
object_property_set_int(OBJECT(bmc->soc), "hw-strap2", amc->hw_strap2,
&error_abort);
@@ -436,21 +446,25 @@ static void aspeed_machine_init(MachineState *machine)
for (i = 0; i < bmc->soc->sdhci.num_slots; i++) {
sdhci_attach_drive(&bmc->soc->sdhci.slots[i],
- drive_get(IF_SD, 0, i));
+ drive_get(IF_SD, 0, i), false, false);
}
+ boot_emmc = sc->boot_from_emmc(bmc->soc);
+
if (bmc->soc->emmc.num_slots) {
- sdhci_attach_drive(&bmc->soc->emmc.slots[0],
- drive_get(IF_SD, 0, bmc->soc->sdhci.num_slots));
+ emmc0 = drive_get(IF_SD, 0, bmc->soc->sdhci.num_slots);
+ sdhci_attach_drive(&bmc->soc->emmc.slots[0], emmc0, true, boot_emmc);
}
if (!bmc->mmio_exec) {
DeviceState *dev = ssi_get_cs(bmc->soc->fmc.spi, 0);
BlockBackend *fmc0 = dev ? m25p80_get_blk(dev) : NULL;
- if (fmc0) {
+ if (fmc0 && !boot_emmc) {
uint64_t rom_size = memory_region_size(&bmc->soc->spi_boot);
aspeed_install_boot_rom(bmc, fmc0, rom_size);
+ } else if (emmc0) {
+ aspeed_install_boot_rom(bmc, blk_by_legacy_dinfo(emmc0), 64 * KiB);
}
}
@@ -463,8 +477,10 @@ static void palmetto_bmc_i2c_init(AspeedMachineState *bmc)
DeviceState *dev;
uint8_t *eeprom_buf = g_malloc0(32 * 1024);
- /* The palmetto platform expects a ds3231 RTC but a ds1338 is
- * enough to provide basic RTC features. Alarms will be missing */
+ /*
+ * The palmetto platform expects a ds3231 RTC but a ds1338 is
+ * enough to provide basic RTC features. Alarms will be missing
+ */
i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 0), "ds1338", 0x68);
smbus_eeprom_init_one(aspeed_i2c_get_bus(&soc->i2c, 0), 0x50,
@@ -555,8 +571,10 @@ static void romulus_bmc_i2c_init(AspeedMachineState *bmc)
{
AspeedSoCState *soc = bmc->soc;
- /* The romulus board expects Epson RX8900 I2C RTC but a ds1338 is
- * good enough */
+ /*
+ * The romulus board expects Epson RX8900 I2C RTC but a ds1338 is
+ * good enough
+ */
i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 11), "ds1338", 0x32);
}
@@ -664,8 +682,10 @@ static void witherspoon_bmc_i2c_init(AspeedMachineState *bmc)
i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 9), TYPE_TMP105,
0x4a);
- /* The witherspoon board expects Epson RX8900 I2C RTC but a ds1338 is
- * good enough */
+ /*
+ * The witherspoon board expects Epson RX8900 I2C RTC but a ds1338 is
+ * good enough
+ */
i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 11), "ds1338", 0x32);
smbus_eeprom_init_one(aspeed_i2c_get_bus(&soc->i2c, 11), 0x51,
@@ -1065,7 +1085,10 @@ static void aspeed_set_mmio_exec(Object *obj, bool value, Error **errp)
static void aspeed_machine_instance_init(Object *obj)
{
+ AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(obj);
+
ASPEED_MACHINE(obj)->mmio_exec = false;
+ ASPEED_MACHINE(obj)->hw_strap1 = amc->hw_strap1;
}
static char *aspeed_get_fmc_model(Object *obj, Error **errp)
@@ -1162,6 +1185,34 @@ static void aspeed_machine_class_init_cpus_defaults(MachineClass *mc)
mc->valid_cpu_types = sc->valid_cpu_types;
}
+static bool aspeed_machine_ast2600_get_boot_from_emmc(Object *obj, Error **errp)
+{
+ AspeedMachineState *bmc = ASPEED_MACHINE(obj);
+
+ return !!(bmc->hw_strap1 & SCU_AST2600_HW_STRAP_BOOT_SRC_EMMC);
+}
+
+static void aspeed_machine_ast2600_set_boot_from_emmc(Object *obj, bool value,
+ Error **errp)
+{
+ AspeedMachineState *bmc = ASPEED_MACHINE(obj);
+
+ if (value) {
+ bmc->hw_strap1 |= SCU_AST2600_HW_STRAP_BOOT_SRC_EMMC;
+ } else {
+ bmc->hw_strap1 &= ~SCU_AST2600_HW_STRAP_BOOT_SRC_EMMC;
+ }
+}
+
+static void aspeed_machine_ast2600_class_emmc_init(ObjectClass *oc)
+{
+ object_class_property_add_bool(oc, "boot-emmc",
+ aspeed_machine_ast2600_get_boot_from_emmc,
+ aspeed_machine_ast2600_set_boot_from_emmc);
+ object_class_property_set_description(oc, "boot-emmc",
+ "Set or unset boot from EMMC");
+}
+
static void aspeed_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -1361,6 +1412,7 @@ static void aspeed_machine_ast2600_evb_class_init(ObjectClass *oc, void *data)
amc->i2c_init = ast2600_evb_i2c_init;
mc->default_ram_size = 1 * GiB;
aspeed_machine_class_init_cpus_defaults(mc);
+ aspeed_machine_ast2600_class_emmc_init(oc);
};
static void aspeed_machine_tacoma_class_init(ObjectClass *oc, void *data)
@@ -1433,6 +1485,7 @@ static void aspeed_machine_rainier_class_init(ObjectClass *oc, void *data)
amc->i2c_init = rainier_bmc_i2c_init;
mc->default_ram_size = 1 * GiB;
aspeed_machine_class_init_cpus_defaults(mc);
+ aspeed_machine_ast2600_class_emmc_init(oc);
};
#define FUJI_BMC_RAM_SIZE ASPEED_RAM_SIZE(2 * GiB)
@@ -1476,12 +1529,12 @@ static void aspeed_machine_bletchley_class_init(ObjectClass *oc, void *data)
aspeed_machine_class_init_cpus_defaults(mc);
}
-static void fby35_reset(MachineState *state, ShutdownCause reason)
+static void fby35_reset(MachineState *state, ResetType type)
{
AspeedMachineState *bmc = ASPEED_MACHINE(state);
AspeedGPIOState *gpio = &bmc->soc->gpio;
- qemu_devices_reset(reason);
+ qemu_devices_reset(type);
/* Board ID: 7 (Class-1, 4 slots) */
object_property_set_bool(OBJECT(gpio), "gpioV4", true, &error_fatal);
@@ -1589,14 +1642,23 @@ static void aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc,
mc->init = aspeed_minibmc_machine_init;
amc->i2c_init = ast1030_evb_i2c_init;
mc->default_ram_size = 0;
- amc->fmc_model = "sst25vf032b";
- amc->spi_model = "sst25vf032b";
+ amc->fmc_model = "w25q80bl";
+ amc->spi_model = "w25q256";
amc->num_cs = 2;
amc->macs_mask = 0;
aspeed_machine_class_init_cpus_defaults(mc);
}
#ifdef TARGET_AARCH64
+static void ast2700_evb_i2c_init(AspeedMachineState *bmc)
+{
+ AspeedSoCState *soc = bmc->soc;
+
+ /* LM75 is compatible with TMP105 driver */
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 0),
+ TYPE_TMP105, 0x4d);
+}
+
static void aspeed_machine_ast2700_evb_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -1611,6 +1673,7 @@ static void aspeed_machine_ast2700_evb_class_init(ObjectClass *oc, void *data)
amc->num_cs = 2;
amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON | ASPEED_MAC2_ON;
amc->uart_default = ASPEED_DEV_UART12;
+ amc->i2c_init = ast2700_evb_i2c_init;
mc->default_ram_size = 1 * GiB;
aspeed_machine_class_init_cpus_defaults(mc);
}
diff --git a/hw/arm/aspeed_ast2400.c b/hw/arm/aspeed_ast2400.c
index d125886..ecc81ec 100644
--- a/hw/arm/aspeed_ast2400.c
+++ b/hw/arm/aspeed_ast2400.c
@@ -15,7 +15,7 @@
#include "qapi/error.h"
#include "hw/misc/unimp.h"
#include "hw/arm/aspeed_soc.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "qemu/module.h"
#include "qemu/error-report.h"
#include "hw/i2c/aspeed_i2c.h"
diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c
index 31713de..be3eb70 100644
--- a/hw/arm/aspeed_ast2600.c
+++ b/hw/arm/aspeed_ast2600.c
@@ -646,6 +646,13 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
}
}
+static bool aspeed_soc_ast2600_boot_from_emmc(AspeedSoCState *s)
+{
+ uint32_t hw_strap1 = object_property_get_uint(OBJECT(&s->scu),
+ "hw-strap1", &error_abort);
+ return !!(hw_strap1 & SCU_AST2600_HW_STRAP_BOOT_SRC_EMMC);
+}
+
static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data)
{
static const char * const valid_cpu_types[] = {
@@ -673,6 +680,7 @@ static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data)
sc->memmap = aspeed_soc_ast2600_memmap;
sc->num_cpus = 2;
sc->get_irq = aspeed_soc_ast2600_get_irq;
+ sc->boot_from_emmc = aspeed_soc_ast2600_boot_from_emmc;
}
static const TypeInfo aspeed_soc_ast2600_types[] = {
diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index a9fb0d4..dca660e 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -60,6 +60,9 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = {
[ASPEED_DEV_SLIIO] = 0x14C1E000,
[ASPEED_GIC_DIST] = 0x12200000,
[ASPEED_GIC_REDIST] = 0x12280000,
+ [ASPEED_DEV_ADC] = 0x14C00000,
+ [ASPEED_DEV_I2C] = 0x14C0F000,
+ [ASPEED_DEV_GPIO] = 0x14C0B000,
};
#define AST2700_MAX_IRQ 288
@@ -85,8 +88,7 @@ static const int aspeed_soc_ast2700_irqmap[] = {
[ASPEED_DEV_ADC] = 130,
[ASPEED_DEV_XDMA] = 5,
[ASPEED_DEV_EMMC] = 15,
- [ASPEED_DEV_GPIO] = 11,
- [ASPEED_DEV_GPIO_1_8V] = 130,
+ [ASPEED_DEV_GPIO] = 130,
[ASPEED_DEV_RTC] = 13,
[ASPEED_DEV_TIMER1] = 16,
[ASPEED_DEV_TIMER2] = 17,
@@ -122,7 +124,7 @@ static const int aspeed_soc_ast2700_gic128_intcmap[] = {
static const int aspeed_soc_ast2700_gic130_intcmap[] = {
[ASPEED_DEV_I2C] = 0,
[ASPEED_DEV_ADC] = 16,
- [ASPEED_DEV_GPIO_1_8V] = 18,
+ [ASPEED_DEV_GPIO] = 18,
};
/* GICINT 131 */
@@ -192,6 +194,27 @@ static qemu_irq aspeed_soc_ast2700_get_irq(AspeedSoCState *s, int dev)
return qdev_get_gpio_in(DEVICE(&a->gic), sc->irqmap[dev]);
}
+static qemu_irq aspeed_soc_ast2700_get_irq_index(AspeedSoCState *s, int dev,
+ int index)
+{
+ Aspeed27x0SoCState *a = ASPEED27X0_SOC(s);
+ AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(aspeed_soc_ast2700_gic_intcmap); i++) {
+ if (sc->irqmap[dev] == aspeed_soc_ast2700_gic_intcmap[i].irq) {
+ assert(aspeed_soc_ast2700_gic_intcmap[i].ptr);
+ return qdev_get_gpio_in(DEVICE(&a->intc.orgates[i]),
+ aspeed_soc_ast2700_gic_intcmap[i].ptr[dev] + index);
+ }
+ }
+
+ /*
+ * Invalid orgate index, device irq should be 128 to 136.
+ */
+ g_assert_not_reached();
+}
+
static uint64_t aspeed_ram_capacity_read(void *opaque, hwaddr addr,
unsigned int size)
{
@@ -344,6 +367,15 @@ static void aspeed_soc_ast2700_init(Object *obj)
object_initialize_child(obj, "sli", &s->sli, TYPE_ASPEED_2700_SLI);
object_initialize_child(obj, "sliio", &s->sliio, TYPE_ASPEED_2700_SLIIO);
object_initialize_child(obj, "intc", &a->intc, TYPE_ASPEED_2700_INTC);
+
+ snprintf(typename, sizeof(typename), "aspeed.adc-%s", socname);
+ object_initialize_child(obj, "adc", &s->adc, typename);
+
+ snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
+ object_initialize_child(obj, "i2c", &s->i2c, typename);
+
+ snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname);
+ object_initialize_child(obj, "gpio", &s->gpio, typename);
}
/*
@@ -427,6 +459,7 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp)
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
AspeedINTCClass *ic = ASPEED_INTC_GET_CLASS(&a->intc);
g_autofree char *sram_name = NULL;
+ qemu_irq irq;
/* Default boot region (SPI memory or ROMs) */
memory_region_init(&s->spi_boot_container, OBJECT(s),
@@ -601,6 +634,42 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp)
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sliio), 0,
sc->memmap[ASPEED_DEV_SLIIO]);
+ /* ADC */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc), errp)) {
+ return;
+ }
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->adc), 0, sc->memmap[ASPEED_DEV_ADC]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0,
+ aspeed_soc_get_irq(s, ASPEED_DEV_ADC));
+
+ /* I2C */
+ object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr),
+ &error_abort);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) {
+ return;
+ }
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]);
+ for (i = 0; i < ASPEED_I2C_GET_CLASS(&s->i2c)->num_busses; i++) {
+ /*
+ * The AST2700 I2C controller has one source INTC per bus.
+ * I2C buses interrupt are connected to GICINT130_INTC
+ * from bit 0 to bit 15.
+ * I2C bus 0 is connected to GICINT130_INTC at bit 0.
+ * I2C bus 15 is connected to GICINT130_INTC at bit 15.
+ */
+ irq = aspeed_soc_ast2700_get_irq_index(s, ASPEED_DEV_I2C, i);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq);
+ }
+
+ /* GPIO */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
+ return;
+ }
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0,
+ sc->memmap[ASPEED_DEV_GPIO]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0,
+ aspeed_soc_get_irq(s, ASPEED_DEV_GPIO));
+
create_unimplemented_device("ast2700.dpmcu", 0x11000000, 0x40000);
create_unimplemented_device("ast2700.iomem0", 0x12000000, 0x01000000);
create_unimplemented_device("ast2700.iomem1", 0x14000000, 0x01000000);
diff --git a/hw/arm/aspeed_soc_common.c b/hw/arm/aspeed_soc_common.c
index 1e8f255..a5ff33c 100644
--- a/hw/arm/aspeed_soc_common.c
+++ b/hw/arm/aspeed_soc_common.c
@@ -15,7 +15,7 @@
#include "hw/qdev-properties.h"
#include "hw/misc/unimp.h"
#include "hw/arm/aspeed_soc.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
const char *aspeed_soc_cpu_type(AspeedSoCClass *sc)
@@ -134,6 +134,11 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
}
}
+static bool aspeed_soc_boot_from_emmc(AspeedSoCState *s)
+{
+ return false;
+}
+
static Property aspeed_soc_properties[] = {
DEFINE_PROP_LINK("dram", AspeedSoCState, dram_mr, TYPE_MEMORY_REGION,
MemoryRegion *),
@@ -145,9 +150,11 @@ static Property aspeed_soc_properties[] = {
static void aspeed_soc_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
+ AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc);
dc->realize = aspeed_soc_realize;
device_class_set_props(dc, aspeed_soc_properties);
+ sc->boot_from_emmc = aspeed_soc_boot_from_emmc;
}
static const TypeInfo aspeed_soc_types[] = {
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index d480a7d..5301d8d 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -799,14 +799,18 @@ static ssize_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry,
} elf_header;
int data_swab = 0;
bool big_endian;
- ssize_t ret = -1;
+ ssize_t ret;
Error *err = NULL;
load_elf_hdr(info->kernel_filename, &elf_header, &elf_is64, &err);
if (err) {
+ /*
+ * If the file is not an ELF file we silently return.
+ * The caller will fall back to try other formats.
+ */
error_free(err);
- return ret;
+ return -1;
}
if (elf_is64) {
@@ -839,6 +843,8 @@ static ssize_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry,
1, data_swab, as);
if (ret <= 0) {
/* The header loaded but the image didn't */
+ error_report("Couldn't load elf '%s': %s",
+ info->kernel_filename, load_elf_strerror(ret));
exit(1);
}
diff --git a/hw/arm/gumstix.c b/hw/arm/gumstix.c
deleted file mode 100644
index 9146269..0000000
--- a/hw/arm/gumstix.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Gumstix Platforms
- *
- * Copyright (c) 2007 by Thorsten Zitterell <info@bitmux.org>
- *
- * Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-/*
- * Example usage:
- *
- * connex:
- * =======
- * create image:
- * # dd of=flash bs=1k count=16k if=/dev/zero
- * # dd of=flash bs=1k conv=notrunc if=u-boot.bin
- * # dd of=flash bs=1k conv=notrunc seek=256 if=rootfs.arm_nofpu.jffs2
- * start it:
- * # qemu-system-arm -M connex -pflash flash -monitor null -nographic
- *
- * verdex:
- * =======
- * create image:
- * # dd of=flash bs=1k count=32k if=/dev/zero
- * # dd of=flash bs=1k conv=notrunc if=u-boot.bin
- * # dd of=flash bs=1k conv=notrunc seek=256 if=rootfs.arm_nofpu.jffs2
- * # dd of=flash bs=1k conv=notrunc seek=31744 if=uImage
- * start it:
- * # qemu-system-arm -M verdex -pflash flash -monitor null -nographic -m 289
- */
-
-#include "qemu/osdep.h"
-#include "qemu/units.h"
-#include "qemu/error-report.h"
-#include "hw/arm/pxa.h"
-#include "net/net.h"
-#include "hw/block/flash.h"
-#include "hw/net/smc91c111.h"
-#include "hw/boards.h"
-#include "exec/address-spaces.h"
-#include "sysemu/qtest.h"
-
-#define CONNEX_FLASH_SIZE (16 * MiB)
-#define CONNEX_RAM_SIZE (64 * MiB)
-
-#define VERDEX_FLASH_SIZE (32 * MiB)
-#define VERDEX_RAM_SIZE (256 * MiB)
-
-#define FLASH_SECTOR_SIZE (128 * KiB)
-
-static void connex_init(MachineState *machine)
-{
- PXA2xxState *cpu;
- DriveInfo *dinfo;
-
- cpu = pxa255_init(CONNEX_RAM_SIZE);
-
- dinfo = drive_get(IF_PFLASH, 0, 0);
- if (!dinfo && !qtest_enabled()) {
- error_report("A flash image must be given with the "
- "'pflash' parameter");
- exit(1);
- }
-
- /* Numonyx RC28F128J3F75 */
- pflash_cfi01_register(0x00000000, "connext.rom", CONNEX_FLASH_SIZE,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- FLASH_SECTOR_SIZE, 2, 0, 0, 0, 0, 0);
-
- /* Interrupt line of NIC is connected to GPIO line 36 */
- smc91c111_init(0x04000300, qdev_get_gpio_in(cpu->gpio, 36));
-}
-
-static void verdex_init(MachineState *machine)
-{
- PXA2xxState *cpu;
- DriveInfo *dinfo;
-
- cpu = pxa270_init(VERDEX_RAM_SIZE, machine->cpu_type);
-
- dinfo = drive_get(IF_PFLASH, 0, 0);
- if (!dinfo && !qtest_enabled()) {
- error_report("A flash image must be given with the "
- "'pflash' parameter");
- exit(1);
- }
-
- /* Micron RC28F256P30TFA */
- pflash_cfi01_register(0x00000000, "verdex.rom", VERDEX_FLASH_SIZE,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- FLASH_SECTOR_SIZE, 2, 0, 0, 0, 0, 0);
-
- /* Interrupt line of NIC is connected to GPIO line 99 */
- smc91c111_init(0x04000300, qdev_get_gpio_in(cpu->gpio, 99));
-}
-
-static void connex_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Gumstix Connex (PXA255)";
- mc->init = connex_init;
- mc->ignore_memory_transaction_failures = true;
- mc->deprecation_reason = "machine is old and unmaintained";
-}
-
-static const TypeInfo connex_type = {
- .name = MACHINE_TYPE_NAME("connex"),
- .parent = TYPE_MACHINE,
- .class_init = connex_class_init,
-};
-
-static void verdex_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Gumstix Verdex Pro XL6P COMs (PXA270)";
- mc->init = verdex_init;
- mc->ignore_memory_transaction_failures = true;
- mc->deprecation_reason = "machine is old and unmaintained";
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c0");
-}
-
-static const TypeInfo verdex_type = {
- .name = MACHINE_TYPE_NAME("verdex"),
- .parent = TYPE_MACHINE,
- .class_init = verdex_class_init,
-};
-
-static void gumstix_machine_init(void)
-{
- type_register_static(&connex_type);
- type_register_static(&verdex_type);
-}
-
-type_init(gumstix_machine_init)
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
index c71b1a8..f103921 100644
--- a/hw/arm/highbank.c
+++ b/hw/arm/highbank.c
@@ -145,7 +145,7 @@ static void highbank_regs_class_init(ObjectClass *klass, void *data)
dc->desc = "Calxeda Highbank registers";
dc->vmsd = &vmstate_highbank_regs;
- dc->reset = highbank_regs_reset;
+ device_class_set_legacy_reset(dc, highbank_regs_reset);
}
static const TypeInfo highbank_regs_info = {
@@ -199,7 +199,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
machine->cpu_type = ARM_CPU_TYPE_NAME("cortex-a15");
break;
default:
- assert(0);
+ g_assert_not_reached();
}
for (n = 0; n < smp_cpus; n++) {
diff --git a/hw/arm/kzm.c b/hw/arm/kzm.c
index 2ccd6f8..fbd140e 100644
--- a/hw/arm/kzm.c
+++ b/hw/arm/kzm.c
@@ -22,7 +22,7 @@
#include "exec/address-spaces.h"
#include "net/net.h"
#include "hw/net/lan9118.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "sysemu/qtest.h"
#include "sysemu/sysemu.h"
#include "qemu/cutils.h"
diff --git a/hw/arm/mainstone.c b/hw/arm/mainstone.c
deleted file mode 100644
index 3a6c22f..0000000
--- a/hw/arm/mainstone.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * PXA270-based Intel Mainstone platforms.
- *
- * Copyright (c) 2007 by Armin Kuster <akuster@kama-aina.net> or
- * <akuster@mvista.com>
- *
- * Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-#include "qemu/osdep.h"
-#include "qemu/units.h"
-#include "qemu/error-report.h"
-#include "qapi/error.h"
-#include "hw/arm/pxa.h"
-#include "hw/arm/boot.h"
-#include "net/net.h"
-#include "hw/net/smc91c111.h"
-#include "hw/boards.h"
-#include "hw/block/flash.h"
-#include "hw/sysbus.h"
-#include "exec/address-spaces.h"
-
-/* Device addresses */
-#define MST_FPGA_PHYS 0x08000000
-#define MST_ETH_PHYS 0x10000300
-#define MST_FLASH_0 0x00000000
-#define MST_FLASH_1 0x04000000
-
-/* IRQ definitions */
-#define MMC_IRQ 0
-#define USIM_IRQ 1
-#define USBC_IRQ 2
-#define ETHERNET_IRQ 3
-#define AC97_IRQ 4
-#define PEN_IRQ 5
-#define MSINS_IRQ 6
-#define EXBRD_IRQ 7
-#define S0_CD_IRQ 9
-#define S0_STSCHG_IRQ 10
-#define S0_IRQ 11
-#define S1_CD_IRQ 13
-#define S1_STSCHG_IRQ 14
-#define S1_IRQ 15
-
-static const struct keymap map[0xE0] = {
- [0 ... 0xDF] = { -1, -1 },
- [0x1e] = {0,0}, /* a */
- [0x30] = {0,1}, /* b */
- [0x2e] = {0,2}, /* c */
- [0x20] = {0,3}, /* d */
- [0x12] = {0,4}, /* e */
- [0x21] = {0,5}, /* f */
- [0x22] = {1,0}, /* g */
- [0x23] = {1,1}, /* h */
- [0x17] = {1,2}, /* i */
- [0x24] = {1,3}, /* j */
- [0x25] = {1,4}, /* k */
- [0x26] = {1,5}, /* l */
- [0x32] = {2,0}, /* m */
- [0x31] = {2,1}, /* n */
- [0x18] = {2,2}, /* o */
- [0x19] = {2,3}, /* p */
- [0x10] = {2,4}, /* q */
- [0x13] = {2,5}, /* r */
- [0x1f] = {3,0}, /* s */
- [0x14] = {3,1}, /* t */
- [0x16] = {3,2}, /* u */
- [0x2f] = {3,3}, /* v */
- [0x11] = {3,4}, /* w */
- [0x2d] = {3,5}, /* x */
- [0x34] = {4,0}, /* . */
- [0x15] = {4,2}, /* y */
- [0x2c] = {4,3}, /* z */
- [0x35] = {4,4}, /* / */
- [0xc7] = {5,0}, /* Home */
- [0x2a] = {5,1}, /* shift */
- /*
- * There are two matrix positions which map to space,
- * but QEMU can only use one of them for the reverse
- * mapping, so simply use the second one.
- */
- /* [0x39] = {5,2}, space */
- [0x39] = {5,3}, /* space */
- /*
- * Matrix position {5,4} and other keys are missing here.
- * TODO: Compare with Linux code and test real hardware.
- */
- [0x1c] = {5,4}, /* enter */
- [0x0e] = {5,5}, /* backspace */
- [0xc8] = {6,0}, /* up */
- [0xd0] = {6,1}, /* down */
- [0xcb] = {6,2}, /* left */
- [0xcd] = {6,3}, /* right */
-};
-
-enum mainstone_model_e { mainstone };
-
-#define MAINSTONE_RAM_SIZE (64 * MiB)
-#define MAINSTONE_ROM_SIZE (8 * MiB)
-#define MAINSTONE_FLASH_SIZE (32 * MiB)
-
-static struct arm_boot_info mainstone_binfo = {
- .loader_start = PXA2XX_SDRAM_BASE,
- .ram_size = MAINSTONE_RAM_SIZE,
-};
-
-#define FLASH_SECTOR_SIZE (256 * KiB)
-
-static void mainstone_common_init(MachineState *machine,
- enum mainstone_model_e model, int arm_id)
-{
- hwaddr mainstone_flash_base[] = { MST_FLASH_0, MST_FLASH_1 };
- PXA2xxState *mpu;
- DeviceState *mst_irq;
- DriveInfo *dinfo;
- int i;
- MemoryRegion *rom = g_new(MemoryRegion, 1);
-
- /* Setup CPU & memory */
- mpu = pxa270_init(mainstone_binfo.ram_size, machine->cpu_type);
- memory_region_init_rom(rom, NULL, "mainstone.rom", MAINSTONE_ROM_SIZE,
- &error_fatal);
- memory_region_add_subregion(get_system_memory(), 0x00000000, rom);
-
- /* There are two 32MiB flash devices on the board */
- for (i = 0; i < 2; i ++) {
- dinfo = drive_get(IF_PFLASH, 0, i);
- pflash_cfi01_register(mainstone_flash_base[i],
- i ? "mainstone.flash1" : "mainstone.flash0",
- MAINSTONE_FLASH_SIZE,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- FLASH_SECTOR_SIZE, 4, 0, 0, 0, 0, 0);
- }
-
- mst_irq = sysbus_create_simple("mainstone-fpga", MST_FPGA_PHYS,
- qdev_get_gpio_in(mpu->gpio, 0));
-
- /* setup keypad */
- pxa27x_register_keypad(mpu->kp, map, 0xe0);
-
- /* MMC/SD host */
- pxa2xx_mmci_handlers(mpu->mmc, NULL, qdev_get_gpio_in(mst_irq, MMC_IRQ));
-
- pxa2xx_pcmcia_set_irq_cb(mpu->pcmcia[0],
- qdev_get_gpio_in(mst_irq, S0_IRQ),
- qdev_get_gpio_in(mst_irq, S0_CD_IRQ));
- pxa2xx_pcmcia_set_irq_cb(mpu->pcmcia[1],
- qdev_get_gpio_in(mst_irq, S1_IRQ),
- qdev_get_gpio_in(mst_irq, S1_CD_IRQ));
-
- smc91c111_init(MST_ETH_PHYS, qdev_get_gpio_in(mst_irq, ETHERNET_IRQ));
-
- mainstone_binfo.board_id = arm_id;
- arm_load_kernel(mpu->cpu, machine, &mainstone_binfo);
-}
-
-static void mainstone_init(MachineState *machine)
-{
- mainstone_common_init(machine, mainstone, 0x196);
-}
-
-static void mainstone2_machine_init(MachineClass *mc)
-{
- mc->desc = "Mainstone II (PXA27x)";
- mc->init = mainstone_init;
- mc->ignore_memory_transaction_failures = true;
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c5");
- mc->deprecation_reason = "machine is old and unmaintained";
-}
-
-DEFINE_MACHINE("mainstone", mainstone2_machine_init)
diff --git a/hw/arm/meson.build b/hw/arm/meson.build
index 0c07ab5..490234b 100644
--- a/hw/arm/meson.build
+++ b/hw/arm/meson.build
@@ -6,14 +6,12 @@ arm_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic_boards.c'))
arm_ss.add(when: 'CONFIG_EMCRAFT_SF2', if_true: files('msf2-som.c'))
arm_ss.add(when: 'CONFIG_HIGHBANK', if_true: files('highbank.c'))
arm_ss.add(when: 'CONFIG_INTEGRATOR', if_true: files('integratorcp.c'))
-arm_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mainstone.c'))
arm_ss.add(when: 'CONFIG_MICROBIT', if_true: files('microbit.c'))
arm_ss.add(when: 'CONFIG_MPS3R', if_true: files('mps3r.c'))
arm_ss.add(when: 'CONFIG_MUSICPAL', if_true: files('musicpal.c'))
arm_ss.add(when: 'CONFIG_NETDUINOPLUS2', if_true: files('netduinoplus2.c'))
arm_ss.add(when: 'CONFIG_OLIMEX_STM32_H405', if_true: files('olimex-stm32-h405.c'))
arm_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx.c', 'npcm7xx_boards.c'))
-arm_ss.add(when: 'CONFIG_NSERIES', if_true: files('nseries.c'))
arm_ss.add(when: 'CONFIG_REALVIEW', if_true: files('realview.c'))
arm_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa-ref.c'))
arm_ss.add(when: 'CONFIG_STELLARIS', if_true: files('stellaris.c'))
@@ -23,7 +21,6 @@ arm_ss.add(when: 'CONFIG_SABRELITE', if_true: files('sabrelite.c'))
arm_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m.c'))
arm_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210.c'))
-arm_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx.c', 'pxa2xx_gpio.c', 'pxa2xx_pic.c'))
arm_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic.c'))
arm_ss.add(when: 'CONFIG_OMAP', if_true: files('omap1.c'))
arm_ss.add(when: 'CONFIG_ALLWINNER_A10', if_true: files('allwinner-a10.c', 'cubieboard.c'))
@@ -59,23 +56,20 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre.
arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmuv3.c'))
arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c'))
arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c'))
-arm_ss.add(when: 'CONFIG_XEN', if_true: files('xen_arm.c'))
+arm_ss.add(when: 'CONFIG_XEN', if_true: files(
+ 'xen-stubs.c',
+ 'xen-pvh.c',
+))
system_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c'))
-system_ss.add(when: 'CONFIG_CHEETAH', if_true: files('palm.c'))
system_ss.add(when: 'CONFIG_COLLIE', if_true: files('collie.c'))
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4_boards.c'))
-system_ss.add(when: 'CONFIG_GUMSTIX', if_true: files('gumstix.c'))
system_ss.add(when: 'CONFIG_NETDUINO2', if_true: files('netduino2.c'))
-system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap2.c'))
system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_peripherals.c'))
system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2838_peripherals.c'))
-system_ss.add(when: 'CONFIG_SPITZ', if_true: files('spitz.c'))
system_ss.add(when: 'CONFIG_STRONGARM', if_true: files('strongarm.c'))
system_ss.add(when: 'CONFIG_SX1', if_true: files('omap_sx1.c'))
-system_ss.add(when: 'CONFIG_TOSA', if_true: files('tosa.c'))
system_ss.add(when: 'CONFIG_VERSATILE', if_true: files('versatilepb.c'))
system_ss.add(when: 'CONFIG_VEXPRESS', if_true: files('vexpress.c'))
-system_ss.add(when: 'CONFIG_Z2', if_true: files('z2.c'))
hw_arch += {'arm': arm_ss}
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
index a2d18af..8edf57a 100644
--- a/hw/arm/mps2-tz.c
+++ b/hw/arm/mps2-tz.c
@@ -435,7 +435,7 @@ static MemoryRegion *make_uart(MPS2TZMachineState *mms, void *opaque,
const char *name, hwaddr size,
const int *irqs, const PPCExtraData *extradata)
{
- /* The irq[] array is tx, rx, combined, in that order */
+ /* The irq[] array is rx, tx, combined, in that order */
MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms);
CMSDKAPBUART *uart = opaque;
int i = uart - &mms->uart[0];
@@ -447,8 +447,8 @@ static MemoryRegion *make_uart(MPS2TZMachineState *mms, void *opaque,
qdev_prop_set_uint32(DEVICE(uart), "pclk-frq", mmc->apb_periph_frq);
sysbus_realize(SYS_BUS_DEVICE(uart), &error_fatal);
s = SYS_BUS_DEVICE(uart);
- sysbus_connect_irq(s, 0, get_sse_irq_in(mms, irqs[0]));
- sysbus_connect_irq(s, 1, get_sse_irq_in(mms, irqs[1]));
+ sysbus_connect_irq(s, 0, get_sse_irq_in(mms, irqs[1]));
+ sysbus_connect_irq(s, 1, get_sse_irq_in(mms, irqs[0]));
sysbus_connect_irq(s, 2, qdev_get_gpio_in(orgate_dev, i * 2));
sysbus_connect_irq(s, 3, qdev_get_gpio_in(orgate_dev, i * 2 + 1));
sysbus_connect_irq(s, 4, get_sse_irq_in(mms, irqs[2]));
@@ -1254,7 +1254,7 @@ static void mps2_set_remap(Object *obj, const char *value, Error **errp)
}
}
-static void mps2_machine_reset(MachineState *machine, ShutdownCause reason)
+static void mps2_machine_reset(MachineState *machine, ResetType type)
{
MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine);
@@ -1264,7 +1264,7 @@ static void mps2_machine_reset(MachineState *machine, ShutdownCause reason)
* reset see the correct mapping.
*/
remap_memory(mms, mms->remap);
- qemu_devices_reset(reason);
+ qemu_devices_reset(type);
}
static void mps2tz_class_init(ObjectClass *oc, void *data)
diff --git a/hw/arm/msf2-soc.c b/hw/arm/msf2-soc.c
index a94a10a..c4999eb 100644
--- a/hw/arm/msf2-soc.c
+++ b/hw/arm/msf2-soc.c
@@ -26,7 +26,7 @@
#include "qemu/units.h"
#include "qapi/error.h"
#include "exec/address-spaces.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/arm/msf2-soc.h"
#include "hw/misc/unimp.h"
#include "hw/qdev-clock.h"
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index 2020f73..33ece06 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -18,7 +18,7 @@
#include "net/net.h"
#include "sysemu/sysemu.h"
#include "hw/boards.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "qemu/timer.h"
#include "hw/ptimer.h"
#include "hw/qdev-properties.h"
@@ -411,7 +411,7 @@ static void mv88w8618_pic_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = mv88w8618_pic_reset;
+ device_class_set_legacy_reset(dc, mv88w8618_pic_reset);
dc->vmsd = &mv88w8618_pic_vmsd;
}
@@ -605,7 +605,7 @@ static void mv88w8618_pit_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = mv88w8618_pit_reset;
+ device_class_set_legacy_reset(dc, mv88w8618_pit_reset);
dc->vmsd = &mv88w8618_pit_vmsd;
}
@@ -1030,7 +1030,7 @@ static void musicpal_gpio_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = musicpal_gpio_reset;
+ device_class_set_legacy_reset(dc, musicpal_gpio_reset);
dc->vmsd = &musicpal_gpio_vmsd;
}
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
index cb77913..af04c4b 100644
--- a/hw/arm/npcm7xx.c
+++ b/hw/arm/npcm7xx.c
@@ -18,7 +18,7 @@
#include "hw/arm/boot.h"
#include "hw/arm/npcm7xx.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/loader.h"
#include "hw/misc/unimp.h"
#include "hw/qdev-clock.h"
diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c
deleted file mode 100644
index 3536431..0000000
--- a/hw/arm/nseries.c
+++ /dev/null
@@ -1,1473 +0,0 @@
-/*
- * Nokia N-series internet tablets.
- *
- * Copyright (C) 2007 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "cpu.h"
-#include "chardev/char.h"
-#include "qemu/cutils.h"
-#include "qemu/bswap.h"
-#include "qemu/hw-version.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
-#include "sysemu/sysemu.h"
-#include "hw/arm/omap.h"
-#include "hw/arm/boot.h"
-#include "hw/irq.h"
-#include "ui/console.h"
-#include "hw/boards.h"
-#include "hw/i2c/i2c.h"
-#include "hw/display/blizzard.h"
-#include "hw/input/lm832x.h"
-#include "hw/input/tsc2xxx.h"
-#include "hw/misc/cbus.h"
-#include "hw/sensor/tmp105.h"
-#include "hw/qdev-properties.h"
-#include "hw/block/flash.h"
-#include "hw/hw.h"
-#include "hw/loader.h"
-#include "hw/sysbus.h"
-#include "qemu/log.h"
-#include "qemu/error-report.h"
-
-
-/* Nokia N8x0 support */
-struct n800_s {
- struct omap_mpu_state_s *mpu;
-
- struct rfbi_chip_s blizzard;
- struct {
- void *opaque;
- uint32_t (*txrx)(void *opaque, uint32_t value, int len);
- uWireSlave *chip;
- } ts;
-
- int keymap[0x80];
- DeviceState *kbd;
-
- DeviceState *usb;
- void *retu;
- void *tahvo;
- DeviceState *nand;
-};
-
-/* GPIO pins */
-#define N8X0_TUSB_ENABLE_GPIO 0
-#define N800_MMC2_WP_GPIO 8
-#define N800_UNKNOWN_GPIO0 9 /* out */
-#define N810_MMC2_VIOSD_GPIO 9
-#define N810_HEADSET_AMP_GPIO 10
-#define N800_CAM_TURN_GPIO 12
-#define N810_GPS_RESET_GPIO 12
-#define N800_BLIZZARD_POWERDOWN_GPIO 15
-#define N800_MMC1_WP_GPIO 23
-#define N810_MMC2_VSD_GPIO 23
-#define N8X0_ONENAND_GPIO 26
-#define N810_BLIZZARD_RESET_GPIO 30
-#define N800_UNKNOWN_GPIO2 53 /* out */
-#define N8X0_TUSB_INT_GPIO 58
-#define N8X0_BT_WKUP_GPIO 61
-#define N8X0_STI_GPIO 62
-#define N8X0_CBUS_SEL_GPIO 64
-#define N8X0_CBUS_DAT_GPIO 65
-#define N8X0_CBUS_CLK_GPIO 66
-#define N8X0_WLAN_IRQ_GPIO 87
-#define N8X0_BT_RESET_GPIO 92
-#define N8X0_TEA5761_CS_GPIO 93
-#define N800_UNKNOWN_GPIO 94
-#define N810_TSC_RESET_GPIO 94
-#define N800_CAM_ACT_GPIO 95
-#define N810_GPS_WAKEUP_GPIO 95
-#define N8X0_MMC_CS_GPIO 96
-#define N8X0_WLAN_PWR_GPIO 97
-#define N8X0_BT_HOST_WKUP_GPIO 98
-#define N810_SPEAKER_AMP_GPIO 101
-#define N810_KB_LOCK_GPIO 102
-#define N800_TSC_TS_GPIO 103
-#define N810_TSC_TS_GPIO 106
-#define N8X0_HEADPHONE_GPIO 107
-#define N8X0_RETU_GPIO 108
-#define N800_TSC_KP_IRQ_GPIO 109
-#define N810_KEYBOARD_GPIO 109
-#define N800_BAT_COVER_GPIO 110
-#define N810_SLIDE_GPIO 110
-#define N8X0_TAHVO_GPIO 111
-#define N800_UNKNOWN_GPIO4 112 /* out */
-#define N810_SLEEPX_LED_GPIO 112
-#define N800_TSC_RESET_GPIO 118 /* ? */
-#define N810_AIC33_RESET_GPIO 118
-#define N800_TSC_UNKNOWN_GPIO 119 /* out */
-#define N8X0_TMP105_GPIO 125
-
-/* Config */
-#define BT_UART 0
-#define XLDR_LL_UART 1
-
-/* Addresses on the I2C bus 0 */
-#define N810_TLV320AIC33_ADDR 0x18 /* Audio CODEC */
-#define N8X0_TCM825x_ADDR 0x29 /* Camera */
-#define N810_LP5521_ADDR 0x32 /* LEDs */
-#define N810_TSL2563_ADDR 0x3d /* Light sensor */
-#define N810_LM8323_ADDR 0x45 /* Keyboard */
-/* Addresses on the I2C bus 1 */
-#define N8X0_TMP105_ADDR 0x48 /* Temperature sensor */
-#define N8X0_MENELAUS_ADDR 0x72 /* Power management */
-
-/* Chipselects on GPMC NOR interface */
-#define N8X0_ONENAND_CS 0
-#define N8X0_USB_ASYNC_CS 1
-#define N8X0_USB_SYNC_CS 4
-
-#define N8X0_BD_ADDR 0x00, 0x1a, 0x89, 0x9e, 0x3e, 0x81
-
-static void n800_mmc_cs_cb(void *opaque, int line, int level)
-{
- /* TODO: this seems to actually be connected to the menelaus, to
- * which also both MMC slots connect. */
- omap_mmc_enable((struct omap_mmc_s *) opaque, !level);
-}
-
-static void n8x0_gpio_setup(struct n800_s *s)
-{
- qdev_connect_gpio_out(s->mpu->gpio, N8X0_MMC_CS_GPIO,
- qemu_allocate_irq(n800_mmc_cs_cb, s->mpu->mmc, 0));
- qemu_irq_lower(qdev_get_gpio_in(s->mpu->gpio, N800_BAT_COVER_GPIO));
-}
-
-#define MAEMO_CAL_HEADER(...) \
- 'C', 'o', 'n', 'F', 0x02, 0x00, 0x04, 0x00, \
- __VA_ARGS__, \
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
-static const uint8_t n8x0_cal_wlan_mac[] = {
- MAEMO_CAL_HEADER('w', 'l', 'a', 'n', '-', 'm', 'a', 'c')
- 0x1c, 0x00, 0x00, 0x00, 0x47, 0xd6, 0x69, 0xb3,
- 0x30, 0x08, 0xa0, 0x83, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
- 0x89, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00,
- 0x5d, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00,
-};
-
-static const uint8_t n8x0_cal_bt_id[] = {
- MAEMO_CAL_HEADER('b', 't', '-', 'i', 'd', 0, 0, 0)
- 0x0a, 0x00, 0x00, 0x00, 0xa3, 0x4b, 0xf6, 0x96,
- 0xa8, 0xeb, 0xb2, 0x41, 0x00, 0x00, 0x00, 0x00,
- N8X0_BD_ADDR,
-};
-
-static void n8x0_nand_setup(struct n800_s *s)
-{
- char *otp_region;
- DriveInfo *dinfo;
-
- s->nand = qdev_new("onenand");
- qdev_prop_set_uint16(s->nand, "manufacturer_id", NAND_MFR_SAMSUNG);
- /* Either 0x40 or 0x48 are OK for the device ID */
- qdev_prop_set_uint16(s->nand, "device_id", 0x48);
- qdev_prop_set_uint16(s->nand, "version_id", 0);
- qdev_prop_set_int32(s->nand, "shift", 1);
- dinfo = drive_get(IF_MTD, 0, 0);
- if (dinfo) {
- qdev_prop_set_drive_err(s->nand, "drive", blk_by_legacy_dinfo(dinfo),
- &error_fatal);
- }
- sysbus_realize_and_unref(SYS_BUS_DEVICE(s->nand), &error_fatal);
- sysbus_connect_irq(SYS_BUS_DEVICE(s->nand), 0,
- qdev_get_gpio_in(s->mpu->gpio, N8X0_ONENAND_GPIO));
- omap_gpmc_attach(s->mpu->gpmc, N8X0_ONENAND_CS,
- sysbus_mmio_get_region(SYS_BUS_DEVICE(s->nand), 0));
- otp_region = onenand_raw_otp(s->nand);
-
- memcpy(otp_region + 0x000, n8x0_cal_wlan_mac, sizeof(n8x0_cal_wlan_mac));
- memcpy(otp_region + 0x800, n8x0_cal_bt_id, sizeof(n8x0_cal_bt_id));
- /* XXX: in theory should also update the OOB for both pages */
-}
-
-static qemu_irq n8x0_system_powerdown;
-
-static void n8x0_powerdown_req(Notifier *n, void *opaque)
-{
- qemu_irq_raise(n8x0_system_powerdown);
-}
-
-static Notifier n8x0_system_powerdown_notifier = {
- .notify = n8x0_powerdown_req
-};
-
-static void n8x0_i2c_setup(struct n800_s *s)
-{
- DeviceState *dev;
- qemu_irq tmp_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TMP105_GPIO);
- I2CBus *i2c = omap_i2c_bus(s->mpu->i2c[0]);
-
- /* Attach a menelaus PM chip */
- dev = DEVICE(i2c_slave_create_simple(i2c, "twl92230", N8X0_MENELAUS_ADDR));
- qdev_connect_gpio_out(dev, 3,
- qdev_get_gpio_in(s->mpu->ih[0],
- OMAP_INT_24XX_SYS_NIRQ));
-
- n8x0_system_powerdown = qdev_get_gpio_in(dev, 3);
- qemu_register_powerdown_notifier(&n8x0_system_powerdown_notifier);
-
- /* Attach a TMP105 PM chip (A0 wired to ground) */
- dev = DEVICE(i2c_slave_create_simple(i2c, TYPE_TMP105, N8X0_TMP105_ADDR));
- qdev_connect_gpio_out(dev, 0, tmp_irq);
-}
-
-/* Touchscreen and keypad controller */
-static const MouseTransformInfo n800_pointercal = {
- .x = 800,
- .y = 480,
- .a = { 14560, -68, -3455208, -39, -9621, 35152972, 65536 },
-};
-
-static const MouseTransformInfo n810_pointercal = {
- .x = 800,
- .y = 480,
- .a = { 15041, 148, -4731056, 171, -10238, 35933380, 65536 },
-};
-
-#define RETU_KEYCODE 61 /* F3 */
-
-static void n800_key_event(void *opaque, int keycode)
-{
- struct n800_s *s = (struct n800_s *) opaque;
- int code = s->keymap[keycode & 0x7f];
-
- if (code == -1) {
- if ((keycode & 0x7f) == RETU_KEYCODE) {
- retu_key_event(s->retu, !(keycode & 0x80));
- }
- return;
- }
-
- tsc210x_key_event(s->ts.chip, code, !(keycode & 0x80));
-}
-
-static const int n800_keys[16] = {
- -1,
- 72, /* Up */
- 63, /* Home (F5) */
- -1,
- 75, /* Left */
- 28, /* Enter */
- 77, /* Right */
- -1,
- 1, /* Cycle (ESC) */
- 80, /* Down */
- 62, /* Menu (F4) */
- -1,
- 66, /* Zoom- (F8) */
- 64, /* FullScreen (F6) */
- 65, /* Zoom+ (F7) */
- -1,
-};
-
-static void n800_tsc_kbd_setup(struct n800_s *s)
-{
- int i;
-
- /* XXX: are the three pins inverted inside the chip between the
- * tsc and the cpu (N4111)? */
- qemu_irq penirq = NULL; /* NC */
- qemu_irq kbirq = qdev_get_gpio_in(s->mpu->gpio, N800_TSC_KP_IRQ_GPIO);
- qemu_irq dav = qdev_get_gpio_in(s->mpu->gpio, N800_TSC_TS_GPIO);
-
- s->ts.chip = tsc2301_init(penirq, kbirq, dav);
- s->ts.opaque = s->ts.chip->opaque;
- s->ts.txrx = tsc210x_txrx;
-
- for (i = 0; i < 0x80; i++) {
- s->keymap[i] = -1;
- }
- for (i = 0; i < 0x10; i++) {
- if (n800_keys[i] >= 0) {
- s->keymap[n800_keys[i]] = i;
- }
- }
-
- qemu_add_kbd_event_handler(n800_key_event, s);
-
- tsc210x_set_transform(s->ts.chip, &n800_pointercal);
-}
-
-static void n810_tsc_setup(struct n800_s *s)
-{
- qemu_irq pintdav = qdev_get_gpio_in(s->mpu->gpio, N810_TSC_TS_GPIO);
-
- s->ts.opaque = tsc2005_init(pintdav);
- s->ts.txrx = tsc2005_txrx;
-
- tsc2005_set_transform(s->ts.opaque, &n810_pointercal);
-}
-
-/* N810 Keyboard controller */
-static void n810_key_event(void *opaque, int keycode)
-{
- struct n800_s *s = (struct n800_s *) opaque;
- int code = s->keymap[keycode & 0x7f];
-
- if (code == -1) {
- if ((keycode & 0x7f) == RETU_KEYCODE) {
- retu_key_event(s->retu, !(keycode & 0x80));
- }
- return;
- }
-
- lm832x_key_event(s->kbd, code, !(keycode & 0x80));
-}
-
-#define M 0
-
-static const int n810_keys[0x80] = {
- [0x01] = 16, /* Q */
- [0x02] = 37, /* K */
- [0x03] = 24, /* O */
- [0x04] = 25, /* P */
- [0x05] = 14, /* Backspace */
- [0x06] = 30, /* A */
- [0x07] = 31, /* S */
- [0x08] = 32, /* D */
- [0x09] = 33, /* F */
- [0x0a] = 34, /* G */
- [0x0b] = 35, /* H */
- [0x0c] = 36, /* J */
-
- [0x11] = 17, /* W */
- [0x12] = 62, /* Menu (F4) */
- [0x13] = 38, /* L */
- [0x14] = 40, /* ' (Apostrophe) */
- [0x16] = 44, /* Z */
- [0x17] = 45, /* X */
- [0x18] = 46, /* C */
- [0x19] = 47, /* V */
- [0x1a] = 48, /* B */
- [0x1b] = 49, /* N */
- [0x1c] = 42, /* Shift (Left shift) */
- [0x1f] = 65, /* Zoom+ (F7) */
-
- [0x21] = 18, /* E */
- [0x22] = 39, /* ; (Semicolon) */
- [0x23] = 12, /* - (Minus) */
- [0x24] = 13, /* = (Equal) */
- [0x2b] = 56, /* Fn (Left Alt) */
- [0x2c] = 50, /* M */
- [0x2f] = 66, /* Zoom- (F8) */
-
- [0x31] = 19, /* R */
- [0x32] = 29 | M, /* Right Ctrl */
- [0x34] = 57, /* Space */
- [0x35] = 51, /* , (Comma) */
- [0x37] = 72 | M, /* Up */
- [0x3c] = 82 | M, /* Compose (Insert) */
- [0x3f] = 64, /* FullScreen (F6) */
-
- [0x41] = 20, /* T */
- [0x44] = 52, /* . (Dot) */
- [0x46] = 77 | M, /* Right */
- [0x4f] = 63, /* Home (F5) */
- [0x51] = 21, /* Y */
- [0x53] = 80 | M, /* Down */
- [0x55] = 28, /* Enter */
- [0x5f] = 1, /* Cycle (ESC) */
-
- [0x61] = 22, /* U */
- [0x64] = 75 | M, /* Left */
-
- [0x71] = 23, /* I */
-#if 0
- [0x75] = 28 | M, /* KP Enter (KP Enter) */
-#else
- [0x75] = 15, /* KP Enter (Tab) */
-#endif
-};
-
-#undef M
-
-static void n810_kbd_setup(struct n800_s *s)
-{
- qemu_irq kbd_irq = qdev_get_gpio_in(s->mpu->gpio, N810_KEYBOARD_GPIO);
- int i;
-
- for (i = 0; i < 0x80; i++) {
- s->keymap[i] = -1;
- }
- for (i = 0; i < 0x80; i++) {
- if (n810_keys[i] > 0) {
- s->keymap[n810_keys[i]] = i;
- }
- }
-
- qemu_add_kbd_event_handler(n810_key_event, s);
-
- /* Attach the LM8322 keyboard to the I2C bus,
- * should happen in n8x0_i2c_setup and s->kbd be initialised here. */
- s->kbd = DEVICE(i2c_slave_create_simple(omap_i2c_bus(s->mpu->i2c[0]),
- TYPE_LM8323, N810_LM8323_ADDR));
- qdev_connect_gpio_out(s->kbd, 0, kbd_irq);
-}
-
-/* LCD MIPI DBI-C controller (URAL) */
-struct mipid_s {
- int resp[4];
- int param[4];
- int p;
- int pm;
- int cmd;
-
- int sleep;
- int booster;
- int te;
- int selfcheck;
- int partial;
- int normal;
- int vscr;
- int invert;
- int onoff;
- int gamma;
- uint32_t id;
-};
-
-static void mipid_reset(struct mipid_s *s)
-{
- s->pm = 0;
- s->cmd = 0;
-
- s->sleep = 1;
- s->booster = 0;
- s->selfcheck =
- (1 << 7) | /* Register loading OK. */
- (1 << 5) | /* The chip is attached. */
- (1 << 4); /* Display glass still in one piece. */
- s->te = 0;
- s->partial = 0;
- s->normal = 1;
- s->vscr = 0;
- s->invert = 0;
- s->onoff = 1;
- s->gamma = 0;
-}
-
-static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len)
-{
- struct mipid_s *s = (struct mipid_s *) opaque;
- uint8_t ret;
-
- if (len > 9) {
- hw_error("%s: FIXME: bad SPI word width %i\n", __func__, len);
- }
-
- if (s->p >= ARRAY_SIZE(s->resp)) {
- ret = 0;
- } else {
- ret = s->resp[s->p++];
- }
- if (s->pm-- > 0) {
- s->param[s->pm] = cmd;
- } else {
- s->cmd = cmd;
- }
-
- switch (s->cmd) {
- case 0x00: /* NOP */
- break;
-
- case 0x01: /* SWRESET */
- mipid_reset(s);
- break;
-
- case 0x02: /* BSTROFF */
- s->booster = 0;
- break;
- case 0x03: /* BSTRON */
- s->booster = 1;
- break;
-
- case 0x04: /* RDDID */
- s->p = 0;
- s->resp[0] = (s->id >> 16) & 0xff;
- s->resp[1] = (s->id >> 8) & 0xff;
- s->resp[2] = (s->id >> 0) & 0xff;
- break;
-
- case 0x06: /* RD_RED */
- case 0x07: /* RD_GREEN */
- /* XXX the bootloader sometimes issues RD_BLUE meaning RDDID so
- * for the bootloader one needs to change this. */
- case 0x08: /* RD_BLUE */
- s->p = 0;
- /* TODO: return first pixel components */
- s->resp[0] = 0x01;
- break;
-
- case 0x09: /* RDDST */
- s->p = 0;
- s->resp[0] = s->booster << 7;
- s->resp[1] = (5 << 4) | (s->partial << 2) |
- (s->sleep << 1) | s->normal;
- s->resp[2] = (s->vscr << 7) | (s->invert << 5) |
- (s->onoff << 2) | (s->te << 1) | (s->gamma >> 2);
- s->resp[3] = s->gamma << 6;
- break;
-
- case 0x0a: /* RDDPM */
- s->p = 0;
- s->resp[0] = (s->onoff << 2) | (s->normal << 3) | (s->sleep << 4) |
- (s->partial << 5) | (s->sleep << 6) | (s->booster << 7);
- break;
- case 0x0b: /* RDDMADCTR */
- s->p = 0;
- s->resp[0] = 0;
- break;
- case 0x0c: /* RDDCOLMOD */
- s->p = 0;
- s->resp[0] = 5; /* 65K colours */
- break;
- case 0x0d: /* RDDIM */
- s->p = 0;
- s->resp[0] = (s->invert << 5) | (s->vscr << 7) | s->gamma;
- break;
- case 0x0e: /* RDDSM */
- s->p = 0;
- s->resp[0] = s->te << 7;
- break;
- case 0x0f: /* RDDSDR */
- s->p = 0;
- s->resp[0] = s->selfcheck;
- break;
-
- case 0x10: /* SLPIN */
- s->sleep = 1;
- break;
- case 0x11: /* SLPOUT */
- s->sleep = 0;
- s->selfcheck ^= 1 << 6; /* POFF self-diagnosis Ok */
- break;
-
- case 0x12: /* PTLON */
- s->partial = 1;
- s->normal = 0;
- s->vscr = 0;
- break;
- case 0x13: /* NORON */
- s->partial = 0;
- s->normal = 1;
- s->vscr = 0;
- break;
-
- case 0x20: /* INVOFF */
- s->invert = 0;
- break;
- case 0x21: /* INVON */
- s->invert = 1;
- break;
-
- case 0x22: /* APOFF */
- case 0x23: /* APON */
- goto bad_cmd;
-
- case 0x25: /* WRCNTR */
- if (s->pm < 0) {
- s->pm = 1;
- }
- goto bad_cmd;
-
- case 0x26: /* GAMSET */
- if (!s->pm) {
- s->gamma = ctz32(s->param[0] & 0xf);
- if (s->gamma == 32) {
- s->gamma = -1; /* XXX: should this be 0? */
- }
- } else if (s->pm < 0) {
- s->pm = 1;
- }
- break;
-
- case 0x28: /* DISPOFF */
- s->onoff = 0;
- break;
- case 0x29: /* DISPON */
- s->onoff = 1;
- break;
-
- case 0x2a: /* CASET */
- case 0x2b: /* RASET */
- case 0x2c: /* RAMWR */
- case 0x2d: /* RGBSET */
- case 0x2e: /* RAMRD */
- case 0x30: /* PTLAR */
- case 0x33: /* SCRLAR */
- goto bad_cmd;
-
- case 0x34: /* TEOFF */
- s->te = 0;
- break;
- case 0x35: /* TEON */
- if (!s->pm) {
- s->te = 1;
- } else if (s->pm < 0) {
- s->pm = 1;
- }
- break;
-
- case 0x36: /* MADCTR */
- goto bad_cmd;
-
- case 0x37: /* VSCSAD */
- s->partial = 0;
- s->normal = 0;
- s->vscr = 1;
- break;
-
- case 0x38: /* IDMOFF */
- case 0x39: /* IDMON */
- case 0x3a: /* COLMOD */
- goto bad_cmd;
-
- case 0xb0: /* CLKINT / DISCTL */
- case 0xb1: /* CLKEXT */
- if (s->pm < 0) {
- s->pm = 2;
- }
- break;
-
- case 0xb4: /* FRMSEL */
- break;
-
- case 0xb5: /* FRM8SEL */
- case 0xb6: /* TMPRNG / INIESC */
- case 0xb7: /* TMPHIS / NOP2 */
- case 0xb8: /* TMPREAD / MADCTL */
- case 0xba: /* DISTCTR */
- case 0xbb: /* EPVOL */
- goto bad_cmd;
-
- case 0xbd: /* Unknown */
- s->p = 0;
- s->resp[0] = 0;
- s->resp[1] = 1;
- break;
-
- case 0xc2: /* IFMOD */
- if (s->pm < 0) {
- s->pm = 2;
- }
- break;
-
- case 0xc6: /* PWRCTL */
- case 0xc7: /* PPWRCTL */
- case 0xd0: /* EPWROUT */
- case 0xd1: /* EPWRIN */
- case 0xd4: /* RDEV */
- case 0xd5: /* RDRR */
- goto bad_cmd;
-
- case 0xda: /* RDID1 */
- s->p = 0;
- s->resp[0] = (s->id >> 16) & 0xff;
- break;
- case 0xdb: /* RDID2 */
- s->p = 0;
- s->resp[0] = (s->id >> 8) & 0xff;
- break;
- case 0xdc: /* RDID3 */
- s->p = 0;
- s->resp[0] = (s->id >> 0) & 0xff;
- break;
-
- default:
- bad_cmd:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: unknown command 0x%02x\n", __func__, s->cmd);
- break;
- }
-
- return ret;
-}
-
-static void *mipid_init(void)
-{
- struct mipid_s *s = g_malloc0(sizeof(*s));
-
- s->id = 0x838f03;
- mipid_reset(s);
-
- return s;
-}
-
-static void n8x0_spi_setup(struct n800_s *s)
-{
- void *tsc = s->ts.opaque;
- void *mipid = mipid_init();
-
- omap_mcspi_attach(s->mpu->mcspi[0], s->ts.txrx, tsc, 0);
- omap_mcspi_attach(s->mpu->mcspi[0], mipid_txrx, mipid, 1);
-}
-
-/* This task is normally performed by the bootloader. If we're loading
- * a kernel directly, we need to enable the Blizzard ourselves. */
-static void n800_dss_init(struct rfbi_chip_s *chip)
-{
- uint8_t *fb_blank;
-
- chip->write(chip->opaque, 0, 0x2a); /* LCD Width register */
- chip->write(chip->opaque, 1, 0x64);
- chip->write(chip->opaque, 0, 0x2c); /* LCD HNDP register */
- chip->write(chip->opaque, 1, 0x1e);
- chip->write(chip->opaque, 0, 0x2e); /* LCD Height 0 register */
- chip->write(chip->opaque, 1, 0xe0);
- chip->write(chip->opaque, 0, 0x30); /* LCD Height 1 register */
- chip->write(chip->opaque, 1, 0x01);
- chip->write(chip->opaque, 0, 0x32); /* LCD VNDP register */
- chip->write(chip->opaque, 1, 0x06);
- chip->write(chip->opaque, 0, 0x68); /* Display Mode register */
- chip->write(chip->opaque, 1, 1); /* Enable bit */
-
- chip->write(chip->opaque, 0, 0x6c);
- chip->write(chip->opaque, 1, 0x00); /* Input X Start Position */
- chip->write(chip->opaque, 1, 0x00); /* Input X Start Position */
- chip->write(chip->opaque, 1, 0x00); /* Input Y Start Position */
- chip->write(chip->opaque, 1, 0x00); /* Input Y Start Position */
- chip->write(chip->opaque, 1, 0x1f); /* Input X End Position */
- chip->write(chip->opaque, 1, 0x03); /* Input X End Position */
- chip->write(chip->opaque, 1, 0xdf); /* Input Y End Position */
- chip->write(chip->opaque, 1, 0x01); /* Input Y End Position */
- chip->write(chip->opaque, 1, 0x00); /* Output X Start Position */
- chip->write(chip->opaque, 1, 0x00); /* Output X Start Position */
- chip->write(chip->opaque, 1, 0x00); /* Output Y Start Position */
- chip->write(chip->opaque, 1, 0x00); /* Output Y Start Position */
- chip->write(chip->opaque, 1, 0x1f); /* Output X End Position */
- chip->write(chip->opaque, 1, 0x03); /* Output X End Position */
- chip->write(chip->opaque, 1, 0xdf); /* Output Y End Position */
- chip->write(chip->opaque, 1, 0x01); /* Output Y End Position */
- chip->write(chip->opaque, 1, 0x01); /* Input Data Format */
- chip->write(chip->opaque, 1, 0x01); /* Data Source Select */
-
- fb_blank = memset(g_malloc(800 * 480 * 2), 0xff, 800 * 480 * 2);
- /* Display Memory Data Port */
- chip->block(chip->opaque, 1, fb_blank, 800 * 480 * 2, 800);
- g_free(fb_blank);
-}
-
-static void n8x0_dss_setup(struct n800_s *s)
-{
- s->blizzard.opaque = s1d13745_init(NULL);
- s->blizzard.block = s1d13745_write_block;
- s->blizzard.write = s1d13745_write;
- s->blizzard.read = s1d13745_read;
-
- omap_rfbi_attach(s->mpu->dss, 0, &s->blizzard);
-}
-
-static void n8x0_cbus_setup(struct n800_s *s)
-{
- qemu_irq dat_out = qdev_get_gpio_in(s->mpu->gpio, N8X0_CBUS_DAT_GPIO);
- qemu_irq retu_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_RETU_GPIO);
- qemu_irq tahvo_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TAHVO_GPIO);
-
- CBus *cbus = cbus_init(dat_out);
-
- qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_CLK_GPIO, cbus->clk);
- qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_DAT_GPIO, cbus->dat);
- qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_SEL_GPIO, cbus->sel);
-
- cbus_attach(cbus, s->retu = retu_init(retu_irq, 1));
- cbus_attach(cbus, s->tahvo = tahvo_init(tahvo_irq, 1));
-}
-
-static void n8x0_usb_setup(struct n800_s *s)
-{
- SysBusDevice *dev;
- s->usb = qdev_new("tusb6010");
- dev = SYS_BUS_DEVICE(s->usb);
- sysbus_realize_and_unref(dev, &error_fatal);
- sysbus_connect_irq(dev, 0,
- qdev_get_gpio_in(s->mpu->gpio, N8X0_TUSB_INT_GPIO));
- /* Using the NOR interface */
- omap_gpmc_attach(s->mpu->gpmc, N8X0_USB_ASYNC_CS,
- sysbus_mmio_get_region(dev, 0));
- omap_gpmc_attach(s->mpu->gpmc, N8X0_USB_SYNC_CS,
- sysbus_mmio_get_region(dev, 1));
- qdev_connect_gpio_out(s->mpu->gpio, N8X0_TUSB_ENABLE_GPIO,
- qdev_get_gpio_in(s->usb, 0)); /* tusb_pwr */
-}
-
-/* Setup done before the main bootloader starts by some early setup code
- * - used when we want to run the main bootloader in emulation. This
- * isn't documented. */
-static const uint32_t n800_pinout[104] = {
- 0x080f00d8, 0x00d40808, 0x03080808, 0x080800d0,
- 0x00dc0808, 0x0b0f0f00, 0x080800b4, 0x00c00808,
- 0x08080808, 0x180800c4, 0x00b80000, 0x08080808,
- 0x080800bc, 0x00cc0808, 0x08081818, 0x18180128,
- 0x01241800, 0x18181818, 0x000000f0, 0x01300000,
- 0x00001b0b, 0x1b0f0138, 0x00e0181b, 0x1b031b0b,
- 0x180f0078, 0x00740018, 0x0f0f0f1a, 0x00000080,
- 0x007c0000, 0x00000000, 0x00000088, 0x00840000,
- 0x00000000, 0x00000094, 0x00980300, 0x0f180003,
- 0x0000008c, 0x00900f0f, 0x0f0f1b00, 0x0f00009c,
- 0x01140000, 0x1b1b0f18, 0x0818013c, 0x01400008,
- 0x00001818, 0x000b0110, 0x010c1800, 0x0b030b0f,
- 0x181800f4, 0x00f81818, 0x00000018, 0x000000fc,
- 0x00401808, 0x00000000, 0x0f1b0030, 0x003c0008,
- 0x00000000, 0x00000038, 0x00340000, 0x00000000,
- 0x1a080070, 0x00641a1a, 0x08080808, 0x08080060,
- 0x005c0808, 0x08080808, 0x08080058, 0x00540808,
- 0x08080808, 0x0808006c, 0x00680808, 0x08080808,
- 0x000000a8, 0x00b00000, 0x08080808, 0x000000a0,
- 0x00a40000, 0x00000000, 0x08ff0050, 0x004c0808,
- 0xffffffff, 0xffff0048, 0x0044ffff, 0xffffffff,
- 0x000000ac, 0x01040800, 0x08080b0f, 0x18180100,
- 0x01081818, 0x0b0b1808, 0x1a0300e4, 0x012c0b1a,
- 0x02020018, 0x0b000134, 0x011c0800, 0x0b1b1b00,
- 0x0f0000c8, 0x00ec181b, 0x000f0f02, 0x00180118,
- 0x01200000, 0x0f0b1b1b, 0x0f0200e8, 0x0000020b,
-};
-
-static void n800_setup_nolo_tags(void *sram_base)
-{
- int i;
- uint32_t *p = sram_base + 0x8000;
- uint32_t *v = sram_base + 0xa000;
-
- memset(p, 0, 0x3000);
-
- strcpy((void *) (p + 0), "QEMU N800");
-
- strcpy((void *) (p + 8), "F5");
-
- stl_p(p + 10, 0x04f70000);
- strcpy((void *) (p + 9), "RX-34");
-
- /* RAM size in MB? */
- stl_p(p + 12, 0x80);
-
- /* Pointer to the list of tags */
- stl_p(p + 13, OMAP2_SRAM_BASE + 0x9000);
-
- /* The NOLO tags start here */
- p = sram_base + 0x9000;
-#define ADD_TAG(tag, len) \
- stw_p((uint16_t *) p + 0, tag); \
- stw_p((uint16_t *) p + 1, len); p++; \
- stl_p(p++, OMAP2_SRAM_BASE | (((void *) v - sram_base) & 0xffff));
-
- /* OMAP STI console? Pin out settings? */
- ADD_TAG(0x6e01, 414);
- for (i = 0; i < ARRAY_SIZE(n800_pinout); i++) {
- stl_p(v++, n800_pinout[i]);
- }
-
- /* Kernel memsize? */
- ADD_TAG(0x6e05, 1);
- stl_p(v++, 2);
-
- /* NOLO serial console */
- ADD_TAG(0x6e02, 4);
- stl_p(v++, XLDR_LL_UART); /* UART number (1 - 3) */
-
-#if 0
- /* CBUS settings (Retu/AVilma) */
- ADD_TAG(0x6e03, 6);
- stw_p((uint16_t *) v + 0, 65); /* CBUS GPIO0 */
- stw_p((uint16_t *) v + 1, 66); /* CBUS GPIO1 */
- stw_p((uint16_t *) v + 2, 64); /* CBUS GPIO2 */
- v += 2;
-#endif
-
- /* Nokia ASIC BB5 (Retu/Tahvo) */
- ADD_TAG(0x6e0a, 4);
- stw_p((uint16_t *) v + 0, 111); /* "Retu" interrupt GPIO */
- stw_p((uint16_t *) v + 1, 108); /* "Tahvo" interrupt GPIO */
- v++;
-
- /* LCD console? */
- ADD_TAG(0x6e04, 4);
- stw_p((uint16_t *) v + 0, 30); /* ??? */
- stw_p((uint16_t *) v + 1, 24); /* ??? */
- v++;
-
-#if 0
- /* LCD settings */
- ADD_TAG(0x6e06, 2);
- stw_p((uint16_t *) (v++), 15); /* ??? */
-#endif
-
- /* I^2C (Menelaus) */
- ADD_TAG(0x6e07, 4);
- stl_p(v++, 0x00720000); /* ??? */
-
- /* Unknown */
- ADD_TAG(0x6e0b, 6);
- stw_p((uint16_t *) v + 0, 94); /* ??? */
- stw_p((uint16_t *) v + 1, 23); /* ??? */
- stw_p((uint16_t *) v + 2, 0); /* ??? */
- v += 2;
-
- /* OMAP gpio switch info */
- ADD_TAG(0x6e0c, 80);
- strcpy((void *) v, "bat_cover"); v += 3;
- stw_p((uint16_t *) v + 0, 110); /* GPIO num ??? */
- stw_p((uint16_t *) v + 1, 1); /* GPIO num ??? */
- v += 2;
- strcpy((void *) v, "cam_act"); v += 3;
- stw_p((uint16_t *) v + 0, 95); /* GPIO num ??? */
- stw_p((uint16_t *) v + 1, 32); /* GPIO num ??? */
- v += 2;
- strcpy((void *) v, "cam_turn"); v += 3;
- stw_p((uint16_t *) v + 0, 12); /* GPIO num ??? */
- stw_p((uint16_t *) v + 1, 33); /* GPIO num ??? */
- v += 2;
- strcpy((void *) v, "headphone"); v += 3;
- stw_p((uint16_t *) v + 0, 107); /* GPIO num ??? */
- stw_p((uint16_t *) v + 1, 17); /* GPIO num ??? */
- v += 2;
-
- /* Bluetooth */
- ADD_TAG(0x6e0e, 12);
- stl_p(v++, 0x5c623d01); /* ??? */
- stl_p(v++, 0x00000201); /* ??? */
- stl_p(v++, 0x00000000); /* ??? */
-
- /* CX3110x WLAN settings */
- ADD_TAG(0x6e0f, 8);
- stl_p(v++, 0x00610025); /* ??? */
- stl_p(v++, 0xffff0057); /* ??? */
-
- /* MMC host settings */
- ADD_TAG(0x6e10, 12);
- stl_p(v++, 0xffff000f); /* ??? */
- stl_p(v++, 0xffffffff); /* ??? */
- stl_p(v++, 0x00000060); /* ??? */
-
- /* OneNAND chip select */
- ADD_TAG(0x6e11, 10);
- stl_p(v++, 0x00000401); /* ??? */
- stl_p(v++, 0x0002003a); /* ??? */
- stl_p(v++, 0x00000002); /* ??? */
-
- /* TEA5761 sensor settings */
- ADD_TAG(0x6e12, 2);
- stl_p(v++, 93); /* GPIO num ??? */
-
-#if 0
- /* Unknown tag */
- ADD_TAG(6e09, 0);
-
- /* Kernel UART / console */
- ADD_TAG(6e12, 0);
-#endif
-
- /* End of the list */
- stl_p(p++, 0x00000000);
- stl_p(p++, 0x00000000);
-}
-
-/* This task is normally performed by the bootloader. If we're loading
- * a kernel directly, we need to set up GPMC mappings ourselves. */
-static void n800_gpmc_init(struct n800_s *s)
-{
- uint32_t config7 =
- (0xf << 8) | /* MASKADDRESS */
- (1 << 6) | /* CSVALID */
- (4 << 0); /* BASEADDRESS */
-
- cpu_physical_memory_write(0x6800a078, /* GPMC_CONFIG7_0 */
- &config7, sizeof(config7));
-}
-
-/* Setup sequence done by the bootloader */
-static void n8x0_boot_init(void *opaque)
-{
- struct n800_s *s = (struct n800_s *) opaque;
- uint32_t buf;
-
- /* PRCM setup */
-#define omap_writel(addr, val) \
- buf = (val); \
- cpu_physical_memory_write(addr, &buf, sizeof(buf))
-
- omap_writel(0x48008060, 0x41); /* PRCM_CLKSRC_CTRL */
- omap_writel(0x48008070, 1); /* PRCM_CLKOUT_CTRL */
- omap_writel(0x48008078, 0); /* PRCM_CLKEMUL_CTRL */
- omap_writel(0x48008090, 0); /* PRCM_VOLTSETUP */
- omap_writel(0x48008094, 0); /* PRCM_CLKSSETUP */
- omap_writel(0x48008098, 0); /* PRCM_POLCTRL */
- omap_writel(0x48008140, 2); /* CM_CLKSEL_MPU */
- omap_writel(0x48008148, 0); /* CM_CLKSTCTRL_MPU */
- omap_writel(0x48008158, 1); /* RM_RSTST_MPU */
- omap_writel(0x480081c8, 0x15); /* PM_WKDEP_MPU */
- omap_writel(0x480081d4, 0x1d4); /* PM_EVGENCTRL_MPU */
- omap_writel(0x480081d8, 0); /* PM_EVEGENONTIM_MPU */
- omap_writel(0x480081dc, 0); /* PM_EVEGENOFFTIM_MPU */
- omap_writel(0x480081e0, 0xc); /* PM_PWSTCTRL_MPU */
- omap_writel(0x48008200, 0x047e7ff7); /* CM_FCLKEN1_CORE */
- omap_writel(0x48008204, 0x00000004); /* CM_FCLKEN2_CORE */
- omap_writel(0x48008210, 0x047e7ff1); /* CM_ICLKEN1_CORE */
- omap_writel(0x48008214, 0x00000004); /* CM_ICLKEN2_CORE */
- omap_writel(0x4800821c, 0x00000000); /* CM_ICLKEN4_CORE */
- omap_writel(0x48008230, 0); /* CM_AUTOIDLE1_CORE */
- omap_writel(0x48008234, 0); /* CM_AUTOIDLE2_CORE */
- omap_writel(0x48008238, 7); /* CM_AUTOIDLE3_CORE */
- omap_writel(0x4800823c, 0); /* CM_AUTOIDLE4_CORE */
- omap_writel(0x48008240, 0x04360626); /* CM_CLKSEL1_CORE */
- omap_writel(0x48008244, 0x00000014); /* CM_CLKSEL2_CORE */
- omap_writel(0x48008248, 0); /* CM_CLKSTCTRL_CORE */
- omap_writel(0x48008300, 0x00000000); /* CM_FCLKEN_GFX */
- omap_writel(0x48008310, 0x00000000); /* CM_ICLKEN_GFX */
- omap_writel(0x48008340, 0x00000001); /* CM_CLKSEL_GFX */
- omap_writel(0x48008400, 0x00000004); /* CM_FCLKEN_WKUP */
- omap_writel(0x48008410, 0x00000004); /* CM_ICLKEN_WKUP */
- omap_writel(0x48008440, 0x00000000); /* CM_CLKSEL_WKUP */
- omap_writel(0x48008500, 0x000000cf); /* CM_CLKEN_PLL */
- omap_writel(0x48008530, 0x0000000c); /* CM_AUTOIDLE_PLL */
- omap_writel(0x48008540, /* CM_CLKSEL1_PLL */
- (0x78 << 12) | (6 << 8));
- omap_writel(0x48008544, 2); /* CM_CLKSEL2_PLL */
-
- /* GPMC setup */
- n800_gpmc_init(s);
-
- /* Video setup */
- n800_dss_init(&s->blizzard);
-
- /* CPU setup */
- s->mpu->cpu->env.GE = 0x5;
-
- /* If the machine has a slided keyboard, open it */
- if (s->kbd) {
- qemu_irq_raise(qdev_get_gpio_in(s->mpu->gpio, N810_SLIDE_GPIO));
- }
-}
-
-#define OMAP_TAG_NOKIA_BT 0x4e01
-#define OMAP_TAG_WLAN_CX3110X 0x4e02
-#define OMAP_TAG_CBUS 0x4e03
-#define OMAP_TAG_EM_ASIC_BB5 0x4e04
-
-static const struct omap_gpiosw_info_s {
- const char *name;
- int line;
- int type;
-} n800_gpiosw_info[] = {
- {
- "bat_cover", N800_BAT_COVER_GPIO,
- OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
- }, {
- "cam_act", N800_CAM_ACT_GPIO,
- OMAP_GPIOSW_TYPE_ACTIVITY,
- }, {
- "cam_turn", N800_CAM_TURN_GPIO,
- OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED,
- }, {
- "headphone", N8X0_HEADPHONE_GPIO,
- OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED,
- },
- { /* end of list */ }
-}, n810_gpiosw_info[] = {
- {
- "gps_reset", N810_GPS_RESET_GPIO,
- OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT,
- }, {
- "gps_wakeup", N810_GPS_WAKEUP_GPIO,
- OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT,
- }, {
- "headphone", N8X0_HEADPHONE_GPIO,
- OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED,
- }, {
- "kb_lock", N810_KB_LOCK_GPIO,
- OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
- }, {
- "sleepx_led", N810_SLEEPX_LED_GPIO,
- OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED | OMAP_GPIOSW_OUTPUT,
- }, {
- "slide", N810_SLIDE_GPIO,
- OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
- },
- { /* end of list */ }
-};
-
-static const struct omap_partition_info_s {
- uint32_t offset;
- uint32_t size;
- int mask;
- const char *name;
-} n800_part_info[] = {
- { 0x00000000, 0x00020000, 0x3, "bootloader" },
- { 0x00020000, 0x00060000, 0x0, "config" },
- { 0x00080000, 0x00200000, 0x0, "kernel" },
- { 0x00280000, 0x00200000, 0x3, "initfs" },
- { 0x00480000, 0x0fb80000, 0x3, "rootfs" },
- { /* end of list */ }
-}, n810_part_info[] = {
- { 0x00000000, 0x00020000, 0x3, "bootloader" },
- { 0x00020000, 0x00060000, 0x0, "config" },
- { 0x00080000, 0x00220000, 0x0, "kernel" },
- { 0x002a0000, 0x00400000, 0x0, "initfs" },
- { 0x006a0000, 0x0f960000, 0x0, "rootfs" },
- { /* end of list */ }
-};
-
-static const uint8_t n8x0_bd_addr[6] = { N8X0_BD_ADDR };
-
-static int n8x0_atag_setup(void *p, int model)
-{
- uint8_t *b;
- uint16_t *w;
- uint32_t *l;
- const struct omap_gpiosw_info_s *gpiosw;
- const struct omap_partition_info_s *partition;
- const char *tag;
-
- w = p;
-
- stw_p(w++, OMAP_TAG_UART); /* u16 tag */
- stw_p(w++, 4); /* u16 len */
- stw_p(w++, (1 << 2) | (1 << 1) | (1 << 0)); /* uint enabled_uarts */
- w++;
-
-#if 0
- stw_p(w++, OMAP_TAG_SERIAL_CONSOLE); /* u16 tag */
- stw_p(w++, 4); /* u16 len */
- stw_p(w++, XLDR_LL_UART + 1); /* u8 console_uart */
- stw_p(w++, 115200); /* u32 console_speed */
-#endif
-
- stw_p(w++, OMAP_TAG_LCD); /* u16 tag */
- stw_p(w++, 36); /* u16 len */
- strcpy((void *) w, "QEMU LCD panel"); /* char panel_name[16] */
- w += 8;
- strcpy((void *) w, "blizzard"); /* char ctrl_name[16] */
- w += 8;
- stw_p(w++, N810_BLIZZARD_RESET_GPIO); /* TODO: n800 s16 nreset_gpio */
- stw_p(w++, 24); /* u8 data_lines */
-
- stw_p(w++, OMAP_TAG_CBUS); /* u16 tag */
- stw_p(w++, 8); /* u16 len */
- stw_p(w++, N8X0_CBUS_CLK_GPIO); /* s16 clk_gpio */
- stw_p(w++, N8X0_CBUS_DAT_GPIO); /* s16 dat_gpio */
- stw_p(w++, N8X0_CBUS_SEL_GPIO); /* s16 sel_gpio */
- w++;
-
- stw_p(w++, OMAP_TAG_EM_ASIC_BB5); /* u16 tag */
- stw_p(w++, 4); /* u16 len */
- stw_p(w++, N8X0_RETU_GPIO); /* s16 retu_irq_gpio */
- stw_p(w++, N8X0_TAHVO_GPIO); /* s16 tahvo_irq_gpio */
-
- gpiosw = (model == 810) ? n810_gpiosw_info : n800_gpiosw_info;
- for (; gpiosw->name; gpiosw++) {
- stw_p(w++, OMAP_TAG_GPIO_SWITCH); /* u16 tag */
- stw_p(w++, 20); /* u16 len */
- strcpy((void *) w, gpiosw->name); /* char name[12] */
- w += 6;
- stw_p(w++, gpiosw->line); /* u16 gpio */
- stw_p(w++, gpiosw->type);
- stw_p(w++, 0);
- stw_p(w++, 0);
- }
-
- stw_p(w++, OMAP_TAG_NOKIA_BT); /* u16 tag */
- stw_p(w++, 12); /* u16 len */
- b = (void *) w;
- stb_p(b++, 0x01); /* u8 chip_type (CSR) */
- stb_p(b++, N8X0_BT_WKUP_GPIO); /* u8 bt_wakeup_gpio */
- stb_p(b++, N8X0_BT_HOST_WKUP_GPIO); /* u8 host_wakeup_gpio */
- stb_p(b++, N8X0_BT_RESET_GPIO); /* u8 reset_gpio */
- stb_p(b++, BT_UART + 1); /* u8 bt_uart */
- memcpy(b, &n8x0_bd_addr, 6); /* u8 bd_addr[6] */
- b += 6;
- stb_p(b++, 0x02); /* u8 bt_sysclk (38.4) */
- w = (void *) b;
-
- stw_p(w++, OMAP_TAG_WLAN_CX3110X); /* u16 tag */
- stw_p(w++, 8); /* u16 len */
- stw_p(w++, 0x25); /* u8 chip_type */
- stw_p(w++, N8X0_WLAN_PWR_GPIO); /* s16 power_gpio */
- stw_p(w++, N8X0_WLAN_IRQ_GPIO); /* s16 irq_gpio */
- stw_p(w++, -1); /* s16 spi_cs_gpio */
-
- stw_p(w++, OMAP_TAG_MMC); /* u16 tag */
- stw_p(w++, 16); /* u16 len */
- if (model == 810) {
- stw_p(w++, 0x23f); /* unsigned flags */
- stw_p(w++, -1); /* s16 power_pin */
- stw_p(w++, -1); /* s16 switch_pin */
- stw_p(w++, -1); /* s16 wp_pin */
- stw_p(w++, 0x240); /* unsigned flags */
- stw_p(w++, 0xc000); /* s16 power_pin */
- stw_p(w++, 0x0248); /* s16 switch_pin */
- stw_p(w++, 0xc000); /* s16 wp_pin */
- } else {
- stw_p(w++, 0xf); /* unsigned flags */
- stw_p(w++, -1); /* s16 power_pin */
- stw_p(w++, -1); /* s16 switch_pin */
- stw_p(w++, -1); /* s16 wp_pin */
- stw_p(w++, 0); /* unsigned flags */
- stw_p(w++, 0); /* s16 power_pin */
- stw_p(w++, 0); /* s16 switch_pin */
- stw_p(w++, 0); /* s16 wp_pin */
- }
-
- stw_p(w++, OMAP_TAG_TEA5761); /* u16 tag */
- stw_p(w++, 4); /* u16 len */
- stw_p(w++, N8X0_TEA5761_CS_GPIO); /* u16 enable_gpio */
- w++;
-
- partition = (model == 810) ? n810_part_info : n800_part_info;
- for (; partition->name; partition++) {
- stw_p(w++, OMAP_TAG_PARTITION); /* u16 tag */
- stw_p(w++, 28); /* u16 len */
- strcpy((void *) w, partition->name); /* char name[16] */
- l = (void *) (w + 8);
- stl_p(l++, partition->size); /* unsigned int size */
- stl_p(l++, partition->offset); /* unsigned int offset */
- stl_p(l++, partition->mask); /* unsigned int mask_flags */
- w = (void *) l;
- }
-
- stw_p(w++, OMAP_TAG_BOOT_REASON); /* u16 tag */
- stw_p(w++, 12); /* u16 len */
-#if 0
- strcpy((void *) w, "por"); /* char reason_str[12] */
- strcpy((void *) w, "charger"); /* char reason_str[12] */
- strcpy((void *) w, "32wd_to"); /* char reason_str[12] */
- strcpy((void *) w, "sw_rst"); /* char reason_str[12] */
- strcpy((void *) w, "mbus"); /* char reason_str[12] */
- strcpy((void *) w, "unknown"); /* char reason_str[12] */
- strcpy((void *) w, "swdg_to"); /* char reason_str[12] */
- strcpy((void *) w, "sec_vio"); /* char reason_str[12] */
- strcpy((void *) w, "pwr_key"); /* char reason_str[12] */
- strcpy((void *) w, "rtc_alarm"); /* char reason_str[12] */
-#else
- strcpy((void *) w, "pwr_key"); /* char reason_str[12] */
-#endif
- w += 6;
-
- tag = (model == 810) ? "RX-44" : "RX-34";
- stw_p(w++, OMAP_TAG_VERSION_STR); /* u16 tag */
- stw_p(w++, 24); /* u16 len */
- strcpy((void *) w, "product"); /* char component[12] */
- w += 6;
- strcpy((void *) w, tag); /* char version[12] */
- w += 6;
-
- stw_p(w++, OMAP_TAG_VERSION_STR); /* u16 tag */
- stw_p(w++, 24); /* u16 len */
- strcpy((void *) w, "hw-build"); /* char component[12] */
- w += 6;
- strcpy((void *) w, "QEMU ");
- pstrcat((void *) w, 12, qemu_hw_version()); /* char version[12] */
- w += 6;
-
- tag = (model == 810) ? "1.1.10-qemu" : "1.1.6-qemu";
- stw_p(w++, OMAP_TAG_VERSION_STR); /* u16 tag */
- stw_p(w++, 24); /* u16 len */
- strcpy((void *) w, "nolo"); /* char component[12] */
- w += 6;
- strcpy((void *) w, tag); /* char version[12] */
- w += 6;
-
- return (void *) w - p;
-}
-
-static int n800_atag_setup(const struct arm_boot_info *info, void *p)
-{
- return n8x0_atag_setup(p, 800);
-}
-
-static int n810_atag_setup(const struct arm_boot_info *info, void *p)
-{
- return n8x0_atag_setup(p, 810);
-}
-
-static void n8x0_init(MachineState *machine,
- struct arm_boot_info *binfo, int model)
-{
- struct n800_s *s = g_malloc0(sizeof(*s));
- MachineClass *mc = MACHINE_GET_CLASS(machine);
-
- 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);
- }
- binfo->ram_size = machine->ram_size;
-
- memory_region_add_subregion(get_system_memory(), OMAP2_Q2_BASE,
- machine->ram);
-
- s->mpu = omap2420_mpu_init(machine->ram, machine->cpu_type);
-
- /* Setup peripherals
- *
- * Believed external peripherals layout in the N810:
- * (spi bus 1)
- * tsc2005
- * lcd_mipid
- * (spi bus 2)
- * Conexant cx3110x (WLAN)
- * optional: pc2400m (WiMAX)
- * (i2c bus 0)
- * TLV320AIC33 (audio codec)
- * TCM825x (camera by Toshiba)
- * lp5521 (clever LEDs)
- * tsl2563 (light sensor, hwmon, model 7, rev. 0)
- * lm8323 (keypad, manf 00, rev 04)
- * (i2c bus 1)
- * tmp105 (temperature sensor, hwmon)
- * menelaus (pm)
- * (somewhere on i2c - maybe N800-only)
- * tea5761 (FM tuner)
- * (serial 0)
- * GPS
- * (some serial port)
- * csr41814 (Bluetooth)
- */
- n8x0_gpio_setup(s);
- n8x0_nand_setup(s);
- n8x0_i2c_setup(s);
- if (model == 800) {
- n800_tsc_kbd_setup(s);
- } else if (model == 810) {
- n810_tsc_setup(s);
- n810_kbd_setup(s);
- }
- n8x0_spi_setup(s);
- n8x0_dss_setup(s);
- n8x0_cbus_setup(s);
- n8x0_usb_setup(s);
-
- if (machine->kernel_filename) {
- /* Or at the linux loader. */
- arm_load_kernel(s->mpu->cpu, machine, binfo);
-
- qemu_register_reset(n8x0_boot_init, s);
- }
-
- if (option_rom[0].name &&
- (machine->boot_config.order[0] == 'n' || !machine->kernel_filename)) {
- uint8_t *nolo_tags = g_new(uint8_t, 0x10000);
- /* No, wait, better start at the ROM. */
- s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000;
-
- /*
- * This is intended for loading the `secondary.bin' program from
- * Nokia images (the NOLO bootloader). The entry point seems
- * to be at OMAP2_Q2_BASE + 0x400000.
- *
- * The `2nd.bin' files contain some kind of earlier boot code and
- * for them the entry point needs to be set to OMAP2_SRAM_BASE.
- *
- * The code above is for loading the `zImage' file from Nokia
- * images.
- */
- if (load_image_targphys(option_rom[0].name,
- OMAP2_Q2_BASE + 0x400000,
- machine->ram_size - 0x400000) < 0) {
- error_report("Failed to load secondary bootloader %s",
- option_rom[0].name);
- exit(EXIT_FAILURE);
- }
-
- n800_setup_nolo_tags(nolo_tags);
- cpu_physical_memory_write(OMAP2_SRAM_BASE, nolo_tags, 0x10000);
- g_free(nolo_tags);
- }
-}
-
-static struct arm_boot_info n800_binfo = {
- .loader_start = OMAP2_Q2_BASE,
- .board_id = 0x4f7,
- .atag_board = n800_atag_setup,
-};
-
-static struct arm_boot_info n810_binfo = {
- .loader_start = OMAP2_Q2_BASE,
- /* 0x60c and 0x6bf (WiMAX Edition) have been assigned but are not
- * used by some older versions of the bootloader and 5555 is used
- * instead (including versions that shipped with many devices). */
- .board_id = 0x60c,
- .atag_board = n810_atag_setup,
-};
-
-static void n800_init(MachineState *machine)
-{
- n8x0_init(machine, &n800_binfo, 800);
-}
-
-static void n810_init(MachineState *machine)
-{
- n8x0_init(machine, &n810_binfo, 810);
-}
-
-static void n800_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Nokia N800 tablet aka. RX-34 (OMAP2420)";
- mc->init = n800_init;
- mc->default_boot_order = "";
- mc->ignore_memory_transaction_failures = true;
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm1136-r2");
- /* Actually two chips of 0x4000000 bytes each */
- mc->default_ram_size = 0x08000000;
- mc->default_ram_id = "omap2.dram";
- mc->deprecation_reason = "machine is old and unmaintained";
-
- machine_add_audiodev_property(mc);
-}
-
-static const TypeInfo n800_type = {
- .name = MACHINE_TYPE_NAME("n800"),
- .parent = TYPE_MACHINE,
- .class_init = n800_class_init,
-};
-
-static void n810_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->desc = "Nokia N810 tablet aka. RX-44 (OMAP2420)";
- mc->init = n810_init;
- mc->default_boot_order = "";
- mc->ignore_memory_transaction_failures = true;
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm1136-r2");
- /* Actually two chips of 0x4000000 bytes each */
- mc->default_ram_size = 0x08000000;
- mc->default_ram_id = "omap2.dram";
- mc->deprecation_reason = "machine is old and unmaintained";
-
- machine_add_audiodev_property(mc);
-}
-
-static const TypeInfo n810_type = {
- .name = MACHINE_TYPE_NAME("n810"),
- .parent = TYPE_MACHINE,
- .class_init = n810_class_init,
-};
-
-static void nseries_machine_init(void)
-{
- type_register_static(&n800_type);
- type_register_static(&n810_type);
-}
-
-type_init(nseries_machine_init)
diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c
index 86ee336..25030c7 100644
--- a/hw/arm/omap1.c
+++ b/hw/arm/omap1.c
@@ -2170,29 +2170,27 @@ struct omap_uwire_s {
uint16_t rxbuf;
uint16_t control;
uint16_t setup[5];
-
- uWireSlave *chip[4];
};
static void omap_uwire_transfer_start(struct omap_uwire_s *s)
{
int chipselect = (s->control >> 10) & 3; /* INDEX */
- uWireSlave *slave = s->chip[chipselect];
if ((s->control >> 5) & 0x1f) { /* NB_BITS_WR */
- if (s->control & (1 << 12)) /* CS_CMD */
- if (slave && slave->send)
- slave->send(slave->opaque,
- s->txbuf >> (16 - ((s->control >> 5) & 0x1f)));
+ if (s->control & (1 << 12)) { /* CS_CMD */
+ qemu_log_mask(LOG_UNIMP, "uWireSlave TX CS:%d data:0x%04x\n",
+ chipselect,
+ s->txbuf >> (16 - ((s->control >> 5) & 0x1f)));
+ }
s->control &= ~(1 << 14); /* CSRB */
/* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or
* a DRQ. When is the level IRQ supposed to be reset? */
}
if ((s->control >> 0) & 0x1f) { /* NB_BITS_RD */
- if (s->control & (1 << 12)) /* CS_CMD */
- if (slave && slave->receive)
- s->rxbuf = slave->receive(slave->opaque);
+ if (s->control & (1 << 12)) { /* CS_CMD */
+ qemu_log_mask(LOG_UNIMP, "uWireSlave RX CS:%d\n", chipselect);
+ }
s->control |= 1 << 15; /* RDRB */
/* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or
* a DRQ. When is the level IRQ supposed to be reset? */
@@ -2321,17 +2319,6 @@ static struct omap_uwire_s *omap_uwire_init(MemoryRegion *system_memory,
return s;
}
-void omap_uwire_attach(struct omap_uwire_s *s,
- uWireSlave *slave, int chipselect)
-{
- if (chipselect < 0 || chipselect > 3) {
- error_report("%s: Bad chipselect %i", __func__, chipselect);
- exit(-1);
- }
-
- s->chip[chipselect] = slave;
-}
-
/* Pseudonoise Pulse-Width Light Modulator */
struct omap_pwl_s {
MemoryRegion iomem;
diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c
deleted file mode 100644
index d968327..0000000
--- a/hw/arm/omap2.c
+++ /dev/null
@@ -1,2715 +0,0 @@
-/*
- * TI OMAP processors emulation.
- *
- * Copyright (C) 2007-2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/error-report.h"
-#include "qapi/error.h"
-#include "exec/address-spaces.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/qtest.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
-#include "hw/irq.h"
-#include "hw/qdev-properties.h"
-#include "hw/arm/boot.h"
-#include "hw/arm/omap.h"
-#include "sysemu/sysemu.h"
-#include "qemu/timer.h"
-#include "chardev/char-fe.h"
-#include "hw/block/flash.h"
-#include "hw/arm/soc_dma.h"
-#include "hw/sysbus.h"
-#include "hw/boards.h"
-#include "audio/audio.h"
-#include "target/arm/cpu-qom.h"
-
-/* Enhanced Audio Controller (CODEC only) */
-struct omap_eac_s {
- qemu_irq irq;
- MemoryRegion iomem;
-
- uint16_t sysconfig;
- uint8_t config[4];
- uint8_t control;
- uint8_t address;
- uint16_t data;
- uint8_t vtol;
- uint8_t vtsl;
- uint16_t mixer;
- uint16_t gain[4];
- uint8_t att;
- uint16_t max[7];
-
- struct {
- qemu_irq txdrq;
- qemu_irq rxdrq;
- uint32_t (*txrx)(void *opaque, uint32_t, int);
- void *opaque;
-
-#define EAC_BUF_LEN 1024
- uint32_t rxbuf[EAC_BUF_LEN];
- int rxoff;
- int rxlen;
- int rxavail;
- uint32_t txbuf[EAC_BUF_LEN];
- int txlen;
- int txavail;
-
- int enable;
- int rate;
-
- uint16_t config[4];
-
- /* These need to be moved to the actual codec */
- QEMUSoundCard card;
- SWVoiceIn *in_voice;
- SWVoiceOut *out_voice;
- int hw_enable;
- } codec;
-
- struct {
- uint8_t control;
- uint16_t config;
- } modem, bt;
-};
-
-static inline void omap_eac_interrupt_update(struct omap_eac_s *s)
-{
- qemu_set_irq(s->irq, (s->codec.config[1] >> 14) & 1); /* AURDI */
-}
-
-static inline void omap_eac_in_dmarequest_update(struct omap_eac_s *s)
-{
- qemu_set_irq(s->codec.rxdrq, (s->codec.rxavail || s->codec.rxlen) &&
- ((s->codec.config[1] >> 12) & 1)); /* DMAREN */
-}
-
-static inline void omap_eac_out_dmarequest_update(struct omap_eac_s *s)
-{
- qemu_set_irq(s->codec.txdrq, s->codec.txlen < s->codec.txavail &&
- ((s->codec.config[1] >> 11) & 1)); /* DMAWEN */
-}
-
-static inline void omap_eac_in_refill(struct omap_eac_s *s)
-{
- int left = MIN(EAC_BUF_LEN - s->codec.rxlen, s->codec.rxavail) << 2;
- int start = ((s->codec.rxoff + s->codec.rxlen) & (EAC_BUF_LEN - 1)) << 2;
- int leftwrap = MIN(left, (EAC_BUF_LEN << 2) - start);
- int recv = 1;
- uint8_t *buf = (uint8_t *) s->codec.rxbuf + start;
-
- left -= leftwrap;
- start = 0;
- while (leftwrap && (recv = AUD_read(s->codec.in_voice, buf + start,
- leftwrap)) > 0) { /* Be defensive */
- start += recv;
- leftwrap -= recv;
- }
- if (recv <= 0)
- s->codec.rxavail = 0;
- else
- s->codec.rxavail -= start >> 2;
- s->codec.rxlen += start >> 2;
-
- if (recv > 0 && left > 0) {
- start = 0;
- while (left && (recv = AUD_read(s->codec.in_voice,
- (uint8_t *) s->codec.rxbuf + start,
- left)) > 0) { /* Be defensive */
- start += recv;
- left -= recv;
- }
- if (recv <= 0)
- s->codec.rxavail = 0;
- else
- s->codec.rxavail -= start >> 2;
- s->codec.rxlen += start >> 2;
- }
-}
-
-static inline void omap_eac_out_empty(struct omap_eac_s *s)
-{
- int left = s->codec.txlen << 2;
- int start = 0;
- int sent = 1;
-
- while (left && (sent = AUD_write(s->codec.out_voice,
- (uint8_t *) s->codec.txbuf + start,
- left)) > 0) { /* Be defensive */
- start += sent;
- left -= sent;
- }
-
- if (!sent) {
- s->codec.txavail = 0;
- omap_eac_out_dmarequest_update(s);
- }
-
- if (start)
- s->codec.txlen = 0;
-}
-
-static void omap_eac_in_cb(void *opaque, int avail_b)
-{
- struct omap_eac_s *s = opaque;
-
- s->codec.rxavail = avail_b >> 2;
- omap_eac_in_refill(s);
- /* TODO: possibly discard current buffer if overrun */
- omap_eac_in_dmarequest_update(s);
-}
-
-static void omap_eac_out_cb(void *opaque, int free_b)
-{
- struct omap_eac_s *s = opaque;
-
- s->codec.txavail = free_b >> 2;
- if (s->codec.txlen)
- omap_eac_out_empty(s);
- else
- omap_eac_out_dmarequest_update(s);
-}
-
-static void omap_eac_enable_update(struct omap_eac_s *s)
-{
- s->codec.enable = !(s->codec.config[1] & 1) && /* EACPWD */
- (s->codec.config[1] & 2) && /* AUDEN */
- s->codec.hw_enable;
-}
-
-static const int omap_eac_fsint[4] = {
- 8000,
- 11025,
- 22050,
- 44100,
-};
-
-static const int omap_eac_fsint2[8] = {
- 8000,
- 11025,
- 22050,
- 44100,
- 48000,
- 0, 0, 0,
-};
-
-static const int omap_eac_fsint3[16] = {
- 8000,
- 11025,
- 16000,
- 22050,
- 24000,
- 32000,
- 44100,
- 48000,
- 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-static void omap_eac_rate_update(struct omap_eac_s *s)
-{
- int fsint[3];
-
- fsint[2] = (s->codec.config[3] >> 9) & 0xf;
- fsint[1] = (s->codec.config[2] >> 0) & 0x7;
- fsint[0] = (s->codec.config[0] >> 6) & 0x3;
- if (fsint[2] < 0xf)
- s->codec.rate = omap_eac_fsint3[fsint[2]];
- else if (fsint[1] < 0x7)
- s->codec.rate = omap_eac_fsint2[fsint[1]];
- else
- s->codec.rate = omap_eac_fsint[fsint[0]];
-}
-
-static void omap_eac_volume_update(struct omap_eac_s *s)
-{
- /* TODO */
-}
-
-static void omap_eac_format_update(struct omap_eac_s *s)
-{
- struct audsettings fmt;
-
- /* The hardware buffers at most one sample */
- if (s->codec.rxlen)
- s->codec.rxlen = 1;
-
- if (s->codec.in_voice) {
- AUD_set_active_in(s->codec.in_voice, 0);
- AUD_close_in(&s->codec.card, s->codec.in_voice);
- s->codec.in_voice = NULL;
- }
- if (s->codec.out_voice) {
- omap_eac_out_empty(s);
- AUD_set_active_out(s->codec.out_voice, 0);
- AUD_close_out(&s->codec.card, s->codec.out_voice);
- s->codec.out_voice = NULL;
- s->codec.txavail = 0;
- }
- /* Discard what couldn't be written */
- s->codec.txlen = 0;
-
- omap_eac_enable_update(s);
- if (!s->codec.enable)
- return;
-
- omap_eac_rate_update(s);
- fmt.endianness = ((s->codec.config[0] >> 8) & 1); /* LI_BI */
- fmt.nchannels = ((s->codec.config[0] >> 10) & 1) ? 2 : 1; /* MN_ST */
- fmt.freq = s->codec.rate;
- /* TODO: signedness possibly depends on the CODEC hardware - or
- * does I2S specify it? */
- /* All register writes are 16 bits so we store 16-bit samples
- * in the buffers regardless of AGCFR[B8_16] value. */
- fmt.fmt = AUDIO_FORMAT_U16;
-
- s->codec.in_voice = AUD_open_in(&s->codec.card, s->codec.in_voice,
- "eac.codec.in", s, omap_eac_in_cb, &fmt);
- s->codec.out_voice = AUD_open_out(&s->codec.card, s->codec.out_voice,
- "eac.codec.out", s, omap_eac_out_cb, &fmt);
-
- omap_eac_volume_update(s);
-
- AUD_set_active_in(s->codec.in_voice, 1);
- AUD_set_active_out(s->codec.out_voice, 1);
-}
-
-static void omap_eac_reset(struct omap_eac_s *s)
-{
- s->sysconfig = 0;
- s->config[0] = 0x0c;
- s->config[1] = 0x09;
- s->config[2] = 0xab;
- s->config[3] = 0x03;
- s->control = 0x00;
- s->address = 0x00;
- s->data = 0x0000;
- s->vtol = 0x00;
- s->vtsl = 0x00;
- s->mixer = 0x0000;
- s->gain[0] = 0xe7e7;
- s->gain[1] = 0x6767;
- s->gain[2] = 0x6767;
- s->gain[3] = 0x6767;
- s->att = 0xce;
- s->max[0] = 0;
- s->max[1] = 0;
- s->max[2] = 0;
- s->max[3] = 0;
- s->max[4] = 0;
- s->max[5] = 0;
- s->max[6] = 0;
-
- s->modem.control = 0x00;
- s->modem.config = 0x0000;
- s->bt.control = 0x00;
- s->bt.config = 0x0000;
- s->codec.config[0] = 0x0649;
- s->codec.config[1] = 0x0000;
- s->codec.config[2] = 0x0007;
- s->codec.config[3] = 0x1ffc;
- s->codec.rxoff = 0;
- s->codec.rxlen = 0;
- s->codec.txlen = 0;
- s->codec.rxavail = 0;
- s->codec.txavail = 0;
-
- omap_eac_format_update(s);
- omap_eac_interrupt_update(s);
-}
-
-static uint64_t omap_eac_read(void *opaque, hwaddr addr, unsigned size)
-{
- struct omap_eac_s *s = opaque;
- uint32_t ret;
-
- if (size != 2) {
- return omap_badwidth_read16(opaque, addr);
- }
-
- switch (addr) {
- case 0x000: /* CPCFR1 */
- return s->config[0];
- case 0x004: /* CPCFR2 */
- return s->config[1];
- case 0x008: /* CPCFR3 */
- return s->config[2];
- case 0x00c: /* CPCFR4 */
- return s->config[3];
-
- case 0x010: /* CPTCTL */
- return s->control | ((s->codec.rxavail + s->codec.rxlen > 0) << 7) |
- ((s->codec.txlen < s->codec.txavail) << 5);
-
- case 0x014: /* CPTTADR */
- return s->address;
- case 0x018: /* CPTDATL */
- return s->data & 0xff;
- case 0x01c: /* CPTDATH */
- return s->data >> 8;
- case 0x020: /* CPTVSLL */
- return s->vtol;
- case 0x024: /* CPTVSLH */
- return s->vtsl | (3 << 5); /* CRDY1 | CRDY2 */
- case 0x040: /* MPCTR */
- return s->modem.control;
- case 0x044: /* MPMCCFR */
- return s->modem.config;
- case 0x060: /* BPCTR */
- return s->bt.control;
- case 0x064: /* BPMCCFR */
- return s->bt.config;
- case 0x080: /* AMSCFR */
- return s->mixer;
- case 0x084: /* AMVCTR */
- return s->gain[0];
- case 0x088: /* AM1VCTR */
- return s->gain[1];
- case 0x08c: /* AM2VCTR */
- return s->gain[2];
- case 0x090: /* AM3VCTR */
- return s->gain[3];
- case 0x094: /* ASTCTR */
- return s->att;
- case 0x098: /* APD1LCR */
- return s->max[0];
- case 0x09c: /* APD1RCR */
- return s->max[1];
- case 0x0a0: /* APD2LCR */
- return s->max[2];
- case 0x0a4: /* APD2RCR */
- return s->max[3];
- case 0x0a8: /* APD3LCR */
- return s->max[4];
- case 0x0ac: /* APD3RCR */
- return s->max[5];
- case 0x0b0: /* APD4R */
- return s->max[6];
- case 0x0b4: /* ADWR */
- /* This should be write-only? Docs list it as read-only. */
- return 0x0000;
- case 0x0b8: /* ADRDR */
- if (likely(s->codec.rxlen > 1)) {
- ret = s->codec.rxbuf[s->codec.rxoff ++];
- s->codec.rxlen --;
- s->codec.rxoff &= EAC_BUF_LEN - 1;
- return ret;
- } else if (s->codec.rxlen) {
- ret = s->codec.rxbuf[s->codec.rxoff ++];
- s->codec.rxlen --;
- s->codec.rxoff &= EAC_BUF_LEN - 1;
- if (s->codec.rxavail)
- omap_eac_in_refill(s);
- omap_eac_in_dmarequest_update(s);
- return ret;
- }
- return 0x0000;
- case 0x0bc: /* AGCFR */
- return s->codec.config[0];
- case 0x0c0: /* AGCTR */
- return s->codec.config[1] | ((s->codec.config[1] & 2) << 14);
- case 0x0c4: /* AGCFR2 */
- return s->codec.config[2];
- case 0x0c8: /* AGCFR3 */
- return s->codec.config[3];
- case 0x0cc: /* MBPDMACTR */
- case 0x0d0: /* MPDDMARR */
- case 0x0d8: /* MPUDMARR */
- case 0x0e4: /* BPDDMARR */
- case 0x0ec: /* BPUDMARR */
- return 0x0000;
-
- case 0x100: /* VERSION_NUMBER */
- return 0x0010;
-
- case 0x104: /* SYSCONFIG */
- return s->sysconfig;
-
- case 0x108: /* SYSSTATUS */
- return 1 | 0xe; /* RESETDONE | stuff */
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_eac_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_eac_s *s = opaque;
-
- if (size != 2) {
- omap_badwidth_write16(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x098: /* APD1LCR */
- case 0x09c: /* APD1RCR */
- case 0x0a0: /* APD2LCR */
- case 0x0a4: /* APD2RCR */
- case 0x0a8: /* APD3LCR */
- case 0x0ac: /* APD3RCR */
- case 0x0b0: /* APD4R */
- case 0x0b8: /* ADRDR */
- case 0x0d0: /* MPDDMARR */
- case 0x0d8: /* MPUDMARR */
- case 0x0e4: /* BPDDMARR */
- case 0x0ec: /* BPUDMARR */
- case 0x100: /* VERSION_NUMBER */
- case 0x108: /* SYSSTATUS */
- OMAP_RO_REG(addr);
- return;
-
- case 0x000: /* CPCFR1 */
- s->config[0] = value & 0xff;
- omap_eac_format_update(s);
- break;
- case 0x004: /* CPCFR2 */
- s->config[1] = value & 0xff;
- omap_eac_format_update(s);
- break;
- case 0x008: /* CPCFR3 */
- s->config[2] = value & 0xff;
- omap_eac_format_update(s);
- break;
- case 0x00c: /* CPCFR4 */
- s->config[3] = value & 0xff;
- omap_eac_format_update(s);
- break;
-
- case 0x010: /* CPTCTL */
- /* Assuming TXF and TXE bits are read-only... */
- s->control = value & 0x5f;
- omap_eac_interrupt_update(s);
- break;
-
- case 0x014: /* CPTTADR */
- s->address = value & 0xff;
- break;
- case 0x018: /* CPTDATL */
- s->data &= 0xff00;
- s->data |= value & 0xff;
- break;
- case 0x01c: /* CPTDATH */
- s->data &= 0x00ff;
- s->data |= value << 8;
- break;
- case 0x020: /* CPTVSLL */
- s->vtol = value & 0xf8;
- break;
- case 0x024: /* CPTVSLH */
- s->vtsl = value & 0x9f;
- break;
- case 0x040: /* MPCTR */
- s->modem.control = value & 0x8f;
- break;
- case 0x044: /* MPMCCFR */
- s->modem.config = value & 0x7fff;
- break;
- case 0x060: /* BPCTR */
- s->bt.control = value & 0x8f;
- break;
- case 0x064: /* BPMCCFR */
- s->bt.config = value & 0x7fff;
- break;
- case 0x080: /* AMSCFR */
- s->mixer = value & 0x0fff;
- break;
- case 0x084: /* AMVCTR */
- s->gain[0] = value & 0xffff;
- break;
- case 0x088: /* AM1VCTR */
- s->gain[1] = value & 0xff7f;
- break;
- case 0x08c: /* AM2VCTR */
- s->gain[2] = value & 0xff7f;
- break;
- case 0x090: /* AM3VCTR */
- s->gain[3] = value & 0xff7f;
- break;
- case 0x094: /* ASTCTR */
- s->att = value & 0xff;
- break;
-
- case 0x0b4: /* ADWR */
- s->codec.txbuf[s->codec.txlen ++] = value;
- if (unlikely(s->codec.txlen == EAC_BUF_LEN ||
- s->codec.txlen == s->codec.txavail)) {
- if (s->codec.txavail)
- omap_eac_out_empty(s);
- /* Discard what couldn't be written */
- s->codec.txlen = 0;
- }
- break;
-
- case 0x0bc: /* AGCFR */
- s->codec.config[0] = value & 0x07ff;
- omap_eac_format_update(s);
- break;
- case 0x0c0: /* AGCTR */
- s->codec.config[1] = value & 0x780f;
- omap_eac_format_update(s);
- break;
- case 0x0c4: /* AGCFR2 */
- s->codec.config[2] = value & 0x003f;
- omap_eac_format_update(s);
- break;
- case 0x0c8: /* AGCFR3 */
- s->codec.config[3] = value & 0xffff;
- omap_eac_format_update(s);
- break;
- case 0x0cc: /* MBPDMACTR */
- case 0x0d4: /* MPDDMAWR */
- case 0x0e0: /* MPUDMAWR */
- case 0x0e8: /* BPDDMAWR */
- case 0x0f0: /* BPUDMAWR */
- break;
-
- case 0x104: /* SYSCONFIG */
- if (value & (1 << 1)) /* SOFTRESET */
- omap_eac_reset(s);
- s->sysconfig = value & 0x31d;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_eac_ops = {
- .read = omap_eac_read,
- .write = omap_eac_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static struct omap_eac_s *omap_eac_init(struct omap_target_agent_s *ta,
- qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk)
-{
- struct omap_eac_s *s = g_new0(struct omap_eac_s, 1);
-
- s->irq = irq;
- s->codec.rxdrq = *drq ++;
- s->codec.txdrq = *drq;
- omap_eac_reset(s);
-
- if (current_machine->audiodev) {
- s->codec.card.name = g_strdup(current_machine->audiodev);
- s->codec.card.state = audio_state_by_name(s->codec.card.name, &error_fatal);
- }
- AUD_register_card("OMAP EAC", &s->codec.card, &error_fatal);
-
- memory_region_init_io(&s->iomem, NULL, &omap_eac_ops, s, "omap.eac",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &s->iomem);
-
- return s;
-}
-
-/* STI/XTI (emulation interface) console - reverse engineered only */
-struct omap_sti_s {
- qemu_irq irq;
- MemoryRegion iomem;
- MemoryRegion iomem_fifo;
- CharBackend chr;
-
- uint32_t sysconfig;
- uint32_t systest;
- uint32_t irqst;
- uint32_t irqen;
- uint32_t clkcontrol;
- uint32_t serial_config;
-};
-
-#define STI_TRACE_CONSOLE_CHANNEL 239
-#define STI_TRACE_CONTROL_CHANNEL 253
-
-static inline void omap_sti_interrupt_update(struct omap_sti_s *s)
-{
- qemu_set_irq(s->irq, s->irqst & s->irqen);
-}
-
-static void omap_sti_reset(struct omap_sti_s *s)
-{
- s->sysconfig = 0;
- s->irqst = 0;
- s->irqen = 0;
- s->clkcontrol = 0;
- s->serial_config = 0;
-
- omap_sti_interrupt_update(s);
-}
-
-static uint64_t omap_sti_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_sti_s *s = opaque;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* STI_REVISION */
- return 0x10;
-
- case 0x10: /* STI_SYSCONFIG */
- return s->sysconfig;
-
- case 0x14: /* STI_SYSSTATUS / STI_RX_STATUS / XTI_SYSSTATUS */
- return 0x00;
-
- case 0x18: /* STI_IRQSTATUS */
- return s->irqst;
-
- case 0x1c: /* STI_IRQSETEN / STI_IRQCLREN */
- return s->irqen;
-
- case 0x24: /* STI_ER / STI_DR / XTI_TRACESELECT */
- case 0x28: /* STI_RX_DR / XTI_RXDATA */
- /* TODO */
- return 0;
-
- case 0x2c: /* STI_CLK_CTRL / XTI_SCLKCRTL */
- return s->clkcontrol;
-
- case 0x30: /* STI_SERIAL_CFG / XTI_SCONFIG */
- return s->serial_config;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_sti_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_sti_s *s = opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* STI_REVISION */
- case 0x14: /* STI_SYSSTATUS / STI_RX_STATUS / XTI_SYSSTATUS */
- OMAP_RO_REG(addr);
- return;
-
- case 0x10: /* STI_SYSCONFIG */
- if (value & (1 << 1)) /* SOFTRESET */
- omap_sti_reset(s);
- s->sysconfig = value & 0xfe;
- break;
-
- case 0x18: /* STI_IRQSTATUS */
- s->irqst &= ~value;
- omap_sti_interrupt_update(s);
- break;
-
- case 0x1c: /* STI_IRQSETEN / STI_IRQCLREN */
- s->irqen = value & 0xffff;
- omap_sti_interrupt_update(s);
- break;
-
- case 0x2c: /* STI_CLK_CTRL / XTI_SCLKCRTL */
- s->clkcontrol = value & 0xff;
- break;
-
- case 0x30: /* STI_SERIAL_CFG / XTI_SCONFIG */
- s->serial_config = value & 0xff;
- break;
-
- case 0x24: /* STI_ER / STI_DR / XTI_TRACESELECT */
- case 0x28: /* STI_RX_DR / XTI_RXDATA */
- /* TODO */
- return;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_sti_ops = {
- .read = omap_sti_read,
- .write = omap_sti_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t omap_sti_fifo_read(void *opaque, hwaddr addr, unsigned size)
-{
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_sti_fifo_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_sti_s *s = opaque;
- int ch = addr >> 6;
- uint8_t byte = value;
-
- if (size != 1) {
- omap_badwidth_write8(opaque, addr, size);
- return;
- }
-
- if (ch == STI_TRACE_CONTROL_CHANNEL) {
- /* Flush channel <i>value</i>. */
- /* XXX this blocks entire thread. Rewrite to use
- * qemu_chr_fe_write and background I/O callbacks */
- qemu_chr_fe_write_all(&s->chr, (const uint8_t *) "\r", 1);
- } else if (ch == STI_TRACE_CONSOLE_CHANNEL || 1) {
- if (value == 0xc0 || value == 0xc3) {
- /* Open channel <i>ch</i>. */
- } else if (value == 0x00) {
- qemu_chr_fe_write_all(&s->chr, (const uint8_t *) "\n", 1);
- } else {
- qemu_chr_fe_write_all(&s->chr, &byte, 1);
- }
- }
-}
-
-static const MemoryRegionOps omap_sti_fifo_ops = {
- .read = omap_sti_fifo_read,
- .write = omap_sti_fifo_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static struct omap_sti_s *omap_sti_init(struct omap_target_agent_s *ta,
- MemoryRegion *sysmem,
- hwaddr channel_base, qemu_irq irq, omap_clk clk,
- Chardev *chr)
-{
- struct omap_sti_s *s = g_new0(struct omap_sti_s, 1);
-
- s->irq = irq;
- omap_sti_reset(s);
-
- qemu_chr_fe_init(&s->chr, chr ?: qemu_chr_new("null", "null", NULL),
- &error_abort);
-
- memory_region_init_io(&s->iomem, NULL, &omap_sti_ops, s, "omap.sti",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &s->iomem);
-
- memory_region_init_io(&s->iomem_fifo, NULL, &omap_sti_fifo_ops, s,
- "omap.sti.fifo", 0x10000);
- memory_region_add_subregion(sysmem, channel_base, &s->iomem_fifo);
-
- return s;
-}
-
-/* L4 Interconnect */
-#define L4TA(n) (n)
-#define L4TAO(n) ((n) + 39)
-
-static const struct omap_l4_region_s omap_l4_region[125] = {
- [ 1] = { 0x40800, 0x800, 32 }, /* Initiator agent */
- [ 2] = { 0x41000, 0x1000, 32 }, /* Link agent */
- [ 0] = { 0x40000, 0x800, 32 }, /* Address and protection */
- [ 3] = { 0x00000, 0x1000, 32 | 16 | 8 }, /* System Control and Pinout */
- [ 4] = { 0x01000, 0x1000, 32 | 16 | 8 }, /* L4TAO1 */
- [ 5] = { 0x04000, 0x1000, 32 | 16 }, /* 32K Timer */
- [ 6] = { 0x05000, 0x1000, 32 | 16 | 8 }, /* L4TAO2 */
- [ 7] = { 0x08000, 0x800, 32 }, /* PRCM Region A */
- [ 8] = { 0x08800, 0x800, 32 }, /* PRCM Region B */
- [ 9] = { 0x09000, 0x1000, 32 | 16 | 8 }, /* L4TAO */
- [ 10] = { 0x12000, 0x1000, 32 | 16 | 8 }, /* Test (BCM) */
- [ 11] = { 0x13000, 0x1000, 32 | 16 | 8 }, /* L4TA1 */
- [ 12] = { 0x14000, 0x1000, 32 }, /* Test/emulation (TAP) */
- [ 13] = { 0x15000, 0x1000, 32 | 16 | 8 }, /* L4TA2 */
- [ 14] = { 0x18000, 0x1000, 32 | 16 | 8 }, /* GPIO1 */
- [ 16] = { 0x1a000, 0x1000, 32 | 16 | 8 }, /* GPIO2 */
- [ 18] = { 0x1c000, 0x1000, 32 | 16 | 8 }, /* GPIO3 */
- [ 19] = { 0x1e000, 0x1000, 32 | 16 | 8 }, /* GPIO4 */
- [ 15] = { 0x19000, 0x1000, 32 | 16 | 8 }, /* Quad GPIO TOP */
- [ 17] = { 0x1b000, 0x1000, 32 | 16 | 8 }, /* L4TA3 */
- [ 20] = { 0x20000, 0x1000, 32 | 16 | 8 }, /* WD Timer 1 (Secure) */
- [ 22] = { 0x22000, 0x1000, 32 | 16 | 8 }, /* WD Timer 2 (OMAP) */
- [ 21] = { 0x21000, 0x1000, 32 | 16 | 8 }, /* Dual WD timer TOP */
- [ 23] = { 0x23000, 0x1000, 32 | 16 | 8 }, /* L4TA4 */
- [ 24] = { 0x28000, 0x1000, 32 | 16 | 8 }, /* GP Timer 1 */
- [ 25] = { 0x29000, 0x1000, 32 | 16 | 8 }, /* L4TA7 */
- [ 26] = { 0x48000, 0x2000, 32 | 16 | 8 }, /* Emulation (ARM11ETB) */
- [ 27] = { 0x4a000, 0x1000, 32 | 16 | 8 }, /* L4TA9 */
- [ 28] = { 0x50000, 0x400, 32 | 16 | 8 }, /* Display top */
- [ 29] = { 0x50400, 0x400, 32 | 16 | 8 }, /* Display control */
- [ 30] = { 0x50800, 0x400, 32 | 16 | 8 }, /* Display RFBI */
- [ 31] = { 0x50c00, 0x400, 32 | 16 | 8 }, /* Display encoder */
- [ 32] = { 0x51000, 0x1000, 32 | 16 | 8 }, /* L4TA10 */
- [ 33] = { 0x52000, 0x400, 32 | 16 | 8 }, /* Camera top */
- [ 34] = { 0x52400, 0x400, 32 | 16 | 8 }, /* Camera core */
- [ 35] = { 0x52800, 0x400, 32 | 16 | 8 }, /* Camera DMA */
- [ 36] = { 0x52c00, 0x400, 32 | 16 | 8 }, /* Camera MMU */
- [ 37] = { 0x53000, 0x1000, 32 | 16 | 8 }, /* L4TA11 */
- [ 38] = { 0x56000, 0x1000, 32 | 16 | 8 }, /* sDMA */
- [ 39] = { 0x57000, 0x1000, 32 | 16 | 8 }, /* L4TA12 */
- [ 40] = { 0x58000, 0x1000, 32 | 16 | 8 }, /* SSI top */
- [ 41] = { 0x59000, 0x1000, 32 | 16 | 8 }, /* SSI GDD */
- [ 42] = { 0x5a000, 0x1000, 32 | 16 | 8 }, /* SSI Port1 */
- [ 43] = { 0x5b000, 0x1000, 32 | 16 | 8 }, /* SSI Port2 */
- [ 44] = { 0x5c000, 0x1000, 32 | 16 | 8 }, /* L4TA13 */
- [ 45] = { 0x5e000, 0x1000, 32 | 16 | 8 }, /* USB OTG */
- [ 46] = { 0x5f000, 0x1000, 32 | 16 | 8 }, /* L4TAO4 */
- [ 47] = { 0x60000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER1SDRC) */
- [ 48] = { 0x61000, 0x1000, 32 | 16 | 8 }, /* L4TA14 */
- [ 49] = { 0x62000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER2GPMC) */
- [ 50] = { 0x63000, 0x1000, 32 | 16 | 8 }, /* L4TA15 */
- [ 51] = { 0x64000, 0x1000, 32 | 16 | 8 }, /* Emulation (WIN_TRACER3OCM) */
- [ 52] = { 0x65000, 0x1000, 32 | 16 | 8 }, /* L4TA16 */
- [ 53] = { 0x66000, 0x300, 32 | 16 | 8 }, /* Emulation (WIN_TRACER4L4) */
- [ 54] = { 0x67000, 0x1000, 32 | 16 | 8 }, /* L4TA17 */
- [ 55] = { 0x68000, 0x1000, 32 | 16 | 8 }, /* Emulation (XTI) */
- [ 56] = { 0x69000, 0x1000, 32 | 16 | 8 }, /* L4TA18 */
- [ 57] = { 0x6a000, 0x1000, 16 | 8 }, /* UART1 */
- [ 58] = { 0x6b000, 0x1000, 32 | 16 | 8 }, /* L4TA19 */
- [ 59] = { 0x6c000, 0x1000, 16 | 8 }, /* UART2 */
- [ 60] = { 0x6d000, 0x1000, 32 | 16 | 8 }, /* L4TA20 */
- [ 61] = { 0x6e000, 0x1000, 16 | 8 }, /* UART3 */
- [ 62] = { 0x6f000, 0x1000, 32 | 16 | 8 }, /* L4TA21 */
- [ 63] = { 0x70000, 0x1000, 16 }, /* I2C1 */
- [ 64] = { 0x71000, 0x1000, 32 | 16 | 8 }, /* L4TAO5 */
- [ 65] = { 0x72000, 0x1000, 16 }, /* I2C2 */
- [ 66] = { 0x73000, 0x1000, 32 | 16 | 8 }, /* L4TAO6 */
- [ 67] = { 0x74000, 0x1000, 16 }, /* McBSP1 */
- [ 68] = { 0x75000, 0x1000, 32 | 16 | 8 }, /* L4TAO7 */
- [ 69] = { 0x76000, 0x1000, 16 }, /* McBSP2 */
- [ 70] = { 0x77000, 0x1000, 32 | 16 | 8 }, /* L4TAO8 */
- [ 71] = { 0x24000, 0x1000, 32 | 16 | 8 }, /* WD Timer 3 (DSP) */
- [ 72] = { 0x25000, 0x1000, 32 | 16 | 8 }, /* L4TA5 */
- [ 73] = { 0x26000, 0x1000, 32 | 16 | 8 }, /* WD Timer 4 (IVA) */
- [ 74] = { 0x27000, 0x1000, 32 | 16 | 8 }, /* L4TA6 */
- [ 75] = { 0x2a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 2 */
- [ 76] = { 0x2b000, 0x1000, 32 | 16 | 8 }, /* L4TA8 */
- [ 77] = { 0x78000, 0x1000, 32 | 16 | 8 }, /* GP Timer 3 */
- [ 78] = { 0x79000, 0x1000, 32 | 16 | 8 }, /* L4TA22 */
- [ 79] = { 0x7a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 4 */
- [ 80] = { 0x7b000, 0x1000, 32 | 16 | 8 }, /* L4TA23 */
- [ 81] = { 0x7c000, 0x1000, 32 | 16 | 8 }, /* GP Timer 5 */
- [ 82] = { 0x7d000, 0x1000, 32 | 16 | 8 }, /* L4TA24 */
- [ 83] = { 0x7e000, 0x1000, 32 | 16 | 8 }, /* GP Timer 6 */
- [ 84] = { 0x7f000, 0x1000, 32 | 16 | 8 }, /* L4TA25 */
- [ 85] = { 0x80000, 0x1000, 32 | 16 | 8 }, /* GP Timer 7 */
- [ 86] = { 0x81000, 0x1000, 32 | 16 | 8 }, /* L4TA26 */
- [ 87] = { 0x82000, 0x1000, 32 | 16 | 8 }, /* GP Timer 8 */
- [ 88] = { 0x83000, 0x1000, 32 | 16 | 8 }, /* L4TA27 */
- [ 89] = { 0x84000, 0x1000, 32 | 16 | 8 }, /* GP Timer 9 */
- [ 90] = { 0x85000, 0x1000, 32 | 16 | 8 }, /* L4TA28 */
- [ 91] = { 0x86000, 0x1000, 32 | 16 | 8 }, /* GP Timer 10 */
- [ 92] = { 0x87000, 0x1000, 32 | 16 | 8 }, /* L4TA29 */
- [ 93] = { 0x88000, 0x1000, 32 | 16 | 8 }, /* GP Timer 11 */
- [ 94] = { 0x89000, 0x1000, 32 | 16 | 8 }, /* L4TA30 */
- [ 95] = { 0x8a000, 0x1000, 32 | 16 | 8 }, /* GP Timer 12 */
- [ 96] = { 0x8b000, 0x1000, 32 | 16 | 8 }, /* L4TA31 */
- [ 97] = { 0x90000, 0x1000, 16 }, /* EAC */
- [ 98] = { 0x91000, 0x1000, 32 | 16 | 8 }, /* L4TA32 */
- [ 99] = { 0x92000, 0x1000, 16 }, /* FAC */
- [100] = { 0x93000, 0x1000, 32 | 16 | 8 }, /* L4TA33 */
- [101] = { 0x94000, 0x1000, 32 | 16 | 8 }, /* IPC (MAILBOX) */
- [102] = { 0x95000, 0x1000, 32 | 16 | 8 }, /* L4TA34 */
- [103] = { 0x98000, 0x1000, 32 | 16 | 8 }, /* SPI1 */
- [104] = { 0x99000, 0x1000, 32 | 16 | 8 }, /* L4TA35 */
- [105] = { 0x9a000, 0x1000, 32 | 16 | 8 }, /* SPI2 */
- [106] = { 0x9b000, 0x1000, 32 | 16 | 8 }, /* L4TA36 */
- [107] = { 0x9c000, 0x1000, 16 | 8 }, /* MMC SDIO */
- [108] = { 0x9d000, 0x1000, 32 | 16 | 8 }, /* L4TAO9 */
- [109] = { 0x9e000, 0x1000, 32 | 16 | 8 }, /* MS_PRO */
- [110] = { 0x9f000, 0x1000, 32 | 16 | 8 }, /* L4TAO10 */
- [111] = { 0xa0000, 0x1000, 32 }, /* RNG */
- [112] = { 0xa1000, 0x1000, 32 | 16 | 8 }, /* L4TAO11 */
- [113] = { 0xa2000, 0x1000, 32 }, /* DES3DES */
- [114] = { 0xa3000, 0x1000, 32 | 16 | 8 }, /* L4TAO12 */
- [115] = { 0xa4000, 0x1000, 32 }, /* SHA1MD5 */
- [116] = { 0xa5000, 0x1000, 32 | 16 | 8 }, /* L4TAO13 */
- [117] = { 0xa6000, 0x1000, 32 }, /* AES */
- [118] = { 0xa7000, 0x1000, 32 | 16 | 8 }, /* L4TA37 */
- [119] = { 0xa8000, 0x2000, 32 }, /* PKA */
- [120] = { 0xaa000, 0x1000, 32 | 16 | 8 }, /* L4TA38 */
- [121] = { 0xb0000, 0x1000, 32 }, /* MG */
- [122] = { 0xb1000, 0x1000, 32 | 16 | 8 },
- [123] = { 0xb2000, 0x1000, 32 }, /* HDQ/1-Wire */
- [124] = { 0xb3000, 0x1000, 32 | 16 | 8 }, /* L4TA39 */
-};
-
-static const struct omap_l4_agent_info_s omap_l4_agent_info[54] = {
- { 0, 0, 3, 2 }, /* L4IA initiatior agent */
- { L4TAO(1), 3, 2, 1 }, /* Control and pinout module */
- { L4TAO(2), 5, 2, 1 }, /* 32K timer */
- { L4TAO(3), 7, 3, 2 }, /* PRCM */
- { L4TA(1), 10, 2, 1 }, /* BCM */
- { L4TA(2), 12, 2, 1 }, /* Test JTAG */
- { L4TA(3), 14, 6, 3 }, /* Quad GPIO */
- { L4TA(4), 20, 4, 3 }, /* WD timer 1/2 */
- { L4TA(7), 24, 2, 1 }, /* GP timer 1 */
- { L4TA(9), 26, 2, 1 }, /* ATM11 ETB */
- { L4TA(10), 28, 5, 4 }, /* Display subsystem */
- { L4TA(11), 33, 5, 4 }, /* Camera subsystem */
- { L4TA(12), 38, 2, 1 }, /* sDMA */
- { L4TA(13), 40, 5, 4 }, /* SSI */
- { L4TAO(4), 45, 2, 1 }, /* USB */
- { L4TA(14), 47, 2, 1 }, /* Win Tracer1 */
- { L4TA(15), 49, 2, 1 }, /* Win Tracer2 */
- { L4TA(16), 51, 2, 1 }, /* Win Tracer3 */
- { L4TA(17), 53, 2, 1 }, /* Win Tracer4 */
- { L4TA(18), 55, 2, 1 }, /* XTI */
- { L4TA(19), 57, 2, 1 }, /* UART1 */
- { L4TA(20), 59, 2, 1 }, /* UART2 */
- { L4TA(21), 61, 2, 1 }, /* UART3 */
- { L4TAO(5), 63, 2, 1 }, /* I2C1 */
- { L4TAO(6), 65, 2, 1 }, /* I2C2 */
- { L4TAO(7), 67, 2, 1 }, /* McBSP1 */
- { L4TAO(8), 69, 2, 1 }, /* McBSP2 */
- { L4TA(5), 71, 2, 1 }, /* WD Timer 3 (DSP) */
- { L4TA(6), 73, 2, 1 }, /* WD Timer 4 (IVA) */
- { L4TA(8), 75, 2, 1 }, /* GP Timer 2 */
- { L4TA(22), 77, 2, 1 }, /* GP Timer 3 */
- { L4TA(23), 79, 2, 1 }, /* GP Timer 4 */
- { L4TA(24), 81, 2, 1 }, /* GP Timer 5 */
- { L4TA(25), 83, 2, 1 }, /* GP Timer 6 */
- { L4TA(26), 85, 2, 1 }, /* GP Timer 7 */
- { L4TA(27), 87, 2, 1 }, /* GP Timer 8 */
- { L4TA(28), 89, 2, 1 }, /* GP Timer 9 */
- { L4TA(29), 91, 2, 1 }, /* GP Timer 10 */
- { L4TA(30), 93, 2, 1 }, /* GP Timer 11 */
- { L4TA(31), 95, 2, 1 }, /* GP Timer 12 */
- { L4TA(32), 97, 2, 1 }, /* EAC */
- { L4TA(33), 99, 2, 1 }, /* FAC */
- { L4TA(34), 101, 2, 1 }, /* IPC */
- { L4TA(35), 103, 2, 1 }, /* SPI1 */
- { L4TA(36), 105, 2, 1 }, /* SPI2 */
- { L4TAO(9), 107, 2, 1 }, /* MMC SDIO */
- { L4TAO(10), 109, 2, 1 },
- { L4TAO(11), 111, 2, 1 }, /* RNG */
- { L4TAO(12), 113, 2, 1 }, /* DES3DES */
- { L4TAO(13), 115, 2, 1 }, /* SHA1MD5 */
- { L4TA(37), 117, 2, 1 }, /* AES */
- { L4TA(38), 119, 2, 1 }, /* PKA */
- { -1, 121, 2, 1 },
- { L4TA(39), 123, 2, 1 }, /* HDQ/1-Wire */
-};
-
-#define omap_l4ta(bus, cs) \
- omap_l4ta_get(bus, omap_l4_region, omap_l4_agent_info, L4TA(cs))
-#define omap_l4tao(bus, cs) \
- omap_l4ta_get(bus, omap_l4_region, omap_l4_agent_info, L4TAO(cs))
-
-/* Power, Reset, and Clock Management */
-struct omap_prcm_s {
- qemu_irq irq[3];
- struct omap_mpu_state_s *mpu;
- MemoryRegion iomem0;
- MemoryRegion iomem1;
-
- uint32_t irqst[3];
- uint32_t irqen[3];
-
- uint32_t sysconfig;
- uint32_t voltctrl;
- uint32_t scratch[20];
-
- uint32_t clksrc[1];
- uint32_t clkout[1];
- uint32_t clkemul[1];
- uint32_t clkpol[1];
- uint32_t clksel[8];
- uint32_t clken[12];
- uint32_t clkctrl[4];
- uint32_t clkidle[7];
- uint32_t setuptime[2];
-
- uint32_t wkup[3];
- uint32_t wken[3];
- uint32_t wkst[3];
- uint32_t rst[4];
- uint32_t rstctrl[1];
- uint32_t power[4];
- uint32_t rsttime_wkup;
-
- uint32_t ev;
- uint32_t evtime[2];
-
- int dpll_lock, apll_lock[2];
-};
-
-static void omap_prcm_int_update(struct omap_prcm_s *s, int dom)
-{
- qemu_set_irq(s->irq[dom], s->irqst[dom] & s->irqen[dom]);
- /* XXX or is the mask applied before PRCM_IRQSTATUS_* ? */
-}
-
-static uint64_t omap_prcm_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_prcm_s *s = opaque;
- uint32_t ret;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x000: /* PRCM_REVISION */
- return 0x10;
-
- case 0x010: /* PRCM_SYSCONFIG */
- return s->sysconfig;
-
- case 0x018: /* PRCM_IRQSTATUS_MPU */
- return s->irqst[0];
-
- case 0x01c: /* PRCM_IRQENABLE_MPU */
- return s->irqen[0];
-
- case 0x050: /* PRCM_VOLTCTRL */
- return s->voltctrl;
- case 0x054: /* PRCM_VOLTST */
- return s->voltctrl & 3;
-
- case 0x060: /* PRCM_CLKSRC_CTRL */
- return s->clksrc[0];
- case 0x070: /* PRCM_CLKOUT_CTRL */
- return s->clkout[0];
- case 0x078: /* PRCM_CLKEMUL_CTRL */
- return s->clkemul[0];
- case 0x080: /* PRCM_CLKCFG_CTRL */
- case 0x084: /* PRCM_CLKCFG_STATUS */
- return 0;
-
- case 0x090: /* PRCM_VOLTSETUP */
- return s->setuptime[0];
-
- case 0x094: /* PRCM_CLKSSETUP */
- return s->setuptime[1];
-
- case 0x098: /* PRCM_POLCTRL */
- return s->clkpol[0];
-
- case 0x0b0: /* GENERAL_PURPOSE1 */
- case 0x0b4: /* GENERAL_PURPOSE2 */
- case 0x0b8: /* GENERAL_PURPOSE3 */
- case 0x0bc: /* GENERAL_PURPOSE4 */
- case 0x0c0: /* GENERAL_PURPOSE5 */
- case 0x0c4: /* GENERAL_PURPOSE6 */
- case 0x0c8: /* GENERAL_PURPOSE7 */
- case 0x0cc: /* GENERAL_PURPOSE8 */
- case 0x0d0: /* GENERAL_PURPOSE9 */
- case 0x0d4: /* GENERAL_PURPOSE10 */
- case 0x0d8: /* GENERAL_PURPOSE11 */
- case 0x0dc: /* GENERAL_PURPOSE12 */
- case 0x0e0: /* GENERAL_PURPOSE13 */
- case 0x0e4: /* GENERAL_PURPOSE14 */
- case 0x0e8: /* GENERAL_PURPOSE15 */
- case 0x0ec: /* GENERAL_PURPOSE16 */
- case 0x0f0: /* GENERAL_PURPOSE17 */
- case 0x0f4: /* GENERAL_PURPOSE18 */
- case 0x0f8: /* GENERAL_PURPOSE19 */
- case 0x0fc: /* GENERAL_PURPOSE20 */
- return s->scratch[(addr - 0xb0) >> 2];
-
- case 0x140: /* CM_CLKSEL_MPU */
- return s->clksel[0];
- case 0x148: /* CM_CLKSTCTRL_MPU */
- return s->clkctrl[0];
-
- case 0x158: /* RM_RSTST_MPU */
- return s->rst[0];
- case 0x1c8: /* PM_WKDEP_MPU */
- return s->wkup[0];
- case 0x1d4: /* PM_EVGENCTRL_MPU */
- return s->ev;
- case 0x1d8: /* PM_EVEGENONTIM_MPU */
- return s->evtime[0];
- case 0x1dc: /* PM_EVEGENOFFTIM_MPU */
- return s->evtime[1];
- case 0x1e0: /* PM_PWSTCTRL_MPU */
- return s->power[0];
- case 0x1e4: /* PM_PWSTST_MPU */
- return 0;
-
- case 0x200: /* CM_FCLKEN1_CORE */
- return s->clken[0];
- case 0x204: /* CM_FCLKEN2_CORE */
- return s->clken[1];
- case 0x210: /* CM_ICLKEN1_CORE */
- return s->clken[2];
- case 0x214: /* CM_ICLKEN2_CORE */
- return s->clken[3];
- case 0x21c: /* CM_ICLKEN4_CORE */
- return s->clken[4];
-
- case 0x220: /* CM_IDLEST1_CORE */
- /* TODO: check the actual iclk status */
- return 0x7ffffff9;
- case 0x224: /* CM_IDLEST2_CORE */
- /* TODO: check the actual iclk status */
- return 0x00000007;
- case 0x22c: /* CM_IDLEST4_CORE */
- /* TODO: check the actual iclk status */
- return 0x0000001f;
-
- case 0x230: /* CM_AUTOIDLE1_CORE */
- return s->clkidle[0];
- case 0x234: /* CM_AUTOIDLE2_CORE */
- return s->clkidle[1];
- case 0x238: /* CM_AUTOIDLE3_CORE */
- return s->clkidle[2];
- case 0x23c: /* CM_AUTOIDLE4_CORE */
- return s->clkidle[3];
-
- case 0x240: /* CM_CLKSEL1_CORE */
- return s->clksel[1];
- case 0x244: /* CM_CLKSEL2_CORE */
- return s->clksel[2];
-
- case 0x248: /* CM_CLKSTCTRL_CORE */
- return s->clkctrl[1];
-
- case 0x2a0: /* PM_WKEN1_CORE */
- return s->wken[0];
- case 0x2a4: /* PM_WKEN2_CORE */
- return s->wken[1];
-
- case 0x2b0: /* PM_WKST1_CORE */
- return s->wkst[0];
- case 0x2b4: /* PM_WKST2_CORE */
- return s->wkst[1];
- case 0x2c8: /* PM_WKDEP_CORE */
- return 0x1e;
-
- case 0x2e0: /* PM_PWSTCTRL_CORE */
- return s->power[1];
- case 0x2e4: /* PM_PWSTST_CORE */
- return 0x000030 | (s->power[1] & 0xfc00);
-
- case 0x300: /* CM_FCLKEN_GFX */
- return s->clken[5];
- case 0x310: /* CM_ICLKEN_GFX */
- return s->clken[6];
- case 0x320: /* CM_IDLEST_GFX */
- /* TODO: check the actual iclk status */
- return 0x00000001;
- case 0x340: /* CM_CLKSEL_GFX */
- return s->clksel[3];
- case 0x348: /* CM_CLKSTCTRL_GFX */
- return s->clkctrl[2];
- case 0x350: /* RM_RSTCTRL_GFX */
- return s->rstctrl[0];
- case 0x358: /* RM_RSTST_GFX */
- return s->rst[1];
- case 0x3c8: /* PM_WKDEP_GFX */
- return s->wkup[1];
-
- case 0x3e0: /* PM_PWSTCTRL_GFX */
- return s->power[2];
- case 0x3e4: /* PM_PWSTST_GFX */
- return s->power[2] & 3;
-
- case 0x400: /* CM_FCLKEN_WKUP */
- return s->clken[7];
- case 0x410: /* CM_ICLKEN_WKUP */
- return s->clken[8];
- case 0x420: /* CM_IDLEST_WKUP */
- /* TODO: check the actual iclk status */
- return 0x0000003f;
- case 0x430: /* CM_AUTOIDLE_WKUP */
- return s->clkidle[4];
- case 0x440: /* CM_CLKSEL_WKUP */
- return s->clksel[4];
- case 0x450: /* RM_RSTCTRL_WKUP */
- return 0;
- case 0x454: /* RM_RSTTIME_WKUP */
- return s->rsttime_wkup;
- case 0x458: /* RM_RSTST_WKUP */
- return s->rst[2];
- case 0x4a0: /* PM_WKEN_WKUP */
- return s->wken[2];
- case 0x4b0: /* PM_WKST_WKUP */
- return s->wkst[2];
-
- case 0x500: /* CM_CLKEN_PLL */
- return s->clken[9];
- case 0x520: /* CM_IDLEST_CKGEN */
- ret = 0x0000070 | (s->apll_lock[0] << 9) | (s->apll_lock[1] << 8);
- if (!(s->clksel[6] & 3))
- /* Core uses 32-kHz clock */
- ret |= 3 << 0;
- else if (!s->dpll_lock)
- /* DPLL not locked, core uses ref_clk */
- ret |= 1 << 0;
- else
- /* Core uses DPLL */
- ret |= 2 << 0;
- return ret;
- case 0x530: /* CM_AUTOIDLE_PLL */
- return s->clkidle[5];
- case 0x540: /* CM_CLKSEL1_PLL */
- return s->clksel[5];
- case 0x544: /* CM_CLKSEL2_PLL */
- return s->clksel[6];
-
- case 0x800: /* CM_FCLKEN_DSP */
- return s->clken[10];
- case 0x810: /* CM_ICLKEN_DSP */
- return s->clken[11];
- case 0x820: /* CM_IDLEST_DSP */
- /* TODO: check the actual iclk status */
- return 0x00000103;
- case 0x830: /* CM_AUTOIDLE_DSP */
- return s->clkidle[6];
- case 0x840: /* CM_CLKSEL_DSP */
- return s->clksel[7];
- case 0x848: /* CM_CLKSTCTRL_DSP */
- return s->clkctrl[3];
- case 0x850: /* RM_RSTCTRL_DSP */
- return 0;
- case 0x858: /* RM_RSTST_DSP */
- return s->rst[3];
- case 0x8c8: /* PM_WKDEP_DSP */
- return s->wkup[2];
- case 0x8e0: /* PM_PWSTCTRL_DSP */
- return s->power[3];
- case 0x8e4: /* PM_PWSTST_DSP */
- return 0x008030 | (s->power[3] & 0x3003);
-
- case 0x8f0: /* PRCM_IRQSTATUS_DSP */
- return s->irqst[1];
- case 0x8f4: /* PRCM_IRQENABLE_DSP */
- return s->irqen[1];
-
- case 0x8f8: /* PRCM_IRQSTATUS_IVA */
- return s->irqst[2];
- case 0x8fc: /* PRCM_IRQENABLE_IVA */
- return s->irqen[2];
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_prcm_apll_update(struct omap_prcm_s *s)
-{
- int mode[2];
-
- mode[0] = (s->clken[9] >> 6) & 3;
- s->apll_lock[0] = (mode[0] == 3);
- mode[1] = (s->clken[9] >> 2) & 3;
- s->apll_lock[1] = (mode[1] == 3);
- /* TODO: update clocks */
-
- if (mode[0] == 1 || mode[0] == 2 || mode[1] == 1 || mode[1] == 2)
- fprintf(stderr, "%s: bad EN_54M_PLL or bad EN_96M_PLL\n",
- __func__);
-}
-
-static void omap_prcm_dpll_update(struct omap_prcm_s *s)
-{
- omap_clk dpll = omap_findclk(s->mpu, "dpll");
- omap_clk dpll_x2 = omap_findclk(s->mpu, "dpll");
- omap_clk core = omap_findclk(s->mpu, "core_clk");
- int mode = (s->clken[9] >> 0) & 3;
- int mult, div;
-
- mult = (s->clksel[5] >> 12) & 0x3ff;
- div = (s->clksel[5] >> 8) & 0xf;
- if (mult == 0 || mult == 1)
- mode = 1; /* Bypass */
-
- s->dpll_lock = 0;
- switch (mode) {
- case 0:
- fprintf(stderr, "%s: bad EN_DPLL\n", __func__);
- break;
- case 1: /* Low-power bypass mode (Default) */
- case 2: /* Fast-relock bypass mode */
- omap_clk_setrate(dpll, 1, 1);
- omap_clk_setrate(dpll_x2, 1, 1);
- break;
- case 3: /* Lock mode */
- s->dpll_lock = 1; /* After 20 FINT cycles (ref_clk / (div + 1)). */
-
- omap_clk_setrate(dpll, div + 1, mult);
- omap_clk_setrate(dpll_x2, div + 1, mult * 2);
- break;
- }
-
- switch ((s->clksel[6] >> 0) & 3) {
- case 0:
- omap_clk_reparent(core, omap_findclk(s->mpu, "clk32-kHz"));
- break;
- case 1:
- omap_clk_reparent(core, dpll);
- break;
- case 2:
- /* Default */
- omap_clk_reparent(core, dpll_x2);
- break;
- case 3:
- fprintf(stderr, "%s: bad CORE_CLK_SRC\n", __func__);
- break;
- }
-}
-
-static void omap_prcm_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_prcm_s *s = opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x000: /* PRCM_REVISION */
- case 0x054: /* PRCM_VOLTST */
- case 0x084: /* PRCM_CLKCFG_STATUS */
- case 0x1e4: /* PM_PWSTST_MPU */
- case 0x220: /* CM_IDLEST1_CORE */
- case 0x224: /* CM_IDLEST2_CORE */
- case 0x22c: /* CM_IDLEST4_CORE */
- case 0x2c8: /* PM_WKDEP_CORE */
- case 0x2e4: /* PM_PWSTST_CORE */
- case 0x320: /* CM_IDLEST_GFX */
- case 0x3e4: /* PM_PWSTST_GFX */
- case 0x420: /* CM_IDLEST_WKUP */
- case 0x520: /* CM_IDLEST_CKGEN */
- case 0x820: /* CM_IDLEST_DSP */
- case 0x8e4: /* PM_PWSTST_DSP */
- OMAP_RO_REG(addr);
- return;
-
- case 0x010: /* PRCM_SYSCONFIG */
- s->sysconfig = value & 1;
- break;
-
- case 0x018: /* PRCM_IRQSTATUS_MPU */
- s->irqst[0] &= ~value;
- omap_prcm_int_update(s, 0);
- break;
- case 0x01c: /* PRCM_IRQENABLE_MPU */
- s->irqen[0] = value & 0x3f;
- omap_prcm_int_update(s, 0);
- break;
-
- case 0x050: /* PRCM_VOLTCTRL */
- s->voltctrl = value & 0xf1c3;
- break;
-
- case 0x060: /* PRCM_CLKSRC_CTRL */
- s->clksrc[0] = value & 0xdb;
- /* TODO update clocks */
- break;
-
- case 0x070: /* PRCM_CLKOUT_CTRL */
- s->clkout[0] = value & 0xbbbb;
- /* TODO update clocks */
- break;
-
- case 0x078: /* PRCM_CLKEMUL_CTRL */
- s->clkemul[0] = value & 1;
- /* TODO update clocks */
- break;
-
- case 0x080: /* PRCM_CLKCFG_CTRL */
- break;
-
- case 0x090: /* PRCM_VOLTSETUP */
- s->setuptime[0] = value & 0xffff;
- break;
- case 0x094: /* PRCM_CLKSSETUP */
- s->setuptime[1] = value & 0xffff;
- break;
-
- case 0x098: /* PRCM_POLCTRL */
- s->clkpol[0] = value & 0x701;
- break;
-
- case 0x0b0: /* GENERAL_PURPOSE1 */
- case 0x0b4: /* GENERAL_PURPOSE2 */
- case 0x0b8: /* GENERAL_PURPOSE3 */
- case 0x0bc: /* GENERAL_PURPOSE4 */
- case 0x0c0: /* GENERAL_PURPOSE5 */
- case 0x0c4: /* GENERAL_PURPOSE6 */
- case 0x0c8: /* GENERAL_PURPOSE7 */
- case 0x0cc: /* GENERAL_PURPOSE8 */
- case 0x0d0: /* GENERAL_PURPOSE9 */
- case 0x0d4: /* GENERAL_PURPOSE10 */
- case 0x0d8: /* GENERAL_PURPOSE11 */
- case 0x0dc: /* GENERAL_PURPOSE12 */
- case 0x0e0: /* GENERAL_PURPOSE13 */
- case 0x0e4: /* GENERAL_PURPOSE14 */
- case 0x0e8: /* GENERAL_PURPOSE15 */
- case 0x0ec: /* GENERAL_PURPOSE16 */
- case 0x0f0: /* GENERAL_PURPOSE17 */
- case 0x0f4: /* GENERAL_PURPOSE18 */
- case 0x0f8: /* GENERAL_PURPOSE19 */
- case 0x0fc: /* GENERAL_PURPOSE20 */
- s->scratch[(addr - 0xb0) >> 2] = value;
- break;
-
- case 0x140: /* CM_CLKSEL_MPU */
- s->clksel[0] = value & 0x1f;
- /* TODO update clocks */
- break;
- case 0x148: /* CM_CLKSTCTRL_MPU */
- s->clkctrl[0] = value & 0x1f;
- break;
-
- case 0x158: /* RM_RSTST_MPU */
- s->rst[0] &= ~value;
- break;
- case 0x1c8: /* PM_WKDEP_MPU */
- s->wkup[0] = value & 0x15;
- break;
-
- case 0x1d4: /* PM_EVGENCTRL_MPU */
- s->ev = value & 0x1f;
- break;
- case 0x1d8: /* PM_EVEGENONTIM_MPU */
- s->evtime[0] = value;
- break;
- case 0x1dc: /* PM_EVEGENOFFTIM_MPU */
- s->evtime[1] = value;
- break;
-
- case 0x1e0: /* PM_PWSTCTRL_MPU */
- s->power[0] = value & 0xc0f;
- break;
-
- case 0x200: /* CM_FCLKEN1_CORE */
- s->clken[0] = value & 0xbfffffff;
- /* TODO update clocks */
- /* The EN_EAC bit only gets/puts func_96m_clk. */
- break;
- case 0x204: /* CM_FCLKEN2_CORE */
- s->clken[1] = value & 0x00000007;
- /* TODO update clocks */
- break;
- case 0x210: /* CM_ICLKEN1_CORE */
- s->clken[2] = value & 0xfffffff9;
- /* TODO update clocks */
- /* The EN_EAC bit only gets/puts core_l4_iclk. */
- break;
- case 0x214: /* CM_ICLKEN2_CORE */
- s->clken[3] = value & 0x00000007;
- /* TODO update clocks */
- break;
- case 0x21c: /* CM_ICLKEN4_CORE */
- s->clken[4] = value & 0x0000001f;
- /* TODO update clocks */
- break;
-
- case 0x230: /* CM_AUTOIDLE1_CORE */
- s->clkidle[0] = value & 0xfffffff9;
- /* TODO update clocks */
- break;
- case 0x234: /* CM_AUTOIDLE2_CORE */
- s->clkidle[1] = value & 0x00000007;
- /* TODO update clocks */
- break;
- case 0x238: /* CM_AUTOIDLE3_CORE */
- s->clkidle[2] = value & 0x00000007;
- /* TODO update clocks */
- break;
- case 0x23c: /* CM_AUTOIDLE4_CORE */
- s->clkidle[3] = value & 0x0000001f;
- /* TODO update clocks */
- break;
-
- case 0x240: /* CM_CLKSEL1_CORE */
- s->clksel[1] = value & 0x0fffbf7f;
- /* TODO update clocks */
- break;
-
- case 0x244: /* CM_CLKSEL2_CORE */
- s->clksel[2] = value & 0x00fffffc;
- /* TODO update clocks */
- break;
-
- case 0x248: /* CM_CLKSTCTRL_CORE */
- s->clkctrl[1] = value & 0x7;
- break;
-
- case 0x2a0: /* PM_WKEN1_CORE */
- s->wken[0] = value & 0x04667ff8;
- break;
- case 0x2a4: /* PM_WKEN2_CORE */
- s->wken[1] = value & 0x00000005;
- break;
-
- case 0x2b0: /* PM_WKST1_CORE */
- s->wkst[0] &= ~value;
- break;
- case 0x2b4: /* PM_WKST2_CORE */
- s->wkst[1] &= ~value;
- break;
-
- case 0x2e0: /* PM_PWSTCTRL_CORE */
- s->power[1] = (value & 0x00fc3f) | (1 << 2);
- break;
-
- case 0x300: /* CM_FCLKEN_GFX */
- s->clken[5] = value & 6;
- /* TODO update clocks */
- break;
- case 0x310: /* CM_ICLKEN_GFX */
- s->clken[6] = value & 1;
- /* TODO update clocks */
- break;
- case 0x340: /* CM_CLKSEL_GFX */
- s->clksel[3] = value & 7;
- /* TODO update clocks */
- break;
- case 0x348: /* CM_CLKSTCTRL_GFX */
- s->clkctrl[2] = value & 1;
- break;
- case 0x350: /* RM_RSTCTRL_GFX */
- s->rstctrl[0] = value & 1;
- /* TODO: reset */
- break;
- case 0x358: /* RM_RSTST_GFX */
- s->rst[1] &= ~value;
- break;
- case 0x3c8: /* PM_WKDEP_GFX */
- s->wkup[1] = value & 0x13;
- break;
- case 0x3e0: /* PM_PWSTCTRL_GFX */
- s->power[2] = (value & 0x00c0f) | (3 << 2);
- break;
-
- case 0x400: /* CM_FCLKEN_WKUP */
- s->clken[7] = value & 0xd;
- /* TODO update clocks */
- break;
- case 0x410: /* CM_ICLKEN_WKUP */
- s->clken[8] = value & 0x3f;
- /* TODO update clocks */
- break;
- case 0x430: /* CM_AUTOIDLE_WKUP */
- s->clkidle[4] = value & 0x0000003f;
- /* TODO update clocks */
- break;
- case 0x440: /* CM_CLKSEL_WKUP */
- s->clksel[4] = value & 3;
- /* TODO update clocks */
- break;
- case 0x450: /* RM_RSTCTRL_WKUP */
- /* TODO: reset */
- if (value & 2)
- qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
- break;
- case 0x454: /* RM_RSTTIME_WKUP */
- s->rsttime_wkup = value & 0x1fff;
- break;
- case 0x458: /* RM_RSTST_WKUP */
- s->rst[2] &= ~value;
- break;
- case 0x4a0: /* PM_WKEN_WKUP */
- s->wken[2] = value & 0x00000005;
- break;
- case 0x4b0: /* PM_WKST_WKUP */
- s->wkst[2] &= ~value;
- break;
-
- case 0x500: /* CM_CLKEN_PLL */
- if (value & 0xffffff30)
- fprintf(stderr, "%s: write 0s in CM_CLKEN_PLL for "
- "future compatibility\n", __func__);
- if ((s->clken[9] ^ value) & 0xcc) {
- s->clken[9] &= ~0xcc;
- s->clken[9] |= value & 0xcc;
- omap_prcm_apll_update(s);
- }
- if ((s->clken[9] ^ value) & 3) {
- s->clken[9] &= ~3;
- s->clken[9] |= value & 3;
- omap_prcm_dpll_update(s);
- }
- break;
- case 0x530: /* CM_AUTOIDLE_PLL */
- s->clkidle[5] = value & 0x000000cf;
- /* TODO update clocks */
- break;
- case 0x540: /* CM_CLKSEL1_PLL */
- if (value & 0xfc4000d7)
- fprintf(stderr, "%s: write 0s in CM_CLKSEL1_PLL for "
- "future compatibility\n", __func__);
- if ((s->clksel[5] ^ value) & 0x003fff00) {
- s->clksel[5] = value & 0x03bfff28;
- omap_prcm_dpll_update(s);
- }
- /* TODO update the other clocks */
-
- s->clksel[5] = value & 0x03bfff28;
- break;
- case 0x544: /* CM_CLKSEL2_PLL */
- if (value & ~3)
- fprintf(stderr, "%s: write 0s in CM_CLKSEL2_PLL[31:2] for "
- "future compatibility\n", __func__);
- if (s->clksel[6] != (value & 3)) {
- s->clksel[6] = value & 3;
- omap_prcm_dpll_update(s);
- }
- break;
-
- case 0x800: /* CM_FCLKEN_DSP */
- s->clken[10] = value & 0x501;
- /* TODO update clocks */
- break;
- case 0x810: /* CM_ICLKEN_DSP */
- s->clken[11] = value & 0x2;
- /* TODO update clocks */
- break;
- case 0x830: /* CM_AUTOIDLE_DSP */
- s->clkidle[6] = value & 0x2;
- /* TODO update clocks */
- break;
- case 0x840: /* CM_CLKSEL_DSP */
- s->clksel[7] = value & 0x3fff;
- /* TODO update clocks */
- break;
- case 0x848: /* CM_CLKSTCTRL_DSP */
- s->clkctrl[3] = value & 0x101;
- break;
- case 0x850: /* RM_RSTCTRL_DSP */
- /* TODO: reset */
- break;
- case 0x858: /* RM_RSTST_DSP */
- s->rst[3] &= ~value;
- break;
- case 0x8c8: /* PM_WKDEP_DSP */
- s->wkup[2] = value & 0x13;
- break;
- case 0x8e0: /* PM_PWSTCTRL_DSP */
- s->power[3] = (value & 0x03017) | (3 << 2);
- break;
-
- case 0x8f0: /* PRCM_IRQSTATUS_DSP */
- s->irqst[1] &= ~value;
- omap_prcm_int_update(s, 1);
- break;
- case 0x8f4: /* PRCM_IRQENABLE_DSP */
- s->irqen[1] = value & 0x7;
- omap_prcm_int_update(s, 1);
- break;
-
- case 0x8f8: /* PRCM_IRQSTATUS_IVA */
- s->irqst[2] &= ~value;
- omap_prcm_int_update(s, 2);
- break;
- case 0x8fc: /* PRCM_IRQENABLE_IVA */
- s->irqen[2] = value & 0x7;
- omap_prcm_int_update(s, 2);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_prcm_ops = {
- .read = omap_prcm_read,
- .write = omap_prcm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_prcm_reset(struct omap_prcm_s *s)
-{
- s->sysconfig = 0;
- s->irqst[0] = 0;
- s->irqst[1] = 0;
- s->irqst[2] = 0;
- s->irqen[0] = 0;
- s->irqen[1] = 0;
- s->irqen[2] = 0;
- s->voltctrl = 0x1040;
- s->ev = 0x14;
- s->evtime[0] = 0;
- s->evtime[1] = 0;
- s->clkctrl[0] = 0;
- s->clkctrl[1] = 0;
- s->clkctrl[2] = 0;
- s->clkctrl[3] = 0;
- s->clken[1] = 7;
- s->clken[3] = 7;
- s->clken[4] = 0;
- s->clken[5] = 0;
- s->clken[6] = 0;
- s->clken[7] = 0xc;
- s->clken[8] = 0x3e;
- s->clken[9] = 0x0d;
- s->clken[10] = 0;
- s->clken[11] = 0;
- s->clkidle[0] = 0;
- s->clkidle[2] = 7;
- s->clkidle[3] = 0;
- s->clkidle[4] = 0;
- s->clkidle[5] = 0x0c;
- s->clkidle[6] = 0;
- s->clksel[0] = 0x01;
- s->clksel[1] = 0x02100121;
- s->clksel[2] = 0x00000000;
- s->clksel[3] = 0x01;
- s->clksel[4] = 0;
- s->clksel[7] = 0x0121;
- s->wkup[0] = 0x15;
- s->wkup[1] = 0x13;
- s->wkup[2] = 0x13;
- s->wken[0] = 0x04667ff8;
- s->wken[1] = 0x00000005;
- s->wken[2] = 5;
- s->wkst[0] = 0;
- s->wkst[1] = 0;
- s->wkst[2] = 0;
- s->power[0] = 0x00c;
- s->power[1] = 4;
- s->power[2] = 0x0000c;
- s->power[3] = 0x14;
- s->rstctrl[0] = 1;
- s->rst[3] = 1;
- omap_prcm_apll_update(s);
- omap_prcm_dpll_update(s);
-}
-
-static void omap_prcm_coldreset(struct omap_prcm_s *s)
-{
- s->setuptime[0] = 0;
- s->setuptime[1] = 0;
- memset(&s->scratch, 0, sizeof(s->scratch));
- s->rst[0] = 0x01;
- s->rst[1] = 0x00;
- s->rst[2] = 0x01;
- s->clken[0] = 0;
- s->clken[2] = 0;
- s->clkidle[1] = 0;
- s->clksel[5] = 0;
- s->clksel[6] = 2;
- s->clksrc[0] = 0x43;
- s->clkout[0] = 0x0303;
- s->clkemul[0] = 0;
- s->clkpol[0] = 0x100;
- s->rsttime_wkup = 0x1002;
-
- omap_prcm_reset(s);
-}
-
-static struct omap_prcm_s *omap_prcm_init(struct omap_target_agent_s *ta,
- qemu_irq mpu_int, qemu_irq dsp_int, qemu_irq iva_int,
- struct omap_mpu_state_s *mpu)
-{
- struct omap_prcm_s *s = g_new0(struct omap_prcm_s, 1);
-
- s->irq[0] = mpu_int;
- s->irq[1] = dsp_int;
- s->irq[2] = iva_int;
- s->mpu = mpu;
- omap_prcm_coldreset(s);
-
- memory_region_init_io(&s->iomem0, NULL, &omap_prcm_ops, s, "omap.pcrm0",
- omap_l4_region_size(ta, 0));
- memory_region_init_io(&s->iomem1, NULL, &omap_prcm_ops, s, "omap.pcrm1",
- omap_l4_region_size(ta, 1));
- omap_l4_attach(ta, 0, &s->iomem0);
- omap_l4_attach(ta, 1, &s->iomem1);
-
- return s;
-}
-
-/* System and Pinout control */
-struct omap_sysctl_s {
- struct omap_mpu_state_s *mpu;
- MemoryRegion iomem;
-
- uint32_t sysconfig;
- uint32_t devconfig;
- uint32_t psaconfig;
- uint32_t padconf[0x45];
- uint8_t obs;
- uint32_t msuspendmux[5];
-};
-
-static uint32_t omap_sysctl_read8(void *opaque, hwaddr addr)
-{
-
- struct omap_sysctl_s *s = opaque;
- int pad_offset, byte_offset;
- int value;
-
- switch (addr) {
- case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */
- pad_offset = (addr - 0x30) >> 2;
- byte_offset = (addr - 0x30) & (4 - 1);
-
- value = s->padconf[pad_offset];
- value = (value >> (byte_offset * 8)) & 0xff;
-
- return value;
-
- default:
- break;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static uint32_t omap_sysctl_read(void *opaque, hwaddr addr)
-{
- struct omap_sysctl_s *s = opaque;
-
- switch (addr) {
- case 0x000: /* CONTROL_REVISION */
- return 0x20;
-
- case 0x010: /* CONTROL_SYSCONFIG */
- return s->sysconfig;
-
- case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */
- return s->padconf[(addr - 0x30) >> 2];
-
- case 0x270: /* CONTROL_DEBOBS */
- return s->obs;
-
- case 0x274: /* CONTROL_DEVCONF */
- return s->devconfig;
-
- case 0x28c: /* CONTROL_EMU_SUPPORT */
- return 0;
-
- case 0x290: /* CONTROL_MSUSPENDMUX_0 */
- return s->msuspendmux[0];
- case 0x294: /* CONTROL_MSUSPENDMUX_1 */
- return s->msuspendmux[1];
- case 0x298: /* CONTROL_MSUSPENDMUX_2 */
- return s->msuspendmux[2];
- case 0x29c: /* CONTROL_MSUSPENDMUX_3 */
- return s->msuspendmux[3];
- case 0x2a0: /* CONTROL_MSUSPENDMUX_4 */
- return s->msuspendmux[4];
- case 0x2a4: /* CONTROL_MSUSPENDMUX_5 */
- return 0;
-
- case 0x2b8: /* CONTROL_PSA_CTRL */
- return s->psaconfig;
- case 0x2bc: /* CONTROL_PSA_CMD */
- case 0x2c0: /* CONTROL_PSA_VALUE */
- return 0;
-
- case 0x2b0: /* CONTROL_SEC_CTRL */
- return 0x800000f1;
- case 0x2d0: /* CONTROL_SEC_EMU */
- return 0x80000015;
- case 0x2d4: /* CONTROL_SEC_TAP */
- return 0x8000007f;
- case 0x2b4: /* CONTROL_SEC_TEST */
- case 0x2f0: /* CONTROL_SEC_STATUS */
- case 0x2f4: /* CONTROL_SEC_ERR_STATUS */
- /* Secure mode is not present on general-pusrpose device. Outside
- * secure mode these values cannot be read or written. */
- return 0;
-
- case 0x2d8: /* CONTROL_OCM_RAM_PERM */
- return 0xff;
- case 0x2dc: /* CONTROL_OCM_PUB_RAM_ADD */
- case 0x2e0: /* CONTROL_EXT_SEC_RAM_START_ADD */
- case 0x2e4: /* CONTROL_EXT_SEC_RAM_STOP_ADD */
- /* No secure mode so no Extended Secure RAM present. */
- return 0;
-
- case 0x2f8: /* CONTROL_STATUS */
- /* Device Type => General-purpose */
- return 0x0300;
- case 0x2fc: /* CONTROL_GENERAL_PURPOSE_STATUS */
-
- case 0x300: /* CONTROL_RPUB_KEY_H_0 */
- case 0x304: /* CONTROL_RPUB_KEY_H_1 */
- case 0x308: /* CONTROL_RPUB_KEY_H_2 */
- case 0x30c: /* CONTROL_RPUB_KEY_H_3 */
- return 0xdecafbad;
-
- case 0x310: /* CONTROL_RAND_KEY_0 */
- case 0x314: /* CONTROL_RAND_KEY_1 */
- case 0x318: /* CONTROL_RAND_KEY_2 */
- case 0x31c: /* CONTROL_RAND_KEY_3 */
- case 0x320: /* CONTROL_CUST_KEY_0 */
- case 0x324: /* CONTROL_CUST_KEY_1 */
- case 0x330: /* CONTROL_TEST_KEY_0 */
- case 0x334: /* CONTROL_TEST_KEY_1 */
- case 0x338: /* CONTROL_TEST_KEY_2 */
- case 0x33c: /* CONTROL_TEST_KEY_3 */
- case 0x340: /* CONTROL_TEST_KEY_4 */
- case 0x344: /* CONTROL_TEST_KEY_5 */
- case 0x348: /* CONTROL_TEST_KEY_6 */
- case 0x34c: /* CONTROL_TEST_KEY_7 */
- case 0x350: /* CONTROL_TEST_KEY_8 */
- case 0x354: /* CONTROL_TEST_KEY_9 */
- /* Can only be accessed in secure mode and when C_FieldAccEnable
- * bit is set in CONTROL_SEC_CTRL.
- * TODO: otherwise an interconnect access error is generated. */
- return 0;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_sysctl_write8(void *opaque, hwaddr addr, uint32_t value)
-{
- struct omap_sysctl_s *s = opaque;
- int pad_offset, byte_offset;
- int prev_value;
-
- switch (addr) {
- case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */
- pad_offset = (addr - 0x30) >> 2;
- byte_offset = (addr - 0x30) & (4 - 1);
-
- prev_value = s->padconf[pad_offset];
- prev_value &= ~(0xff << (byte_offset * 8));
- prev_value |= ((value & 0x1f1f1f1f) << (byte_offset * 8)) & 0x1f1f1f1f;
- s->padconf[pad_offset] = prev_value;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- break;
- }
-}
-
-static void omap_sysctl_write(void *opaque, hwaddr addr, uint32_t value)
-{
- struct omap_sysctl_s *s = opaque;
-
- switch (addr) {
- case 0x000: /* CONTROL_REVISION */
- case 0x2a4: /* CONTROL_MSUSPENDMUX_5 */
- case 0x2c0: /* CONTROL_PSA_VALUE */
- case 0x2f8: /* CONTROL_STATUS */
- case 0x2fc: /* CONTROL_GENERAL_PURPOSE_STATUS */
- case 0x300: /* CONTROL_RPUB_KEY_H_0 */
- case 0x304: /* CONTROL_RPUB_KEY_H_1 */
- case 0x308: /* CONTROL_RPUB_KEY_H_2 */
- case 0x30c: /* CONTROL_RPUB_KEY_H_3 */
- case 0x310: /* CONTROL_RAND_KEY_0 */
- case 0x314: /* CONTROL_RAND_KEY_1 */
- case 0x318: /* CONTROL_RAND_KEY_2 */
- case 0x31c: /* CONTROL_RAND_KEY_3 */
- case 0x320: /* CONTROL_CUST_KEY_0 */
- case 0x324: /* CONTROL_CUST_KEY_1 */
- case 0x330: /* CONTROL_TEST_KEY_0 */
- case 0x334: /* CONTROL_TEST_KEY_1 */
- case 0x338: /* CONTROL_TEST_KEY_2 */
- case 0x33c: /* CONTROL_TEST_KEY_3 */
- case 0x340: /* CONTROL_TEST_KEY_4 */
- case 0x344: /* CONTROL_TEST_KEY_5 */
- case 0x348: /* CONTROL_TEST_KEY_6 */
- case 0x34c: /* CONTROL_TEST_KEY_7 */
- case 0x350: /* CONTROL_TEST_KEY_8 */
- case 0x354: /* CONTROL_TEST_KEY_9 */
- OMAP_RO_REG(addr);
- return;
-
- case 0x010: /* CONTROL_SYSCONFIG */
- s->sysconfig = value & 0x1e;
- break;
-
- case 0x030 ... 0x140: /* CONTROL_PADCONF - only used in the POP */
- /* XXX: should check constant bits */
- s->padconf[(addr - 0x30) >> 2] = value & 0x1f1f1f1f;
- break;
-
- case 0x270: /* CONTROL_DEBOBS */
- s->obs = value & 0xff;
- break;
-
- case 0x274: /* CONTROL_DEVCONF */
- s->devconfig = value & 0xffffc7ff;
- break;
-
- case 0x28c: /* CONTROL_EMU_SUPPORT */
- break;
-
- case 0x290: /* CONTROL_MSUSPENDMUX_0 */
- s->msuspendmux[0] = value & 0x3fffffff;
- break;
- case 0x294: /* CONTROL_MSUSPENDMUX_1 */
- s->msuspendmux[1] = value & 0x3fffffff;
- break;
- case 0x298: /* CONTROL_MSUSPENDMUX_2 */
- s->msuspendmux[2] = value & 0x3fffffff;
- break;
- case 0x29c: /* CONTROL_MSUSPENDMUX_3 */
- s->msuspendmux[3] = value & 0x3fffffff;
- break;
- case 0x2a0: /* CONTROL_MSUSPENDMUX_4 */
- s->msuspendmux[4] = value & 0x3fffffff;
- break;
-
- case 0x2b8: /* CONTROL_PSA_CTRL */
- s->psaconfig = value & 0x1c;
- s->psaconfig |= (value & 0x20) ? 2 : 1;
- break;
- case 0x2bc: /* CONTROL_PSA_CMD */
- break;
-
- case 0x2b0: /* CONTROL_SEC_CTRL */
- case 0x2b4: /* CONTROL_SEC_TEST */
- case 0x2d0: /* CONTROL_SEC_EMU */
- case 0x2d4: /* CONTROL_SEC_TAP */
- case 0x2d8: /* CONTROL_OCM_RAM_PERM */
- case 0x2dc: /* CONTROL_OCM_PUB_RAM_ADD */
- case 0x2e0: /* CONTROL_EXT_SEC_RAM_START_ADD */
- case 0x2e4: /* CONTROL_EXT_SEC_RAM_STOP_ADD */
- case 0x2f0: /* CONTROL_SEC_STATUS */
- case 0x2f4: /* CONTROL_SEC_ERR_STATUS */
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static uint64_t omap_sysctl_readfn(void *opaque, hwaddr addr,
- unsigned size)
-{
- switch (size) {
- case 1:
- return omap_sysctl_read8(opaque, addr);
- case 2:
- return omap_badwidth_read32(opaque, addr); /* TODO */
- case 4:
- return omap_sysctl_read(opaque, addr);
- default:
- g_assert_not_reached();
- }
-}
-
-static void omap_sysctl_writefn(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- switch (size) {
- case 1:
- omap_sysctl_write8(opaque, addr, value);
- break;
- case 2:
- omap_badwidth_write32(opaque, addr, value); /* TODO */
- break;
- case 4:
- omap_sysctl_write(opaque, addr, value);
- break;
- default:
- g_assert_not_reached();
- }
-}
-
-static const MemoryRegionOps omap_sysctl_ops = {
- .read = omap_sysctl_readfn,
- .write = omap_sysctl_writefn,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_sysctl_reset(struct omap_sysctl_s *s)
-{
- /* (power-on reset) */
- s->sysconfig = 0;
- s->obs = 0;
- s->devconfig = 0x0c000000;
- s->msuspendmux[0] = 0x00000000;
- s->msuspendmux[1] = 0x00000000;
- s->msuspendmux[2] = 0x00000000;
- s->msuspendmux[3] = 0x00000000;
- s->msuspendmux[4] = 0x00000000;
- s->psaconfig = 1;
-
- s->padconf[0x00] = 0x000f0f0f;
- s->padconf[0x01] = 0x00000000;
- s->padconf[0x02] = 0x00000000;
- s->padconf[0x03] = 0x00000000;
- s->padconf[0x04] = 0x00000000;
- s->padconf[0x05] = 0x00000000;
- s->padconf[0x06] = 0x00000000;
- s->padconf[0x07] = 0x00000000;
- s->padconf[0x08] = 0x08080800;
- s->padconf[0x09] = 0x08080808;
- s->padconf[0x0a] = 0x08080808;
- s->padconf[0x0b] = 0x08080808;
- s->padconf[0x0c] = 0x08080808;
- s->padconf[0x0d] = 0x08080800;
- s->padconf[0x0e] = 0x08080808;
- s->padconf[0x0f] = 0x08080808;
- s->padconf[0x10] = 0x18181808; /* | 0x07070700 if SBoot3 */
- s->padconf[0x11] = 0x18181818; /* | 0x07070707 if SBoot3 */
- s->padconf[0x12] = 0x18181818; /* | 0x07070707 if SBoot3 */
- s->padconf[0x13] = 0x18181818; /* | 0x07070707 if SBoot3 */
- s->padconf[0x14] = 0x18181818; /* | 0x00070707 if SBoot3 */
- s->padconf[0x15] = 0x18181818;
- s->padconf[0x16] = 0x18181818; /* | 0x07000000 if SBoot3 */
- s->padconf[0x17] = 0x1f001f00;
- s->padconf[0x18] = 0x1f1f1f1f;
- s->padconf[0x19] = 0x00000000;
- s->padconf[0x1a] = 0x1f180000;
- s->padconf[0x1b] = 0x00001f1f;
- s->padconf[0x1c] = 0x1f001f00;
- s->padconf[0x1d] = 0x00000000;
- s->padconf[0x1e] = 0x00000000;
- s->padconf[0x1f] = 0x08000000;
- s->padconf[0x20] = 0x08080808;
- s->padconf[0x21] = 0x08080808;
- s->padconf[0x22] = 0x0f080808;
- s->padconf[0x23] = 0x0f0f0f0f;
- s->padconf[0x24] = 0x000f0f0f;
- s->padconf[0x25] = 0x1f1f1f0f;
- s->padconf[0x26] = 0x080f0f1f;
- s->padconf[0x27] = 0x070f1808;
- s->padconf[0x28] = 0x0f070707;
- s->padconf[0x29] = 0x000f0f1f;
- s->padconf[0x2a] = 0x0f0f0f1f;
- s->padconf[0x2b] = 0x08000000;
- s->padconf[0x2c] = 0x0000001f;
- s->padconf[0x2d] = 0x0f0f1f00;
- s->padconf[0x2e] = 0x1f1f0f0f;
- s->padconf[0x2f] = 0x0f1f1f1f;
- s->padconf[0x30] = 0x0f0f0f0f;
- s->padconf[0x31] = 0x0f1f0f1f;
- s->padconf[0x32] = 0x0f0f0f0f;
- s->padconf[0x33] = 0x0f1f0f1f;
- s->padconf[0x34] = 0x1f1f0f0f;
- s->padconf[0x35] = 0x0f0f1f1f;
- s->padconf[0x36] = 0x0f0f1f0f;
- s->padconf[0x37] = 0x0f0f0f0f;
- s->padconf[0x38] = 0x1f18180f;
- s->padconf[0x39] = 0x1f1f1f1f;
- s->padconf[0x3a] = 0x00001f1f;
- s->padconf[0x3b] = 0x00000000;
- s->padconf[0x3c] = 0x00000000;
- s->padconf[0x3d] = 0x0f0f0f0f;
- s->padconf[0x3e] = 0x18000f0f;
- s->padconf[0x3f] = 0x00070000;
- s->padconf[0x40] = 0x00000707;
- s->padconf[0x41] = 0x0f1f0700;
- s->padconf[0x42] = 0x1f1f070f;
- s->padconf[0x43] = 0x0008081f;
- s->padconf[0x44] = 0x00000800;
-}
-
-static struct omap_sysctl_s *omap_sysctl_init(struct omap_target_agent_s *ta,
- omap_clk iclk, struct omap_mpu_state_s *mpu)
-{
- struct omap_sysctl_s *s = g_new0(struct omap_sysctl_s, 1);
-
- s->mpu = mpu;
- omap_sysctl_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_sysctl_ops, s, "omap.sysctl",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &s->iomem);
-
- return s;
-}
-
-/* General chip reset */
-static void omap2_mpu_reset(void *opaque)
-{
- struct omap_mpu_state_s *mpu = opaque;
-
- omap_dma_reset(mpu->dma);
- omap_prcm_reset(mpu->prcm);
- omap_sysctl_reset(mpu->sysc);
- omap_gp_timer_reset(mpu->gptimer[0]);
- omap_gp_timer_reset(mpu->gptimer[1]);
- omap_gp_timer_reset(mpu->gptimer[2]);
- omap_gp_timer_reset(mpu->gptimer[3]);
- omap_gp_timer_reset(mpu->gptimer[4]);
- omap_gp_timer_reset(mpu->gptimer[5]);
- omap_gp_timer_reset(mpu->gptimer[6]);
- omap_gp_timer_reset(mpu->gptimer[7]);
- omap_gp_timer_reset(mpu->gptimer[8]);
- omap_gp_timer_reset(mpu->gptimer[9]);
- omap_gp_timer_reset(mpu->gptimer[10]);
- omap_gp_timer_reset(mpu->gptimer[11]);
- omap_synctimer_reset(mpu->synctimer);
- omap_sdrc_reset(mpu->sdrc);
- omap_gpmc_reset(mpu->gpmc);
- omap_dss_reset(mpu->dss);
- omap_uart_reset(mpu->uart[0]);
- omap_uart_reset(mpu->uart[1]);
- omap_uart_reset(mpu->uart[2]);
- omap_mmc_reset(mpu->mmc);
- omap_mcspi_reset(mpu->mcspi[0]);
- omap_mcspi_reset(mpu->mcspi[1]);
- cpu_reset(CPU(mpu->cpu));
-}
-
-static int omap2_validate_addr(struct omap_mpu_state_s *s,
- hwaddr addr)
-{
- return 1;
-}
-
-static const struct dma_irq_map omap2_dma_irq_map[] = {
- { 0, OMAP_INT_24XX_SDMA_IRQ0 },
- { 0, OMAP_INT_24XX_SDMA_IRQ1 },
- { 0, OMAP_INT_24XX_SDMA_IRQ2 },
- { 0, OMAP_INT_24XX_SDMA_IRQ3 },
-};
-
-struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sdram,
- const char *cpu_type)
-{
- struct omap_mpu_state_s *s = g_new0(struct omap_mpu_state_s, 1);
- qemu_irq dma_irqs[4];
- DriveInfo *dinfo;
- int i;
- SysBusDevice *busdev;
- struct omap_target_agent_s *ta;
- MemoryRegion *sysmem = get_system_memory();
-
- /* Core */
- s->mpu_model = omap2420;
- s->cpu = ARM_CPU(cpu_create(cpu_type));
- s->sram_size = OMAP242X_SRAM_SIZE;
-
- s->wakeup = qemu_allocate_irq(omap_mpu_wakeup, s, 0);
-
- /* Clocks */
- omap_clk_init(s);
-
- /* Memory-mapped stuff */
- memory_region_init_ram(&s->sram, NULL, "omap2.sram", s->sram_size,
- &error_fatal);
- memory_region_add_subregion(sysmem, OMAP2_SRAM_BASE, &s->sram);
-
- s->l4 = omap_l4_init(sysmem, OMAP2_L4_BASE, 54);
-
- /* Actually mapped at any 2K boundary in the ARM11 private-peripheral if */
- s->ih[0] = qdev_new("omap2-intc");
- qdev_prop_set_uint8(s->ih[0], "revision", 0x21);
- omap_intc_set_fclk(OMAP_INTC(s->ih[0]), omap_findclk(s, "mpu_intc_fclk"));
- omap_intc_set_iclk(OMAP_INTC(s->ih[0]), omap_findclk(s, "mpu_intc_iclk"));
- busdev = SYS_BUS_DEVICE(s->ih[0]);
- sysbus_realize_and_unref(busdev, &error_fatal);
- sysbus_connect_irq(busdev, 0,
- qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ));
- sysbus_connect_irq(busdev, 1,
- qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ));
- sysbus_mmio_map(busdev, 0, 0x480fe000);
- s->prcm = omap_prcm_init(omap_l4tao(s->l4, 3),
- qdev_get_gpio_in(s->ih[0],
- OMAP_INT_24XX_PRCM_MPU_IRQ),
- NULL, NULL, s);
-
- s->sysc = omap_sysctl_init(omap_l4tao(s->l4, 1),
- omap_findclk(s, "omapctrl_iclk"), s);
-
- for (i = 0; i < 4; i++) {
- dma_irqs[i] = qdev_get_gpio_in(s->ih[omap2_dma_irq_map[i].ih],
- omap2_dma_irq_map[i].intr);
- }
- s->dma = omap_dma4_init(0x48056000, dma_irqs, sysmem, s, 256, 32,
- omap_findclk(s, "sdma_iclk"),
- omap_findclk(s, "sdma_fclk"));
- s->port->addr_valid = omap2_validate_addr;
-
- /* Register SDRAM and SRAM ports for fast DMA transfers. */
- soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(sdram),
- OMAP2_Q2_BASE, memory_region_size(sdram));
- soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->sram),
- OMAP2_SRAM_BASE, s->sram_size);
-
- s->uart[0] = omap2_uart_init(sysmem, omap_l4ta(s->l4, 19),
- qdev_get_gpio_in(s->ih[0],
- OMAP_INT_24XX_UART1_IRQ),
- omap_findclk(s, "uart1_fclk"),
- omap_findclk(s, "uart1_iclk"),
- s->drq[OMAP24XX_DMA_UART1_TX],
- s->drq[OMAP24XX_DMA_UART1_RX],
- "uart1",
- serial_hd(0));
- s->uart[1] = omap2_uart_init(sysmem, omap_l4ta(s->l4, 20),
- qdev_get_gpio_in(s->ih[0],
- OMAP_INT_24XX_UART2_IRQ),
- omap_findclk(s, "uart2_fclk"),
- omap_findclk(s, "uart2_iclk"),
- s->drq[OMAP24XX_DMA_UART2_TX],
- s->drq[OMAP24XX_DMA_UART2_RX],
- "uart2",
- serial_hd(0) ? serial_hd(1) : NULL);
- s->uart[2] = omap2_uart_init(sysmem, omap_l4ta(s->l4, 21),
- qdev_get_gpio_in(s->ih[0],
- OMAP_INT_24XX_UART3_IRQ),
- omap_findclk(s, "uart3_fclk"),
- omap_findclk(s, "uart3_iclk"),
- s->drq[OMAP24XX_DMA_UART3_TX],
- s->drq[OMAP24XX_DMA_UART3_RX],
- "uart3",
- serial_hd(0) && serial_hd(1) ? serial_hd(2) : NULL);
-
- s->gptimer[0] = omap_gp_timer_init(omap_l4ta(s->l4, 7),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER1),
- omap_findclk(s, "wu_gpt1_clk"),
- omap_findclk(s, "wu_l4_iclk"));
- s->gptimer[1] = omap_gp_timer_init(omap_l4ta(s->l4, 8),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER2),
- omap_findclk(s, "core_gpt2_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[2] = omap_gp_timer_init(omap_l4ta(s->l4, 22),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER3),
- omap_findclk(s, "core_gpt3_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[3] = omap_gp_timer_init(omap_l4ta(s->l4, 23),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER4),
- omap_findclk(s, "core_gpt4_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[4] = omap_gp_timer_init(omap_l4ta(s->l4, 24),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER5),
- omap_findclk(s, "core_gpt5_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[5] = omap_gp_timer_init(omap_l4ta(s->l4, 25),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER6),
- omap_findclk(s, "core_gpt6_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[6] = omap_gp_timer_init(omap_l4ta(s->l4, 26),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER7),
- omap_findclk(s, "core_gpt7_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[7] = omap_gp_timer_init(omap_l4ta(s->l4, 27),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER8),
- omap_findclk(s, "core_gpt8_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[8] = omap_gp_timer_init(omap_l4ta(s->l4, 28),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER9),
- omap_findclk(s, "core_gpt9_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[9] = omap_gp_timer_init(omap_l4ta(s->l4, 29),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER10),
- omap_findclk(s, "core_gpt10_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[10] = omap_gp_timer_init(omap_l4ta(s->l4, 30),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER11),
- omap_findclk(s, "core_gpt11_clk"),
- omap_findclk(s, "core_l4_iclk"));
- s->gptimer[11] = omap_gp_timer_init(omap_l4ta(s->l4, 31),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPTIMER12),
- omap_findclk(s, "core_gpt12_clk"),
- omap_findclk(s, "core_l4_iclk"));
-
- omap_tap_init(omap_l4ta(s->l4, 2), s);
-
- s->synctimer = omap_synctimer_init(omap_l4tao(s->l4, 2), s,
- omap_findclk(s, "clk32-kHz"),
- omap_findclk(s, "core_l4_iclk"));
-
- s->i2c[0] = qdev_new("omap_i2c");
- qdev_prop_set_uint8(s->i2c[0], "revision", 0x34);
- omap_i2c_set_iclk(OMAP_I2C(s->i2c[0]), omap_findclk(s, "i2c1.iclk"));
- omap_i2c_set_fclk(OMAP_I2C(s->i2c[0]), omap_findclk(s, "i2c1.fclk"));
- busdev = SYS_BUS_DEVICE(s->i2c[0]);
- sysbus_realize_and_unref(busdev, &error_fatal);
- sysbus_connect_irq(busdev, 0,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C1_IRQ));
- sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_I2C1_TX]);
- sysbus_connect_irq(busdev, 2, s->drq[OMAP24XX_DMA_I2C1_RX]);
- sysbus_mmio_map(busdev, 0, omap_l4_region_base(omap_l4tao(s->l4, 5), 0));
-
- s->i2c[1] = qdev_new("omap_i2c");
- qdev_prop_set_uint8(s->i2c[1], "revision", 0x34);
- omap_i2c_set_iclk(OMAP_I2C(s->i2c[1]), omap_findclk(s, "i2c2.iclk"));
- omap_i2c_set_fclk(OMAP_I2C(s->i2c[1]), omap_findclk(s, "i2c2.fclk"));
- busdev = SYS_BUS_DEVICE(s->i2c[1]);
- sysbus_realize_and_unref(busdev, &error_fatal);
- sysbus_connect_irq(busdev, 0,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_I2C2_IRQ));
- sysbus_connect_irq(busdev, 1, s->drq[OMAP24XX_DMA_I2C2_TX]);
- sysbus_connect_irq(busdev, 2, s->drq[OMAP24XX_DMA_I2C2_RX]);
- sysbus_mmio_map(busdev, 0, omap_l4_region_base(omap_l4tao(s->l4, 6), 0));
-
- s->gpio = qdev_new("omap2-gpio");
- qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model);
- omap2_gpio_set_iclk(OMAP2_GPIO(s->gpio), omap_findclk(s, "gpio_iclk"));
- omap2_gpio_set_fclk(OMAP2_GPIO(s->gpio), 0, omap_findclk(s, "gpio1_dbclk"));
- omap2_gpio_set_fclk(OMAP2_GPIO(s->gpio), 1, omap_findclk(s, "gpio2_dbclk"));
- omap2_gpio_set_fclk(OMAP2_GPIO(s->gpio), 2, omap_findclk(s, "gpio3_dbclk"));
- omap2_gpio_set_fclk(OMAP2_GPIO(s->gpio), 3, omap_findclk(s, "gpio4_dbclk"));
- if (s->mpu_model == omap2430) {
- omap2_gpio_set_fclk(OMAP2_GPIO(s->gpio), 4,
- omap_findclk(s, "gpio5_dbclk"));
- }
- busdev = SYS_BUS_DEVICE(s->gpio);
- sysbus_realize_and_unref(busdev, &error_fatal);
- sysbus_connect_irq(busdev, 0,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK1));
- sysbus_connect_irq(busdev, 3,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK2));
- sysbus_connect_irq(busdev, 6,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK3));
- sysbus_connect_irq(busdev, 9,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPIO_BANK4));
- if (s->mpu_model == omap2430) {
- sysbus_connect_irq(busdev, 12,
- qdev_get_gpio_in(s->ih[0],
- OMAP_INT_243X_GPIO_BANK5));
- }
- ta = omap_l4ta(s->l4, 3);
- sysbus_mmio_map(busdev, 0, omap_l4_region_base(ta, 1));
- sysbus_mmio_map(busdev, 1, omap_l4_region_base(ta, 0));
- sysbus_mmio_map(busdev, 2, omap_l4_region_base(ta, 2));
- sysbus_mmio_map(busdev, 3, omap_l4_region_base(ta, 4));
- sysbus_mmio_map(busdev, 4, omap_l4_region_base(ta, 5));
-
- s->sdrc = omap_sdrc_init(sysmem, 0x68009000);
- s->gpmc = omap_gpmc_init(s, 0x6800a000,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_GPMC_IRQ),
- s->drq[OMAP24XX_DMA_GPMC]);
-
- dinfo = drive_get(IF_SD, 0, 0);
- if (!dinfo && !qtest_enabled()) {
- warn_report("missing SecureDigital device");
- }
- s->mmc = omap2_mmc_init(omap_l4tao(s->l4, 9),
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MMC_IRQ),
- &s->drq[OMAP24XX_DMA_MMC1_TX],
- omap_findclk(s, "mmc_fclk"), omap_findclk(s, "mmc_iclk"));
-
- s->mcspi[0] = omap_mcspi_init(omap_l4ta(s->l4, 35), 4,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MCSPI1_IRQ),
- &s->drq[OMAP24XX_DMA_SPI1_TX0],
- omap_findclk(s, "spi1_fclk"),
- omap_findclk(s, "spi1_iclk"));
- s->mcspi[1] = omap_mcspi_init(omap_l4ta(s->l4, 36), 2,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MCSPI2_IRQ),
- &s->drq[OMAP24XX_DMA_SPI2_TX0],
- omap_findclk(s, "spi2_fclk"),
- omap_findclk(s, "spi2_iclk"));
-
- s->dss = omap_dss_init(omap_l4ta(s->l4, 10), sysmem, 0x68000800,
- /* XXX wire M_IRQ_25, D_L2_IRQ_30 and I_IRQ_13 together */
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_DSS_IRQ),
- s->drq[OMAP24XX_DMA_DSS],
- omap_findclk(s, "dss_clk1"), omap_findclk(s, "dss_clk2"),
- omap_findclk(s, "dss_54m_clk"),
- omap_findclk(s, "dss_l3_iclk"),
- omap_findclk(s, "dss_l4_iclk"));
-
- omap_sti_init(omap_l4ta(s->l4, 18), sysmem, 0x54000000,
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_STI),
- omap_findclk(s, "emul_ck"),
- serial_hd(0) && serial_hd(1) && serial_hd(2) ?
- serial_hd(3) : NULL);
-
- s->eac = omap_eac_init(omap_l4ta(s->l4, 32),
- qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_EAC_IRQ),
- /* Ten consecutive lines */
- &s->drq[OMAP24XX_DMA_EAC_AC_RD],
- omap_findclk(s, "func_96m_clk"),
- omap_findclk(s, "core_l4_iclk"));
-
- /* All register mappings (including those not currently implemented):
- * SystemControlMod 48000000 - 48000fff
- * SystemControlL4 48001000 - 48001fff
- * 32kHz Timer Mod 48004000 - 48004fff
- * 32kHz Timer L4 48005000 - 48005fff
- * PRCM ModA 48008000 - 480087ff
- * PRCM ModB 48008800 - 48008fff
- * PRCM L4 48009000 - 48009fff
- * TEST-BCM Mod 48012000 - 48012fff
- * TEST-BCM L4 48013000 - 48013fff
- * TEST-TAP Mod 48014000 - 48014fff
- * TEST-TAP L4 48015000 - 48015fff
- * GPIO1 Mod 48018000 - 48018fff
- * GPIO Top 48019000 - 48019fff
- * GPIO2 Mod 4801a000 - 4801afff
- * GPIO L4 4801b000 - 4801bfff
- * GPIO3 Mod 4801c000 - 4801cfff
- * GPIO4 Mod 4801e000 - 4801efff
- * WDTIMER1 Mod 48020000 - 48010fff
- * WDTIMER Top 48021000 - 48011fff
- * WDTIMER2 Mod 48022000 - 48012fff
- * WDTIMER L4 48023000 - 48013fff
- * WDTIMER3 Mod 48024000 - 48014fff
- * WDTIMER3 L4 48025000 - 48015fff
- * WDTIMER4 Mod 48026000 - 48016fff
- * WDTIMER4 L4 48027000 - 48017fff
- * GPTIMER1 Mod 48028000 - 48018fff
- * GPTIMER1 L4 48029000 - 48019fff
- * GPTIMER2 Mod 4802a000 - 4801afff
- * GPTIMER2 L4 4802b000 - 4801bfff
- * L4-Config AP 48040000 - 480407ff
- * L4-Config IP 48040800 - 48040fff
- * L4-Config LA 48041000 - 48041fff
- * ARM11ETB Mod 48048000 - 48049fff
- * ARM11ETB L4 4804a000 - 4804afff
- * DISPLAY Top 48050000 - 480503ff
- * DISPLAY DISPC 48050400 - 480507ff
- * DISPLAY RFBI 48050800 - 48050bff
- * DISPLAY VENC 48050c00 - 48050fff
- * DISPLAY L4 48051000 - 48051fff
- * CAMERA Top 48052000 - 480523ff
- * CAMERA core 48052400 - 480527ff
- * CAMERA DMA 48052800 - 48052bff
- * CAMERA MMU 48052c00 - 48052fff
- * CAMERA L4 48053000 - 48053fff
- * SDMA Mod 48056000 - 48056fff
- * SDMA L4 48057000 - 48057fff
- * SSI Top 48058000 - 48058fff
- * SSI GDD 48059000 - 48059fff
- * SSI Port1 4805a000 - 4805afff
- * SSI Port2 4805b000 - 4805bfff
- * SSI L4 4805c000 - 4805cfff
- * USB Mod 4805e000 - 480fefff
- * USB L4 4805f000 - 480fffff
- * WIN_TRACER1 Mod 48060000 - 48060fff
- * WIN_TRACER1 L4 48061000 - 48061fff
- * WIN_TRACER2 Mod 48062000 - 48062fff
- * WIN_TRACER2 L4 48063000 - 48063fff
- * WIN_TRACER3 Mod 48064000 - 48064fff
- * WIN_TRACER3 L4 48065000 - 48065fff
- * WIN_TRACER4 Top 48066000 - 480660ff
- * WIN_TRACER4 ETT 48066100 - 480661ff
- * WIN_TRACER4 WT 48066200 - 480662ff
- * WIN_TRACER4 L4 48067000 - 48067fff
- * XTI Mod 48068000 - 48068fff
- * XTI L4 48069000 - 48069fff
- * UART1 Mod 4806a000 - 4806afff
- * UART1 L4 4806b000 - 4806bfff
- * UART2 Mod 4806c000 - 4806cfff
- * UART2 L4 4806d000 - 4806dfff
- * UART3 Mod 4806e000 - 4806efff
- * UART3 L4 4806f000 - 4806ffff
- * I2C1 Mod 48070000 - 48070fff
- * I2C1 L4 48071000 - 48071fff
- * I2C2 Mod 48072000 - 48072fff
- * I2C2 L4 48073000 - 48073fff
- * McBSP1 Mod 48074000 - 48074fff
- * McBSP1 L4 48075000 - 48075fff
- * McBSP2 Mod 48076000 - 48076fff
- * McBSP2 L4 48077000 - 48077fff
- * GPTIMER3 Mod 48078000 - 48078fff
- * GPTIMER3 L4 48079000 - 48079fff
- * GPTIMER4 Mod 4807a000 - 4807afff
- * GPTIMER4 L4 4807b000 - 4807bfff
- * GPTIMER5 Mod 4807c000 - 4807cfff
- * GPTIMER5 L4 4807d000 - 4807dfff
- * GPTIMER6 Mod 4807e000 - 4807efff
- * GPTIMER6 L4 4807f000 - 4807ffff
- * GPTIMER7 Mod 48080000 - 48080fff
- * GPTIMER7 L4 48081000 - 48081fff
- * GPTIMER8 Mod 48082000 - 48082fff
- * GPTIMER8 L4 48083000 - 48083fff
- * GPTIMER9 Mod 48084000 - 48084fff
- * GPTIMER9 L4 48085000 - 48085fff
- * GPTIMER10 Mod 48086000 - 48086fff
- * GPTIMER10 L4 48087000 - 48087fff
- * GPTIMER11 Mod 48088000 - 48088fff
- * GPTIMER11 L4 48089000 - 48089fff
- * GPTIMER12 Mod 4808a000 - 4808afff
- * GPTIMER12 L4 4808b000 - 4808bfff
- * EAC Mod 48090000 - 48090fff
- * EAC L4 48091000 - 48091fff
- * FAC Mod 48092000 - 48092fff
- * FAC L4 48093000 - 48093fff
- * MAILBOX Mod 48094000 - 48094fff
- * MAILBOX L4 48095000 - 48095fff
- * SPI1 Mod 48098000 - 48098fff
- * SPI1 L4 48099000 - 48099fff
- * SPI2 Mod 4809a000 - 4809afff
- * SPI2 L4 4809b000 - 4809bfff
- * MMC/SDIO Mod 4809c000 - 4809cfff
- * MMC/SDIO L4 4809d000 - 4809dfff
- * MS_PRO Mod 4809e000 - 4809efff
- * MS_PRO L4 4809f000 - 4809ffff
- * RNG Mod 480a0000 - 480a0fff
- * RNG L4 480a1000 - 480a1fff
- * DES3DES Mod 480a2000 - 480a2fff
- * DES3DES L4 480a3000 - 480a3fff
- * SHA1MD5 Mod 480a4000 - 480a4fff
- * SHA1MD5 L4 480a5000 - 480a5fff
- * AES Mod 480a6000 - 480a6fff
- * AES L4 480a7000 - 480a7fff
- * PKA Mod 480a8000 - 480a9fff
- * PKA L4 480aa000 - 480aafff
- * MG Mod 480b0000 - 480b0fff
- * MG L4 480b1000 - 480b1fff
- * HDQ/1-wire Mod 480b2000 - 480b2fff
- * HDQ/1-wire L4 480b3000 - 480b3fff
- * MPU interrupt 480fe000 - 480fefff
- * STI channel base 54000000 - 5400ffff
- * IVA RAM 5c000000 - 5c01ffff
- * IVA ROM 5c020000 - 5c027fff
- * IMG_BUF_A 5c040000 - 5c040fff
- * IMG_BUF_B 5c042000 - 5c042fff
- * VLCDS 5c048000 - 5c0487ff
- * IMX_COEF 5c049000 - 5c04afff
- * IMX_CMD 5c051000 - 5c051fff
- * VLCDQ 5c053000 - 5c0533ff
- * VLCDH 5c054000 - 5c054fff
- * SEQ_CMD 5c055000 - 5c055fff
- * IMX_REG 5c056000 - 5c0560ff
- * VLCD_REG 5c056100 - 5c0561ff
- * SEQ_REG 5c056200 - 5c0562ff
- * IMG_BUF_REG 5c056300 - 5c0563ff
- * SEQIRQ_REG 5c056400 - 5c0564ff
- * OCP_REG 5c060000 - 5c060fff
- * SYSC_REG 5c070000 - 5c070fff
- * MMU_REG 5d000000 - 5d000fff
- * sDMA R 68000400 - 680005ff
- * sDMA W 68000600 - 680007ff
- * Display Control 68000800 - 680009ff
- * DSP subsystem 68000a00 - 68000bff
- * MPU subsystem 68000c00 - 68000dff
- * IVA subsystem 68001000 - 680011ff
- * USB 68001200 - 680013ff
- * Camera 68001400 - 680015ff
- * VLYNQ (firewall) 68001800 - 68001bff
- * VLYNQ 68001e00 - 68001fff
- * SSI 68002000 - 680021ff
- * L4 68002400 - 680025ff
- * DSP (firewall) 68002800 - 68002bff
- * DSP subsystem 68002e00 - 68002fff
- * IVA (firewall) 68003000 - 680033ff
- * IVA 68003600 - 680037ff
- * GFX 68003a00 - 68003bff
- * CMDWR emulation 68003c00 - 68003dff
- * SMS 68004000 - 680041ff
- * OCM 68004200 - 680043ff
- * GPMC 68004400 - 680045ff
- * RAM (firewall) 68005000 - 680053ff
- * RAM (err login) 68005400 - 680057ff
- * ROM (firewall) 68005800 - 68005bff
- * ROM (err login) 68005c00 - 68005fff
- * GPMC (firewall) 68006000 - 680063ff
- * GPMC (err login) 68006400 - 680067ff
- * SMS (err login) 68006c00 - 68006fff
- * SMS registers 68008000 - 68008fff
- * SDRC registers 68009000 - 68009fff
- * GPMC registers 6800a000 6800afff
- */
-
- qemu_register_reset(omap2_mpu_reset, s);
-
- return s;
-}
diff --git a/hw/arm/palm.c b/hw/arm/palm.c
deleted file mode 100644
index e04ac92..0000000
--- a/hw/arm/palm.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * PalmOne's (TM) PDAs.
- *
- * Copyright (C) 2006-2007 Andrzej Zaborowski <balrog@zabor.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "audio/audio.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/qtest.h"
-#include "ui/console.h"
-#include "hw/arm/omap.h"
-#include "hw/boards.h"
-#include "hw/arm/boot.h"
-#include "hw/input/tsc2xxx.h"
-#include "hw/irq.h"
-#include "hw/loader.h"
-#include "qemu/cutils.h"
-#include "qom/object.h"
-#include "qemu/error-report.h"
-
-
-static uint64_t static_read(void *opaque, hwaddr offset, unsigned size)
-{
- uint32_t *val = (uint32_t *)opaque;
- uint32_t sizemask = 7 >> size;
-
- return *val >> ((offset & sizemask) << 3);
-}
-
-static void static_write(void *opaque, hwaddr offset, uint64_t value,
- unsigned size)
-{
-#ifdef SPY
- printf("%s: value %08lx written at " PA_FMT "\n",
- __func__, value, offset);
-#endif
-}
-
-static const MemoryRegionOps static_ops = {
- .read = static_read,
- .write = static_write,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/* Palm Tunsgten|E support */
-
-/* Shared GPIOs */
-#define PALMTE_USBDETECT_GPIO 0
-#define PALMTE_USB_OR_DC_GPIO 1
-#define PALMTE_TSC_GPIO 4
-#define PALMTE_PINTDAV_GPIO 6
-#define PALMTE_MMC_WP_GPIO 8
-#define PALMTE_MMC_POWER_GPIO 9
-#define PALMTE_HDQ_GPIO 11
-#define PALMTE_HEADPHONES_GPIO 14
-#define PALMTE_SPEAKER_GPIO 15
-/* MPU private GPIOs */
-#define PALMTE_DC_GPIO 2
-#define PALMTE_MMC_SWITCH_GPIO 4
-#define PALMTE_MMC1_GPIO 6
-#define PALMTE_MMC2_GPIO 7
-#define PALMTE_MMC3_GPIO 11
-
-static MouseTransformInfo palmte_pointercal = {
- .x = 320,
- .y = 320,
- .a = { -5909, 8, 22465308, 104, 7644, -1219972, 65536 },
-};
-
-static void palmte_microwire_setup(struct omap_mpu_state_s *cpu)
-{
- uWireSlave *tsc;
-
- tsc = tsc2102_init(qdev_get_gpio_in(cpu->gpio, PALMTE_PINTDAV_GPIO));
-
- omap_uwire_attach(cpu->microwire, tsc, 0);
- omap_mcbsp_i2s_attach(cpu->mcbsp1, tsc210x_codec(tsc));
-
- tsc210x_set_transform(tsc, &palmte_pointercal);
-}
-
-static struct {
- int row;
- int column;
-} palmte_keymap[0x80] = {
- [0 ... 0x7f] = { -1, -1 },
- [0x3b] = { 0, 0 }, /* F1 -> Calendar */
- [0x3c] = { 1, 0 }, /* F2 -> Contacts */
- [0x3d] = { 2, 0 }, /* F3 -> Tasks List */
- [0x3e] = { 3, 0 }, /* F4 -> Note Pad */
- [0x01] = { 4, 0 }, /* Esc -> Power */
- [0x4b] = { 0, 1 }, /* Left */
- [0x50] = { 1, 1 }, /* Down */
- [0x48] = { 2, 1 }, /* Up */
- [0x4d] = { 3, 1 }, /* Right */
- [0x4c] = { 4, 1 }, /* Centre */
- [0x39] = { 4, 1 }, /* Spc -> Centre */
-};
-
-static void palmte_button_event(void *opaque, int keycode)
-{
- struct omap_mpu_state_s *cpu = opaque;
-
- if (palmte_keymap[keycode & 0x7f].row != -1)
- omap_mpuio_key(cpu->mpuio,
- palmte_keymap[keycode & 0x7f].row,
- palmte_keymap[keycode & 0x7f].column,
- !(keycode & 0x80));
-}
-
-/*
- * Encapsulation of some GPIO line behaviour for the Palm board
- *
- * QEMU interface:
- * + unnamed GPIO inputs 0..6: for the various miscellaneous input lines
- */
-
-#define TYPE_PALM_MISC_GPIO "palm-misc-gpio"
-OBJECT_DECLARE_SIMPLE_TYPE(PalmMiscGPIOState, PALM_MISC_GPIO)
-
-struct PalmMiscGPIOState {
- SysBusDevice parent_obj;
-};
-
-static void palmte_onoff_gpios(void *opaque, int line, int level)
-{
- switch (line) {
- case 0:
- printf("%s: current to MMC/SD card %sabled.\n",
- __func__, level ? "dis" : "en");
- break;
- case 1:
- printf("%s: internal speaker amplifier %s.\n",
- __func__, level ? "down" : "on");
- break;
-
- /* These LCD & Audio output signals have not been identified yet. */
- case 2:
- case 3:
- case 4:
- printf("%s: LCD GPIO%i %s.\n",
- __func__, line - 1, level ? "high" : "low");
- break;
- case 5:
- case 6:
- printf("%s: Audio GPIO%i %s.\n",
- __func__, line - 4, level ? "high" : "low");
- break;
- }
-}
-
-static void palm_misc_gpio_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
-
- qdev_init_gpio_in(dev, palmte_onoff_gpios, 7);
-}
-
-static const TypeInfo palm_misc_gpio_info = {
- .name = TYPE_PALM_MISC_GPIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PalmMiscGPIOState),
- .instance_init = palm_misc_gpio_init,
- /*
- * No class init required: device has no internal state so does not
- * need to set up reset or vmstate, and has no realize method.
- */
-};
-
-static void palmte_gpio_setup(struct omap_mpu_state_s *cpu)
-{
- DeviceState *misc_gpio;
-
- misc_gpio = sysbus_create_simple(TYPE_PALM_MISC_GPIO, -1, NULL);
-
- omap_mmc_handlers(cpu->mmc,
- qdev_get_gpio_in(cpu->gpio, PALMTE_MMC_WP_GPIO),
- qemu_irq_invert(omap_mpuio_in_get(cpu->mpuio)
- [PALMTE_MMC_SWITCH_GPIO]));
-
- qdev_connect_gpio_out(cpu->gpio, PALMTE_MMC_POWER_GPIO,
- qdev_get_gpio_in(misc_gpio, 0));
- qdev_connect_gpio_out(cpu->gpio, PALMTE_SPEAKER_GPIO,
- qdev_get_gpio_in(misc_gpio, 1));
- qdev_connect_gpio_out(cpu->gpio, 11, qdev_get_gpio_in(misc_gpio, 2));
- qdev_connect_gpio_out(cpu->gpio, 12, qdev_get_gpio_in(misc_gpio, 3));
- qdev_connect_gpio_out(cpu->gpio, 13, qdev_get_gpio_in(misc_gpio, 4));
- omap_mpuio_out_set(cpu->mpuio, 1, qdev_get_gpio_in(misc_gpio, 5));
- omap_mpuio_out_set(cpu->mpuio, 3, qdev_get_gpio_in(misc_gpio, 6));
-
- /* Reset some inputs to initial state. */
- qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USBDETECT_GPIO));
- qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USB_OR_DC_GPIO));
- qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, 4));
- qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_HEADPHONES_GPIO));
- qemu_irq_lower(omap_mpuio_in_get(cpu->mpuio)[PALMTE_DC_GPIO]);
- qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[6]);
- qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[7]);
- qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[11]);
-}
-
-static struct arm_boot_info palmte_binfo = {
- .loader_start = OMAP_EMIFF_BASE,
- .ram_size = 0x02000000,
- .board_id = 0x331,
-};
-
-static void palmte_init(MachineState *machine)
-{
- MemoryRegion *address_space_mem = get_system_memory();
- struct omap_mpu_state_s *mpu;
- int flash_size = 0x00800000;
- static uint32_t cs0val = 0xffffffff;
- static uint32_t cs1val = 0x0000e1a0;
- static uint32_t cs2val = 0x0000e1a0;
- static uint32_t cs3val = 0xe1a0e1a0;
- int rom_size, rom_loaded = 0;
- MachineClass *mc = MACHINE_GET_CLASS(machine);
- MemoryRegion *flash = g_new(MemoryRegion, 1);
- MemoryRegion *cs = g_new(MemoryRegion, 4);
-
- 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_region_add_subregion(address_space_mem, OMAP_EMIFF_BASE,
- machine->ram);
-
- mpu = omap310_mpu_init(machine->ram, machine->cpu_type);
-
- /* External Flash (EMIFS) */
- memory_region_init_rom(flash, NULL, "palmte.flash", flash_size,
- &error_fatal);
- memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE, flash);
-
- memory_region_init_io(&cs[0], NULL, &static_ops, &cs0val, "palmte-cs0",
- OMAP_CS0_SIZE - flash_size);
- memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE + flash_size,
- &cs[0]);
- memory_region_init_io(&cs[1], NULL, &static_ops, &cs1val, "palmte-cs1",
- OMAP_CS1_SIZE);
- memory_region_add_subregion(address_space_mem, OMAP_CS1_BASE, &cs[1]);
- memory_region_init_io(&cs[2], NULL, &static_ops, &cs2val, "palmte-cs2",
- OMAP_CS2_SIZE);
- memory_region_add_subregion(address_space_mem, OMAP_CS2_BASE, &cs[2]);
- memory_region_init_io(&cs[3], NULL, &static_ops, &cs3val, "palmte-cs3",
- OMAP_CS3_SIZE);
- memory_region_add_subregion(address_space_mem, OMAP_CS3_BASE, &cs[3]);
-
- palmte_microwire_setup(mpu);
-
- qemu_add_kbd_event_handler(palmte_button_event, mpu);
-
- palmte_gpio_setup(mpu);
-
- /* Setup initial (reset) machine state */
- if (nb_option_roms) {
- rom_size = get_image_size(option_rom[0].name);
- if (rom_size > flash_size) {
- fprintf(stderr, "%s: ROM image too big (%x > %x)\n",
- __func__, rom_size, flash_size);
- rom_size = 0;
- }
- if (rom_size > 0) {
- rom_size = load_image_targphys(option_rom[0].name, OMAP_CS0_BASE,
- flash_size);
- rom_loaded = 1;
- }
- if (rom_size < 0) {
- fprintf(stderr, "%s: error loading '%s'\n",
- __func__, option_rom[0].name);
- }
- }
-
- if (!rom_loaded && !machine->kernel_filename && !qtest_enabled()) {
- fprintf(stderr, "Kernel or ROM image must be specified\n");
- exit(1);
- }
-
- /* Load the kernel. */
- arm_load_kernel(mpu->cpu, machine, &palmte_binfo);
-}
-
-static void palmte_machine_init(MachineClass *mc)
-{
- mc->desc = "Palm Tungsten|E aka. Cheetah PDA (OMAP310)";
- mc->init = palmte_init;
- mc->ignore_memory_transaction_failures = true;
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("ti925t");
- mc->default_ram_size = 0x02000000;
- mc->default_ram_id = "omap1.dram";
- mc->deprecation_reason = "machine is old and unmaintained";
-
- machine_add_audiodev_property(mc);
-}
-
-DEFINE_MACHINE("cheetah", palmte_machine_init)
-
-static void palm_register_types(void)
-{
- type_register_static(&palm_misc_gpio_info);
-}
-
-type_init(palm_register_types)
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
deleted file mode 100644
index 6b2e544..0000000
--- a/hw/arm/pxa2xx.c
+++ /dev/null
@@ -1,2393 +0,0 @@
-/*
- * Intel XScale PXA255/270 processor support.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/error-report.h"
-#include "qemu/module.h"
-#include "qapi/error.h"
-#include "exec/address-spaces.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "hw/arm/pxa.h"
-#include "sysemu/sysemu.h"
-#include "hw/char/serial.h"
-#include "hw/i2c/i2c.h"
-#include "hw/irq.h"
-#include "hw/qdev-properties.h"
-#include "hw/qdev-properties-system.h"
-#include "hw/ssi/ssi.h"
-#include "hw/sd/sd.h"
-#include "chardev/char-fe.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/qtest.h"
-#include "sysemu/rtc.h"
-#include "qemu/cutils.h"
-#include "qemu/log.h"
-#include "qom/object.h"
-#include "target/arm/cpregs.h"
-
-static struct {
- hwaddr io_base;
- int irqn;
-} pxa255_serial[] = {
- { 0x40100000, PXA2XX_PIC_FFUART },
- { 0x40200000, PXA2XX_PIC_BTUART },
- { 0x40700000, PXA2XX_PIC_STUART },
- { 0x41600000, PXA25X_PIC_HWUART },
- { 0, 0 }
-}, pxa270_serial[] = {
- { 0x40100000, PXA2XX_PIC_FFUART },
- { 0x40200000, PXA2XX_PIC_BTUART },
- { 0x40700000, PXA2XX_PIC_STUART },
- { 0, 0 }
-};
-
-typedef struct PXASSPDef {
- hwaddr io_base;
- int irqn;
-} PXASSPDef;
-
-#if 0
-static PXASSPDef pxa250_ssp[] = {
- { 0x41000000, PXA2XX_PIC_SSP },
- { 0, 0 }
-};
-#endif
-
-static PXASSPDef pxa255_ssp[] = {
- { 0x41000000, PXA2XX_PIC_SSP },
- { 0x41400000, PXA25X_PIC_NSSP },
- { 0, 0 }
-};
-
-#if 0
-static PXASSPDef pxa26x_ssp[] = {
- { 0x41000000, PXA2XX_PIC_SSP },
- { 0x41400000, PXA25X_PIC_NSSP },
- { 0x41500000, PXA26X_PIC_ASSP },
- { 0, 0 }
-};
-#endif
-
-static PXASSPDef pxa27x_ssp[] = {
- { 0x41000000, PXA2XX_PIC_SSP },
- { 0x41700000, PXA27X_PIC_SSP2 },
- { 0x41900000, PXA2XX_PIC_SSP3 },
- { 0, 0 }
-};
-
-#define PMCR 0x00 /* Power Manager Control register */
-#define PSSR 0x04 /* Power Manager Sleep Status register */
-#define PSPR 0x08 /* Power Manager Scratch-Pad register */
-#define PWER 0x0c /* Power Manager Wake-Up Enable register */
-#define PRER 0x10 /* Power Manager Rising-Edge Detect Enable register */
-#define PFER 0x14 /* Power Manager Falling-Edge Detect Enable register */
-#define PEDR 0x18 /* Power Manager Edge-Detect Status register */
-#define PCFR 0x1c /* Power Manager General Configuration register */
-#define PGSR0 0x20 /* Power Manager GPIO Sleep-State register 0 */
-#define PGSR1 0x24 /* Power Manager GPIO Sleep-State register 1 */
-#define PGSR2 0x28 /* Power Manager GPIO Sleep-State register 2 */
-#define PGSR3 0x2c /* Power Manager GPIO Sleep-State register 3 */
-#define RCSR 0x30 /* Reset Controller Status register */
-#define PSLR 0x34 /* Power Manager Sleep Configuration register */
-#define PTSR 0x38 /* Power Manager Standby Configuration register */
-#define PVCR 0x40 /* Power Manager Voltage Change Control register */
-#define PUCR 0x4c /* Power Manager USIM Card Control/Status register */
-#define PKWR 0x50 /* Power Manager Keyboard Wake-Up Enable register */
-#define PKSR 0x54 /* Power Manager Keyboard Level-Detect Status */
-#define PCMD0 0x80 /* Power Manager I2C Command register File 0 */
-#define PCMD31 0xfc /* Power Manager I2C Command register File 31 */
-
-static uint64_t pxa2xx_pm_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxState *s = (PXA2xxState *) opaque;
-
- switch (addr) {
- case PMCR ... PCMD31:
- if (addr & 3)
- goto fail;
-
- return s->pm_regs[addr >> 2];
- default:
- fail:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_pm_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- PXA2xxState *s = (PXA2xxState *) opaque;
-
- switch (addr) {
- case PMCR:
- /* Clear the write-one-to-clear bits... */
- s->pm_regs[addr >> 2] &= ~(value & 0x2a);
- /* ...and set the plain r/w bits */
- s->pm_regs[addr >> 2] &= ~0x15;
- s->pm_regs[addr >> 2] |= value & 0x15;
- break;
-
- case PSSR: /* Read-clean registers */
- case RCSR:
- case PKSR:
- s->pm_regs[addr >> 2] &= ~value;
- break;
-
- default: /* Read-write registers */
- if (!(addr & 3)) {
- s->pm_regs[addr >> 2] = value;
- break;
- }
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
-}
-
-static const MemoryRegionOps pxa2xx_pm_ops = {
- .read = pxa2xx_pm_read,
- .write = pxa2xx_pm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pxa2xx_pm = {
- .name = "pxa2xx_pm",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32_ARRAY(pm_regs, PXA2xxState, 0x40),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#define CCCR 0x00 /* Core Clock Configuration register */
-#define CKEN 0x04 /* Clock Enable register */
-#define OSCC 0x08 /* Oscillator Configuration register */
-#define CCSR 0x0c /* Core Clock Status register */
-
-static uint64_t pxa2xx_cm_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxState *s = (PXA2xxState *) opaque;
-
- switch (addr) {
- case CCCR:
- case CKEN:
- case OSCC:
- return s->cm_regs[addr >> 2];
-
- case CCSR:
- return s->cm_regs[CCCR >> 2] | (3 << 28);
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_cm_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- PXA2xxState *s = (PXA2xxState *) opaque;
-
- switch (addr) {
- case CCCR:
- case CKEN:
- s->cm_regs[addr >> 2] = value;
- break;
-
- case OSCC:
- s->cm_regs[addr >> 2] &= ~0x6c;
- s->cm_regs[addr >> 2] |= value & 0x6e;
- if ((value >> 1) & 1) /* OON */
- s->cm_regs[addr >> 2] |= 1 << 0; /* Oscillator is now stable */
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
-}
-
-static const MemoryRegionOps pxa2xx_cm_ops = {
- .read = pxa2xx_cm_read,
- .write = pxa2xx_cm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pxa2xx_cm = {
- .name = "pxa2xx_cm",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32_ARRAY(cm_regs, PXA2xxState, 4),
- VMSTATE_UINT32(clkcfg, PXA2xxState),
- VMSTATE_UINT32(pmnc, PXA2xxState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static uint64_t pxa2xx_clkcfg_read(CPUARMState *env, const ARMCPRegInfo *ri)
-{
- PXA2xxState *s = (PXA2xxState *)ri->opaque;
- return s->clkcfg;
-}
-
-static void pxa2xx_clkcfg_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- PXA2xxState *s = (PXA2xxState *)ri->opaque;
- s->clkcfg = value & 0xf;
- if (value & 2) {
- printf("%s: CPU frequency change attempt\n", __func__);
- }
-}
-
-static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- PXA2xxState *s = (PXA2xxState *)ri->opaque;
- static const char *pwrmode[8] = {
- "Normal", "Idle", "Deep-idle", "Standby",
- "Sleep", "reserved (!)", "reserved (!)", "Deep-sleep",
- };
-
- if (value & 8) {
- printf("%s: CPU voltage change attempt\n", __func__);
- }
- switch (value & 7) {
- case 0:
- /* Do nothing */
- break;
-
- case 1:
- /* Idle */
- if (!(s->cm_regs[CCCR >> 2] & (1U << 31))) { /* CPDIS */
- cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HALT);
- break;
- }
- /* Fall through. */
-
- case 2:
- /* Deep-Idle */
- cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HALT);
- s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
- goto message;
-
- case 3:
- s->cpu->env.uncached_cpsr = ARM_CPU_MODE_SVC;
- s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I;
- s->cpu->env.cp15.sctlr_ns = 0;
- s->cpu->env.cp15.cpacr_el1 = 0;
- s->cpu->env.cp15.ttbr0_el[1] = 0;
- s->cpu->env.cp15.dacr_ns = 0;
- s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */
- s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
-
- /*
- * The scratch-pad register is almost universally used
- * for storing the return address on suspend. For the
- * lack of a resuming bootloader, perform a jump
- * directly to that address.
- */
- memset(s->cpu->env.regs, 0, 4 * 15);
- s->cpu->env.regs[15] = s->pm_regs[PSPR >> 2];
-
-#if 0
- buffer = 0xe59ff000; /* ldr pc, [pc, #0] */
- cpu_physical_memory_write(0, &buffer, 4);
- buffer = s->pm_regs[PSPR >> 2];
- cpu_physical_memory_write(8, &buffer, 4);
-#endif
-
- /* Suspend */
- cpu_interrupt(current_cpu, CPU_INTERRUPT_HALT);
-
- goto message;
-
- default:
- message:
- printf("%s: machine entered %s mode\n", __func__,
- pwrmode[value & 7]);
- }
-}
-
-static uint64_t pxa2xx_cppmnc_read(CPUARMState *env, const ARMCPRegInfo *ri)
-{
- PXA2xxState *s = (PXA2xxState *)ri->opaque;
- return s->pmnc;
-}
-
-static void pxa2xx_cppmnc_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- PXA2xxState *s = (PXA2xxState *)ri->opaque;
- s->pmnc = value;
-}
-
-static uint64_t pxa2xx_cpccnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
-{
- PXA2xxState *s = (PXA2xxState *)ri->opaque;
- if (s->pmnc & 1) {
- return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- } else {
- return 0;
- }
-}
-
-static const ARMCPRegInfo pxa_cp_reginfo[] = {
- /* cp14 crm==1: perf registers */
- { .name = "CPPMNC", .cp = 14, .crn = 0, .crm = 1, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_IO,
- .readfn = pxa2xx_cppmnc_read, .writefn = pxa2xx_cppmnc_write },
- { .name = "CPCCNT", .cp = 14, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_IO,
- .readfn = pxa2xx_cpccnt_read, .writefn = arm_cp_write_ignore },
- { .name = "CPINTEN", .cp = 14, .crn = 4, .crm = 1, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
- { .name = "CPFLAG", .cp = 14, .crn = 5, .crm = 1, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
- { .name = "CPEVTSEL", .cp = 14, .crn = 8, .crm = 1, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
- /* cp14 crm==2: performance count registers */
- { .name = "CPPMN0", .cp = 14, .crn = 0, .crm = 2, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
- { .name = "CPPMN1", .cp = 14, .crn = 1, .crm = 2, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
- { .name = "CPPMN2", .cp = 14, .crn = 2, .crm = 2, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
- { .name = "CPPMN3", .cp = 14, .crn = 2, .crm = 3, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
- /* cp14 crn==6: CLKCFG */
- { .name = "CLKCFG", .cp = 14, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_IO,
- .readfn = pxa2xx_clkcfg_read, .writefn = pxa2xx_clkcfg_write },
- /* cp14 crn==7: PWRMODE */
- { .name = "PWRMODE", .cp = 14, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .type = ARM_CP_IO,
- .readfn = arm_cp_read_zero, .writefn = pxa2xx_pwrmode_write },
-};
-
-static void pxa2xx_setup_cp14(PXA2xxState *s)
-{
- define_arm_cp_regs_with_opaque(s->cpu, pxa_cp_reginfo, s);
-}
-
-#define MDCNFG 0x00 /* SDRAM Configuration register */
-#define MDREFR 0x04 /* SDRAM Refresh Control register */
-#define MSC0 0x08 /* Static Memory Control register 0 */
-#define MSC1 0x0c /* Static Memory Control register 1 */
-#define MSC2 0x10 /* Static Memory Control register 2 */
-#define MECR 0x14 /* Expansion Memory Bus Config register */
-#define SXCNFG 0x1c /* Synchronous Static Memory Config register */
-#define MCMEM0 0x28 /* PC Card Memory Socket 0 Timing register */
-#define MCMEM1 0x2c /* PC Card Memory Socket 1 Timing register */
-#define MCATT0 0x30 /* PC Card Attribute Socket 0 register */
-#define MCATT1 0x34 /* PC Card Attribute Socket 1 register */
-#define MCIO0 0x38 /* PC Card I/O Socket 0 Timing register */
-#define MCIO1 0x3c /* PC Card I/O Socket 1 Timing register */
-#define MDMRS 0x40 /* SDRAM Mode Register Set Config register */
-#define BOOT_DEF 0x44 /* Boot-time Default Configuration register */
-#define ARB_CNTL 0x48 /* Arbiter Control register */
-#define BSCNTR0 0x4c /* Memory Buffer Strength Control register 0 */
-#define BSCNTR1 0x50 /* Memory Buffer Strength Control register 1 */
-#define LCDBSCNTR 0x54 /* LCD Buffer Strength Control register */
-#define MDMRSLP 0x58 /* Low Power SDRAM Mode Set Config register */
-#define BSCNTR2 0x5c /* Memory Buffer Strength Control register 2 */
-#define BSCNTR3 0x60 /* Memory Buffer Strength Control register 3 */
-#define SA1110 0x64 /* SA-1110 Memory Compatibility register */
-
-static uint64_t pxa2xx_mm_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxState *s = (PXA2xxState *) opaque;
-
- switch (addr) {
- case MDCNFG ... SA1110:
- if ((addr & 3) == 0)
- return s->mm_regs[addr >> 2];
- /* fall through */
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_mm_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- PXA2xxState *s = (PXA2xxState *) opaque;
-
- switch (addr) {
- case MDCNFG ... SA1110:
- if ((addr & 3) == 0) {
- s->mm_regs[addr >> 2] = value;
- break;
- }
- /* fallthrough */
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
-}
-
-static const MemoryRegionOps pxa2xx_mm_ops = {
- .read = pxa2xx_mm_read,
- .write = pxa2xx_mm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pxa2xx_mm = {
- .name = "pxa2xx_mm",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32_ARRAY(mm_regs, PXA2xxState, 0x1a),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#define TYPE_PXA2XX_SSP "pxa2xx-ssp"
-OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxSSPState, PXA2XX_SSP)
-
-/* Synchronous Serial Ports */
-struct PXA2xxSSPState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- qemu_irq irq;
- uint32_t enable;
- SSIBus *bus;
-
- uint32_t sscr[2];
- uint32_t sspsp;
- uint32_t ssto;
- uint32_t ssitr;
- uint32_t sssr;
- uint8_t sstsa;
- uint8_t ssrsa;
- uint8_t ssacd;
-
- uint32_t rx_fifo[16];
- uint32_t rx_level;
- uint32_t rx_start;
-};
-
-static bool pxa2xx_ssp_vmstate_validate(void *opaque, int version_id)
-{
- PXA2xxSSPState *s = opaque;
-
- return s->rx_start < sizeof(s->rx_fifo);
-}
-
-static const VMStateDescription vmstate_pxa2xx_ssp = {
- .name = "pxa2xx-ssp",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32(enable, PXA2xxSSPState),
- VMSTATE_UINT32_ARRAY(sscr, PXA2xxSSPState, 2),
- VMSTATE_UINT32(sspsp, PXA2xxSSPState),
- VMSTATE_UINT32(ssto, PXA2xxSSPState),
- VMSTATE_UINT32(ssitr, PXA2xxSSPState),
- VMSTATE_UINT32(sssr, PXA2xxSSPState),
- VMSTATE_UINT8(sstsa, PXA2xxSSPState),
- VMSTATE_UINT8(ssrsa, PXA2xxSSPState),
- VMSTATE_UINT8(ssacd, PXA2xxSSPState),
- VMSTATE_UINT32(rx_level, PXA2xxSSPState),
- VMSTATE_UINT32(rx_start, PXA2xxSSPState),
- VMSTATE_VALIDATE("fifo is 16 bytes", pxa2xx_ssp_vmstate_validate),
- VMSTATE_UINT32_ARRAY(rx_fifo, PXA2xxSSPState, 16),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#define SSCR0 0x00 /* SSP Control register 0 */
-#define SSCR1 0x04 /* SSP Control register 1 */
-#define SSSR 0x08 /* SSP Status register */
-#define SSITR 0x0c /* SSP Interrupt Test register */
-#define SSDR 0x10 /* SSP Data register */
-#define SSTO 0x28 /* SSP Time-Out register */
-#define SSPSP 0x2c /* SSP Programmable Serial Protocol register */
-#define SSTSA 0x30 /* SSP TX Time Slot Active register */
-#define SSRSA 0x34 /* SSP RX Time Slot Active register */
-#define SSTSS 0x38 /* SSP Time Slot Status register */
-#define SSACD 0x3c /* SSP Audio Clock Divider register */
-
-/* Bitfields for above registers */
-#define SSCR0_SPI(x) (((x) & 0x30) == 0x00)
-#define SSCR0_SSP(x) (((x) & 0x30) == 0x10)
-#define SSCR0_UWIRE(x) (((x) & 0x30) == 0x20)
-#define SSCR0_PSP(x) (((x) & 0x30) == 0x30)
-#define SSCR0_SSE (1 << 7)
-#define SSCR0_RIM (1 << 22)
-#define SSCR0_TIM (1 << 23)
-#define SSCR0_MOD (1U << 31)
-#define SSCR0_DSS(x) (((((x) >> 16) & 0x10) | ((x) & 0xf)) + 1)
-#define SSCR1_RIE (1 << 0)
-#define SSCR1_TIE (1 << 1)
-#define SSCR1_LBM (1 << 2)
-#define SSCR1_MWDS (1 << 5)
-#define SSCR1_TFT(x) ((((x) >> 6) & 0xf) + 1)
-#define SSCR1_RFT(x) ((((x) >> 10) & 0xf) + 1)
-#define SSCR1_EFWR (1 << 14)
-#define SSCR1_PINTE (1 << 18)
-#define SSCR1_TINTE (1 << 19)
-#define SSCR1_RSRE (1 << 20)
-#define SSCR1_TSRE (1 << 21)
-#define SSCR1_EBCEI (1 << 29)
-#define SSITR_INT (7 << 5)
-#define SSSR_TNF (1 << 2)
-#define SSSR_RNE (1 << 3)
-#define SSSR_TFS (1 << 5)
-#define SSSR_RFS (1 << 6)
-#define SSSR_ROR (1 << 7)
-#define SSSR_PINT (1 << 18)
-#define SSSR_TINT (1 << 19)
-#define SSSR_EOC (1 << 20)
-#define SSSR_TUR (1 << 21)
-#define SSSR_BCE (1 << 23)
-#define SSSR_RW 0x00bc0080
-
-static void pxa2xx_ssp_int_update(PXA2xxSSPState *s)
-{
- int level = 0;
-
- level |= s->ssitr & SSITR_INT;
- level |= (s->sssr & SSSR_BCE) && (s->sscr[1] & SSCR1_EBCEI);
- level |= (s->sssr & SSSR_TUR) && !(s->sscr[0] & SSCR0_TIM);
- level |= (s->sssr & SSSR_EOC) && (s->sssr & (SSSR_TINT | SSSR_PINT));
- level |= (s->sssr & SSSR_TINT) && (s->sscr[1] & SSCR1_TINTE);
- level |= (s->sssr & SSSR_PINT) && (s->sscr[1] & SSCR1_PINTE);
- level |= (s->sssr & SSSR_ROR) && !(s->sscr[0] & SSCR0_RIM);
- level |= (s->sssr & SSSR_RFS) && (s->sscr[1] & SSCR1_RIE);
- level |= (s->sssr & SSSR_TFS) && (s->sscr[1] & SSCR1_TIE);
- qemu_set_irq(s->irq, !!level);
-}
-
-static void pxa2xx_ssp_fifo_update(PXA2xxSSPState *s)
-{
- s->sssr &= ~(0xf << 12); /* Clear RFL */
- s->sssr &= ~(0xf << 8); /* Clear TFL */
- s->sssr &= ~SSSR_TFS;
- s->sssr &= ~SSSR_TNF;
- if (s->enable) {
- s->sssr |= ((s->rx_level - 1) & 0xf) << 12;
- if (s->rx_level >= SSCR1_RFT(s->sscr[1]))
- s->sssr |= SSSR_RFS;
- else
- s->sssr &= ~SSSR_RFS;
- if (s->rx_level)
- s->sssr |= SSSR_RNE;
- else
- s->sssr &= ~SSSR_RNE;
- /* TX FIFO is never filled, so it is always in underrun
- condition if SSP is enabled */
- s->sssr |= SSSR_TFS;
- s->sssr |= SSSR_TNF;
- }
-
- pxa2xx_ssp_int_update(s);
-}
-
-static uint64_t pxa2xx_ssp_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
- uint32_t retval;
-
- switch (addr) {
- case SSCR0:
- return s->sscr[0];
- case SSCR1:
- return s->sscr[1];
- case SSPSP:
- return s->sspsp;
- case SSTO:
- return s->ssto;
- case SSITR:
- return s->ssitr;
- case SSSR:
- return s->sssr | s->ssitr;
- case SSDR:
- if (!s->enable)
- return 0xffffffff;
- if (s->rx_level < 1) {
- printf("%s: SSP Rx Underrun\n", __func__);
- return 0xffffffff;
- }
- s->rx_level --;
- retval = s->rx_fifo[s->rx_start ++];
- s->rx_start &= 0xf;
- pxa2xx_ssp_fifo_update(s);
- return retval;
- case SSTSA:
- return s->sstsa;
- case SSRSA:
- return s->ssrsa;
- case SSTSS:
- return 0;
- case SSACD:
- return s->ssacd;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_ssp_write(void *opaque, hwaddr addr,
- uint64_t value64, unsigned size)
-{
- PXA2xxSSPState *s = (PXA2xxSSPState *) opaque;
- uint32_t value = value64;
-
- switch (addr) {
- case SSCR0:
- s->sscr[0] = value & 0xc7ffffff;
- s->enable = value & SSCR0_SSE;
- if (value & SSCR0_MOD)
- printf("%s: Attempt to use network mode\n", __func__);
- if (s->enable && SSCR0_DSS(value) < 4)
- printf("%s: Wrong data size: %u bits\n", __func__,
- SSCR0_DSS(value));
- if (!(value & SSCR0_SSE)) {
- s->sssr = 0;
- s->ssitr = 0;
- s->rx_level = 0;
- }
- pxa2xx_ssp_fifo_update(s);
- break;
-
- case SSCR1:
- s->sscr[1] = value;
- if (value & (SSCR1_LBM | SSCR1_EFWR))
- printf("%s: Attempt to use SSP test mode\n", __func__);
- pxa2xx_ssp_fifo_update(s);
- break;
-
- case SSPSP:
- s->sspsp = value;
- break;
-
- case SSTO:
- s->ssto = value;
- break;
-
- case SSITR:
- s->ssitr = value & SSITR_INT;
- pxa2xx_ssp_int_update(s);
- break;
-
- case SSSR:
- s->sssr &= ~(value & SSSR_RW);
- pxa2xx_ssp_int_update(s);
- break;
-
- case SSDR:
- if (SSCR0_UWIRE(s->sscr[0])) {
- if (s->sscr[1] & SSCR1_MWDS)
- value &= 0xffff;
- else
- value &= 0xff;
- } else
- /* Note how 32bits overflow does no harm here */
- value &= (1 << SSCR0_DSS(s->sscr[0])) - 1;
-
- /* Data goes from here to the Tx FIFO and is shifted out from
- * there directly to the slave, no need to buffer it.
- */
- if (s->enable) {
- uint32_t readval;
- readval = ssi_transfer(s->bus, value);
- if (s->rx_level < 0x10) {
- s->rx_fifo[(s->rx_start + s->rx_level ++) & 0xf] = readval;
- } else {
- s->sssr |= SSSR_ROR;
- }
- }
- pxa2xx_ssp_fifo_update(s);
- break;
-
- case SSTSA:
- s->sstsa = value;
- break;
-
- case SSRSA:
- s->ssrsa = value;
- break;
-
- case SSACD:
- s->ssacd = value;
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
-}
-
-static const MemoryRegionOps pxa2xx_ssp_ops = {
- .read = pxa2xx_ssp_read,
- .write = pxa2xx_ssp_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pxa2xx_ssp_reset(DeviceState *d)
-{
- PXA2xxSSPState *s = PXA2XX_SSP(d);
-
- s->enable = 0;
- s->sscr[0] = s->sscr[1] = 0;
- s->sspsp = 0;
- s->ssto = 0;
- s->ssitr = 0;
- s->sssr = 0;
- s->sstsa = 0;
- s->ssrsa = 0;
- s->ssacd = 0;
- s->rx_start = s->rx_level = 0;
-}
-
-static void pxa2xx_ssp_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- PXA2xxSSPState *s = PXA2XX_SSP(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- sysbus_init_irq(sbd, &s->irq);
-
- memory_region_init_io(&s->iomem, obj, &pxa2xx_ssp_ops, s,
- "pxa2xx-ssp", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
-
- s->bus = ssi_create_bus(dev, "ssi");
-}
-
-/* Real-Time Clock */
-#define RCNR 0x00 /* RTC Counter register */
-#define RTAR 0x04 /* RTC Alarm register */
-#define RTSR 0x08 /* RTC Status register */
-#define RTTR 0x0c /* RTC Timer Trim register */
-#define RDCR 0x10 /* RTC Day Counter register */
-#define RYCR 0x14 /* RTC Year Counter register */
-#define RDAR1 0x18 /* RTC Wristwatch Day Alarm register 1 */
-#define RYAR1 0x1c /* RTC Wristwatch Year Alarm register 1 */
-#define RDAR2 0x20 /* RTC Wristwatch Day Alarm register 2 */
-#define RYAR2 0x24 /* RTC Wristwatch Year Alarm register 2 */
-#define SWCR 0x28 /* RTC Stopwatch Counter register */
-#define SWAR1 0x2c /* RTC Stopwatch Alarm register 1 */
-#define SWAR2 0x30 /* RTC Stopwatch Alarm register 2 */
-#define RTCPICR 0x34 /* RTC Periodic Interrupt Counter register */
-#define PIAR 0x38 /* RTC Periodic Interrupt Alarm register */
-
-#define TYPE_PXA2XX_RTC "pxa2xx_rtc"
-OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxRTCState, PXA2XX_RTC)
-
-struct PXA2xxRTCState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- uint32_t rttr;
- uint32_t rtsr;
- uint32_t rtar;
- uint32_t rdar1;
- uint32_t rdar2;
- uint32_t ryar1;
- uint32_t ryar2;
- uint32_t swar1;
- uint32_t swar2;
- uint32_t piar;
- uint32_t last_rcnr;
- uint32_t last_rdcr;
- uint32_t last_rycr;
- uint32_t last_swcr;
- uint32_t last_rtcpicr;
- int64_t last_hz;
- int64_t last_sw;
- int64_t last_pi;
- QEMUTimer *rtc_hz;
- QEMUTimer *rtc_rdal1;
- QEMUTimer *rtc_rdal2;
- QEMUTimer *rtc_swal1;
- QEMUTimer *rtc_swal2;
- QEMUTimer *rtc_pi;
- qemu_irq rtc_irq;
-};
-
-static inline void pxa2xx_rtc_int_update(PXA2xxRTCState *s)
-{
- qemu_set_irq(s->rtc_irq, !!(s->rtsr & 0x2553));
-}
-
-static void pxa2xx_rtc_hzupdate(PXA2xxRTCState *s)
-{
- int64_t rt = qemu_clock_get_ms(rtc_clock);
- s->last_rcnr += ((rt - s->last_hz) << 15) /
- (1000 * ((s->rttr & 0xffff) + 1));
- s->last_rdcr += ((rt - s->last_hz) << 15) /
- (1000 * ((s->rttr & 0xffff) + 1));
- s->last_hz = rt;
-}
-
-static void pxa2xx_rtc_swupdate(PXA2xxRTCState *s)
-{
- int64_t rt = qemu_clock_get_ms(rtc_clock);
- if (s->rtsr & (1 << 12))
- s->last_swcr += (rt - s->last_sw) / 10;
- s->last_sw = rt;
-}
-
-static void pxa2xx_rtc_piupdate(PXA2xxRTCState *s)
-{
- int64_t rt = qemu_clock_get_ms(rtc_clock);
- if (s->rtsr & (1 << 15))
- s->last_swcr += rt - s->last_pi;
- s->last_pi = rt;
-}
-
-static inline void pxa2xx_rtc_alarm_update(PXA2xxRTCState *s,
- uint32_t rtsr)
-{
- if ((rtsr & (1 << 2)) && !(rtsr & (1 << 0)))
- timer_mod(s->rtc_hz, s->last_hz +
- (((s->rtar - s->last_rcnr) * 1000 *
- ((s->rttr & 0xffff) + 1)) >> 15));
- else
- timer_del(s->rtc_hz);
-
- if ((rtsr & (1 << 5)) && !(rtsr & (1 << 4)))
- timer_mod(s->rtc_rdal1, s->last_hz +
- (((s->rdar1 - s->last_rdcr) * 1000 *
- ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */
- else
- timer_del(s->rtc_rdal1);
-
- if ((rtsr & (1 << 7)) && !(rtsr & (1 << 6)))
- timer_mod(s->rtc_rdal2, s->last_hz +
- (((s->rdar2 - s->last_rdcr) * 1000 *
- ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */
- else
- timer_del(s->rtc_rdal2);
-
- if ((rtsr & 0x1200) == 0x1200 && !(rtsr & (1 << 8)))
- timer_mod(s->rtc_swal1, s->last_sw +
- (s->swar1 - s->last_swcr) * 10); /* TODO: fixup */
- else
- timer_del(s->rtc_swal1);
-
- if ((rtsr & 0x1800) == 0x1800 && !(rtsr & (1 << 10)))
- timer_mod(s->rtc_swal2, s->last_sw +
- (s->swar2 - s->last_swcr) * 10); /* TODO: fixup */
- else
- timer_del(s->rtc_swal2);
-
- if ((rtsr & 0xc000) == 0xc000 && !(rtsr & (1 << 13)))
- timer_mod(s->rtc_pi, s->last_pi +
- (s->piar & 0xffff) - s->last_rtcpicr);
- else
- timer_del(s->rtc_pi);
-}
-
-static inline void pxa2xx_rtc_hz_tick(void *opaque)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
- s->rtsr |= (1 << 0);
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static inline void pxa2xx_rtc_rdal1_tick(void *opaque)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
- s->rtsr |= (1 << 4);
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static inline void pxa2xx_rtc_rdal2_tick(void *opaque)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
- s->rtsr |= (1 << 6);
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static inline void pxa2xx_rtc_swal1_tick(void *opaque)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
- s->rtsr |= (1 << 8);
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static inline void pxa2xx_rtc_swal2_tick(void *opaque)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
- s->rtsr |= (1 << 10);
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static inline void pxa2xx_rtc_pi_tick(void *opaque)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
- s->rtsr |= (1 << 13);
- pxa2xx_rtc_piupdate(s);
- s->last_rtcpicr = 0;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static uint64_t pxa2xx_rtc_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
-
- switch (addr) {
- case RTTR:
- return s->rttr;
- case RTSR:
- return s->rtsr;
- case RTAR:
- return s->rtar;
- case RDAR1:
- return s->rdar1;
- case RDAR2:
- return s->rdar2;
- case RYAR1:
- return s->ryar1;
- case RYAR2:
- return s->ryar2;
- case SWAR1:
- return s->swar1;
- case SWAR2:
- return s->swar2;
- case PIAR:
- return s->piar;
- case RCNR:
- return s->last_rcnr +
- ((qemu_clock_get_ms(rtc_clock) - s->last_hz) << 15) /
- (1000 * ((s->rttr & 0xffff) + 1));
- case RDCR:
- return s->last_rdcr +
- ((qemu_clock_get_ms(rtc_clock) - s->last_hz) << 15) /
- (1000 * ((s->rttr & 0xffff) + 1));
- case RYCR:
- return s->last_rycr;
- case SWCR:
- if (s->rtsr & (1 << 12))
- return s->last_swcr +
- (qemu_clock_get_ms(rtc_clock) - s->last_sw) / 10;
- else
- return s->last_swcr;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_rtc_write(void *opaque, hwaddr addr,
- uint64_t value64, unsigned size)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
- uint32_t value = value64;
-
- switch (addr) {
- case RTTR:
- if (!(s->rttr & (1U << 31))) {
- pxa2xx_rtc_hzupdate(s);
- s->rttr = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- }
- break;
-
- case RTSR:
- if ((s->rtsr ^ value) & (1 << 15))
- pxa2xx_rtc_piupdate(s);
-
- if ((s->rtsr ^ value) & (1 << 12))
- pxa2xx_rtc_swupdate(s);
-
- if (((s->rtsr ^ value) & 0x4aac) | (value & ~0xdaac))
- pxa2xx_rtc_alarm_update(s, value);
-
- s->rtsr = (value & 0xdaac) | (s->rtsr & ~(value & ~0xdaac));
- pxa2xx_rtc_int_update(s);
- break;
-
- case RTAR:
- s->rtar = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RDAR1:
- s->rdar1 = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RDAR2:
- s->rdar2 = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RYAR1:
- s->ryar1 = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RYAR2:
- s->ryar2 = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case SWAR1:
- pxa2xx_rtc_swupdate(s);
- s->swar1 = value;
- s->last_swcr = 0;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case SWAR2:
- s->swar2 = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case PIAR:
- s->piar = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RCNR:
- pxa2xx_rtc_hzupdate(s);
- s->last_rcnr = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RDCR:
- pxa2xx_rtc_hzupdate(s);
- s->last_rdcr = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RYCR:
- s->last_rycr = value;
- break;
-
- case SWCR:
- pxa2xx_rtc_swupdate(s);
- s->last_swcr = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RTCPICR:
- pxa2xx_rtc_piupdate(s);
- s->last_rtcpicr = value & 0xffff;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- }
-}
-
-static const MemoryRegionOps pxa2xx_rtc_ops = {
- .read = pxa2xx_rtc_read,
- .write = pxa2xx_rtc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pxa2xx_rtc_init(Object *obj)
-{
- PXA2xxRTCState *s = PXA2XX_RTC(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
- struct tm tm;
- int wom;
-
- s->rttr = 0x7fff;
- s->rtsr = 0;
-
- qemu_get_timedate(&tm, 0);
- wom = ((tm.tm_mday - 1) / 7) + 1;
-
- s->last_rcnr = (uint32_t) mktimegm(&tm);
- s->last_rdcr = (wom << 20) | ((tm.tm_wday + 1) << 17) |
- (tm.tm_hour << 12) | (tm.tm_min << 6) | tm.tm_sec;
- s->last_rycr = ((tm.tm_year + 1900) << 9) |
- ((tm.tm_mon + 1) << 5) | tm.tm_mday;
- s->last_swcr = (tm.tm_hour << 19) |
- (tm.tm_min << 13) | (tm.tm_sec << 7);
- s->last_rtcpicr = 0;
- s->last_hz = s->last_sw = s->last_pi = qemu_clock_get_ms(rtc_clock);
-
- sysbus_init_irq(dev, &s->rtc_irq);
-
- memory_region_init_io(&s->iomem, obj, &pxa2xx_rtc_ops, s,
- "pxa2xx-rtc", 0x10000);
- sysbus_init_mmio(dev, &s->iomem);
-}
-
-static void pxa2xx_rtc_realize(DeviceState *dev, Error **errp)
-{
- PXA2xxRTCState *s = PXA2XX_RTC(dev);
- s->rtc_hz = timer_new_ms(rtc_clock, pxa2xx_rtc_hz_tick, s);
- s->rtc_rdal1 = timer_new_ms(rtc_clock, pxa2xx_rtc_rdal1_tick, s);
- s->rtc_rdal2 = timer_new_ms(rtc_clock, pxa2xx_rtc_rdal2_tick, s);
- s->rtc_swal1 = timer_new_ms(rtc_clock, pxa2xx_rtc_swal1_tick, s);
- s->rtc_swal2 = timer_new_ms(rtc_clock, pxa2xx_rtc_swal2_tick, s);
- s->rtc_pi = timer_new_ms(rtc_clock, pxa2xx_rtc_pi_tick, s);
-}
-
-static int pxa2xx_rtc_pre_save(void *opaque)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
-
- pxa2xx_rtc_hzupdate(s);
- pxa2xx_rtc_piupdate(s);
- pxa2xx_rtc_swupdate(s);
-
- return 0;
-}
-
-static int pxa2xx_rtc_post_load(void *opaque, int version_id)
-{
- PXA2xxRTCState *s = (PXA2xxRTCState *) opaque;
-
- pxa2xx_rtc_alarm_update(s, s->rtsr);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_pxa2xx_rtc_regs = {
- .name = "pxa2xx_rtc",
- .version_id = 0,
- .minimum_version_id = 0,
- .pre_save = pxa2xx_rtc_pre_save,
- .post_load = pxa2xx_rtc_post_load,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32(rttr, PXA2xxRTCState),
- VMSTATE_UINT32(rtsr, PXA2xxRTCState),
- VMSTATE_UINT32(rtar, PXA2xxRTCState),
- VMSTATE_UINT32(rdar1, PXA2xxRTCState),
- VMSTATE_UINT32(rdar2, PXA2xxRTCState),
- VMSTATE_UINT32(ryar1, PXA2xxRTCState),
- VMSTATE_UINT32(ryar2, PXA2xxRTCState),
- VMSTATE_UINT32(swar1, PXA2xxRTCState),
- VMSTATE_UINT32(swar2, PXA2xxRTCState),
- VMSTATE_UINT32(piar, PXA2xxRTCState),
- VMSTATE_UINT32(last_rcnr, PXA2xxRTCState),
- VMSTATE_UINT32(last_rdcr, PXA2xxRTCState),
- VMSTATE_UINT32(last_rycr, PXA2xxRTCState),
- VMSTATE_UINT32(last_swcr, PXA2xxRTCState),
- VMSTATE_UINT32(last_rtcpicr, PXA2xxRTCState),
- VMSTATE_INT64(last_hz, PXA2xxRTCState),
- VMSTATE_INT64(last_sw, PXA2xxRTCState),
- VMSTATE_INT64(last_pi, PXA2xxRTCState),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static void pxa2xx_rtc_sysbus_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->desc = "PXA2xx RTC Controller";
- dc->vmsd = &vmstate_pxa2xx_rtc_regs;
- dc->realize = pxa2xx_rtc_realize;
-}
-
-static const TypeInfo pxa2xx_rtc_sysbus_info = {
- .name = TYPE_PXA2XX_RTC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxRTCState),
- .instance_init = pxa2xx_rtc_init,
- .class_init = pxa2xx_rtc_sysbus_class_init,
-};
-
-/* I2C Interface */
-
-#define TYPE_PXA2XX_I2C_SLAVE "pxa2xx-i2c-slave"
-OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxI2CSlaveState, PXA2XX_I2C_SLAVE)
-
-struct PXA2xxI2CSlaveState {
- I2CSlave parent_obj;
-
- PXA2xxI2CState *host;
-};
-
-struct PXA2xxI2CState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- PXA2xxI2CSlaveState *slave;
- I2CBus *bus;
- qemu_irq irq;
- uint32_t offset;
- uint32_t region_size;
-
- uint16_t control;
- uint16_t status;
- uint8_t ibmr;
- uint8_t data;
-};
-
-#define IBMR 0x80 /* I2C Bus Monitor register */
-#define IDBR 0x88 /* I2C Data Buffer register */
-#define ICR 0x90 /* I2C Control register */
-#define ISR 0x98 /* I2C Status register */
-#define ISAR 0xa0 /* I2C Slave Address register */
-
-static void pxa2xx_i2c_update(PXA2xxI2CState *s)
-{
- uint16_t level = 0;
- level |= s->status & s->control & (1 << 10); /* BED */
- level |= (s->status & (1 << 7)) && (s->control & (1 << 9)); /* IRF */
- level |= (s->status & (1 << 6)) && (s->control & (1 << 8)); /* ITE */
- level |= s->status & (1 << 9); /* SAD */
- qemu_set_irq(s->irq, !!level);
-}
-
-/* These are only stubs now. */
-static int pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
-{
- PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c);
- PXA2xxI2CState *s = slave->host;
-
- switch (event) {
- case I2C_START_SEND:
- s->status |= (1 << 9); /* set SAD */
- s->status &= ~(1 << 0); /* clear RWM */
- break;
- case I2C_START_RECV:
- s->status |= (1 << 9); /* set SAD */
- s->status |= 1 << 0; /* set RWM */
- break;
- case I2C_FINISH:
- s->status |= (1 << 4); /* set SSD */
- break;
- case I2C_NACK:
- s->status |= 1 << 1; /* set ACKNAK */
- break;
- default:
- return -1;
- }
- pxa2xx_i2c_update(s);
-
- return 0;
-}
-
-static uint8_t pxa2xx_i2c_rx(I2CSlave *i2c)
-{
- PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c);
- PXA2xxI2CState *s = slave->host;
-
- if ((s->control & (1 << 14)) || !(s->control & (1 << 6))) {
- return 0;
- }
-
- if (s->status & (1 << 0)) { /* RWM */
- s->status |= 1 << 6; /* set ITE */
- }
- pxa2xx_i2c_update(s);
-
- return s->data;
-}
-
-static int pxa2xx_i2c_tx(I2CSlave *i2c, uint8_t data)
-{
- PXA2xxI2CSlaveState *slave = PXA2XX_I2C_SLAVE(i2c);
- PXA2xxI2CState *s = slave->host;
-
- if ((s->control & (1 << 14)) || !(s->control & (1 << 6))) {
- return 1;
- }
-
- if (!(s->status & (1 << 0))) { /* RWM */
- s->status |= 1 << 7; /* set IRF */
- s->data = data;
- }
- pxa2xx_i2c_update(s);
-
- return 1;
-}
-
-static uint64_t pxa2xx_i2c_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxI2CState *s = (PXA2xxI2CState *) opaque;
- I2CSlave *slave;
-
- addr -= s->offset;
- switch (addr) {
- case ICR:
- return s->control;
- case ISR:
- return s->status | (i2c_bus_busy(s->bus) << 2);
- case ISAR:
- slave = I2C_SLAVE(s->slave);
- return slave->address;
- case IDBR:
- return s->data;
- case IBMR:
- if (s->status & (1 << 2))
- s->ibmr ^= 3; /* Fake SCL and SDA pin changes */
- else
- s->ibmr = 0;
- return s->ibmr;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_i2c_write(void *opaque, hwaddr addr,
- uint64_t value64, unsigned size)
-{
- PXA2xxI2CState *s = (PXA2xxI2CState *) opaque;
- uint32_t value = value64;
- int ack;
-
- addr -= s->offset;
- switch (addr) {
- case ICR:
- s->control = value & 0xfff7;
- if ((value & (1 << 3)) && (value & (1 << 6))) { /* TB and IUE */
- /* TODO: slave mode */
- if (value & (1 << 0)) { /* START condition */
- if (s->data & 1)
- s->status |= 1 << 0; /* set RWM */
- else
- s->status &= ~(1 << 0); /* clear RWM */
- ack = !i2c_start_transfer(s->bus, s->data >> 1, s->data & 1);
- } else {
- if (s->status & (1 << 0)) { /* RWM */
- s->data = i2c_recv(s->bus);
- if (value & (1 << 2)) /* ACKNAK */
- i2c_nack(s->bus);
- ack = 1;
- } else
- ack = !i2c_send(s->bus, s->data);
- }
-
- if (value & (1 << 1)) /* STOP condition */
- i2c_end_transfer(s->bus);
-
- if (ack) {
- if (value & (1 << 0)) /* START condition */
- s->status |= 1 << 6; /* set ITE */
- else
- if (s->status & (1 << 0)) /* RWM */
- s->status |= 1 << 7; /* set IRF */
- else
- s->status |= 1 << 6; /* set ITE */
- s->status &= ~(1 << 1); /* clear ACKNAK */
- } else {
- s->status |= 1 << 6; /* set ITE */
- s->status |= 1 << 10; /* set BED */
- s->status |= 1 << 1; /* set ACKNAK */
- }
- }
- if (!(value & (1 << 3)) && (value & (1 << 6))) /* !TB and IUE */
- if (value & (1 << 4)) /* MA */
- i2c_end_transfer(s->bus);
- pxa2xx_i2c_update(s);
- break;
-
- case ISR:
- s->status &= ~(value & 0x07f0);
- pxa2xx_i2c_update(s);
- break;
-
- case ISAR:
- i2c_slave_set_address(I2C_SLAVE(s->slave), value & 0x7f);
- break;
-
- case IDBR:
- s->data = value & 0xff;
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- }
-}
-
-static const MemoryRegionOps pxa2xx_i2c_ops = {
- .read = pxa2xx_i2c_read,
- .write = pxa2xx_i2c_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pxa2xx_i2c_slave = {
- .name = "pxa2xx_i2c_slave",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
- VMSTATE_I2C_SLAVE(parent_obj, PXA2xxI2CSlaveState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_pxa2xx_i2c = {
- .name = "pxa2xx_i2c",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT16(control, PXA2xxI2CState),
- VMSTATE_UINT16(status, PXA2xxI2CState),
- VMSTATE_UINT8(ibmr, PXA2xxI2CState),
- VMSTATE_UINT8(data, PXA2xxI2CState),
- VMSTATE_STRUCT_POINTER(slave, PXA2xxI2CState,
- vmstate_pxa2xx_i2c_slave, PXA2xxI2CSlaveState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void pxa2xx_i2c_slave_class_init(ObjectClass *klass, void *data)
-{
- I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
-
- k->event = pxa2xx_i2c_event;
- k->recv = pxa2xx_i2c_rx;
- k->send = pxa2xx_i2c_tx;
-}
-
-static const TypeInfo pxa2xx_i2c_slave_info = {
- .name = TYPE_PXA2XX_I2C_SLAVE,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(PXA2xxI2CSlaveState),
- .class_init = pxa2xx_i2c_slave_class_init,
-};
-
-PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base,
- qemu_irq irq, uint32_t region_size)
-{
- DeviceState *dev;
- SysBusDevice *i2c_dev;
- PXA2xxI2CState *s;
- I2CBus *i2cbus;
-
- dev = qdev_new(TYPE_PXA2XX_I2C);
- qdev_prop_set_uint32(dev, "size", region_size + 1);
- qdev_prop_set_uint32(dev, "offset", base & region_size);
-
- /* FIXME: Should the slave device really be on a separate bus? */
- i2cbus = i2c_init_bus(dev, "dummy");
-
- i2c_dev = SYS_BUS_DEVICE(dev);
- sysbus_realize_and_unref(i2c_dev, &error_fatal);
- sysbus_mmio_map(i2c_dev, 0, base & ~region_size);
- sysbus_connect_irq(i2c_dev, 0, irq);
-
- s = PXA2XX_I2C(i2c_dev);
- s->slave = PXA2XX_I2C_SLAVE(i2c_slave_create_simple(i2cbus,
- TYPE_PXA2XX_I2C_SLAVE,
- 0));
- s->slave->host = s;
-
- return s;
-}
-
-static void pxa2xx_i2c_initfn(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- PXA2xxI2CState *s = PXA2XX_I2C(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- s->bus = i2c_init_bus(dev, NULL);
-
- memory_region_init_io(&s->iomem, obj, &pxa2xx_i2c_ops, s,
- "pxa2xx-i2c", s->region_size);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
-}
-
-I2CBus *pxa2xx_i2c_bus(PXA2xxI2CState *s)
-{
- return s->bus;
-}
-
-static Property pxa2xx_i2c_properties[] = {
- DEFINE_PROP_UINT32("size", PXA2xxI2CState, region_size, 0x10000),
- DEFINE_PROP_UINT32("offset", PXA2xxI2CState, offset, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxa2xx_i2c_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->desc = "PXA2xx I2C Bus Controller";
- dc->vmsd = &vmstate_pxa2xx_i2c;
- device_class_set_props(dc, pxa2xx_i2c_properties);
-}
-
-static const TypeInfo pxa2xx_i2c_info = {
- .name = TYPE_PXA2XX_I2C,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxI2CState),
- .instance_init = pxa2xx_i2c_initfn,
- .class_init = pxa2xx_i2c_class_init,
-};
-
-/* PXA Inter-IC Sound Controller */
-static void pxa2xx_i2s_reset(PXA2xxI2SState *i2s)
-{
- i2s->rx_len = 0;
- i2s->tx_len = 0;
- i2s->fifo_len = 0;
- i2s->clk = 0x1a;
- i2s->control[0] = 0x00;
- i2s->control[1] = 0x00;
- i2s->status = 0x00;
- i2s->mask = 0x00;
-}
-
-#define SACR_TFTH(val) ((val >> 8) & 0xf)
-#define SACR_RFTH(val) ((val >> 12) & 0xf)
-#define SACR_DREC(val) (val & (1 << 3))
-#define SACR_DPRL(val) (val & (1 << 4))
-
-static inline void pxa2xx_i2s_update(PXA2xxI2SState *i2s)
-{
- int rfs, tfs;
- rfs = SACR_RFTH(i2s->control[0]) < i2s->rx_len &&
- !SACR_DREC(i2s->control[1]);
- tfs = (i2s->tx_len || i2s->fifo_len < SACR_TFTH(i2s->control[0])) &&
- i2s->enable && !SACR_DPRL(i2s->control[1]);
-
- qemu_set_irq(i2s->rx_dma, rfs);
- qemu_set_irq(i2s->tx_dma, tfs);
-
- i2s->status &= 0xe0;
- if (i2s->fifo_len < 16 || !i2s->enable)
- i2s->status |= 1 << 0; /* TNF */
- if (i2s->rx_len)
- i2s->status |= 1 << 1; /* RNE */
- if (i2s->enable)
- i2s->status |= 1 << 2; /* BSY */
- if (tfs)
- i2s->status |= 1 << 3; /* TFS */
- if (rfs)
- i2s->status |= 1 << 4; /* RFS */
- if (!(i2s->tx_len && i2s->enable))
- i2s->status |= i2s->fifo_len << 8; /* TFL */
- i2s->status |= MAX(i2s->rx_len, 0xf) << 12; /* RFL */
-
- qemu_set_irq(i2s->irq, i2s->status & i2s->mask);
-}
-
-#define SACR0 0x00 /* Serial Audio Global Control register */
-#define SACR1 0x04 /* Serial Audio I2S/MSB-Justified Control register */
-#define SASR0 0x0c /* Serial Audio Interface and FIFO Status register */
-#define SAIMR 0x14 /* Serial Audio Interrupt Mask register */
-#define SAICR 0x18 /* Serial Audio Interrupt Clear register */
-#define SADIV 0x60 /* Serial Audio Clock Divider register */
-#define SADR 0x80 /* Serial Audio Data register */
-
-static uint64_t pxa2xx_i2s_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
-
- switch (addr) {
- case SACR0:
- return s->control[0];
- case SACR1:
- return s->control[1];
- case SASR0:
- return s->status;
- case SAIMR:
- return s->mask;
- case SAICR:
- return 0;
- case SADIV:
- return s->clk;
- case SADR:
- if (s->rx_len > 0) {
- s->rx_len --;
- pxa2xx_i2s_update(s);
- return s->codec_in(s->opaque);
- }
- return 0;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_i2s_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
- uint32_t *sample;
-
- switch (addr) {
- case SACR0:
- if (value & (1 << 3)) /* RST */
- pxa2xx_i2s_reset(s);
- s->control[0] = value & 0xff3d;
- if (!s->enable && (value & 1) && s->tx_len) { /* ENB */
- for (sample = s->fifo; s->fifo_len > 0; s->fifo_len --, sample ++)
- s->codec_out(s->opaque, *sample);
- s->status &= ~(1 << 7); /* I2SOFF */
- }
- if (value & (1 << 4)) /* EFWR */
- printf("%s: Attempt to use special function\n", __func__);
- s->enable = (value & 9) == 1; /* ENB && !RST*/
- pxa2xx_i2s_update(s);
- break;
- case SACR1:
- s->control[1] = value & 0x0039;
- if (value & (1 << 5)) /* ENLBF */
- printf("%s: Attempt to use loopback function\n", __func__);
- if (value & (1 << 4)) /* DPRL */
- s->fifo_len = 0;
- pxa2xx_i2s_update(s);
- break;
- case SAIMR:
- s->mask = value & 0x0078;
- pxa2xx_i2s_update(s);
- break;
- case SAICR:
- s->status &= ~(value & (3 << 5));
- pxa2xx_i2s_update(s);
- break;
- case SADIV:
- s->clk = value & 0x007f;
- break;
- case SADR:
- if (s->tx_len && s->enable) {
- s->tx_len --;
- pxa2xx_i2s_update(s);
- s->codec_out(s->opaque, value);
- } else if (s->fifo_len < 16) {
- s->fifo[s->fifo_len ++] = value;
- pxa2xx_i2s_update(s);
- }
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- }
-}
-
-static const MemoryRegionOps pxa2xx_i2s_ops = {
- .read = pxa2xx_i2s_read,
- .write = pxa2xx_i2s_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pxa2xx_i2s = {
- .name = "pxa2xx_i2s",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32_ARRAY(control, PXA2xxI2SState, 2),
- VMSTATE_UINT32(status, PXA2xxI2SState),
- VMSTATE_UINT32(mask, PXA2xxI2SState),
- VMSTATE_UINT32(clk, PXA2xxI2SState),
- VMSTATE_INT32(enable, PXA2xxI2SState),
- VMSTATE_INT32(rx_len, PXA2xxI2SState),
- VMSTATE_INT32(tx_len, PXA2xxI2SState),
- VMSTATE_INT32(fifo_len, PXA2xxI2SState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void pxa2xx_i2s_data_req(void *opaque, int tx, int rx)
-{
- PXA2xxI2SState *s = (PXA2xxI2SState *) opaque;
- uint32_t *sample;
-
- /* Signal FIFO errors */
- if (s->enable && s->tx_len)
- s->status |= 1 << 5; /* TUR */
- if (s->enable && s->rx_len)
- s->status |= 1 << 6; /* ROR */
-
- /* Should be tx - MIN(tx, s->fifo_len) but we don't really need to
- * handle the cases where it makes a difference. */
- s->tx_len = tx - s->fifo_len;
- s->rx_len = rx;
- /* Note that is s->codec_out wasn't set, we wouldn't get called. */
- if (s->enable)
- for (sample = s->fifo; s->fifo_len; s->fifo_len --, sample ++)
- s->codec_out(s->opaque, *sample);
- pxa2xx_i2s_update(s);
-}
-
-static PXA2xxI2SState *pxa2xx_i2s_init(MemoryRegion *sysmem,
- hwaddr base,
- qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma)
-{
- PXA2xxI2SState *s = g_new0(PXA2xxI2SState, 1);
-
- s->irq = irq;
- s->rx_dma = rx_dma;
- s->tx_dma = tx_dma;
- s->data_req = pxa2xx_i2s_data_req;
-
- pxa2xx_i2s_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &pxa2xx_i2s_ops, s,
- "pxa2xx-i2s", 0x100000);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- vmstate_register(NULL, base, &vmstate_pxa2xx_i2s, s);
-
- return s;
-}
-
-/* PXA Fast Infra-red Communications Port */
-struct PXA2xxFIrState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- qemu_irq irq;
- qemu_irq rx_dma;
- qemu_irq tx_dma;
- uint32_t enable;
- CharBackend chr;
-
- uint8_t control[3];
- uint8_t status[2];
-
- uint32_t rx_len;
- uint32_t rx_start;
- uint8_t rx_fifo[64];
-};
-
-static void pxa2xx_fir_reset(DeviceState *d)
-{
- PXA2xxFIrState *s = PXA2XX_FIR(d);
-
- s->control[0] = 0x00;
- s->control[1] = 0x00;
- s->control[2] = 0x00;
- s->status[0] = 0x00;
- s->status[1] = 0x00;
- s->enable = 0;
-}
-
-static inline void pxa2xx_fir_update(PXA2xxFIrState *s)
-{
- static const int tresh[4] = { 8, 16, 32, 0 };
- int intr = 0;
- if ((s->control[0] & (1 << 4)) && /* RXE */
- s->rx_len >= tresh[s->control[2] & 3]) /* TRIG */
- s->status[0] |= 1 << 4; /* RFS */
- else
- s->status[0] &= ~(1 << 4); /* RFS */
- if (s->control[0] & (1 << 3)) /* TXE */
- s->status[0] |= 1 << 3; /* TFS */
- else
- s->status[0] &= ~(1 << 3); /* TFS */
- if (s->rx_len)
- s->status[1] |= 1 << 2; /* RNE */
- else
- s->status[1] &= ~(1 << 2); /* RNE */
- if (s->control[0] & (1 << 4)) /* RXE */
- s->status[1] |= 1 << 0; /* RSY */
- else
- s->status[1] &= ~(1 << 0); /* RSY */
-
- intr |= (s->control[0] & (1 << 5)) && /* RIE */
- (s->status[0] & (1 << 4)); /* RFS */
- intr |= (s->control[0] & (1 << 6)) && /* TIE */
- (s->status[0] & (1 << 3)); /* TFS */
- intr |= (s->control[2] & (1 << 4)) && /* TRAIL */
- (s->status[0] & (1 << 6)); /* EOC */
- intr |= (s->control[0] & (1 << 2)) && /* TUS */
- (s->status[0] & (1 << 1)); /* TUR */
- intr |= s->status[0] & 0x25; /* FRE, RAB, EIF */
-
- qemu_set_irq(s->rx_dma, (s->status[0] >> 4) & 1);
- qemu_set_irq(s->tx_dma, (s->status[0] >> 3) & 1);
-
- qemu_set_irq(s->irq, intr && s->enable);
-}
-
-#define ICCR0 0x00 /* FICP Control register 0 */
-#define ICCR1 0x04 /* FICP Control register 1 */
-#define ICCR2 0x08 /* FICP Control register 2 */
-#define ICDR 0x0c /* FICP Data register */
-#define ICSR0 0x14 /* FICP Status register 0 */
-#define ICSR1 0x18 /* FICP Status register 1 */
-#define ICFOR 0x1c /* FICP FIFO Occupancy Status register */
-
-static uint64_t pxa2xx_fir_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
- uint8_t ret;
-
- switch (addr) {
- case ICCR0:
- return s->control[0];
- case ICCR1:
- return s->control[1];
- case ICCR2:
- return s->control[2];
- case ICDR:
- s->status[0] &= ~0x01;
- s->status[1] &= ~0x72;
- if (s->rx_len) {
- s->rx_len --;
- ret = s->rx_fifo[s->rx_start ++];
- s->rx_start &= 63;
- pxa2xx_fir_update(s);
- return ret;
- }
- printf("%s: Rx FIFO underrun.\n", __func__);
- break;
- case ICSR0:
- return s->status[0];
- case ICSR1:
- return s->status[1] | (1 << 3); /* TNF */
- case ICFOR:
- return s->rx_len;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_fir_write(void *opaque, hwaddr addr,
- uint64_t value64, unsigned size)
-{
- PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
- uint32_t value = value64;
- uint8_t ch;
-
- switch (addr) {
- case ICCR0:
- s->control[0] = value;
- if (!(value & (1 << 4))) /* RXE */
- s->rx_len = s->rx_start = 0;
- if (!(value & (1 << 3))) { /* TXE */
- /* Nop */
- }
- s->enable = value & 1; /* ITR */
- if (!s->enable)
- s->status[0] = 0;
- pxa2xx_fir_update(s);
- break;
- case ICCR1:
- s->control[1] = value;
- break;
- case ICCR2:
- s->control[2] = value & 0x3f;
- pxa2xx_fir_update(s);
- break;
- case ICDR:
- if (s->control[2] & (1 << 2)) { /* TXP */
- ch = value;
- } else {
- ch = ~value;
- }
- if (s->enable && (s->control[0] & (1 << 3))) { /* TXE */
- /* 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 ICSR0:
- s->status[0] &= ~(value & 0x66);
- pxa2xx_fir_update(s);
- break;
- case ICFOR:
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, addr);
- }
-}
-
-static const MemoryRegionOps pxa2xx_fir_ops = {
- .read = pxa2xx_fir_read,
- .write = pxa2xx_fir_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int pxa2xx_fir_is_empty(void *opaque)
-{
- PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
- return (s->rx_len < 64);
-}
-
-static void pxa2xx_fir_rx(void *opaque, const uint8_t *buf, int size)
-{
- PXA2xxFIrState *s = (PXA2xxFIrState *) opaque;
- if (!(s->control[0] & (1 << 4))) /* RXE */
- return;
-
- while (size --) {
- s->status[1] |= 1 << 4; /* EOF */
- if (s->rx_len >= 64) {
- s->status[1] |= 1 << 6; /* ROR */
- break;
- }
-
- if (s->control[2] & (1 << 3)) /* RXP */
- s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = *(buf ++);
- else
- s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = ~*(buf ++);
- }
-
- pxa2xx_fir_update(s);
-}
-
-static void pxa2xx_fir_event(void *opaque, QEMUChrEvent event)
-{
-}
-
-static void pxa2xx_fir_instance_init(Object *obj)
-{
- PXA2xxFIrState *s = PXA2XX_FIR(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- memory_region_init_io(&s->iomem, obj, &pxa2xx_fir_ops, s,
- "pxa2xx-fir", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
- sysbus_init_irq(sbd, &s->rx_dma);
- sysbus_init_irq(sbd, &s->tx_dma);
-}
-
-static void pxa2xx_fir_realize(DeviceState *dev, Error **errp)
-{
- PXA2xxFIrState *s = PXA2XX_FIR(dev);
-
- qemu_chr_fe_set_handlers(&s->chr, pxa2xx_fir_is_empty,
- pxa2xx_fir_rx, pxa2xx_fir_event, NULL, s, NULL,
- true);
-}
-
-static bool pxa2xx_fir_vmstate_validate(void *opaque, int version_id)
-{
- PXA2xxFIrState *s = opaque;
-
- return s->rx_start < ARRAY_SIZE(s->rx_fifo);
-}
-
-static const VMStateDescription pxa2xx_fir_vmsd = {
- .name = "pxa2xx-fir",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32(enable, PXA2xxFIrState),
- VMSTATE_UINT8_ARRAY(control, PXA2xxFIrState, 3),
- VMSTATE_UINT8_ARRAY(status, PXA2xxFIrState, 2),
- VMSTATE_UINT32(rx_len, PXA2xxFIrState),
- VMSTATE_UINT32(rx_start, PXA2xxFIrState),
- VMSTATE_VALIDATE("fifo is 64 bytes", pxa2xx_fir_vmstate_validate),
- VMSTATE_UINT8_ARRAY(rx_fifo, PXA2xxFIrState, 64),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property pxa2xx_fir_properties[] = {
- DEFINE_PROP_CHR("chardev", PXA2xxFIrState, chr),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxa2xx_fir_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = pxa2xx_fir_realize;
- dc->vmsd = &pxa2xx_fir_vmsd;
- device_class_set_props(dc, pxa2xx_fir_properties);
- dc->reset = pxa2xx_fir_reset;
-}
-
-static const TypeInfo pxa2xx_fir_info = {
- .name = TYPE_PXA2XX_FIR,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxFIrState),
- .class_init = pxa2xx_fir_class_init,
- .instance_init = pxa2xx_fir_instance_init,
-};
-
-static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem,
- hwaddr base,
- qemu_irq irq, qemu_irq rx_dma,
- qemu_irq tx_dma,
- Chardev *chr)
-{
- DeviceState *dev;
- SysBusDevice *sbd;
-
- dev = qdev_new(TYPE_PXA2XX_FIR);
- qdev_prop_set_chr(dev, "chardev", chr);
- sbd = SYS_BUS_DEVICE(dev);
- sysbus_realize_and_unref(sbd, &error_fatal);
- sysbus_mmio_map(sbd, 0, base);
- sysbus_connect_irq(sbd, 0, irq);
- sysbus_connect_irq(sbd, 1, rx_dma);
- sysbus_connect_irq(sbd, 2, tx_dma);
- return PXA2XX_FIR(dev);
-}
-
-static void pxa2xx_reset(void *opaque, int line, int level)
-{
- PXA2xxState *s = (PXA2xxState *) opaque;
-
- if (level && (s->pm_regs[PCFR >> 2] & 0x10)) { /* GPR_EN */
- cpu_reset(CPU(s->cpu));
- /* TODO: reset peripherals */
- }
-}
-
-/* Initialise a PXA270 integrated chip (ARM based core). */
-PXA2xxState *pxa270_init(unsigned int sdram_size, const char *cpu_type)
-{
- MemoryRegion *address_space = get_system_memory();
- PXA2xxState *s;
- int i;
- DriveInfo *dinfo;
- s = g_new0(PXA2xxState, 1);
-
- if (strncmp(cpu_type, "pxa27", 5)) {
- error_report("Machine requires a PXA27x processor");
- exit(1);
- }
-
- s->cpu = ARM_CPU(cpu_create(cpu_type));
- s->reset = qemu_allocate_irq(pxa2xx_reset, s, 0);
-
- /* SDRAM & Internal Memory Storage */
- memory_region_init_ram(&s->sdram, NULL, "pxa270.sdram", sdram_size,
- &error_fatal);
- memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram);
- memory_region_init_ram(&s->internal, NULL, "pxa270.internal", 0x40000,
- &error_fatal);
- memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE,
- &s->internal);
-
- s->pic = pxa2xx_pic_init(0x40d00000, s->cpu);
-
- s->dma = pxa27x_dma_init(0x40000000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_DMA));
-
- sysbus_create_varargs("pxa27x-timer", 0x40a00000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 0),
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 1),
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 2),
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 3),
- qdev_get_gpio_in(s->pic, PXA27X_PIC_OST_4_11),
- NULL);
-
- s->gpio = pxa2xx_gpio_init(0x40e00000, s->cpu, s->pic, 121);
-
- s->mmc = pxa2xx_mmci_init(address_space, 0x41100000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC),
- qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI),
- qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI));
- dinfo = drive_get(IF_SD, 0, 0);
- if (dinfo) {
- DeviceState *carddev;
-
- /* Create and plug in the sd card */
- carddev = qdev_new(TYPE_SD_CARD);
- qdev_prop_set_drive_err(carddev, "drive",
- blk_by_legacy_dinfo(dinfo), &error_fatal);
- qdev_realize_and_unref(carddev, qdev_get_child_bus(DEVICE(s->mmc),
- "sd-bus"),
- &error_fatal);
- } else if (!qtest_enabled()) {
- warn_report("missing SecureDigital device");
- }
-
- for (i = 0; pxa270_serial[i].io_base; i++) {
- if (serial_hd(i)) {
- serial_mm_init(address_space, pxa270_serial[i].io_base, 2,
- qdev_get_gpio_in(s->pic, pxa270_serial[i].irqn),
- 14857000 / 16, serial_hd(i),
- DEVICE_NATIVE_ENDIAN);
- } else {
- break;
- }
- }
- if (serial_hd(i))
- s->fir = pxa2xx_fir_init(address_space, 0x40800000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP),
- qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_ICP),
- qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_ICP),
- serial_hd(i));
-
- s->lcd = pxa2xx_lcdc_init(address_space, 0x44000000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_LCD));
-
- s->cm_base = 0x41300000;
- s->cm_regs[CCCR >> 2] = 0x02000210; /* 416.0 MHz */
- s->clkcfg = 0x00000009; /* Turbo mode active */
- memory_region_init_io(&s->cm_iomem, NULL, &pxa2xx_cm_ops, s, "pxa2xx-cm", 0x1000);
- memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem);
- vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s);
-
- pxa2xx_setup_cp14(s);
-
- s->mm_base = 0x48000000;
- s->mm_regs[MDMRS >> 2] = 0x00020002;
- s->mm_regs[MDREFR >> 2] = 0x03ca4000;
- s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */
- memory_region_init_io(&s->mm_iomem, NULL, &pxa2xx_mm_ops, s, "pxa2xx-mm", 0x1000);
- memory_region_add_subregion(address_space, s->mm_base, &s->mm_iomem);
- vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s);
-
- s->pm_base = 0x40f00000;
- memory_region_init_io(&s->pm_iomem, NULL, &pxa2xx_pm_ops, s, "pxa2xx-pm", 0x100);
- memory_region_add_subregion(address_space, s->pm_base, &s->pm_iomem);
- vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s);
-
- for (i = 0; pxa27x_ssp[i].io_base; i ++);
- s->ssp = g_new0(SSIBus *, i);
- for (i = 0; pxa27x_ssp[i].io_base; i ++) {
- DeviceState *dev;
- dev = sysbus_create_simple(TYPE_PXA2XX_SSP, pxa27x_ssp[i].io_base,
- qdev_get_gpio_in(s->pic, pxa27x_ssp[i].irqn));
- s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
- }
-
- sysbus_create_simple("sysbus-ohci", 0x4c000000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1));
-
- s->pcmcia[0] = PXA2XX_PCMCIA(sysbus_create_simple(TYPE_PXA2XX_PCMCIA,
- 0x20000000, NULL));
- s->pcmcia[1] = PXA2XX_PCMCIA(sysbus_create_simple(TYPE_PXA2XX_PCMCIA,
- 0x30000000, NULL));
-
- sysbus_create_simple(TYPE_PXA2XX_RTC, 0x40900000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_RTCALARM));
-
- s->i2c[0] = pxa2xx_i2c_init(0x40301600,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2C), 0xffff);
- s->i2c[1] = pxa2xx_i2c_init(0x40f00100,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_PWRI2C), 0xff);
-
- s->i2s = pxa2xx_i2s_init(address_space, 0x40400000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2S),
- qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_I2S),
- qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_I2S));
-
- s->kp = pxa27x_keypad_init(address_space, 0x41500000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_KEYPAD));
-
- /* GPIO1 resets the processor */
- /* The handler can be overridden by board-specific code */
- qdev_connect_gpio_out(s->gpio, 1, s->reset);
- return s;
-}
-
-/* Initialise a PXA255 integrated chip (ARM based core). */
-PXA2xxState *pxa255_init(unsigned int sdram_size)
-{
- MemoryRegion *address_space = get_system_memory();
- PXA2xxState *s;
- int i;
- DriveInfo *dinfo;
-
- s = g_new0(PXA2xxState, 1);
-
- s->cpu = ARM_CPU(cpu_create(ARM_CPU_TYPE_NAME("pxa255")));
- s->reset = qemu_allocate_irq(pxa2xx_reset, s, 0);
-
- /* SDRAM & Internal Memory Storage */
- memory_region_init_ram(&s->sdram, NULL, "pxa255.sdram", sdram_size,
- &error_fatal);
- memory_region_add_subregion(address_space, PXA2XX_SDRAM_BASE, &s->sdram);
- memory_region_init_ram(&s->internal, NULL, "pxa255.internal",
- PXA2XX_INTERNAL_SIZE, &error_fatal);
- memory_region_add_subregion(address_space, PXA2XX_INTERNAL_BASE,
- &s->internal);
-
- s->pic = pxa2xx_pic_init(0x40d00000, s->cpu);
-
- s->dma = pxa255_dma_init(0x40000000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_DMA));
-
- sysbus_create_varargs("pxa25x-timer", 0x40a00000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 0),
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 1),
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 2),
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_OST_0 + 3),
- NULL);
-
- s->gpio = pxa2xx_gpio_init(0x40e00000, s->cpu, s->pic, 85);
-
- s->mmc = pxa2xx_mmci_init(address_space, 0x41100000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC),
- qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI),
- qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI));
- dinfo = drive_get(IF_SD, 0, 0);
- if (dinfo) {
- DeviceState *carddev;
-
- /* Create and plug in the sd card */
- carddev = qdev_new(TYPE_SD_CARD);
- qdev_prop_set_drive_err(carddev, "drive",
- blk_by_legacy_dinfo(dinfo), &error_fatal);
- qdev_realize_and_unref(carddev, qdev_get_child_bus(DEVICE(s->mmc),
- "sd-bus"),
- &error_fatal);
- } else if (!qtest_enabled()) {
- warn_report("missing SecureDigital device");
- }
-
- for (i = 0; pxa255_serial[i].io_base; i++) {
- if (serial_hd(i)) {
- serial_mm_init(address_space, pxa255_serial[i].io_base, 2,
- qdev_get_gpio_in(s->pic, pxa255_serial[i].irqn),
- 14745600 / 16, serial_hd(i),
- DEVICE_NATIVE_ENDIAN);
- } else {
- break;
- }
- }
- if (serial_hd(i))
- s->fir = pxa2xx_fir_init(address_space, 0x40800000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_ICP),
- qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_ICP),
- qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_ICP),
- serial_hd(i));
-
- s->lcd = pxa2xx_lcdc_init(address_space, 0x44000000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_LCD));
-
- s->cm_base = 0x41300000;
- s->cm_regs[CCCR >> 2] = 0x00000121; /* from datasheet */
- s->cm_regs[CKEN >> 2] = 0x00017def; /* from datasheet */
-
- s->clkcfg = 0x00000009; /* Turbo mode active */
- memory_region_init_io(&s->cm_iomem, NULL, &pxa2xx_cm_ops, s, "pxa2xx-cm", 0x1000);
- memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem);
- vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s);
-
- pxa2xx_setup_cp14(s);
-
- s->mm_base = 0x48000000;
- s->mm_regs[MDMRS >> 2] = 0x00020002;
- s->mm_regs[MDREFR >> 2] = 0x03ca4000;
- s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */
- memory_region_init_io(&s->mm_iomem, NULL, &pxa2xx_mm_ops, s, "pxa2xx-mm", 0x1000);
- memory_region_add_subregion(address_space, s->mm_base, &s->mm_iomem);
- vmstate_register(NULL, 0, &vmstate_pxa2xx_mm, s);
-
- s->pm_base = 0x40f00000;
- memory_region_init_io(&s->pm_iomem, NULL, &pxa2xx_pm_ops, s, "pxa2xx-pm", 0x100);
- memory_region_add_subregion(address_space, s->pm_base, &s->pm_iomem);
- vmstate_register(NULL, 0, &vmstate_pxa2xx_pm, s);
-
- for (i = 0; pxa255_ssp[i].io_base; i ++);
- s->ssp = g_new0(SSIBus *, i);
- for (i = 0; pxa255_ssp[i].io_base; i ++) {
- DeviceState *dev;
- dev = sysbus_create_simple(TYPE_PXA2XX_SSP, pxa255_ssp[i].io_base,
- qdev_get_gpio_in(s->pic, pxa255_ssp[i].irqn));
- s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
- }
-
- s->pcmcia[0] = PXA2XX_PCMCIA(sysbus_create_simple(TYPE_PXA2XX_PCMCIA,
- 0x20000000, NULL));
- s->pcmcia[1] = PXA2XX_PCMCIA(sysbus_create_simple(TYPE_PXA2XX_PCMCIA,
- 0x30000000, NULL));
-
- sysbus_create_simple(TYPE_PXA2XX_RTC, 0x40900000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_RTCALARM));
-
- s->i2c[0] = pxa2xx_i2c_init(0x40301600,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2C), 0xffff);
- s->i2c[1] = pxa2xx_i2c_init(0x40f00100,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_PWRI2C), 0xff);
-
- s->i2s = pxa2xx_i2s_init(address_space, 0x40400000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_I2S),
- qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_I2S),
- qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_I2S));
-
- /* GPIO1 resets the processor */
- /* The handler can be overridden by board-specific code */
- qdev_connect_gpio_out(s->gpio, 1, s->reset);
- return s;
-}
-
-static void pxa2xx_ssp_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = pxa2xx_ssp_reset;
- dc->vmsd = &vmstate_pxa2xx_ssp;
-}
-
-static const TypeInfo pxa2xx_ssp_info = {
- .name = TYPE_PXA2XX_SSP,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxSSPState),
- .instance_init = pxa2xx_ssp_init,
- .class_init = pxa2xx_ssp_class_init,
-};
-
-static void pxa2xx_register_types(void)
-{
- type_register_static(&pxa2xx_i2c_slave_info);
- type_register_static(&pxa2xx_ssp_info);
- type_register_static(&pxa2xx_i2c_info);
- type_register_static(&pxa2xx_rtc_sysbus_info);
- type_register_static(&pxa2xx_fir_info);
-}
-
-type_init(pxa2xx_register_types)
diff --git a/hw/arm/pxa2xx_gpio.c b/hw/arm/pxa2xx_gpio.c
deleted file mode 100644
index 41dca03..0000000
--- a/hw/arm/pxa2xx_gpio.c
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Intel XScale PXA255/270 GPIO controller emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "hw/irq.h"
-#include "hw/qdev-properties.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "hw/arm/pxa.h"
-#include "qapi/error.h"
-#include "qemu/log.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-#define PXA2XX_GPIO_BANKS 4
-
-#define TYPE_PXA2XX_GPIO "pxa2xx-gpio"
-OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxGPIOInfo, PXA2XX_GPIO)
-
-struct PXA2xxGPIOInfo {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- qemu_irq irq0, irq1, irqX;
- int lines;
- ARMCPU *cpu;
-
- /* XXX: GNU C vectors are more suitable */
- uint32_t ilevel[PXA2XX_GPIO_BANKS];
- uint32_t olevel[PXA2XX_GPIO_BANKS];
- uint32_t dir[PXA2XX_GPIO_BANKS];
- uint32_t rising[PXA2XX_GPIO_BANKS];
- uint32_t falling[PXA2XX_GPIO_BANKS];
- uint32_t status[PXA2XX_GPIO_BANKS];
- uint32_t gafr[PXA2XX_GPIO_BANKS * 2];
-
- uint32_t prev_level[PXA2XX_GPIO_BANKS];
- qemu_irq handler[PXA2XX_GPIO_BANKS * 32];
- qemu_irq read_notify;
-};
-
-static struct {
- enum {
- GPIO_NONE,
- GPLR,
- GPSR,
- GPCR,
- GPDR,
- GRER,
- GFER,
- GEDR,
- GAFR_L,
- GAFR_U,
- } reg;
- int bank;
-} pxa2xx_gpio_regs[0x200] = {
- [0 ... 0x1ff] = { GPIO_NONE, 0 },
-#define PXA2XX_REG(reg, a0, a1, a2, a3) \
- [a0] = { reg, 0 }, [a1] = { reg, 1 }, [a2] = { reg, 2 }, [a3] = { reg, 3 },
-
- PXA2XX_REG(GPLR, 0x000, 0x004, 0x008, 0x100)
- PXA2XX_REG(GPSR, 0x018, 0x01c, 0x020, 0x118)
- PXA2XX_REG(GPCR, 0x024, 0x028, 0x02c, 0x124)
- PXA2XX_REG(GPDR, 0x00c, 0x010, 0x014, 0x10c)
- PXA2XX_REG(GRER, 0x030, 0x034, 0x038, 0x130)
- PXA2XX_REG(GFER, 0x03c, 0x040, 0x044, 0x13c)
- PXA2XX_REG(GEDR, 0x048, 0x04c, 0x050, 0x148)
- PXA2XX_REG(GAFR_L, 0x054, 0x05c, 0x064, 0x06c)
- PXA2XX_REG(GAFR_U, 0x058, 0x060, 0x068, 0x070)
-};
-
-static void pxa2xx_gpio_irq_update(PXA2xxGPIOInfo *s)
-{
- if (s->status[0] & (1 << 0))
- qemu_irq_raise(s->irq0);
- else
- qemu_irq_lower(s->irq0);
-
- if (s->status[0] & (1 << 1))
- qemu_irq_raise(s->irq1);
- else
- qemu_irq_lower(s->irq1);
-
- if ((s->status[0] & ~3) | s->status[1] | s->status[2] | s->status[3])
- qemu_irq_raise(s->irqX);
- else
- qemu_irq_lower(s->irqX);
-}
-
-/* Bitmap of pins used as standby and sleep wake-up sources. */
-static const int pxa2xx_gpio_wake[PXA2XX_GPIO_BANKS] = {
- 0x8003fe1b, 0x002001fc, 0xec080000, 0x0012007f,
-};
-
-static void pxa2xx_gpio_set(void *opaque, int line, int level)
-{
- PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque;
- CPUState *cpu = CPU(s->cpu);
- int bank;
- uint32_t mask;
-
- if (line >= s->lines) {
- printf("%s: No GPIO pin %i\n", __func__, line);
- return;
- }
-
- bank = line >> 5;
- mask = 1U << (line & 31);
-
- if (level) {
- s->status[bank] |= s->rising[bank] & mask &
- ~s->ilevel[bank] & ~s->dir[bank];
- s->ilevel[bank] |= mask;
- } else {
- s->status[bank] |= s->falling[bank] & mask &
- s->ilevel[bank] & ~s->dir[bank];
- s->ilevel[bank] &= ~mask;
- }
-
- if (s->status[bank] & mask)
- pxa2xx_gpio_irq_update(s);
-
- /* Wake-up GPIOs */
- if (cpu->halted && (mask & ~s->dir[bank] & pxa2xx_gpio_wake[bank])) {
- cpu_interrupt(cpu, CPU_INTERRUPT_EXITTB);
- }
-}
-
-static void pxa2xx_gpio_handler_update(PXA2xxGPIOInfo *s) {
- uint32_t level, diff;
- int i, bit, line;
- for (i = 0; i < PXA2XX_GPIO_BANKS; i ++) {
- level = s->olevel[i] & s->dir[i];
-
- for (diff = s->prev_level[i] ^ level; diff; diff ^= 1 << bit) {
- bit = ctz32(diff);
- line = bit + 32 * i;
- qemu_set_irq(s->handler[line], (level >> bit) & 1);
- }
-
- s->prev_level[i] = level;
- }
-}
-
-static uint64_t pxa2xx_gpio_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque;
- uint32_t ret;
- int bank;
- if (offset >= 0x200)
- return 0;
-
- bank = pxa2xx_gpio_regs[offset].bank;
- switch (pxa2xx_gpio_regs[offset].reg) {
- case GPDR: /* GPIO Pin-Direction registers */
- return s->dir[bank];
-
- case GPSR: /* GPIO Pin-Output Set registers */
- qemu_log_mask(LOG_GUEST_ERROR,
- "pxa2xx GPIO: read from write only register GPSR\n");
- return 0;
-
- case GPCR: /* GPIO Pin-Output Clear registers */
- qemu_log_mask(LOG_GUEST_ERROR,
- "pxa2xx GPIO: read from write only register GPCR\n");
- return 0;
-
- case GRER: /* GPIO Rising-Edge Detect Enable registers */
- return s->rising[bank];
-
- case GFER: /* GPIO Falling-Edge Detect Enable registers */
- return s->falling[bank];
-
- case GAFR_L: /* GPIO Alternate Function registers */
- return s->gafr[bank * 2];
-
- case GAFR_U: /* GPIO Alternate Function registers */
- return s->gafr[bank * 2 + 1];
-
- case GPLR: /* GPIO Pin-Level registers */
- ret = (s->olevel[bank] & s->dir[bank]) |
- (s->ilevel[bank] & ~s->dir[bank]);
- qemu_irq_raise(s->read_notify);
- return ret;
-
- case GEDR: /* GPIO Edge Detect Status registers */
- return s->status[bank];
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
- __func__, offset);
- }
-
- return 0;
-}
-
-static void pxa2xx_gpio_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque;
- int bank;
- if (offset >= 0x200)
- return;
-
- bank = pxa2xx_gpio_regs[offset].bank;
- switch (pxa2xx_gpio_regs[offset].reg) {
- case GPDR: /* GPIO Pin-Direction registers */
- s->dir[bank] = value;
- pxa2xx_gpio_handler_update(s);
- break;
-
- case GPSR: /* GPIO Pin-Output Set registers */
- s->olevel[bank] |= value;
- pxa2xx_gpio_handler_update(s);
- break;
-
- case GPCR: /* GPIO Pin-Output Clear registers */
- s->olevel[bank] &= ~value;
- pxa2xx_gpio_handler_update(s);
- break;
-
- case GRER: /* GPIO Rising-Edge Detect Enable registers */
- s->rising[bank] = value;
- break;
-
- case GFER: /* GPIO Falling-Edge Detect Enable registers */
- s->falling[bank] = value;
- break;
-
- case GAFR_L: /* GPIO Alternate Function registers */
- s->gafr[bank * 2] = value;
- break;
-
- case GAFR_U: /* GPIO Alternate Function registers */
- s->gafr[bank * 2 + 1] = value;
- break;
-
- case GEDR: /* GPIO Edge Detect Status registers */
- s->status[bank] &= ~value;
- pxa2xx_gpio_irq_update(s);
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
- __func__, offset);
- }
-}
-
-static const MemoryRegionOps pxa_gpio_ops = {
- .read = pxa2xx_gpio_read,
- .write = pxa2xx_gpio_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-DeviceState *pxa2xx_gpio_init(hwaddr base,
- ARMCPU *cpu, DeviceState *pic, int lines)
-{
- DeviceState *dev;
-
- dev = qdev_new(TYPE_PXA2XX_GPIO);
- qdev_prop_set_int32(dev, "lines", lines);
- object_property_set_link(OBJECT(dev), "cpu", OBJECT(cpu), &error_abort);
- 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,
- qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_0));
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1,
- qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_1));
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2,
- qdev_get_gpio_in(pic, PXA2XX_PIC_GPIO_X));
-
- return dev;
-}
-
-static void pxa2xx_gpio_initfn(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- DeviceState *dev = DEVICE(sbd);
- PXA2xxGPIOInfo *s = PXA2XX_GPIO(dev);
-
- memory_region_init_io(&s->iomem, obj, &pxa_gpio_ops,
- s, "pxa2xx-gpio", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq0);
- sysbus_init_irq(sbd, &s->irq1);
- sysbus_init_irq(sbd, &s->irqX);
-}
-
-static void pxa2xx_gpio_realize(DeviceState *dev, Error **errp)
-{
- PXA2xxGPIOInfo *s = PXA2XX_GPIO(dev);
-
- qdev_init_gpio_in(dev, pxa2xx_gpio_set, s->lines);
- qdev_init_gpio_out(dev, s->handler, s->lines);
-}
-
-/*
- * Registers a callback to notify on GPLR reads. This normally
- * shouldn't be needed but it is used for the hack on Spitz machines.
- */
-void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler)
-{
- PXA2xxGPIOInfo *s = PXA2XX_GPIO(dev);
-
- s->read_notify = handler;
-}
-
-static const VMStateDescription vmstate_pxa2xx_gpio_regs = {
- .name = "pxa2xx-gpio",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32_ARRAY(ilevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
- VMSTATE_UINT32_ARRAY(olevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
- VMSTATE_UINT32_ARRAY(dir, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
- VMSTATE_UINT32_ARRAY(rising, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
- VMSTATE_UINT32_ARRAY(falling, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
- VMSTATE_UINT32_ARRAY(status, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
- VMSTATE_UINT32_ARRAY(gafr, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS * 2),
- VMSTATE_UINT32_ARRAY(prev_level, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static Property pxa2xx_gpio_properties[] = {
- DEFINE_PROP_INT32("lines", PXA2xxGPIOInfo, lines, 0),
- DEFINE_PROP_LINK("cpu", PXA2xxGPIOInfo, cpu, TYPE_ARM_CPU, ARMCPU *),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxa2xx_gpio_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->desc = "PXA2xx GPIO controller";
- device_class_set_props(dc, pxa2xx_gpio_properties);
- dc->vmsd = &vmstate_pxa2xx_gpio_regs;
- dc->realize = pxa2xx_gpio_realize;
-}
-
-static const TypeInfo pxa2xx_gpio_info = {
- .name = TYPE_PXA2XX_GPIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxGPIOInfo),
- .instance_init = pxa2xx_gpio_initfn,
- .class_init = pxa2xx_gpio_class_init,
-};
-
-static void pxa2xx_gpio_register_types(void)
-{
- type_register_static(&pxa2xx_gpio_info);
-}
-
-type_init(pxa2xx_gpio_register_types)
diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c
deleted file mode 100644
index 34c5555..0000000
--- a/hw/arm/pxa2xx_pic.c
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * Intel XScale PXA Programmable Interrupt Controller.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Copyright (c) 2006 Thorsten Zitterell
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu/module.h"
-#include "qemu/log.h"
-#include "cpu.h"
-#include "hw/arm/pxa.h"
-#include "hw/sysbus.h"
-#include "hw/qdev-properties.h"
-#include "migration/vmstate.h"
-#include "qom/object.h"
-#include "target/arm/cpregs.h"
-
-#define ICIP 0x00 /* Interrupt Controller IRQ Pending register */
-#define ICMR 0x04 /* Interrupt Controller Mask register */
-#define ICLR 0x08 /* Interrupt Controller Level register */
-#define ICFP 0x0c /* Interrupt Controller FIQ Pending register */
-#define ICPR 0x10 /* Interrupt Controller Pending register */
-#define ICCR 0x14 /* Interrupt Controller Control register */
-#define ICHP 0x18 /* Interrupt Controller Highest Priority register */
-#define IPR0 0x1c /* Interrupt Controller Priority register 0 */
-#define IPR31 0x98 /* Interrupt Controller Priority register 31 */
-#define ICIP2 0x9c /* Interrupt Controller IRQ Pending register 2 */
-#define ICMR2 0xa0 /* Interrupt Controller Mask register 2 */
-#define ICLR2 0xa4 /* Interrupt Controller Level register 2 */
-#define ICFP2 0xa8 /* Interrupt Controller FIQ Pending register 2 */
-#define ICPR2 0xac /* Interrupt Controller Pending register 2 */
-#define IPR32 0xb0 /* Interrupt Controller Priority register 32 */
-#define IPR39 0xcc /* Interrupt Controller Priority register 39 */
-
-#define PXA2XX_PIC_SRCS 40
-
-#define TYPE_PXA2XX_PIC "pxa2xx_pic"
-OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxPICState, PXA2XX_PIC)
-
-struct PXA2xxPICState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- MemoryRegion iomem;
- ARMCPU *cpu;
- uint32_t int_enabled[2];
- uint32_t int_pending[2];
- uint32_t is_fiq[2];
- uint32_t int_idle;
- uint32_t priority[PXA2XX_PIC_SRCS];
-};
-
-static void pxa2xx_pic_update(void *opaque)
-{
- uint32_t mask[2];
- PXA2xxPICState *s = (PXA2xxPICState *) opaque;
- CPUState *cpu = CPU(s->cpu);
-
- if (cpu->halted) {
- mask[0] = s->int_pending[0] & (s->int_enabled[0] | s->int_idle);
- mask[1] = s->int_pending[1] & (s->int_enabled[1] | s->int_idle);
- if (mask[0] || mask[1]) {
- cpu_interrupt(cpu, CPU_INTERRUPT_EXITTB);
- }
- }
-
- mask[0] = s->int_pending[0] & s->int_enabled[0];
- mask[1] = s->int_pending[1] & s->int_enabled[1];
-
- if ((mask[0] & s->is_fiq[0]) || (mask[1] & s->is_fiq[1])) {
- cpu_interrupt(cpu, CPU_INTERRUPT_FIQ);
- } else {
- cpu_reset_interrupt(cpu, CPU_INTERRUPT_FIQ);
- }
-
- if ((mask[0] & ~s->is_fiq[0]) || (mask[1] & ~s->is_fiq[1])) {
- cpu_interrupt(cpu, CPU_INTERRUPT_HARD);
- } else {
- cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD);
- }
-}
-
-/* Note: Here level means state of the signal on a pin, not
- * IRQ/FIQ distinction as in PXA Developer Manual. */
-static void pxa2xx_pic_set_irq(void *opaque, int irq, int level)
-{
- PXA2xxPICState *s = (PXA2xxPICState *) opaque;
- int int_set = (irq >= 32);
- irq &= 31;
-
- if (level)
- s->int_pending[int_set] |= 1 << irq;
- else
- s->int_pending[int_set] &= ~(1 << irq);
-
- pxa2xx_pic_update(opaque);
-}
-
-static inline uint32_t pxa2xx_pic_highest(PXA2xxPICState *s) {
- int i, int_set, irq;
- uint32_t bit, mask[2];
- uint32_t ichp = 0x003f003f; /* Both IDs invalid */
-
- mask[0] = s->int_pending[0] & s->int_enabled[0];
- mask[1] = s->int_pending[1] & s->int_enabled[1];
-
- for (i = PXA2XX_PIC_SRCS - 1; i >= 0; i --) {
- irq = s->priority[i] & 0x3f;
- if ((s->priority[i] & (1U << 31)) && irq < PXA2XX_PIC_SRCS) {
- /* Source peripheral ID is valid. */
- bit = 1 << (irq & 31);
- int_set = (irq >= 32);
-
- if (mask[int_set] & bit & s->is_fiq[int_set]) {
- /* FIQ asserted */
- ichp &= 0xffff0000;
- ichp |= (1 << 15) | irq;
- }
-
- if (mask[int_set] & bit & ~s->is_fiq[int_set]) {
- /* IRQ asserted */
- ichp &= 0x0000ffff;
- ichp |= (1U << 31) | (irq << 16);
- }
- }
- }
-
- return ichp;
-}
-
-static uint64_t pxa2xx_pic_mem_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PXA2xxPICState *s = (PXA2xxPICState *) opaque;
-
- switch (offset) {
- case ICIP: /* IRQ Pending register */
- return s->int_pending[0] & ~s->is_fiq[0] & s->int_enabled[0];
- case ICIP2: /* IRQ Pending register 2 */
- return s->int_pending[1] & ~s->is_fiq[1] & s->int_enabled[1];
- case ICMR: /* Mask register */
- return s->int_enabled[0];
- case ICMR2: /* Mask register 2 */
- return s->int_enabled[1];
- case ICLR: /* Level register */
- return s->is_fiq[0];
- case ICLR2: /* Level register 2 */
- return s->is_fiq[1];
- case ICCR: /* Idle mask */
- return (s->int_idle == 0);
- case ICFP: /* FIQ Pending register */
- return s->int_pending[0] & s->is_fiq[0] & s->int_enabled[0];
- case ICFP2: /* FIQ Pending register 2 */
- return s->int_pending[1] & s->is_fiq[1] & s->int_enabled[1];
- case ICPR: /* Pending register */
- return s->int_pending[0];
- case ICPR2: /* Pending register 2 */
- return s->int_pending[1];
- case IPR0 ... IPR31:
- return s->priority[0 + ((offset - IPR0 ) >> 2)];
- case IPR32 ... IPR39:
- return s->priority[32 + ((offset - IPR32) >> 2)];
- case ICHP: /* Highest Priority register */
- return pxa2xx_pic_highest(s);
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pxa2xx_pic_mem_read: bad register offset 0x%" HWADDR_PRIx
- "\n", offset);
- return 0;
- }
-}
-
-static void pxa2xx_pic_mem_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxPICState *s = (PXA2xxPICState *) opaque;
-
- switch (offset) {
- case ICMR: /* Mask register */
- s->int_enabled[0] = value;
- break;
- case ICMR2: /* Mask register 2 */
- s->int_enabled[1] = value;
- break;
- case ICLR: /* Level register */
- s->is_fiq[0] = value;
- break;
- case ICLR2: /* Level register 2 */
- s->is_fiq[1] = value;
- break;
- case ICCR: /* Idle mask */
- s->int_idle = (value & 1) ? 0 : ~0;
- break;
- case IPR0 ... IPR31:
- s->priority[0 + ((offset - IPR0 ) >> 2)] = value & 0x8000003f;
- break;
- case IPR32 ... IPR39:
- s->priority[32 + ((offset - IPR32) >> 2)] = value & 0x8000003f;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "pxa2xx_pic_mem_write: bad register offset 0x%"
- HWADDR_PRIx "\n", offset);
- return;
- }
- pxa2xx_pic_update(opaque);
-}
-
-/* Interrupt Controller Coprocessor Space Register Mapping */
-static const int pxa2xx_cp_reg_map[0x10] = {
- [0x0 ... 0xf] = -1,
- [0x0] = ICIP,
- [0x1] = ICMR,
- [0x2] = ICLR,
- [0x3] = ICFP,
- [0x4] = ICPR,
- [0x5] = ICHP,
- [0x6] = ICIP2,
- [0x7] = ICMR2,
- [0x8] = ICLR2,
- [0x9] = ICFP2,
- [0xa] = ICPR2,
-};
-
-static uint64_t pxa2xx_pic_cp_read(CPUARMState *env, const ARMCPRegInfo *ri)
-{
- int offset = pxa2xx_cp_reg_map[ri->crn];
- return pxa2xx_pic_mem_read(ri->opaque, offset, 4);
-}
-
-static void pxa2xx_pic_cp_write(CPUARMState *env, const ARMCPRegInfo *ri,
- uint64_t value)
-{
- int offset = pxa2xx_cp_reg_map[ri->crn];
- pxa2xx_pic_mem_write(ri->opaque, offset, value, 4);
-}
-
-#define REGINFO_FOR_PIC_CP(NAME, CRN) \
- { .name = NAME, .cp = 6, .crn = CRN, .crm = 0, .opc1 = 0, .opc2 = 0, \
- .access = PL1_RW, .type = ARM_CP_IO, \
- .readfn = pxa2xx_pic_cp_read, .writefn = pxa2xx_pic_cp_write }
-
-static const ARMCPRegInfo pxa_pic_cp_reginfo[] = {
- REGINFO_FOR_PIC_CP("ICIP", 0),
- REGINFO_FOR_PIC_CP("ICMR", 1),
- REGINFO_FOR_PIC_CP("ICLR", 2),
- REGINFO_FOR_PIC_CP("ICFP", 3),
- REGINFO_FOR_PIC_CP("ICPR", 4),
- REGINFO_FOR_PIC_CP("ICHP", 5),
- REGINFO_FOR_PIC_CP("ICIP2", 6),
- REGINFO_FOR_PIC_CP("ICMR2", 7),
- REGINFO_FOR_PIC_CP("ICLR2", 8),
- REGINFO_FOR_PIC_CP("ICFP2", 9),
- REGINFO_FOR_PIC_CP("ICPR2", 0xa),
-};
-
-static const MemoryRegionOps pxa2xx_pic_ops = {
- .read = pxa2xx_pic_mem_read,
- .write = pxa2xx_pic_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int pxa2xx_pic_post_load(void *opaque, int version_id)
-{
- pxa2xx_pic_update(opaque);
- return 0;
-}
-
-static void pxa2xx_pic_reset_hold(Object *obj, ResetType type)
-{
- PXA2xxPICState *s = PXA2XX_PIC(obj);
-
- s->int_pending[0] = 0;
- s->int_pending[1] = 0;
- s->int_enabled[0] = 0;
- s->int_enabled[1] = 0;
- s->is_fiq[0] = 0;
- s->is_fiq[1] = 0;
-}
-
-DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu)
-{
- DeviceState *dev = qdev_new(TYPE_PXA2XX_PIC);
-
- object_property_set_link(OBJECT(dev), "arm-cpu",
- OBJECT(cpu), &error_abort);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-
- return dev;
-}
-
-static void pxa2xx_pic_realize(DeviceState *dev, Error **errp)
-{
- PXA2xxPICState *s = PXA2XX_PIC(dev);
-
- qdev_init_gpio_in(dev, pxa2xx_pic_set_irq, PXA2XX_PIC_SRCS);
-
- /* Enable IC memory-mapped registers access. */
- memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_pic_ops, s,
- "pxa2xx-pic", 0x00100000);
- sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
-
- /* Enable IC coprocessor access. */
- define_arm_cp_regs_with_opaque(s->cpu, pxa_pic_cp_reginfo, s);
-}
-
-static const VMStateDescription vmstate_pxa2xx_pic_regs = {
- .name = "pxa2xx_pic",
- .version_id = 0,
- .minimum_version_id = 0,
- .post_load = pxa2xx_pic_post_load,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32_ARRAY(int_enabled, PXA2xxPICState, 2),
- VMSTATE_UINT32_ARRAY(int_pending, PXA2xxPICState, 2),
- VMSTATE_UINT32_ARRAY(is_fiq, PXA2xxPICState, 2),
- VMSTATE_UINT32(int_idle, PXA2xxPICState),
- VMSTATE_UINT32_ARRAY(priority, PXA2xxPICState, PXA2XX_PIC_SRCS),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static Property pxa2xx_pic_properties[] = {
- DEFINE_PROP_LINK("arm-cpu", PXA2xxPICState, cpu,
- TYPE_ARM_CPU, ARMCPU *),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxa2xx_pic_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- ResettableClass *rc = RESETTABLE_CLASS(klass);
-
- device_class_set_props(dc, pxa2xx_pic_properties);
- dc->realize = pxa2xx_pic_realize;
- dc->desc = "PXA2xx PIC";
- dc->vmsd = &vmstate_pxa2xx_pic_regs;
- rc->phases.hold = pxa2xx_pic_reset_hold;
-}
-
-static const TypeInfo pxa2xx_pic_info = {
- .name = TYPE_PXA2XX_PIC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxPICState),
- .class_init = pxa2xx_pic_class_init,
-};
-
-static void pxa2xx_pic_register_types(void)
-{
- type_register_static(&pxa2xx_pic_info);
-}
-
-type_init(pxa2xx_pic_register_types)
diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
index ae37a92..e3195d5 100644
--- a/hw/arm/sbsa-ref.c
+++ b/hw/arm/sbsa-ref.c
@@ -164,23 +164,20 @@ static uint64_t sbsa_ref_cpu_mp_affinity(SBSAMachineState *sms, int idx)
static void sbsa_fdt_add_gic_node(SBSAMachineState *sms)
{
- char *nodename;
+ const char *intc_nodename = "/intc";
+ const char *its_nodename = "/intc/its";
- nodename = g_strdup_printf("/intc");
- qemu_fdt_add_subnode(sms->fdt, nodename);
- qemu_fdt_setprop_sized_cells(sms->fdt, nodename, "reg",
+ qemu_fdt_add_subnode(sms->fdt, intc_nodename);
+ qemu_fdt_setprop_sized_cells(sms->fdt, intc_nodename, "reg",
2, sbsa_ref_memmap[SBSA_GIC_DIST].base,
2, sbsa_ref_memmap[SBSA_GIC_DIST].size,
2, sbsa_ref_memmap[SBSA_GIC_REDIST].base,
2, sbsa_ref_memmap[SBSA_GIC_REDIST].size);
- nodename = g_strdup_printf("/intc/its");
- qemu_fdt_add_subnode(sms->fdt, nodename);
- qemu_fdt_setprop_sized_cells(sms->fdt, nodename, "reg",
+ qemu_fdt_add_subnode(sms->fdt, its_nodename);
+ qemu_fdt_setprop_sized_cells(sms->fdt, its_nodename, "reg",
2, sbsa_ref_memmap[SBSA_GIC_ITS].base,
2, sbsa_ref_memmap[SBSA_GIC_ITS].size);
-
- g_free(nodename);
}
/*
@@ -621,6 +618,7 @@ static void create_smmu(const SBSAMachineState *sms, PCIBus *bus)
dev = qdev_new(TYPE_ARM_SMMUV3);
+ object_property_set_str(OBJECT(dev), "stage", "nested", &error_abort);
object_property_set_link(OBJECT(dev), "primary-bus", OBJECT(bus),
&error_abort);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index d73ad62..3f82728 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -674,7 +674,7 @@ error:
/*
* combine S1 and S2 TLB entries into a single entry.
- * As a result the S1 entry is overriden with combined data.
+ * As a result the S1 entry is overridden with combined data.
*/
static void combine_tlb(SMMUTLBEntry *tlbe, SMMUTLBEntry *tlbe_s2,
dma_addr_t iova, SMMUTransCfg *cfg)
diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
index 0ebf2ee..b6b7399 100644
--- a/hw/arm/smmuv3-internal.h
+++ b/hw/arm/smmuv3-internal.h
@@ -599,7 +599,8 @@ static inline int oas2bits(int oas_field)
case 5:
return 48;
}
- return -1;
+
+ g_assert_not_reached();
}
/* CD fields */
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 3971976..4c49b5a 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1981,6 +1981,7 @@ static Property smmuv3_properties[] = {
* Stages of translation advertised.
* "1": Stage 1
* "2": Stage 2
+ * "nested": Both stage 1 and stage 2
* Defaults to stage 1
*/
DEFINE_PROP_STRING("stage", SMMUv3State, stage),
diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c
deleted file mode 100644
index 62cd55b..0000000
--- a/hw/arm/spitz.c
+++ /dev/null
@@ -1,1284 +0,0 @@
-/*
- * PXA270-based Clamshell PDA platforms.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPL v2.
- *
- * 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 "qapi/error.h"
-#include "hw/arm/pxa.h"
-#include "hw/arm/boot.h"
-#include "sysemu/runstate.h"
-#include "sysemu/sysemu.h"
-#include "hw/pcmcia.h"
-#include "hw/qdev-properties.h"
-#include "hw/i2c/i2c.h"
-#include "hw/irq.h"
-#include "hw/ssi/ssi.h"
-#include "hw/block/flash.h"
-#include "qemu/timer.h"
-#include "qemu/log.h"
-#include "hw/arm/sharpsl.h"
-#include "ui/console.h"
-#include "hw/audio/wm8750.h"
-#include "audio/audio.h"
-#include "hw/boards.h"
-#include "hw/sysbus.h"
-#include "hw/adc/max111x.h"
-#include "migration/vmstate.h"
-#include "exec/address-spaces.h"
-#include "qom/object.h"
-#include "audio/audio.h"
-
-enum spitz_model_e { spitz, akita, borzoi, terrier };
-
-struct SpitzMachineClass {
- MachineClass parent;
- enum spitz_model_e model;
- int arm_id;
-};
-
-struct SpitzMachineState {
- MachineState parent;
- PXA2xxState *mpu;
- DeviceState *mux;
- DeviceState *lcdtg;
- DeviceState *ads7846;
- DeviceState *max1111;
- DeviceState *scp0;
- DeviceState *scp1;
- DeviceState *misc_gpio;
-};
-
-#define TYPE_SPITZ_MACHINE "spitz-common"
-OBJECT_DECLARE_TYPE(SpitzMachineState, SpitzMachineClass, SPITZ_MACHINE)
-
-#define zaurus_printf(format, ...) \
- fprintf(stderr, "%s: " format, __func__, ##__VA_ARGS__)
-
-/* Spitz Flash */
-#define FLASH_BASE 0x0c000000
-#define FLASH_ECCLPLB 0x00 /* Line parity 7 - 0 bit */
-#define FLASH_ECCLPUB 0x04 /* Line parity 15 - 8 bit */
-#define FLASH_ECCCP 0x08 /* Column parity 5 - 0 bit */
-#define FLASH_ECCCNTR 0x0c /* ECC byte counter */
-#define FLASH_ECCCLRR 0x10 /* Clear ECC */
-#define FLASH_FLASHIO 0x14 /* Flash I/O */
-#define FLASH_FLASHCTL 0x18 /* Flash Control */
-
-#define FLASHCTL_CE0 (1 << 0)
-#define FLASHCTL_CLE (1 << 1)
-#define FLASHCTL_ALE (1 << 2)
-#define FLASHCTL_WP (1 << 3)
-#define FLASHCTL_CE1 (1 << 4)
-#define FLASHCTL_RYBY (1 << 5)
-#define FLASHCTL_NCE (FLASHCTL_CE0 | FLASHCTL_CE1)
-
-#define TYPE_SL_NAND "sl-nand"
-OBJECT_DECLARE_SIMPLE_TYPE(SLNANDState, SL_NAND)
-
-struct SLNANDState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- DeviceState *nand;
- uint8_t ctl;
- uint8_t manf_id;
- uint8_t chip_id;
- ECCState ecc;
-};
-
-static uint64_t sl_read(void *opaque, hwaddr addr, unsigned size)
-{
- SLNANDState *s = (SLNANDState *) opaque;
- int ryby;
-
- switch (addr) {
-#define BSHR(byte, from, to) ((s->ecc.lp[byte] >> (from - to)) & (1 << to))
- case FLASH_ECCLPLB:
- return BSHR(0, 4, 0) | BSHR(0, 5, 2) | BSHR(0, 6, 4) | BSHR(0, 7, 6) |
- BSHR(1, 4, 1) | BSHR(1, 5, 3) | BSHR(1, 6, 5) | BSHR(1, 7, 7);
-
-#define BSHL(byte, from, to) ((s->ecc.lp[byte] << (to - from)) & (1 << to))
- case FLASH_ECCLPUB:
- return BSHL(0, 0, 0) | BSHL(0, 1, 2) | BSHL(0, 2, 4) | BSHL(0, 3, 6) |
- BSHL(1, 0, 1) | BSHL(1, 1, 3) | BSHL(1, 2, 5) | BSHL(1, 3, 7);
-
- case FLASH_ECCCP:
- return s->ecc.cp;
-
- case FLASH_ECCCNTR:
- return s->ecc.count & 0xff;
-
- case FLASH_FLASHCTL:
- nand_getpins(s->nand, &ryby);
- if (ryby)
- return s->ctl | FLASHCTL_RYBY;
- else
- return s->ctl;
-
- case FLASH_FLASHIO:
- if (size == 4) {
- return ecc_digest(&s->ecc, nand_getio(s->nand)) |
- (ecc_digest(&s->ecc, nand_getio(s->nand)) << 16);
- }
- return ecc_digest(&s->ecc, nand_getio(s->nand));
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "sl_read: bad register offset 0x%02" HWADDR_PRIx "\n",
- addr);
- }
- return 0;
-}
-
-static void sl_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- SLNANDState *s = (SLNANDState *) opaque;
-
- switch (addr) {
- case FLASH_ECCCLRR:
- /* Value is ignored. */
- ecc_reset(&s->ecc);
- break;
-
- case FLASH_FLASHCTL:
- s->ctl = value & 0xff & ~FLASHCTL_RYBY;
- nand_setpins(s->nand,
- s->ctl & FLASHCTL_CLE,
- s->ctl & FLASHCTL_ALE,
- s->ctl & FLASHCTL_NCE,
- s->ctl & FLASHCTL_WP,
- 0);
- break;
-
- case FLASH_FLASHIO:
- nand_setio(s->nand, ecc_digest(&s->ecc, value & 0xff));
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "sl_write: bad register offset 0x%02" HWADDR_PRIx "\n",
- addr);
- }
-}
-
-enum {
- FLASH_128M,
- FLASH_1024M,
-};
-
-static const MemoryRegionOps sl_ops = {
- .read = sl_read,
- .write = sl_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void sl_flash_register(PXA2xxState *cpu, int size)
-{
- DeviceState *dev;
-
- dev = qdev_new(TYPE_SL_NAND);
-
- qdev_prop_set_uint8(dev, "manf_id", NAND_MFR_SAMSUNG);
- if (size == FLASH_128M)
- qdev_prop_set_uint8(dev, "chip_id", 0x73);
- else if (size == FLASH_1024M)
- qdev_prop_set_uint8(dev, "chip_id", 0xf1);
-
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, FLASH_BASE);
-}
-
-static void sl_nand_init(Object *obj)
-{
- SLNANDState *s = SL_NAND(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
-
- s->ctl = 0;
-
- memory_region_init_io(&s->iomem, obj, &sl_ops, s, "sl", 0x40);
- sysbus_init_mmio(dev, &s->iomem);
-}
-
-static void sl_nand_realize(DeviceState *dev, Error **errp)
-{
- SLNANDState *s = SL_NAND(dev);
- DriveInfo *nand;
-
- /* FIXME use a qdev drive property instead of drive_get() */
- nand = drive_get(IF_MTD, 0, 0);
- s->nand = nand_init(nand ? blk_by_legacy_dinfo(nand) : NULL,
- s->manf_id, s->chip_id);
-}
-
-/* Spitz Keyboard */
-
-#define SPITZ_KEY_STROBE_NUM 11
-#define SPITZ_KEY_SENSE_NUM 7
-
-static const int spitz_gpio_key_sense[SPITZ_KEY_SENSE_NUM] = {
- 12, 17, 91, 34, 36, 38, 39
-};
-
-static const int spitz_gpio_key_strobe[SPITZ_KEY_STROBE_NUM] = {
- 88, 23, 24, 25, 26, 27, 52, 103, 107, 108, 114
-};
-
-/* Eighth additional row maps the special keys */
-static int spitz_keymap[SPITZ_KEY_SENSE_NUM + 1][SPITZ_KEY_STROBE_NUM] = {
- { 0x1d, 0x02, 0x04, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0e, 0x3f, 0x40 },
- { -1 , 0x03, 0x05, 0x13, 0x15, 0x09, 0x17, 0x18, 0x19, 0x41, 0x42 },
- { 0x0f, 0x10, 0x12, 0x14, 0x22, 0x16, 0x24, 0x25, -1 , -1 , -1 },
- { 0x3c, 0x11, 0x1f, 0x21, 0x2f, 0x23, 0x32, 0x26, -1 , 0x36, -1 },
- { 0x3b, 0x1e, 0x20, 0x2e, 0x30, 0x31, 0x34, -1 , 0x1c, 0x2a, -1 },
- { 0x44, 0x2c, 0x2d, 0x0c, 0x39, 0x33, -1 , 0x48, -1 , -1 , 0x38 },
- { 0x37, 0x3d, -1 , 0x45, 0x57, 0x58, 0x4b, 0x50, 0x4d, -1 , -1 },
- { 0x52, 0x43, 0x01, 0x47, 0x49, -1 , -1 , -1 , -1 , -1 , -1 },
-};
-
-#define SPITZ_GPIO_AK_INT 13 /* Remote control */
-#define SPITZ_GPIO_SYNC 16 /* Sync button */
-#define SPITZ_GPIO_ON_KEY 95 /* Power button */
-#define SPITZ_GPIO_SWA 97 /* Lid */
-#define SPITZ_GPIO_SWB 96 /* Tablet mode */
-
-/* The special buttons are mapped to unused keys */
-static const int spitz_gpiomap[5] = {
- SPITZ_GPIO_AK_INT, SPITZ_GPIO_SYNC, SPITZ_GPIO_ON_KEY,
- SPITZ_GPIO_SWA, SPITZ_GPIO_SWB,
-};
-
-#define TYPE_SPITZ_KEYBOARD "spitz-keyboard"
-OBJECT_DECLARE_SIMPLE_TYPE(SpitzKeyboardState, SPITZ_KEYBOARD)
-
-struct SpitzKeyboardState {
- SysBusDevice parent_obj;
-
- qemu_irq sense[SPITZ_KEY_SENSE_NUM];
- qemu_irq gpiomap[5];
- int keymap[0x80];
- uint16_t keyrow[SPITZ_KEY_SENSE_NUM];
- uint16_t strobe_state;
- uint16_t sense_state;
-
- uint16_t pre_map[0x100];
- uint16_t modifiers;
- uint16_t imodifiers;
- uint8_t fifo[16];
- int fifopos, fifolen;
- QEMUTimer *kbdtimer;
-};
-
-static void spitz_keyboard_sense_update(SpitzKeyboardState *s)
-{
- int i;
- uint16_t strobe, sense = 0;
- for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++) {
- strobe = s->keyrow[i] & s->strobe_state;
- if (strobe) {
- sense |= 1 << i;
- if (!(s->sense_state & (1 << i)))
- qemu_irq_raise(s->sense[i]);
- } else if (s->sense_state & (1 << i))
- qemu_irq_lower(s->sense[i]);
- }
-
- s->sense_state = sense;
-}
-
-static void spitz_keyboard_strobe(void *opaque, int line, int level)
-{
- SpitzKeyboardState *s = (SpitzKeyboardState *) opaque;
-
- if (level)
- s->strobe_state |= 1 << line;
- else
- s->strobe_state &= ~(1 << line);
- spitz_keyboard_sense_update(s);
-}
-
-static void spitz_keyboard_keydown(SpitzKeyboardState *s, int keycode)
-{
- int spitz_keycode = s->keymap[keycode & 0x7f];
- if (spitz_keycode == -1)
- return;
-
- /* Handle the additional keys */
- if ((spitz_keycode >> 4) == SPITZ_KEY_SENSE_NUM) {
- qemu_set_irq(s->gpiomap[spitz_keycode & 0xf], (keycode < 0x80));
- return;
- }
-
- if (keycode & 0x80)
- s->keyrow[spitz_keycode >> 4] &= ~(1 << (spitz_keycode & 0xf));
- else
- s->keyrow[spitz_keycode >> 4] |= 1 << (spitz_keycode & 0xf);
-
- spitz_keyboard_sense_update(s);
-}
-
-#define SPITZ_MOD_SHIFT (1 << 7)
-#define SPITZ_MOD_CTRL (1 << 8)
-#define SPITZ_MOD_FN (1 << 9)
-
-#define QUEUE_KEY(c) s->fifo[(s->fifopos + s->fifolen ++) & 0xf] = c
-
-static void spitz_keyboard_handler(void *opaque, int keycode)
-{
- SpitzKeyboardState *s = opaque;
- uint16_t code;
- int mapcode;
- switch (keycode) {
- case 0x2a: /* Left Shift */
- s->modifiers |= 1;
- break;
- case 0xaa:
- s->modifiers &= ~1;
- break;
- case 0x36: /* Right Shift */
- s->modifiers |= 2;
- break;
- case 0xb6:
- s->modifiers &= ~2;
- break;
- case 0x1d: /* Control */
- s->modifiers |= 4;
- break;
- case 0x9d:
- s->modifiers &= ~4;
- break;
- case 0x38: /* Alt */
- s->modifiers |= 8;
- break;
- case 0xb8:
- s->modifiers &= ~8;
- break;
- }
-
- code = s->pre_map[mapcode = ((s->modifiers & 3) ?
- (keycode | SPITZ_MOD_SHIFT) :
- (keycode & ~SPITZ_MOD_SHIFT))];
-
- if (code != mapcode) {
-#if 0
- if ((code & SPITZ_MOD_SHIFT) && !(s->modifiers & 1)) {
- QUEUE_KEY(0x2a | (keycode & 0x80));
- }
- if ((code & SPITZ_MOD_CTRL) && !(s->modifiers & 4)) {
- QUEUE_KEY(0x1d | (keycode & 0x80));
- }
- if ((code & SPITZ_MOD_FN) && !(s->modifiers & 8)) {
- QUEUE_KEY(0x38 | (keycode & 0x80));
- }
- if ((code & SPITZ_MOD_FN) && (s->modifiers & 1)) {
- QUEUE_KEY(0x2a | (~keycode & 0x80));
- }
- if ((code & SPITZ_MOD_FN) && (s->modifiers & 2)) {
- QUEUE_KEY(0x36 | (~keycode & 0x80));
- }
-#else
- if (keycode & 0x80) {
- if ((s->imodifiers & 1 ) && !(s->modifiers & 1))
- QUEUE_KEY(0x2a | 0x80);
- if ((s->imodifiers & 4 ) && !(s->modifiers & 4))
- QUEUE_KEY(0x1d | 0x80);
- if ((s->imodifiers & 8 ) && !(s->modifiers & 8))
- QUEUE_KEY(0x38 | 0x80);
- if ((s->imodifiers & 0x10) && (s->modifiers & 1))
- QUEUE_KEY(0x2a);
- if ((s->imodifiers & 0x20) && (s->modifiers & 2))
- QUEUE_KEY(0x36);
- s->imodifiers = 0;
- } else {
- if ((code & SPITZ_MOD_SHIFT) &&
- !((s->modifiers | s->imodifiers) & 1)) {
- QUEUE_KEY(0x2a);
- s->imodifiers |= 1;
- }
- if ((code & SPITZ_MOD_CTRL) &&
- !((s->modifiers | s->imodifiers) & 4)) {
- QUEUE_KEY(0x1d);
- s->imodifiers |= 4;
- }
- if ((code & SPITZ_MOD_FN) &&
- !((s->modifiers | s->imodifiers) & 8)) {
- QUEUE_KEY(0x38);
- s->imodifiers |= 8;
- }
- if ((code & SPITZ_MOD_FN) && (s->modifiers & 1) &&
- !(s->imodifiers & 0x10)) {
- QUEUE_KEY(0x2a | 0x80);
- s->imodifiers |= 0x10;
- }
- if ((code & SPITZ_MOD_FN) && (s->modifiers & 2) &&
- !(s->imodifiers & 0x20)) {
- QUEUE_KEY(0x36 | 0x80);
- s->imodifiers |= 0x20;
- }
- }
-#endif
- }
-
- QUEUE_KEY((code & 0x7f) | (keycode & 0x80));
-}
-
-static void spitz_keyboard_tick(void *opaque)
-{
- SpitzKeyboardState *s = (SpitzKeyboardState *) opaque;
-
- if (s->fifolen) {
- spitz_keyboard_keydown(s, s->fifo[s->fifopos ++]);
- s->fifolen --;
- if (s->fifopos >= 16)
- s->fifopos = 0;
- }
-
- timer_mod(s->kbdtimer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- NANOSECONDS_PER_SECOND / 32);
-}
-
-static void spitz_keyboard_pre_map(SpitzKeyboardState *s)
-{
- int i;
- for (i = 0; i < 0x100; i ++)
- s->pre_map[i] = i;
- s->pre_map[0x02 | SPITZ_MOD_SHIFT] = 0x02 | SPITZ_MOD_SHIFT; /* exclam */
- s->pre_map[0x28 | SPITZ_MOD_SHIFT] = 0x03 | SPITZ_MOD_SHIFT; /* quotedbl */
- s->pre_map[0x04 | SPITZ_MOD_SHIFT] = 0x04 | SPITZ_MOD_SHIFT; /* # */
- s->pre_map[0x05 | SPITZ_MOD_SHIFT] = 0x05 | SPITZ_MOD_SHIFT; /* dollar */
- s->pre_map[0x06 | SPITZ_MOD_SHIFT] = 0x06 | SPITZ_MOD_SHIFT; /* percent */
- s->pre_map[0x08 | SPITZ_MOD_SHIFT] = 0x07 | SPITZ_MOD_SHIFT; /* ampersand */
- s->pre_map[0x28] = 0x08 | SPITZ_MOD_SHIFT; /* ' */
- s->pre_map[0x0a | SPITZ_MOD_SHIFT] = 0x09 | SPITZ_MOD_SHIFT; /* ( */
- s->pre_map[0x0b | SPITZ_MOD_SHIFT] = 0x0a | SPITZ_MOD_SHIFT; /* ) */
- s->pre_map[0x29 | SPITZ_MOD_SHIFT] = 0x0b | SPITZ_MOD_SHIFT; /* tilde */
- s->pre_map[0x03 | SPITZ_MOD_SHIFT] = 0x0c | SPITZ_MOD_SHIFT; /* at */
- s->pre_map[0xd3] = 0x0e | SPITZ_MOD_FN; /* Delete */
- s->pre_map[0x3a] = 0x0f | SPITZ_MOD_FN; /* Caps_Lock */
- s->pre_map[0x07 | SPITZ_MOD_SHIFT] = 0x11 | SPITZ_MOD_FN; /* ^ */
- s->pre_map[0x0d] = 0x12 | SPITZ_MOD_FN; /* equal */
- s->pre_map[0x0d | SPITZ_MOD_SHIFT] = 0x13 | SPITZ_MOD_FN; /* plus */
- s->pre_map[0x1a] = 0x14 | SPITZ_MOD_FN; /* [ */
- s->pre_map[0x1b] = 0x15 | SPITZ_MOD_FN; /* ] */
- s->pre_map[0x1a | SPITZ_MOD_SHIFT] = 0x16 | SPITZ_MOD_FN; /* { */
- s->pre_map[0x1b | SPITZ_MOD_SHIFT] = 0x17 | SPITZ_MOD_FN; /* } */
- s->pre_map[0x27] = 0x22 | SPITZ_MOD_FN; /* semicolon */
- s->pre_map[0x27 | SPITZ_MOD_SHIFT] = 0x23 | SPITZ_MOD_FN; /* colon */
- s->pre_map[0x09 | SPITZ_MOD_SHIFT] = 0x24 | SPITZ_MOD_FN; /* asterisk */
- s->pre_map[0x2b] = 0x25 | SPITZ_MOD_FN; /* backslash */
- s->pre_map[0x2b | SPITZ_MOD_SHIFT] = 0x26 | SPITZ_MOD_FN; /* bar */
- s->pre_map[0x0c | SPITZ_MOD_SHIFT] = 0x30 | SPITZ_MOD_FN; /* _ */
- s->pre_map[0x33 | SPITZ_MOD_SHIFT] = 0x33 | SPITZ_MOD_FN; /* less */
- s->pre_map[0x35] = 0x33 | SPITZ_MOD_SHIFT; /* slash */
- s->pre_map[0x34 | SPITZ_MOD_SHIFT] = 0x34 | SPITZ_MOD_FN; /* greater */
- s->pre_map[0x35 | SPITZ_MOD_SHIFT] = 0x34 | SPITZ_MOD_SHIFT; /* question */
- s->pre_map[0x49] = 0x48 | SPITZ_MOD_FN; /* Page_Up */
- s->pre_map[0x51] = 0x50 | SPITZ_MOD_FN; /* Page_Down */
-
- s->modifiers = 0;
- s->imodifiers = 0;
- s->fifopos = 0;
- s->fifolen = 0;
-}
-
-#undef SPITZ_MOD_SHIFT
-#undef SPITZ_MOD_CTRL
-#undef SPITZ_MOD_FN
-
-static int spitz_keyboard_post_load(void *opaque, int version_id)
-{
- SpitzKeyboardState *s = (SpitzKeyboardState *) opaque;
-
- /* Release all pressed keys */
- memset(s->keyrow, 0, sizeof(s->keyrow));
- spitz_keyboard_sense_update(s);
- s->modifiers = 0;
- s->imodifiers = 0;
- s->fifopos = 0;
- s->fifolen = 0;
-
- return 0;
-}
-
-static void spitz_keyboard_register(PXA2xxState *cpu)
-{
- int i;
- DeviceState *dev;
- SpitzKeyboardState *s;
-
- dev = sysbus_create_simple(TYPE_SPITZ_KEYBOARD, -1, NULL);
- s = SPITZ_KEYBOARD(dev);
-
- for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++)
- qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(cpu->gpio, spitz_gpio_key_sense[i]));
-
- for (i = 0; i < 5; i ++)
- s->gpiomap[i] = qdev_get_gpio_in(cpu->gpio, spitz_gpiomap[i]);
-
- if (!graphic_rotate)
- s->gpiomap[4] = qemu_irq_invert(s->gpiomap[4]);
-
- for (i = 0; i < 5; i++)
- qemu_set_irq(s->gpiomap[i], 0);
-
- for (i = 0; i < SPITZ_KEY_STROBE_NUM; i ++)
- qdev_connect_gpio_out(cpu->gpio, spitz_gpio_key_strobe[i],
- qdev_get_gpio_in(dev, i));
-
- timer_mod(s->kbdtimer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
-
- qemu_add_kbd_event_handler(spitz_keyboard_handler, s);
-}
-
-static void spitz_keyboard_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- SpitzKeyboardState *s = SPITZ_KEYBOARD(obj);
- int i, j;
-
- for (i = 0; i < 0x80; i ++)
- s->keymap[i] = -1;
- for (i = 0; i < SPITZ_KEY_SENSE_NUM + 1; i ++)
- for (j = 0; j < SPITZ_KEY_STROBE_NUM; j ++)
- if (spitz_keymap[i][j] != -1)
- s->keymap[spitz_keymap[i][j]] = (i << 4) | j;
-
- spitz_keyboard_pre_map(s);
-
- qdev_init_gpio_in(dev, spitz_keyboard_strobe, SPITZ_KEY_STROBE_NUM);
- qdev_init_gpio_out(dev, s->sense, SPITZ_KEY_SENSE_NUM);
-}
-
-static void spitz_keyboard_realize(DeviceState *dev, Error **errp)
-{
- SpitzKeyboardState *s = SPITZ_KEYBOARD(dev);
- s->kbdtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, spitz_keyboard_tick, s);
-}
-
-/* LCD backlight controller */
-
-#define LCDTG_RESCTL 0x00
-#define LCDTG_PHACTRL 0x01
-#define LCDTG_DUTYCTRL 0x02
-#define LCDTG_POWERREG0 0x03
-#define LCDTG_POWERREG1 0x04
-#define LCDTG_GPOR3 0x05
-#define LCDTG_PICTRL 0x06
-#define LCDTG_POLCTRL 0x07
-
-#define TYPE_SPITZ_LCDTG "spitz-lcdtg"
-OBJECT_DECLARE_SIMPLE_TYPE(SpitzLCDTG, SPITZ_LCDTG)
-
-struct SpitzLCDTG {
- SSIPeripheral ssidev;
- uint32_t bl_intensity;
- uint32_t bl_power;
-};
-
-static void spitz_bl_update(SpitzLCDTG *s)
-{
- if (s->bl_power && s->bl_intensity)
- zaurus_printf("LCD Backlight now at %u/63\n", s->bl_intensity);
- else
- zaurus_printf("LCD Backlight now off\n");
-}
-
-static inline void spitz_bl_bit5(void *opaque, int line, int level)
-{
- SpitzLCDTG *s = opaque;
- int prev = s->bl_intensity;
-
- if (level)
- s->bl_intensity &= ~0x20;
- else
- s->bl_intensity |= 0x20;
-
- if (s->bl_power && prev != s->bl_intensity)
- spitz_bl_update(s);
-}
-
-static inline void spitz_bl_power(void *opaque, int line, int level)
-{
- SpitzLCDTG *s = opaque;
- s->bl_power = !!level;
- spitz_bl_update(s);
-}
-
-static uint32_t spitz_lcdtg_transfer(SSIPeripheral *dev, uint32_t value)
-{
- SpitzLCDTG *s = SPITZ_LCDTG(dev);
- int addr;
- addr = value >> 5;
- value &= 0x1f;
-
- switch (addr) {
- case LCDTG_RESCTL:
- if (value)
- zaurus_printf("LCD in QVGA mode\n");
- else
- zaurus_printf("LCD in VGA mode\n");
- break;
-
- case LCDTG_DUTYCTRL:
- s->bl_intensity &= ~0x1f;
- s->bl_intensity |= value;
- if (s->bl_power)
- spitz_bl_update(s);
- break;
-
- case LCDTG_POWERREG0:
- /* Set common voltage to M62332FP */
- break;
- }
- return 0;
-}
-
-static void spitz_lcdtg_realize(SSIPeripheral *ssi, Error **errp)
-{
- SpitzLCDTG *s = SPITZ_LCDTG(ssi);
- DeviceState *dev = DEVICE(s);
-
- s->bl_power = 0;
- s->bl_intensity = 0x20;
-
- qdev_init_gpio_in_named(dev, spitz_bl_bit5, "bl_bit5", 1);
- qdev_init_gpio_in_named(dev, spitz_bl_power, "bl_power", 1);
-}
-
-/* SSP devices */
-
-#define CORGI_SSP_PORT 2
-
-#define SPITZ_GPIO_LCDCON_CS 53
-#define SPITZ_GPIO_ADS7846_CS 14
-#define SPITZ_GPIO_MAX1111_CS 20
-#define SPITZ_GPIO_TP_INT 11
-
-#define TYPE_CORGI_SSP "corgi-ssp"
-OBJECT_DECLARE_SIMPLE_TYPE(CorgiSSPState, CORGI_SSP)
-
-/* "Demux" the signal based on current chipselect */
-struct CorgiSSPState {
- SSIPeripheral ssidev;
- SSIBus *bus[3];
- uint32_t enable[3];
-};
-
-static uint32_t corgi_ssp_transfer(SSIPeripheral *dev, uint32_t value)
-{
- CorgiSSPState *s = CORGI_SSP(dev);
- int i;
-
- for (i = 0; i < 3; i++) {
- if (s->enable[i]) {
- return ssi_transfer(s->bus[i], value);
- }
- }
- return 0;
-}
-
-static void corgi_ssp_gpio_cs(void *opaque, int line, int level)
-{
- CorgiSSPState *s = (CorgiSSPState *)opaque;
- assert(line >= 0 && line < 3);
- s->enable[line] = !level;
-}
-
-#define MAX1111_BATT_VOLT 1
-#define MAX1111_BATT_TEMP 2
-#define MAX1111_ACIN_VOLT 3
-
-#define SPITZ_BATTERY_TEMP 0xe0 /* About 2.9V */
-#define SPITZ_BATTERY_VOLT 0xd0 /* About 4.0V */
-#define SPITZ_CHARGEON_ACIN 0x80 /* About 5.0V */
-
-static void corgi_ssp_realize(SSIPeripheral *d, Error **errp)
-{
- DeviceState *dev = DEVICE(d);
- CorgiSSPState *s = CORGI_SSP(d);
-
- qdev_init_gpio_in(dev, corgi_ssp_gpio_cs, 3);
- s->bus[0] = ssi_create_bus(dev, "ssi0");
- s->bus[1] = ssi_create_bus(dev, "ssi1");
- s->bus[2] = ssi_create_bus(dev, "ssi2");
-}
-
-static void spitz_ssp_attach(SpitzMachineState *sms)
-{
- void *bus;
-
- sms->mux = ssi_create_peripheral(sms->mpu->ssp[CORGI_SSP_PORT - 1],
- TYPE_CORGI_SSP);
-
- bus = qdev_get_child_bus(sms->mux, "ssi0");
- sms->lcdtg = ssi_create_peripheral(bus, TYPE_SPITZ_LCDTG);
-
- bus = qdev_get_child_bus(sms->mux, "ssi1");
- sms->ads7846 = ssi_create_peripheral(bus, "ads7846");
- qdev_connect_gpio_out(sms->ads7846, 0,
- qdev_get_gpio_in(sms->mpu->gpio, SPITZ_GPIO_TP_INT));
-
- bus = qdev_get_child_bus(sms->mux, "ssi2");
- sms->max1111 = qdev_new(TYPE_MAX_1111);
- qdev_prop_set_uint8(sms->max1111, "input1" /* BATT_VOLT */,
- SPITZ_BATTERY_VOLT);
- qdev_prop_set_uint8(sms->max1111, "input2" /* BATT_TEMP */, 0);
- qdev_prop_set_uint8(sms->max1111, "input3" /* ACIN_VOLT */,
- SPITZ_CHARGEON_ACIN);
- ssi_realize_and_unref(sms->max1111, bus, &error_fatal);
-
- qdev_connect_gpio_out(sms->mpu->gpio, SPITZ_GPIO_LCDCON_CS,
- qdev_get_gpio_in(sms->mux, 0));
- qdev_connect_gpio_out(sms->mpu->gpio, SPITZ_GPIO_ADS7846_CS,
- qdev_get_gpio_in(sms->mux, 1));
- qdev_connect_gpio_out(sms->mpu->gpio, SPITZ_GPIO_MAX1111_CS,
- qdev_get_gpio_in(sms->mux, 2));
-}
-
-/* CF Microdrive */
-
-static void spitz_microdrive_attach(PXA2xxState *cpu, int slot)
-{
- PCMCIACardState *md;
- DriveInfo *dinfo;
-
- dinfo = drive_get(IF_IDE, 0, 0);
- if (!dinfo || dinfo->media_cd)
- return;
- md = dscm1xxxx_init(dinfo);
- pxa2xx_pcmcia_attach(cpu->pcmcia[slot], md);
-}
-
-/* Wm8750 and Max7310 on I2C */
-
-#define AKITA_MAX_ADDR 0x18
-#define SPITZ_WM_ADDRL 0x1b
-#define SPITZ_WM_ADDRH 0x1a
-
-#define SPITZ_GPIO_WM 5
-
-static void spitz_wm8750_addr(void *opaque, int line, int level)
-{
- I2CSlave *wm = (I2CSlave *) opaque;
- if (level)
- i2c_slave_set_address(wm, SPITZ_WM_ADDRH);
- else
- i2c_slave_set_address(wm, SPITZ_WM_ADDRL);
-}
-
-static void spitz_i2c_setup(MachineState *machine, PXA2xxState *cpu)
-{
- /* Attach the CPU on one end of our I2C bus. */
- I2CBus *bus = pxa2xx_i2c_bus(cpu->i2c[0]);
-
- /* Attach a WM8750 to the bus */
- I2CSlave *i2c_dev = i2c_slave_new(TYPE_WM8750, 0);
- DeviceState *wm = DEVICE(i2c_dev);
-
- if (machine->audiodev) {
- qdev_prop_set_string(wm, "audiodev", machine->audiodev);
- }
- i2c_slave_realize_and_unref(i2c_dev, bus, &error_abort);
-
- spitz_wm8750_addr(wm, 0, 0);
- qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_WM,
- qemu_allocate_irq(spitz_wm8750_addr, wm, 0));
- /* .. and to the sound interface. */
- cpu->i2s->opaque = wm;
- cpu->i2s->codec_out = wm8750_dac_dat;
- cpu->i2s->codec_in = wm8750_adc_dat;
- wm8750_data_req_set(wm, cpu->i2s->data_req, cpu->i2s);
-}
-
-static void spitz_akita_i2c_setup(PXA2xxState *cpu)
-{
- /* Attach a Max7310 to Akita I2C bus. */
- i2c_slave_create_simple(pxa2xx_i2c_bus(cpu->i2c[0]), "max7310",
- AKITA_MAX_ADDR);
-}
-
-/* Other peripherals */
-
-/*
- * Encapsulation of some miscellaneous GPIO line behaviour for the Spitz boards.
- *
- * QEMU interface:
- * + named GPIO inputs "green-led", "orange-led", "charging", "discharging":
- * these currently just print messages that the line has been signalled
- * + named GPIO input "adc-temp-on": set to cause the battery-temperature
- * value to be passed to the max111x ADC
- * + named GPIO output "adc-temp": the ADC value, to be wired up to the max111x
- */
-#define TYPE_SPITZ_MISC_GPIO "spitz-misc-gpio"
-OBJECT_DECLARE_SIMPLE_TYPE(SpitzMiscGPIOState, SPITZ_MISC_GPIO)
-
-struct SpitzMiscGPIOState {
- SysBusDevice parent_obj;
-
- qemu_irq adc_value;
-};
-
-static void spitz_misc_charging(void *opaque, int n, int level)
-{
- zaurus_printf("Charging %s.\n", level ? "off" : "on");
-}
-
-static void spitz_misc_discharging(void *opaque, int n, int level)
-{
- zaurus_printf("Discharging %s.\n", level ? "off" : "on");
-}
-
-static void spitz_misc_green_led(void *opaque, int n, int level)
-{
- zaurus_printf("Green LED %s.\n", level ? "off" : "on");
-}
-
-static void spitz_misc_orange_led(void *opaque, int n, int level)
-{
- zaurus_printf("Orange LED %s.\n", level ? "off" : "on");
-}
-
-static void spitz_misc_adc_temp(void *opaque, int n, int level)
-{
- SpitzMiscGPIOState *s = SPITZ_MISC_GPIO(opaque);
- int batt_temp = level ? SPITZ_BATTERY_TEMP : 0;
-
- qemu_set_irq(s->adc_value, batt_temp);
-}
-
-static void spitz_misc_gpio_init(Object *obj)
-{
- SpitzMiscGPIOState *s = SPITZ_MISC_GPIO(obj);
- DeviceState *dev = DEVICE(obj);
-
- qdev_init_gpio_in_named(dev, spitz_misc_charging, "charging", 1);
- qdev_init_gpio_in_named(dev, spitz_misc_discharging, "discharging", 1);
- qdev_init_gpio_in_named(dev, spitz_misc_green_led, "green-led", 1);
- qdev_init_gpio_in_named(dev, spitz_misc_orange_led, "orange-led", 1);
- qdev_init_gpio_in_named(dev, spitz_misc_adc_temp, "adc-temp-on", 1);
-
- qdev_init_gpio_out_named(dev, &s->adc_value, "adc-temp", 1);
-}
-
-#define SPITZ_SCP_LED_GREEN 1
-#define SPITZ_SCP_JK_B 2
-#define SPITZ_SCP_CHRG_ON 3
-#define SPITZ_SCP_MUTE_L 4
-#define SPITZ_SCP_MUTE_R 5
-#define SPITZ_SCP_CF_POWER 6
-#define SPITZ_SCP_LED_ORANGE 7
-#define SPITZ_SCP_JK_A 8
-#define SPITZ_SCP_ADC_TEMP_ON 9
-#define SPITZ_SCP2_IR_ON 1
-#define SPITZ_SCP2_AKIN_PULLUP 2
-#define SPITZ_SCP2_BACKLIGHT_CONT 7
-#define SPITZ_SCP2_BACKLIGHT_ON 8
-#define SPITZ_SCP2_MIC_BIAS 9
-
-static void spitz_scoop_gpio_setup(SpitzMachineState *sms)
-{
- DeviceState *miscdev = sysbus_create_simple(TYPE_SPITZ_MISC_GPIO, -1, NULL);
-
- sms->misc_gpio = miscdev;
-
- qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_CHRG_ON,
- qdev_get_gpio_in_named(miscdev, "charging", 0));
- qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_JK_B,
- qdev_get_gpio_in_named(miscdev, "discharging", 0));
- qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_LED_GREEN,
- qdev_get_gpio_in_named(miscdev, "green-led", 0));
- qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_LED_ORANGE,
- qdev_get_gpio_in_named(miscdev, "orange-led", 0));
- qdev_connect_gpio_out(sms->scp0, SPITZ_SCP_ADC_TEMP_ON,
- qdev_get_gpio_in_named(miscdev, "adc-temp-on", 0));
- qdev_connect_gpio_out_named(miscdev, "adc-temp", 0,
- qdev_get_gpio_in(sms->max1111, MAX1111_BATT_TEMP));
-
- if (sms->scp1) {
- qdev_connect_gpio_out(sms->scp1, SPITZ_SCP2_BACKLIGHT_CONT,
- qdev_get_gpio_in_named(sms->lcdtg, "bl_bit5", 0));
- qdev_connect_gpio_out(sms->scp1, SPITZ_SCP2_BACKLIGHT_ON,
- qdev_get_gpio_in_named(sms->lcdtg, "bl_power", 0));
- }
-}
-
-#define SPITZ_GPIO_HSYNC 22
-#define SPITZ_GPIO_SD_DETECT 9
-#define SPITZ_GPIO_SD_WP 81
-#define SPITZ_GPIO_ON_RESET 89
-#define SPITZ_GPIO_BAT_COVER 90
-#define SPITZ_GPIO_CF1_IRQ 105
-#define SPITZ_GPIO_CF1_CD 94
-#define SPITZ_GPIO_CF2_IRQ 106
-#define SPITZ_GPIO_CF2_CD 93
-
-static int spitz_hsync;
-
-static void spitz_lcd_hsync_handler(void *opaque, int line, int level)
-{
- PXA2xxState *cpu = (PXA2xxState *) opaque;
- qemu_set_irq(qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_HSYNC), spitz_hsync);
- spitz_hsync ^= 1;
-}
-
-static void spitz_reset(void *opaque, int line, int level)
-{
- if (level) {
- qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
- }
-}
-
-static void spitz_gpio_setup(PXA2xxState *cpu, int slots)
-{
- qemu_irq lcd_hsync;
- qemu_irq reset;
-
- /*
- * Bad hack: We toggle the LCD hsync GPIO on every GPIO status
- * read to satisfy broken guests that poll-wait for hsync.
- * Simulating a real hsync event would be less practical and
- * wouldn't guarantee that a guest ever exits the loop.
- */
- spitz_hsync = 0;
- lcd_hsync = qemu_allocate_irq(spitz_lcd_hsync_handler, cpu, 0);
- pxa2xx_gpio_read_notifier(cpu->gpio, lcd_hsync);
- pxa2xx_lcd_vsync_notifier(cpu->lcd, lcd_hsync);
-
- /* MMC/SD host */
- pxa2xx_mmci_handlers(cpu->mmc,
- qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_SD_WP),
- qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_SD_DETECT));
-
- /* Battery lock always closed */
- qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_BAT_COVER));
-
- /* Handle reset */
- reset = qemu_allocate_irq(spitz_reset, cpu, 0);
- qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_ON_RESET, reset);
-
- /* PCMCIA signals: card's IRQ and Card-Detect */
- if (slots >= 1)
- pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0],
- qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF1_IRQ),
- qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF1_CD));
- if (slots >= 2)
- pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1],
- qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF2_IRQ),
- qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF2_CD));
-}
-
-/* Board init. */
-#define SPITZ_RAM 0x04000000
-#define SPITZ_ROM 0x00800000
-
-static struct arm_boot_info spitz_binfo = {
- .loader_start = PXA2XX_SDRAM_BASE,
- .ram_size = 0x04000000,
-};
-
-static void spitz_common_init(MachineState *machine)
-{
- SpitzMachineClass *smc = SPITZ_MACHINE_GET_CLASS(machine);
- SpitzMachineState *sms = SPITZ_MACHINE(machine);
- enum spitz_model_e model = smc->model;
- PXA2xxState *mpu;
- MemoryRegion *rom = g_new(MemoryRegion, 1);
-
- /* Setup CPU & memory */
- mpu = pxa270_init(spitz_binfo.ram_size, machine->cpu_type);
- sms->mpu = mpu;
-
- sl_flash_register(mpu, (model == spitz) ? FLASH_128M : FLASH_1024M);
-
- memory_region_init_rom(rom, NULL, "spitz.rom", SPITZ_ROM, &error_fatal);
- memory_region_add_subregion(get_system_memory(), 0, rom);
-
- /* Setup peripherals */
- spitz_keyboard_register(mpu);
-
- spitz_ssp_attach(sms);
-
- sms->scp0 = sysbus_create_simple("scoop", 0x10800000, NULL);
- if (model != akita) {
- sms->scp1 = sysbus_create_simple("scoop", 0x08800040, NULL);
- } else {
- sms->scp1 = NULL;
- }
-
- spitz_scoop_gpio_setup(sms);
-
- spitz_gpio_setup(mpu, (model == akita) ? 1 : 2);
-
- spitz_i2c_setup(machine, mpu);
-
- if (model == akita)
- spitz_akita_i2c_setup(mpu);
-
- if (model == terrier)
- /* A 6.0 GB microdrive is permanently sitting in CF slot 1. */
- spitz_microdrive_attach(mpu, 1);
- else if (model != akita)
- /* A 4.0 GB microdrive is permanently sitting in CF slot 0. */
- spitz_microdrive_attach(mpu, 0);
-
- spitz_binfo.board_id = smc->arm_id;
- arm_load_kernel(mpu->cpu, machine, &spitz_binfo);
- sl_bootparam_write(SL_PXA_PARAM_BASE);
-}
-
-static void spitz_common_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->block_default_type = IF_IDE;
- mc->ignore_memory_transaction_failures = true;
- mc->init = spitz_common_init;
- mc->deprecation_reason = "machine is old and unmaintained";
-
- machine_add_audiodev_property(mc);
-}
-
-static const TypeInfo spitz_common_info = {
- .name = TYPE_SPITZ_MACHINE,
- .parent = TYPE_MACHINE,
- .abstract = true,
- .instance_size = sizeof(SpitzMachineState),
- .class_size = sizeof(SpitzMachineClass),
- .class_init = spitz_common_class_init,
-};
-
-static void akitapda_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
- SpitzMachineClass *smc = SPITZ_MACHINE_CLASS(oc);
-
- mc->desc = "Sharp SL-C1000 (Akita) PDA (PXA270)";
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c0");
- smc->model = akita;
- smc->arm_id = 0x2e8;
-}
-
-static const TypeInfo akitapda_type = {
- .name = MACHINE_TYPE_NAME("akita"),
- .parent = TYPE_SPITZ_MACHINE,
- .class_init = akitapda_class_init,
-};
-
-static void spitzpda_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
- SpitzMachineClass *smc = SPITZ_MACHINE_CLASS(oc);
-
- mc->desc = "Sharp SL-C3000 (Spitz) PDA (PXA270)";
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c0");
- smc->model = spitz;
- smc->arm_id = 0x2c9;
-}
-
-static const TypeInfo spitzpda_type = {
- .name = MACHINE_TYPE_NAME("spitz"),
- .parent = TYPE_SPITZ_MACHINE,
- .class_init = spitzpda_class_init,
-};
-
-static void borzoipda_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
- SpitzMachineClass *smc = SPITZ_MACHINE_CLASS(oc);
-
- mc->desc = "Sharp SL-C3100 (Borzoi) PDA (PXA270)";
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c0");
- smc->model = borzoi;
- smc->arm_id = 0x33f;
-}
-
-static const TypeInfo borzoipda_type = {
- .name = MACHINE_TYPE_NAME("borzoi"),
- .parent = TYPE_SPITZ_MACHINE,
- .class_init = borzoipda_class_init,
-};
-
-static void terrierpda_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
- SpitzMachineClass *smc = SPITZ_MACHINE_CLASS(oc);
-
- mc->desc = "Sharp SL-C3200 (Terrier) PDA (PXA270)";
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c5");
- smc->model = terrier;
- smc->arm_id = 0x33f;
-}
-
-static const TypeInfo terrierpda_type = {
- .name = MACHINE_TYPE_NAME("terrier"),
- .parent = TYPE_SPITZ_MACHINE,
- .class_init = terrierpda_class_init,
-};
-
-static void spitz_machine_init(void)
-{
- type_register_static(&spitz_common_info);
- type_register_static(&akitapda_type);
- type_register_static(&spitzpda_type);
- type_register_static(&borzoipda_type);
- type_register_static(&terrierpda_type);
-}
-
-type_init(spitz_machine_init)
-
-static bool is_version_0(void *opaque, int version_id)
-{
- return version_id == 0;
-}
-
-static const VMStateDescription vmstate_sl_nand_info = {
- .name = "sl-nand",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT8(ctl, SLNANDState),
- VMSTATE_STRUCT(ecc, SLNANDState, 0, vmstate_ecc_state, ECCState),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static Property sl_nand_properties[] = {
- DEFINE_PROP_UINT8("manf_id", SLNANDState, manf_id, NAND_MFR_SAMSUNG),
- DEFINE_PROP_UINT8("chip_id", SLNANDState, chip_id, 0xf1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void sl_nand_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_sl_nand_info;
- device_class_set_props(dc, sl_nand_properties);
- dc->realize = sl_nand_realize;
- /* Reason: init() method uses drive_get() */
- dc->user_creatable = false;
-}
-
-static const TypeInfo sl_nand_info = {
- .name = TYPE_SL_NAND,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SLNANDState),
- .instance_init = sl_nand_init,
- .class_init = sl_nand_class_init,
-};
-
-static const VMStateDescription vmstate_spitz_kbd = {
- .name = "spitz-keyboard",
- .version_id = 1,
- .minimum_version_id = 0,
- .post_load = spitz_keyboard_post_load,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT16(sense_state, SpitzKeyboardState),
- VMSTATE_UINT16(strobe_state, SpitzKeyboardState),
- VMSTATE_UNUSED_TEST(is_version_0, 5),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static void spitz_keyboard_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_spitz_kbd;
- dc->realize = spitz_keyboard_realize;
-}
-
-static const TypeInfo spitz_keyboard_info = {
- .name = TYPE_SPITZ_KEYBOARD,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SpitzKeyboardState),
- .instance_init = spitz_keyboard_init,
- .class_init = spitz_keyboard_class_init,
-};
-
-static const VMStateDescription vmstate_corgi_ssp_regs = {
- .name = "corgi-ssp",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (const VMStateField[]) {
- VMSTATE_SSI_PERIPHERAL(ssidev, CorgiSSPState),
- VMSTATE_UINT32_ARRAY(enable, CorgiSSPState, 3),
- VMSTATE_END_OF_LIST(),
- }
-};
-
-static void corgi_ssp_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
-
- k->realize = corgi_ssp_realize;
- k->transfer = corgi_ssp_transfer;
- dc->vmsd = &vmstate_corgi_ssp_regs;
-}
-
-static const TypeInfo corgi_ssp_info = {
- .name = TYPE_CORGI_SSP,
- .parent = TYPE_SSI_PERIPHERAL,
- .instance_size = sizeof(CorgiSSPState),
- .class_init = corgi_ssp_class_init,
-};
-
-static const VMStateDescription vmstate_spitz_lcdtg_regs = {
- .name = "spitz-lcdtg",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
- VMSTATE_SSI_PERIPHERAL(ssidev, SpitzLCDTG),
- VMSTATE_UINT32(bl_intensity, SpitzLCDTG),
- VMSTATE_UINT32(bl_power, SpitzLCDTG),
- VMSTATE_END_OF_LIST(),
- }
-};
-
-static void spitz_lcdtg_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
-
- k->realize = spitz_lcdtg_realize;
- k->transfer = spitz_lcdtg_transfer;
- dc->vmsd = &vmstate_spitz_lcdtg_regs;
-}
-
-static const TypeInfo spitz_lcdtg_info = {
- .name = TYPE_SPITZ_LCDTG,
- .parent = TYPE_SSI_PERIPHERAL,
- .instance_size = sizeof(SpitzLCDTG),
- .class_init = spitz_lcdtg_class_init,
-};
-
-static const TypeInfo spitz_misc_gpio_info = {
- .name = TYPE_SPITZ_MISC_GPIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SpitzMiscGPIOState),
- .instance_init = spitz_misc_gpio_init,
- /*
- * No class_init required: device has no internal state so does not
- * need to set up reset or vmstate, and does not have a realize method.
- */
-};
-
-static void spitz_register_types(void)
-{
- type_register_static(&corgi_ssp_info);
- type_register_static(&spitz_lcdtg_info);
- type_register_static(&spitz_keyboard_info);
- type_register_static(&sl_nand_info);
- type_register_static(&spitz_misc_gpio_info);
-}
-
-type_init(spitz_register_types)
diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c
index 2ad5b79..72ae621 100644
--- a/hw/arm/stm32f405_soc.c
+++ b/hw/arm/stm32f405_soc.c
@@ -30,6 +30,7 @@
#include "hw/qdev-clock.h"
#include "hw/misc/unimp.h"
+#define RCC_ADDR 0x40023800
#define SYSCFG_ADD 0x40013800
static const uint32_t usart_addr[] = { 0x40011000, 0x40004400, 0x40004800,
0x40004C00, 0x40005000, 0x40011400,
@@ -59,6 +60,8 @@ static void stm32f405_soc_initfn(Object *obj)
object_initialize_child(obj, "armv7m", &s->armv7m, TYPE_ARMV7M);
+ object_initialize_child(obj, "rcc", &s->rcc, TYPE_STM32_RCC);
+
object_initialize_child(obj, "syscfg", &s->syscfg, TYPE_STM32F4XX_SYSCFG);
for (i = 0; i < STM_NUM_USARTS; i++) {
@@ -160,6 +163,14 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp)
return;
}
+ /* Reset and clock controller */
+ dev = DEVICE(&s->rcc);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->rcc), errp)) {
+ return;
+ }
+ busdev = SYS_BUS_DEVICE(dev);
+ sysbus_mmio_map(busdev, 0, RCC_ADDR);
+
/* System configuration controller */
dev = DEVICE(&s->syscfg);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->syscfg), errp)) {
@@ -276,7 +287,6 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp)
create_unimplemented_device("GPIOH", 0x40021C00, 0x400);
create_unimplemented_device("GPIOI", 0x40022000, 0x400);
create_unimplemented_device("CRC", 0x40023000, 0x400);
- create_unimplemented_device("RCC", 0x40023800, 0x400);
create_unimplemented_device("Flash Int", 0x40023C00, 0x400);
create_unimplemented_device("BKPSRAM", 0x40024000, 0x400);
create_unimplemented_device("DMA1", 0x40026000, 0x400);
diff --git a/hw/arm/stm32l4x5_soc.c b/hw/arm/stm32l4x5_soc.c
index fac83d3..16e3505 100644
--- a/hw/arm/stm32l4x5_soc.c
+++ b/hw/arm/stm32l4x5_soc.c
@@ -236,6 +236,8 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
/* System configuration controller */
busdev = SYS_BUS_DEVICE(&s->syscfg);
+ qdev_connect_clock_in(DEVICE(&s->syscfg), "clk",
+ qdev_get_clock_out(DEVICE(&(s->rcc)), "syscfg-out"));
if (!sysbus_realize(busdev, errp)) {
return;
}
diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c
index 823b493..612115a 100644
--- a/hw/arm/strongarm.c
+++ b/hw/arm/strongarm.c
@@ -1342,7 +1342,7 @@ static void strongarm_uart_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "StrongARM UART controller";
- dc->reset = strongarm_uart_reset;
+ device_class_set_legacy_reset(dc, strongarm_uart_reset);
dc->vmsd = &vmstate_strongarm_uart_regs;
device_class_set_props(dc, strongarm_uart_properties);
dc->realize = strongarm_uart_realize;
@@ -1595,7 +1595,7 @@ static void strongarm_ssp_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "StrongARM SSP controller";
- dc->reset = strongarm_ssp_reset;
+ device_class_set_legacy_reset(dc, strongarm_ssp_reset);
dc->vmsd = &vmstate_strongarm_ssp_regs;
}
diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c
deleted file mode 100644
index 5891f60..0000000
--- a/hw/arm/tosa.c
+++ /dev/null
@@ -1,327 +0,0 @@
-/* vim:set shiftwidth=4 ts=4 et: */
-/*
- * PXA255 Sharp Zaurus SL-6000 PDA platform
- *
- * Copyright (c) 2008 Dmitry Baryshkov
- *
- * Code based on spitz platform by Andrzej Zaborowski <balrog@zabor.org>
- * This code is licensed under the GNU GPL v2.
- *
- * 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 "qapi/error.h"
-#include "sysemu/runstate.h"
-#include "hw/arm/pxa.h"
-#include "hw/arm/boot.h"
-#include "hw/arm/sharpsl.h"
-#include "hw/pcmcia.h"
-#include "hw/boards.h"
-#include "hw/display/tc6393xb.h"
-#include "hw/i2c/i2c.h"
-#include "hw/irq.h"
-#include "hw/ssi/ssi.h"
-#include "hw/sysbus.h"
-#include "hw/misc/led.h"
-#include "exec/address-spaces.h"
-#include "qom/object.h"
-
-#define TOSA_RAM 0x04000000
-#define TOSA_ROM 0x00800000
-
-#define TOSA_GPIO_USB_IN (5)
-#define TOSA_GPIO_nSD_DETECT (9)
-#define TOSA_GPIO_ON_RESET (19)
-#define TOSA_GPIO_CF_IRQ (21) /* CF slot0 Ready */
-#define TOSA_GPIO_CF_CD (13)
-#define TOSA_GPIO_TC6393XB_INT (15)
-#define TOSA_GPIO_JC_CF_IRQ (36) /* CF slot1 Ready */
-
-#define TOSA_SCOOP_GPIO_BASE 1
-#define TOSA_GPIO_IR_POWERDWN (TOSA_SCOOP_GPIO_BASE + 2)
-#define TOSA_GPIO_SD_WP (TOSA_SCOOP_GPIO_BASE + 3)
-#define TOSA_GPIO_PWR_ON (TOSA_SCOOP_GPIO_BASE + 4)
-
-#define TOSA_SCOOP_JC_GPIO_BASE 1
-#define TOSA_GPIO_BT_LED (TOSA_SCOOP_JC_GPIO_BASE + 0)
-#define TOSA_GPIO_NOTE_LED (TOSA_SCOOP_JC_GPIO_BASE + 1)
-#define TOSA_GPIO_CHRG_ERR_LED (TOSA_SCOOP_JC_GPIO_BASE + 2)
-#define TOSA_GPIO_TC6393XB_L3V_ON (TOSA_SCOOP_JC_GPIO_BASE + 5)
-#define TOSA_GPIO_WLAN_LED (TOSA_SCOOP_JC_GPIO_BASE + 7)
-
-#define DAC_BASE 0x4e
-#define DAC_CH1 0
-#define DAC_CH2 1
-
-static void tosa_microdrive_attach(PXA2xxState *cpu)
-{
- PCMCIACardState *md;
- DriveInfo *dinfo;
-
- dinfo = drive_get(IF_IDE, 0, 0);
- if (!dinfo || dinfo->media_cd)
- return;
- md = dscm1xxxx_init(dinfo);
- pxa2xx_pcmcia_attach(cpu->pcmcia[0], md);
-}
-
-/*
- * Encapsulation of some GPIO line behaviour for the Tosa board
- *
- * QEMU interface:
- * + named GPIO inputs "leds[0..3]": assert to light LEDs
- * + named GPIO input "reset": when asserted, resets the system
- */
-
-#define TYPE_TOSA_MISC_GPIO "tosa-misc-gpio"
-OBJECT_DECLARE_SIMPLE_TYPE(TosaMiscGPIOState, TOSA_MISC_GPIO)
-
-struct TosaMiscGPIOState {
- SysBusDevice parent_obj;
-};
-
-static void tosa_reset(void *opaque, int line, int level)
-{
- if (level) {
- qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
- }
-}
-
-static void tosa_misc_gpio_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
-
- qdev_init_gpio_in_named(dev, tosa_reset, "reset", 1);
-}
-
-static void tosa_gpio_setup(PXA2xxState *cpu,
- DeviceState *scp0,
- DeviceState *scp1,
- TC6393xbState *tmio)
-{
- DeviceState *misc_gpio;
- LEDState *led[4];
-
- misc_gpio = sysbus_create_simple(TYPE_TOSA_MISC_GPIO, -1, NULL);
-
- /* MMC/SD host */
- pxa2xx_mmci_handlers(cpu->mmc,
- qdev_get_gpio_in(scp0, TOSA_GPIO_SD_WP),
- qemu_irq_invert(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_nSD_DETECT)));
-
- /* Handle reset */
- qdev_connect_gpio_out(cpu->gpio, TOSA_GPIO_ON_RESET,
- qdev_get_gpio_in_named(misc_gpio, "reset", 0));
-
- /* PCMCIA signals: card's IRQ and Card-Detect */
- pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0],
- qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_IRQ),
- qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_CD));
-
- pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1],
- qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_JC_CF_IRQ),
- NULL);
-
- led[0] = led_create_simple(OBJECT(misc_gpio), GPIO_POLARITY_ACTIVE_HIGH,
- LED_COLOR_BLUE, "bluetooth");
- led[1] = led_create_simple(OBJECT(misc_gpio), GPIO_POLARITY_ACTIVE_HIGH,
- LED_COLOR_GREEN, "note");
- led[2] = led_create_simple(OBJECT(misc_gpio), GPIO_POLARITY_ACTIVE_HIGH,
- LED_COLOR_AMBER, "charger-error");
- led[3] = led_create_simple(OBJECT(misc_gpio), GPIO_POLARITY_ACTIVE_HIGH,
- LED_COLOR_GREEN, "wlan");
-
- qdev_connect_gpio_out(scp1, TOSA_GPIO_BT_LED,
- qdev_get_gpio_in(DEVICE(led[0]), 0));
- qdev_connect_gpio_out(scp1, TOSA_GPIO_NOTE_LED,
- qdev_get_gpio_in(DEVICE(led[1]), 0));
- qdev_connect_gpio_out(scp1, TOSA_GPIO_CHRG_ERR_LED,
- qdev_get_gpio_in(DEVICE(led[2]), 0));
- qdev_connect_gpio_out(scp1, TOSA_GPIO_WLAN_LED,
- qdev_get_gpio_in(DEVICE(led[3]), 0));
-
- qdev_connect_gpio_out(scp1, TOSA_GPIO_TC6393XB_L3V_ON, tc6393xb_l3v_get(tmio));
-
- /* UDC Vbus */
- qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_USB_IN));
-}
-
-static uint32_t tosa_ssp_tansfer(SSIPeripheral *dev, uint32_t value)
-{
- fprintf(stderr, "TG: %u %02x\n", value >> 5, value & 0x1f);
- return 0;
-}
-
-static void tosa_ssp_realize(SSIPeripheral *dev, Error **errp)
-{
- /* Nothing to do. */
-}
-
-#define TYPE_TOSA_DAC "tosa_dac"
-OBJECT_DECLARE_SIMPLE_TYPE(TosaDACState, TOSA_DAC)
-
-struct TosaDACState {
- I2CSlave parent_obj;
-
- int len;
- char buf[3];
-};
-
-static int tosa_dac_send(I2CSlave *i2c, uint8_t data)
-{
- TosaDACState *s = TOSA_DAC(i2c);
-
- s->buf[s->len] = data;
- if (s->len ++ > 2) {
-#ifdef VERBOSE
- fprintf(stderr, "%s: message too long (%i bytes)\n", __func__, s->len);
-#endif
- return 1;
- }
-
- if (s->len == 2) {
- fprintf(stderr, "dac: channel %d value 0x%02x\n",
- s->buf[0], s->buf[1]);
- }
-
- return 0;
-}
-
-static int tosa_dac_event(I2CSlave *i2c, enum i2c_event event)
-{
- TosaDACState *s = TOSA_DAC(i2c);
-
- s->len = 0;
- switch (event) {
- case I2C_START_SEND:
- break;
- case I2C_START_RECV:
- printf("%s: recv not supported!!!\n", __func__);
- break;
- case I2C_FINISH:
-#ifdef VERBOSE
- if (s->len < 2)
- printf("%s: message too short (%i bytes)\n", __func__, s->len);
- if (s->len > 2)
- printf("%s: message too long\n", __func__);
-#endif
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static uint8_t tosa_dac_recv(I2CSlave *s)
-{
- printf("%s: recv not supported!!!\n", __func__);
- return 0xff;
-}
-
-static void tosa_tg_init(PXA2xxState *cpu)
-{
- I2CBus *bus = pxa2xx_i2c_bus(cpu->i2c[0]);
- i2c_slave_create_simple(bus, TYPE_TOSA_DAC, DAC_BASE);
- ssi_create_peripheral(cpu->ssp[1], "tosa-ssp");
-}
-
-
-static struct arm_boot_info tosa_binfo = {
- .loader_start = PXA2XX_SDRAM_BASE,
- .ram_size = 0x04000000,
-};
-
-static void tosa_init(MachineState *machine)
-{
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *rom = g_new(MemoryRegion, 1);
- PXA2xxState *mpu;
- TC6393xbState *tmio;
- DeviceState *scp0, *scp1;
-
- mpu = pxa255_init(tosa_binfo.ram_size);
-
- memory_region_init_rom(rom, NULL, "tosa.rom", TOSA_ROM, &error_fatal);
- memory_region_add_subregion(address_space_mem, 0, rom);
-
- tmio = tc6393xb_init(address_space_mem, 0x10000000,
- qdev_get_gpio_in(mpu->gpio, TOSA_GPIO_TC6393XB_INT));
-
- scp0 = sysbus_create_simple("scoop", 0x08800000, NULL);
- scp1 = sysbus_create_simple("scoop", 0x14800040, NULL);
-
- tosa_gpio_setup(mpu, scp0, scp1, tmio);
-
- tosa_microdrive_attach(mpu);
-
- tosa_tg_init(mpu);
-
- tosa_binfo.board_id = 0x208;
- arm_load_kernel(mpu->cpu, machine, &tosa_binfo);
- sl_bootparam_write(SL_PXA_PARAM_BASE);
-}
-
-static void tosapda_machine_init(MachineClass *mc)
-{
- mc->desc = "Sharp SL-6000 (Tosa) PDA (PXA255)";
- mc->init = tosa_init;
- mc->block_default_type = IF_IDE;
- mc->ignore_memory_transaction_failures = true;
- mc->deprecation_reason = "machine is old and unmaintained";
-}
-
-DEFINE_MACHINE("tosa", tosapda_machine_init)
-
-static void tosa_dac_class_init(ObjectClass *klass, void *data)
-{
- I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
-
- k->event = tosa_dac_event;
- k->recv = tosa_dac_recv;
- k->send = tosa_dac_send;
-}
-
-static const TypeInfo tosa_dac_info = {
- .name = TYPE_TOSA_DAC,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(TosaDACState),
- .class_init = tosa_dac_class_init,
-};
-
-static void tosa_ssp_class_init(ObjectClass *klass, void *data)
-{
- SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
-
- k->realize = tosa_ssp_realize;
- k->transfer = tosa_ssp_tansfer;
-}
-
-static const TypeInfo tosa_ssp_info = {
- .name = "tosa-ssp",
- .parent = TYPE_SSI_PERIPHERAL,
- .instance_size = sizeof(SSIPeripheral),
- .class_init = tosa_ssp_class_init,
-};
-
-static const TypeInfo tosa_misc_gpio_info = {
- .name = TYPE_TOSA_MISC_GPIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(TosaMiscGPIOState),
- .instance_init = tosa_misc_gpio_init,
- /*
- * No class init required: device has no internal state so does not
- * need to set up reset or vmstate, and has no realize method.
- */
-};
-
-static void tosa_register_types(void)
-{
- type_register_static(&tosa_dac_info);
- type_register_static(&tosa_ssp_info);
- type_register_static(&tosa_misc_gpio_info);
-}
-
-type_init(tosa_register_types)
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
index be6c8f7..c64ad34 100644
--- a/hw/arm/trace-events
+++ b/hw/arm/trace-events
@@ -68,10 +68,5 @@ z2_aer915_send_too_long(int8_t msg) "message too long (%i bytes)"
z2_aer915_send(uint8_t reg, uint8_t value) "reg %d value 0x%02x"
z2_aer915_event(int8_t event, int8_t len) "i2c event =0x%x len=%d bytes"
-# xen_arm.c
-xen_create_virtio_mmio_devices(int i, int irq, uint64_t base) "Created virtio-mmio device %d: irq %d base 0x%"PRIx64
-xen_init_ram(uint64_t machine_ram_size) "Initialized xen ram with size 0x%"PRIx64
-xen_enable_tpm(uint64_t addr) "Connected tpmdev at address 0x%"PRIx64
-
# bcm2838.c
bcm2838_gic_set_irq(int irq, int level) "gic irq:%d lvl:%d"
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index e10cad8..f76fb11 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -154,10 +154,10 @@ static void acpi_dsdt_add_gpio(Aml *scope, const MemMapEntry *gpio_memmap,
aml_append(dev, aml_name_decl("_CRS", crs));
Aml *aei = aml_resource_template();
- /* Pin 3 for power button */
- const uint32_t pin_list[1] = {3};
+
+ const uint32_t pin = GPIO_PIN_POWER_BUTTON;
aml_append(aei, aml_gpio_int(AML_CONSUMER, AML_EDGE, AML_ACTIVE_HIGH,
- AML_EXCLUSIVE, AML_PULL_UP, 0, pin_list, 1,
+ AML_EXCLUSIVE, AML_PULL_UP, 0, &pin, 1,
"GPO0", NULL, 0));
aml_append(dev, aml_name_decl("_AEI", aei));
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index b0c68d6..8b2b991 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -66,6 +66,7 @@
#include "hw/intc/arm_gicv3_its_common.h"
#include "hw/irq.h"
#include "kvm_arm.h"
+#include "hvf_arm.h"
#include "hw/firmware/smbios.h"
#include "qapi/visitor.h"
#include "qapi/qapi-visit-common.h"
@@ -1004,7 +1005,7 @@ static void virt_powerdown_req(Notifier *n, void *opaque)
if (s->acpi_dev) {
acpi_send_event(s->acpi_dev, ACPI_POWER_DOWN_STATUS);
} else {
- /* use gpio Pin 3 for power button event */
+ /* use gpio Pin for power button event */
qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1);
}
}
@@ -1013,7 +1014,8 @@ static void create_gpio_keys(char *fdt, DeviceState *pl061_dev,
uint32_t phandle)
{
gpio_key_dev = sysbus_create_simple("gpio-key", -1,
- qdev_get_gpio_in(pl061_dev, 3));
+ qdev_get_gpio_in(pl061_dev,
+ GPIO_PIN_POWER_BUTTON));
qemu_fdt_add_subnode(fdt, "/gpio-keys");
qemu_fdt_setprop_string(fdt, "/gpio-keys", "compatible", "gpio-keys");
@@ -1024,7 +1026,7 @@ static void create_gpio_keys(char *fdt, DeviceState *pl061_dev,
qemu_fdt_setprop_cell(fdt, "/gpio-keys/poweroff", "linux,code",
KEY_POWER);
qemu_fdt_setprop_cells(fdt, "/gpio-keys/poweroff",
- "gpios", phandle, 3, 0);
+ "gpios", phandle, GPIO_PIN_POWER_BUTTON, 0);
}
#define SECURE_GPIO_POWEROFF 0
@@ -1407,6 +1409,7 @@ static void create_pcie_irq_map(const MachineState *ms,
static void create_smmu(const VirtMachineState *vms,
PCIBus *bus)
{
+ VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
char *node;
const char compat[] = "arm,smmu-v3";
int irq = vms->irqmap[VIRT_SMMU];
@@ -1423,6 +1426,9 @@ static void create_smmu(const VirtMachineState *vms,
dev = qdev_new(TYPE_ARM_SMMUV3);
+ if (!vmc->no_nested_smmu) {
+ object_property_set_str(OBJECT(dev), "stage", "nested", &error_fatal);
+ }
object_property_set_link(OBJECT(dev), "primary-bus", OBJECT(bus),
&error_abort);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
@@ -2106,7 +2112,8 @@ static void machvirt_init(MachineState *machine)
/*
* In accelerated mode, the memory map is computed earlier in kvm_type()
- * to create a VM with the right number of IPA bits.
+ * for Linux, or hvf_get_physical_address_range() for macOS to create a
+ * VM with the right number of IPA bits.
*/
if (!vms->memmap) {
Object *cpuobj;
@@ -3026,6 +3033,39 @@ static int virt_kvm_type(MachineState *ms, const char *type_str)
return fixed_ipa ? 0 : requested_pa_size;
}
+static int virt_hvf_get_physical_address_range(MachineState *ms)
+{
+ VirtMachineState *vms = VIRT_MACHINE(ms);
+
+ int default_ipa_size = hvf_arm_get_default_ipa_bit_size();
+ int max_ipa_size = hvf_arm_get_max_ipa_bit_size();
+
+ /* We freeze the memory map to compute the highest gpa */
+ virt_set_memmap(vms, max_ipa_size);
+
+ int requested_ipa_size = 64 - clz64(vms->highest_gpa);
+
+ /*
+ * If we're <= the default IPA size just use the default.
+ * If we're above the default but below the maximum, round up to
+ * the maximum. hvf_arm_get_max_ipa_bit_size() conveniently only
+ * returns values that are valid ARM PARange values.
+ */
+ if (requested_ipa_size <= default_ipa_size) {
+ requested_ipa_size = default_ipa_size;
+ } else if (requested_ipa_size <= max_ipa_size) {
+ requested_ipa_size = max_ipa_size;
+ } else {
+ error_report("-m and ,maxmem option values "
+ "require an IPA range (%d bits) larger than "
+ "the one supported by the host (%d bits)",
+ requested_ipa_size, max_ipa_size);
+ return -1;
+ }
+
+ return requested_ipa_size;
+}
+
static void virt_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -3085,6 +3125,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
mc->valid_cpu_types = valid_cpu_types;
mc->get_default_cpu_node_id = virt_get_default_cpu_node_id;
mc->kvm_type = virt_kvm_type;
+ mc->hvf_get_physical_address_range = virt_hvf_get_physical_address_range;
assert(!mc->get_hotplug_handler);
mc->get_hotplug_handler = virt_machine_get_hotplug_handler;
hc->pre_plug = virt_machine_device_pre_plug_cb;
@@ -3300,14 +3341,26 @@ static void machvirt_machine_init(void)
}
type_init(machvirt_machine_init);
+static void virt_machine_9_2_options(MachineClass *mc)
+{
+}
+DEFINE_VIRT_MACHINE_AS_LATEST(9, 2)
+
static void virt_machine_9_1_options(MachineClass *mc)
{
+ VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
+
+ virt_machine_9_2_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_9_1, hw_compat_9_1_len);
+ /* 9.1 and earlier have only a stage-1 SMMU, not a nested s1+2 one */
+ vmc->no_nested_smmu = true;
}
-DEFINE_VIRT_MACHINE_AS_LATEST(9, 1)
+DEFINE_VIRT_MACHINE(9, 1)
static void virt_machine_9_0_options(MachineClass *mc)
{
virt_machine_9_1_options(mc);
+ mc->smbios_memory_device_size = 16 * GiB;
compat_props_add(mc->compat_props, hw_compat_9_0, hw_compat_9_0_len);
}
DEFINE_VIRT_MACHINE(9, 0)
diff --git a/hw/arm/xen-pvh.c b/hw/arm/xen-pvh.c
new file mode 100644
index 0000000..33f0dd5
--- /dev/null
+++ b/hw/arm/xen-pvh.c
@@ -0,0 +1,106 @@
+/*
+ * QEMU ARM Xen PVH Machine
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qapi/qapi-commands-migration.h"
+#include "hw/boards.h"
+#include "sysemu/sysemu.h"
+#include "hw/xen/xen-pvh-common.h"
+#include "hw/xen/arch_hvm.h"
+
+#define TYPE_XEN_ARM MACHINE_TYPE_NAME("xenpvh")
+
+/*
+ * VIRTIO_MMIO_DEV_SIZE is imported from tools/libs/light/libxl_arm.c under Xen
+ * repository.
+ *
+ * Origin: git://xenbits.xen.org/xen.git 2128143c114c
+ */
+#define VIRTIO_MMIO_DEV_SIZE 0x200
+
+#define NR_VIRTIO_MMIO_DEVICES \
+ (GUEST_VIRTIO_MMIO_SPI_LAST - GUEST_VIRTIO_MMIO_SPI_FIRST)
+
+static void xen_arm_instance_init(Object *obj)
+{
+ XenPVHMachineState *s = XEN_PVH_MACHINE(obj);
+
+ /* Default values. */
+ s->cfg.ram_low = (MemMapEntry) { GUEST_RAM0_BASE, GUEST_RAM0_SIZE };
+ s->cfg.ram_high = (MemMapEntry) { GUEST_RAM1_BASE, GUEST_RAM1_SIZE };
+
+ s->cfg.virtio_mmio_num = NR_VIRTIO_MMIO_DEVICES;
+ s->cfg.virtio_mmio_irq_base = GUEST_VIRTIO_MMIO_SPI_FIRST;
+ s->cfg.virtio_mmio = (MemMapEntry) { GUEST_VIRTIO_MMIO_BASE,
+ VIRTIO_MMIO_DEV_SIZE };
+}
+
+static void xen_pvh_set_pci_intx_irq(void *opaque, int intx_irq, int level)
+{
+ XenPVHMachineState *s = XEN_PVH_MACHINE(opaque);
+ int irq = s->cfg.pci_intx_irq_base + intx_irq;
+
+ if (xendevicemodel_set_irq_level(xen_dmod, xen_domid, irq, level)) {
+ error_report("xendevicemodel_set_pci_intx_level failed");
+ }
+}
+
+static void xen_arm_machine_class_init(ObjectClass *oc, void *data)
+{
+ XenPVHMachineClass *xpc = XEN_PVH_MACHINE_CLASS(oc);
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->desc = "Xen PVH ARM machine";
+
+ /*
+ * mc->max_cpus holds the MAX value allowed in the -smp command-line opts.
+ *
+ * 1. If users don't pass any -smp option:
+ * ms->smp.cpus will default to 1.
+ * ms->smp.max_cpus will default to 1.
+ *
+ * 2. If users pass -smp X:
+ * ms->smp.cpus will be set to X.
+ * ms->smp.max_cpus will also be set to X.
+ *
+ * 3. If users pass -smp X,maxcpus=Y:
+ * ms->smp.cpus will be set to X.
+ * ms->smp.max_cpus will be set to Y.
+ *
+ * In scenarios 2 and 3, if X or Y are set to something larger than
+ * mc->max_cpus, QEMU will bail out with an error message.
+ */
+ mc->max_cpus = GUEST_MAX_VCPUS;
+
+ /* Xen/ARM does not use buffered IOREQs. */
+ xpc->handle_bufioreq = HVM_IOREQSRV_BUFIOREQ_OFF;
+
+ /* PCI INTX delivery. */
+ xpc->set_pci_intx_irq = xen_pvh_set_pci_intx_irq;
+
+ /* List of supported features known to work on PVH ARM. */
+ xpc->has_pci = true;
+ xpc->has_tpm = true;
+ xpc->has_virtio_mmio = true;
+
+ xen_pvh_class_setup_common_props(xpc);
+}
+
+static const TypeInfo xen_arm_machine_type = {
+ .name = TYPE_XEN_ARM,
+ .parent = TYPE_XEN_PVH_MACHINE,
+ .class_init = xen_arm_machine_class_init,
+ .instance_size = sizeof(XenPVHMachineState),
+ .instance_init = xen_arm_instance_init,
+};
+
+static void xen_arm_machine_register_types(void)
+{
+ type_register_static(&xen_arm_machine_type);
+}
+
+type_init(xen_arm_machine_register_types)
diff --git a/hw/arm/xen-stubs.c b/hw/arm/xen-stubs.c
new file mode 100644
index 0000000..4ac6a56
--- /dev/null
+++ b/hw/arm/xen-stubs.c
@@ -0,0 +1,32 @@
+/*
+ * Stubs for unimplemented Xen functions for ARM.
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qapi/qapi-commands-migration.h"
+#include "hw/boards.h"
+#include "sysemu/sysemu.h"
+#include "hw/xen/xen-hvm-common.h"
+#include "hw/xen/arch_hvm.h"
+
+void arch_handle_ioreq(XenIOState *state, ioreq_t *req)
+{
+ hw_error("Invalid ioreq type 0x%x\n", req->type);
+ return;
+}
+
+void arch_xen_set_memory(XenIOState *state, MemoryRegionSection *section,
+ bool add)
+{
+}
+
+void xen_hvm_modified_memory(ram_addr_t start, ram_addr_t length)
+{
+}
+
+void qmp_xen_set_global_dirty_log(bool enable, Error **errp)
+{
+}
diff --git a/hw/arm/xen_arm.c b/hw/arm/xen_arm.c
deleted file mode 100644
index 6fad829e..0000000
--- a/hw/arm/xen_arm.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * QEMU ARM Xen PVH Machine
- *
- *
- * 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/qapi-commands-migration.h"
-#include "qapi/visitor.h"
-#include "hw/boards.h"
-#include "hw/irq.h"
-#include "hw/sysbus.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/tpm_backend.h"
-#include "sysemu/sysemu.h"
-#include "hw/xen/xen-hvm-common.h"
-#include "sysemu/tpm.h"
-#include "hw/xen/arch_hvm.h"
-#include "trace.h"
-
-#define TYPE_XEN_ARM MACHINE_TYPE_NAME("xenpvh")
-OBJECT_DECLARE_SIMPLE_TYPE(XenArmState, XEN_ARM)
-
-static const MemoryListener xen_memory_listener = {
- .region_add = xen_region_add,
- .region_del = xen_region_del,
- .log_start = NULL,
- .log_stop = NULL,
- .log_sync = NULL,
- .log_global_start = NULL,
- .log_global_stop = NULL,
- .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
-};
-
-struct XenArmState {
- /*< private >*/
- MachineState parent;
-
- XenIOState *state;
-
- struct {
- uint64_t tpm_base_addr;
- } cfg;
-};
-
-static MemoryRegion ram_lo, ram_hi;
-
-/*
- * VIRTIO_MMIO_DEV_SIZE is imported from tools/libs/light/libxl_arm.c under Xen
- * repository.
- *
- * Origin: git://xenbits.xen.org/xen.git 2128143c114c
- */
-#define VIRTIO_MMIO_DEV_SIZE 0x200
-
-#define NR_VIRTIO_MMIO_DEVICES \
- (GUEST_VIRTIO_MMIO_SPI_LAST - GUEST_VIRTIO_MMIO_SPI_FIRST)
-
-static void xen_set_irq(void *opaque, int irq, int level)
-{
- if (xendevicemodel_set_irq_level(xen_dmod, xen_domid, irq, level)) {
- error_report("xendevicemodel_set_irq_level failed");
- }
-}
-
-static void xen_create_virtio_mmio_devices(XenArmState *xam)
-{
- int i;
-
- for (i = 0; i < NR_VIRTIO_MMIO_DEVICES; i++) {
- hwaddr base = GUEST_VIRTIO_MMIO_BASE + i * VIRTIO_MMIO_DEV_SIZE;
- qemu_irq irq = qemu_allocate_irq(xen_set_irq, NULL,
- GUEST_VIRTIO_MMIO_SPI_FIRST + i);
-
- sysbus_create_simple("virtio-mmio", base, irq);
-
- trace_xen_create_virtio_mmio_devices(i,
- GUEST_VIRTIO_MMIO_SPI_FIRST + i,
- base);
- }
-}
-
-static void xen_init_ram(MachineState *machine)
-{
- MemoryRegion *sysmem = get_system_memory();
- ram_addr_t block_len, ram_size[GUEST_RAM_BANKS];
-
- trace_xen_init_ram(machine->ram_size);
- if (machine->ram_size <= GUEST_RAM0_SIZE) {
- ram_size[0] = machine->ram_size;
- ram_size[1] = 0;
- block_len = GUEST_RAM0_BASE + ram_size[0];
- } else {
- ram_size[0] = GUEST_RAM0_SIZE;
- ram_size[1] = machine->ram_size - GUEST_RAM0_SIZE;
- block_len = GUEST_RAM1_BASE + ram_size[1];
- }
-
- memory_region_init_ram(&xen_memory, NULL, "xen.ram", block_len,
- &error_fatal);
-
- memory_region_init_alias(&ram_lo, NULL, "xen.ram.lo", &xen_memory,
- GUEST_RAM0_BASE, ram_size[0]);
- memory_region_add_subregion(sysmem, GUEST_RAM0_BASE, &ram_lo);
- if (ram_size[1] > 0) {
- memory_region_init_alias(&ram_hi, NULL, "xen.ram.hi", &xen_memory,
- GUEST_RAM1_BASE, ram_size[1]);
- memory_region_add_subregion(sysmem, GUEST_RAM1_BASE, &ram_hi);
- }
-
- /* Setup support for grants. */
- memory_region_init_ram(&xen_grants, NULL, "xen.grants", block_len,
- &error_fatal);
- memory_region_add_subregion(sysmem, XEN_GRANT_ADDR_OFF, &xen_grants);
-}
-
-void arch_handle_ioreq(XenIOState *state, ioreq_t *req)
-{
- hw_error("Invalid ioreq type 0x%x\n", req->type);
-
- return;
-}
-
-void arch_xen_set_memory(XenIOState *state, MemoryRegionSection *section,
- bool add)
-{
-}
-
-void xen_hvm_modified_memory(ram_addr_t start, ram_addr_t length)
-{
-}
-
-void qmp_xen_set_global_dirty_log(bool enable, Error **errp)
-{
-}
-
-#ifdef CONFIG_TPM
-static void xen_enable_tpm(XenArmState *xam)
-{
- Error *errp = NULL;
- DeviceState *dev;
- SysBusDevice *busdev;
-
- TPMBackend *be = qemu_find_tpm_be("tpm0");
- if (be == NULL) {
- error_report("Couldn't find tmp0 backend");
- return;
- }
- dev = qdev_new(TYPE_TPM_TIS_SYSBUS);
- object_property_set_link(OBJECT(dev), "tpmdev", OBJECT(be), &errp);
- object_property_set_str(OBJECT(dev), "tpmdev", be->id, &errp);
- busdev = SYS_BUS_DEVICE(dev);
- sysbus_realize_and_unref(busdev, &error_fatal);
- sysbus_mmio_map(busdev, 0, xam->cfg.tpm_base_addr);
-
- trace_xen_enable_tpm(xam->cfg.tpm_base_addr);
-}
-#endif
-
-static void xen_arm_init(MachineState *machine)
-{
- XenArmState *xam = XEN_ARM(machine);
-
- xam->state = g_new0(XenIOState, 1);
-
- if (machine->ram_size == 0) {
- warn_report("%s non-zero ram size not specified. QEMU machine started"
- " without IOREQ (no emulated devices including virtio)",
- MACHINE_CLASS(object_get_class(OBJECT(machine)))->desc);
- return;
- }
-
- xen_init_ram(machine);
-
- xen_register_ioreq(xam->state, machine->smp.cpus, &xen_memory_listener);
-
- xen_create_virtio_mmio_devices(xam);
-
-#ifdef CONFIG_TPM
- if (xam->cfg.tpm_base_addr) {
- xen_enable_tpm(xam);
- } else {
- warn_report("tpm-base-addr is not provided. TPM will not be enabled");
- }
-#endif
-}
-
-#ifdef CONFIG_TPM
-static void xen_arm_get_tpm_base_addr(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- XenArmState *xam = XEN_ARM(obj);
- uint64_t value = xam->cfg.tpm_base_addr;
-
- visit_type_uint64(v, name, &value, errp);
-}
-
-static void xen_arm_set_tpm_base_addr(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- XenArmState *xam = XEN_ARM(obj);
- uint64_t value;
-
- if (!visit_type_uint64(v, name, &value, errp)) {
- return;
- }
-
- xam->cfg.tpm_base_addr = value;
-}
-#endif
-
-static void xen_arm_machine_class_init(ObjectClass *oc, void *data)
-{
-
- MachineClass *mc = MACHINE_CLASS(oc);
- mc->desc = "Xen Para-virtualized PC";
- mc->init = xen_arm_init;
- mc->max_cpus = 1;
- mc->default_machine_opts = "accel=xen";
- /* Set explicitly here to make sure that real ram_size is passed */
- mc->default_ram_size = 0;
-
-#ifdef CONFIG_TPM
- object_class_property_add(oc, "tpm-base-addr", "uint64_t",
- xen_arm_get_tpm_base_addr,
- xen_arm_set_tpm_base_addr,
- NULL, NULL);
- object_class_property_set_description(oc, "tpm-base-addr",
- "Set Base address for TPM device.");
-
- machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
-#endif
-}
-
-static const TypeInfo xen_arm_machine_type = {
- .name = TYPE_XEN_ARM,
- .parent = TYPE_MACHINE,
- .class_init = xen_arm_machine_class_init,
- .instance_size = sizeof(XenArmState),
-};
-
-static void xen_arm_machine_register_types(void)
-{
- type_register_static(&xen_arm_machine_type);
-}
-
-type_init(xen_arm_machine_register_types)
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index 3c56b9a..fde4d94 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -34,6 +34,7 @@
#include "hw/net/cadence_gem.h"
#include "hw/cpu/a9mpcore.h"
#include "hw/qdev-clock.h"
+#include "hw/misc/unimp.h"
#include "sysemu/reset.h"
#include "qom/object.h"
#include "exec/tswap.h"
@@ -219,14 +220,6 @@ static void zynq_init(MachineState *machine)
for (n = 0; n < smp_cpus; n++) {
Object *cpuobj = object_new(machine->cpu_type);
- /*
- * By default A9 CPUs have EL3 enabled. This board does not currently
- * support EL3 so the CPU EL3 property is disabled before realization.
- */
- if (object_property_find(cpuobj, "has_el3")) {
- object_property_set_bool(cpuobj, "has_el3", false, &error_fatal);
- }
-
object_property_set_int(cpuobj, "midr", ZYNQ_BOARD_MIDR,
&error_fatal);
object_property_set_int(cpuobj, "reset-cbar", MPCORE_PERIPHBASE,
@@ -381,6 +374,75 @@ static void zynq_init(MachineState *machine)
sysbus_connect_irq(busdev, 0, pic[40 - IRQ_OFFSET]);
sysbus_mmio_map(busdev, 0, 0xF8007000);
+ /*
+ * Refer to the ug585-Zynq-7000-TRM manual B.3 (Module Summary) and
+ * the zynq-7000.dtsi. Add placeholders for unimplemented devices.
+ */
+ create_unimplemented_device("zynq.i2c0", 0xE0004000, 4 * KiB);
+ create_unimplemented_device("zynq.i2c1", 0xE0005000, 4 * KiB);
+ create_unimplemented_device("zynq.can0", 0xE0008000, 4 * KiB);
+ create_unimplemented_device("zynq.can1", 0xE0009000, 4 * KiB);
+ create_unimplemented_device("zynq.gpio", 0xE000A000, 4 * KiB);
+ create_unimplemented_device("zynq.smcc", 0xE000E000, 4 * KiB);
+
+ /* Direct Memory Access Controller, PL330, Non-Secure Mode */
+ create_unimplemented_device("zynq.dma_ns", 0xF8004000, 4 * KiB);
+
+ /* System Watchdog Timer Registers */
+ create_unimplemented_device("zynq.swdt", 0xF8005000, 4 * KiB);
+
+ /* DDR memory controller */
+ create_unimplemented_device("zynq.ddrc", 0xF8006000, 4 * KiB);
+
+ /* AXI_HP Interface (AFI) */
+ create_unimplemented_device("zynq.axi_hp0", 0xF8008000, 0x28);
+ create_unimplemented_device("zynq.axi_hp1", 0xF8009000, 0x28);
+ create_unimplemented_device("zynq.axi_hp2", 0xF800A000, 0x28);
+ create_unimplemented_device("zynq.axi_hp3", 0xF800B000, 0x28);
+
+ create_unimplemented_device("zynq.efuse", 0xF800d000, 0x20);
+
+ /* Embedded Trace Buffer */
+ create_unimplemented_device("zynq.etb", 0xF8801000, 4 * KiB);
+
+ /* Cross Trigger Interface, ETB and TPIU */
+ create_unimplemented_device("zynq.cti_etb_tpiu", 0xF8802000, 4 * KiB);
+
+ /* Trace Port Interface Unit */
+ create_unimplemented_device("zynq.tpiu", 0xF8803000, 4 * KiB);
+
+ /* CoreSight Trace Funnel */
+ create_unimplemented_device("zynq.funnel", 0xF8804000, 4 * KiB);
+
+ /* Instrumentation Trace Macrocell */
+ create_unimplemented_device("zynq.itm", 0xF8805000, 4 * KiB);
+
+ /* Cross Trigger Interface, FTM */
+ create_unimplemented_device("zynq.cti_ftm", 0xF8809000, 4 * KiB);
+
+ /* Fabric Trace Macrocell */
+ create_unimplemented_device("zynq.ftm", 0xF880B000, 4 * KiB);
+
+ /* Cortex A9 Performance Monitoring Unit, CPU */
+ create_unimplemented_device("cortex-a9.pmu0", 0xF8891000, 4 * KiB);
+ create_unimplemented_device("cortex-a9.pmu1", 0xF8893000, 4 * KiB);
+
+ /* Cross Trigger Interface, CPU */
+ create_unimplemented_device("zynq.cpu_cti0", 0xF8898000, 4 * KiB);
+ create_unimplemented_device("zynq.cpu_cti1", 0xF8899000, 4 * KiB);
+
+ /* CoreSight PTM-A9, CPU */
+ create_unimplemented_device("cortex-a9.ptm0", 0xF889c000, 4 * KiB);
+ create_unimplemented_device("cortex-a9.ptm1", 0xF889d000, 4 * KiB);
+
+ /* AMBA NIC301 TrustZone */
+ create_unimplemented_device("zynq.trustZone", 0xF8900000, 0x20);
+
+ /* AMBA Network Interconnect Advanced Quality of Service (QoS-301) */
+ create_unimplemented_device("zynq.qos301_cpu", 0xF8946000, 0x130);
+ create_unimplemented_device("zynq.qos301_dmac", 0xF8947000, 0x130);
+ create_unimplemented_device("zynq.qos301_iou", 0xF8948000, 0x130);
+
zynq_binfo.ram_size = machine->ram_size;
zynq_binfo.board_id = 0xd32;
zynq_binfo.loader_start = 0;
diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c
index 962f98f..8b12d3e 100644
--- a/hw/arm/xlnx-versal-virt.c
+++ b/hw/arm/xlnx-versal-virt.c
@@ -761,9 +761,9 @@ static void versal_virt_init(MachineState *machine)
if (!flash_klass ||
object_class_is_abstract(flash_klass) ||
!object_class_dynamic_cast(flash_klass, TYPE_M25P80)) {
- error_setg(&error_fatal, "'%s' is either abstract or"
+ error_report("'%s' is either abstract or"
" not a subtype of m25p80", s->ospi_model);
- return;
+ exit(1);
}
}
diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c
index 50cb060..3a1e2e2 100644
--- a/hw/arm/xlnx-versal.c
+++ b/hw/arm/xlnx-versal.c
@@ -258,14 +258,23 @@ static void versal_create_gems(Versal *s, qemu_irq *pic)
char *name = g_strdup_printf("gem%d", i);
DeviceState *dev;
MemoryRegion *mr;
+ OrIRQState *or_irq;
object_initialize_child(OBJECT(s), name, &s->lpd.iou.gem[i],
TYPE_CADENCE_GEM);
+ or_irq = &s->lpd.iou.gem_irq_orgate[i];
+ object_initialize_child(OBJECT(s), "gem-irq-orgate[*]",
+ or_irq, TYPE_OR_IRQ);
dev = DEVICE(&s->lpd.iou.gem[i]);
qemu_configure_nic_device(dev, true, NULL);
object_property_set_int(OBJECT(dev), "phy-addr", 23, &error_abort);
object_property_set_int(OBJECT(dev), "num-priority-queues", 2,
&error_abort);
+ object_property_set_int(OBJECT(or_irq),
+ "num-lines", 2, &error_fatal);
+ qdev_realize(DEVICE(or_irq), NULL, &error_fatal);
+ qdev_connect_gpio_out(DEVICE(or_irq), 0, pic[irqs[i]]);
+
object_property_set_link(OBJECT(dev), "dma", OBJECT(&s->mr_ps),
&error_abort);
sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
@@ -273,7 +282,8 @@ static void versal_create_gems(Versal *s, qemu_irq *pic)
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
memory_region_add_subregion(&s->mr_ps, addrs[i], mr);
- sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[irqs[i]]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(DEVICE(or_irq), 0));
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, qdev_get_gpio_in(DEVICE(or_irq), 1));
g_free(name);
}
}
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index afeb3f8..ab2d50e 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -394,6 +394,8 @@ static void xlnx_zynqmp_init(Object *obj)
for (i = 0; i < XLNX_ZYNQMP_NUM_GEMS; i++) {
object_initialize_child(obj, "gem[*]", &s->gem[i], TYPE_CADENCE_GEM);
+ object_initialize_child(obj, "gem-irq-orgate[*]",
+ &s->gem_irq_orgate[i], TYPE_OR_IRQ);
}
for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) {
@@ -625,12 +627,19 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
&error_abort);
object_property_set_int(OBJECT(&s->gem[i]), "num-priority-queues", 2,
&error_abort);
+ object_property_set_int(OBJECT(&s->gem_irq_orgate[i]),
+ "num-lines", 2, &error_fatal);
+ qdev_realize(DEVICE(&s->gem_irq_orgate[i]), NULL, &error_fatal);
+ qdev_connect_gpio_out(DEVICE(&s->gem_irq_orgate[i]), 0, gic_spi[gem_intr[i]]);
+
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gem[i]), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem[i]), 0, gem_addr[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem[i]), 0,
- gic_spi[gem_intr[i]]);
+ qdev_get_gpio_in(DEVICE(&s->gem_irq_orgate[i]), 0));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem[i]), 1,
+ qdev_get_gpio_in(DEVICE(&s->gem_irq_orgate[i]), 1));
}
for (i = 0; i < XLNX_ZYNQMP_NUM_UARTS; i++) {
diff --git a/hw/arm/z2.c b/hw/arm/z2.c
deleted file mode 100644
index fc5672e..0000000
--- a/hw/arm/z2.c
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * PXA270-based Zipit Z2 device
- *
- * Copyright (c) 2011 by Vasily Khoruzhick <anarsoul@gmail.com>
- *
- * Code is based on mainstone platform.
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/units.h"
-#include "hw/arm/pxa.h"
-#include "hw/arm/boot.h"
-#include "hw/i2c/i2c.h"
-#include "hw/irq.h"
-#include "hw/ssi/ssi.h"
-#include "migration/vmstate.h"
-#include "hw/boards.h"
-#include "hw/block/flash.h"
-#include "ui/console.h"
-#include "hw/audio/wm8750.h"
-#include "audio/audio.h"
-#include "exec/address-spaces.h"
-#include "qom/object.h"
-#include "qapi/error.h"
-#include "trace.h"
-
-static const struct keymap map[0x100] = {
- [0 ... 0xff] = { -1, -1 },
- [0x3b] = {0, 0}, /* Option = F1 */
- [0xc8] = {0, 1}, /* Up */
- [0xd0] = {0, 2}, /* Down */
- [0xcb] = {0, 3}, /* Left */
- [0xcd] = {0, 4}, /* Right */
- [0xcf] = {0, 5}, /* End */
- [0x0d] = {0, 6}, /* KPPLUS */
- [0xc7] = {1, 0}, /* Home */
- [0x10] = {1, 1}, /* Q */
- [0x17] = {1, 2}, /* I */
- [0x22] = {1, 3}, /* G */
- [0x2d] = {1, 4}, /* X */
- [0x1c] = {1, 5}, /* Enter */
- [0x0c] = {1, 6}, /* KPMINUS */
- [0xc9] = {2, 0}, /* PageUp */
- [0x11] = {2, 1}, /* W */
- [0x18] = {2, 2}, /* O */
- [0x23] = {2, 3}, /* H */
- [0x2e] = {2, 4}, /* C */
- [0x38] = {2, 5}, /* LeftAlt */
- [0xd1] = {3, 0}, /* PageDown */
- [0x12] = {3, 1}, /* E */
- [0x19] = {3, 2}, /* P */
- [0x24] = {3, 3}, /* J */
- [0x2f] = {3, 4}, /* V */
- [0x2a] = {3, 5}, /* LeftShift */
- [0x01] = {4, 0}, /* Esc */
- [0x13] = {4, 1}, /* R */
- [0x1e] = {4, 2}, /* A */
- [0x25] = {4, 3}, /* K */
- [0x30] = {4, 4}, /* B */
- [0x1d] = {4, 5}, /* LeftCtrl */
- [0x0f] = {5, 0}, /* Tab */
- [0x14] = {5, 1}, /* T */
- [0x1f] = {5, 2}, /* S */
- [0x26] = {5, 3}, /* L */
- [0x31] = {5, 4}, /* N */
- [0x39] = {5, 5}, /* Space */
- [0x3c] = {6, 0}, /* Stop = F2 */
- [0x15] = {6, 1}, /* Y */
- [0x20] = {6, 2}, /* D */
- [0x0e] = {6, 3}, /* Backspace */
- [0x32] = {6, 4}, /* M */
- [0x33] = {6, 5}, /* Comma */
- [0x3d] = {7, 0}, /* Play = F3 */
- [0x16] = {7, 1}, /* U */
- [0x21] = {7, 2}, /* F */
- [0x2c] = {7, 3}, /* Z */
- [0x27] = {7, 4}, /* Semicolon */
- [0x34] = {7, 5}, /* Dot */
-};
-
-#define Z2_RAM_SIZE 0x02000000
-#define Z2_FLASH_BASE 0x00000000
-#define Z2_FLASH_SIZE 0x00800000
-
-static struct arm_boot_info z2_binfo = {
- .loader_start = PXA2XX_SDRAM_BASE,
- .ram_size = Z2_RAM_SIZE,
-};
-
-#define Z2_GPIO_SD_DETECT 96
-#define Z2_GPIO_AC_IN 0
-#define Z2_GPIO_KEY_ON 1
-#define Z2_GPIO_LCD_CS 88
-
-struct ZipitLCD {
- SSIPeripheral ssidev;
- int32_t selected;
- int32_t enabled;
- uint8_t buf[3];
- uint32_t cur_reg;
- int pos;
-};
-
-#define TYPE_ZIPIT_LCD "zipit-lcd"
-OBJECT_DECLARE_SIMPLE_TYPE(ZipitLCD, ZIPIT_LCD)
-
-static uint32_t zipit_lcd_transfer(SSIPeripheral *dev, uint32_t value)
-{
- ZipitLCD *z = ZIPIT_LCD(dev);
- uint16_t val;
-
- trace_z2_lcd_reg_update(z->cur_reg, z->buf[0], z->buf[1], z->buf[2], value);
- if (z->selected) {
- z->buf[z->pos] = value & 0xff;
- z->pos++;
- }
- if (z->pos == 3) {
- switch (z->buf[0]) {
- case 0x74:
- z->cur_reg = z->buf[2];
- break;
- case 0x76:
- val = z->buf[1] << 8 | z->buf[2];
- if (z->cur_reg == 0x22 && val == 0x0000) {
- z->enabled = 1;
- trace_z2_lcd_enable_disable_result("enabled");
- } else if (z->cur_reg == 0x10 && val == 0x0000) {
- z->enabled = 0;
- trace_z2_lcd_enable_disable_result("disabled");
- }
- break;
- default:
- break;
- }
- z->pos = 0;
- }
- return 0;
-}
-
-static void z2_lcd_cs(void *opaque, int line, int level)
-{
- ZipitLCD *z2_lcd = opaque;
- z2_lcd->selected = !level;
-}
-
-static void zipit_lcd_realize(SSIPeripheral *dev, Error **errp)
-{
- ZipitLCD *z = ZIPIT_LCD(dev);
- z->selected = 0;
- z->enabled = 0;
- z->pos = 0;
-}
-
-static const VMStateDescription vmstate_zipit_lcd_state = {
- .name = "zipit-lcd",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (const VMStateField[]) {
- VMSTATE_SSI_PERIPHERAL(ssidev, ZipitLCD),
- VMSTATE_INT32(selected, ZipitLCD),
- VMSTATE_INT32(enabled, ZipitLCD),
- VMSTATE_BUFFER(buf, ZipitLCD),
- VMSTATE_UINT32(cur_reg, ZipitLCD),
- VMSTATE_INT32(pos, ZipitLCD),
- VMSTATE_END_OF_LIST(),
- }
-};
-
-static void zipit_lcd_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
-
- k->realize = zipit_lcd_realize;
- k->transfer = zipit_lcd_transfer;
- dc->vmsd = &vmstate_zipit_lcd_state;
-}
-
-static const TypeInfo zipit_lcd_info = {
- .name = TYPE_ZIPIT_LCD,
- .parent = TYPE_SSI_PERIPHERAL,
- .instance_size = sizeof(ZipitLCD),
- .class_init = zipit_lcd_class_init,
-};
-
-#define TYPE_AER915 "aer915"
-OBJECT_DECLARE_SIMPLE_TYPE(AER915State, AER915)
-
-struct AER915State {
- I2CSlave parent_obj;
-
- int len;
- uint8_t buf[3];
-};
-
-static int aer915_send(I2CSlave *i2c, uint8_t data)
-{
- AER915State *s = AER915(i2c);
-
- s->buf[s->len] = data;
- if (s->len++ > 2) {
- trace_z2_aer915_send_too_long(s->len);
- return 1;
- }
-
- if (s->len == 2) {
- trace_z2_aer915_send(s->buf[0], s->buf[1]);
- }
-
- return 0;
-}
-
-static int aer915_event(I2CSlave *i2c, enum i2c_event event)
-{
- AER915State *s = AER915(i2c);
-
- trace_z2_aer915_event(s->len, event);
- switch (event) {
- case I2C_START_SEND:
- s->len = 0;
- break;
- case I2C_START_RECV:
- break;
- case I2C_FINISH:
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static uint8_t aer915_recv(I2CSlave *slave)
-{
- AER915State *s = AER915(slave);
- int retval = 0x00;
-
- switch (s->buf[0]) {
- /* Return hardcoded battery voltage,
- * 0xf0 means ~4.1V
- */
- case 0x02:
- retval = 0xf0;
- break;
- /* Return 0x00 for other regs,
- * we don't know what they are for,
- * anyway they return 0x00 on real hardware.
- */
- default:
- break;
- }
-
- return retval;
-}
-
-static const VMStateDescription vmstate_aer915_state = {
- .name = "aer915",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
- VMSTATE_INT32(len, AER915State),
- VMSTATE_BUFFER(buf, AER915State),
- VMSTATE_END_OF_LIST(),
- }
-};
-
-static void aer915_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
-
- k->event = aer915_event;
- k->recv = aer915_recv;
- k->send = aer915_send;
- dc->vmsd = &vmstate_aer915_state;
-}
-
-static const TypeInfo aer915_info = {
- .name = TYPE_AER915,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(AER915State),
- .class_init = aer915_class_init,
-};
-
-#define FLASH_SECTOR_SIZE (64 * KiB)
-
-static void z2_init(MachineState *machine)
-{
- PXA2xxState *mpu;
- DriveInfo *dinfo;
- void *z2_lcd;
- I2CBus *bus;
- DeviceState *wm;
- I2CSlave *i2c_dev;
-
- /* Setup CPU & memory */
- mpu = pxa270_init(z2_binfo.ram_size, machine->cpu_type);
-
- dinfo = drive_get(IF_PFLASH, 0, 0);
- pflash_cfi01_register(Z2_FLASH_BASE, "z2.flash0", Z2_FLASH_SIZE,
- dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
- FLASH_SECTOR_SIZE, 4, 0, 0, 0, 0, 0);
-
- /* setup keypad */
- pxa27x_register_keypad(mpu->kp, map, 0x100);
-
- /* MMC/SD host */
- pxa2xx_mmci_handlers(mpu->mmc,
- NULL,
- qdev_get_gpio_in(mpu->gpio, Z2_GPIO_SD_DETECT));
-
- type_register_static(&zipit_lcd_info);
- type_register_static(&aer915_info);
- z2_lcd = ssi_create_peripheral(mpu->ssp[1], TYPE_ZIPIT_LCD);
- bus = pxa2xx_i2c_bus(mpu->i2c[0]);
-
- i2c_slave_create_simple(bus, TYPE_AER915, 0x55);
-
- i2c_dev = i2c_slave_new(TYPE_WM8750, 0x1b);
- wm = DEVICE(i2c_dev);
-
- if (machine->audiodev) {
- qdev_prop_set_string(wm, "audiodev", machine->audiodev);
- }
- i2c_slave_realize_and_unref(i2c_dev, bus, &error_abort);
-
- mpu->i2s->opaque = wm;
- mpu->i2s->codec_out = wm8750_dac_dat;
- mpu->i2s->codec_in = wm8750_adc_dat;
- wm8750_data_req_set(wm, mpu->i2s->data_req, mpu->i2s);
-
- qdev_connect_gpio_out(mpu->gpio, Z2_GPIO_LCD_CS,
- qemu_allocate_irq(z2_lcd_cs, z2_lcd, 0));
-
- z2_binfo.board_id = 0x6dd;
- arm_load_kernel(mpu->cpu, machine, &z2_binfo);
-}
-
-static void z2_machine_init(MachineClass *mc)
-{
- mc->desc = "Zipit Z2 (PXA27x)";
- mc->init = z2_init;
- mc->ignore_memory_transaction_failures = true;
- mc->default_cpu_type = ARM_CPU_TYPE_NAME("pxa270-c5");
- mc->deprecation_reason = "machine is old and unmaintained";
-
- machine_add_audiodev_property(mc);
-}
-
-DEFINE_MACHINE("z2", z2_machine_init)
diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c
index 3f0053f..e373f09 100644
--- a/hw/audio/ac97.c
+++ b/hw/audio/ac97.c
@@ -1344,7 +1344,7 @@ static void ac97_class_init(ObjectClass *klass, void *data)
dc->desc = "Intel 82801AA AC97 Audio";
dc->vmsd = &vmstate_ac97;
device_class_set_props(dc, ac97_properties);
- dc->reset = ac97_on_reset;
+ device_class_set_legacy_reset(dc, ac97_on_reset);
}
static const TypeInfo ac97_info = {
diff --git a/hw/audio/cs4231.c b/hw/audio/cs4231.c
index 967caa7..8321f89 100644
--- a/hw/audio/cs4231.c
+++ b/hw/audio/cs4231.c
@@ -164,7 +164,7 @@ static void cs4231_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = cs_reset;
+ device_class_set_legacy_reset(dc, cs_reset);
dc->vmsd = &vmstate_cs4231;
}
diff --git a/hw/audio/cs4231a.c b/hw/audio/cs4231a.c
index 9ef57f0..2d69372 100644
--- a/hw/audio/cs4231a.c
+++ b/hw/audio/cs4231a.c
@@ -702,7 +702,7 @@ static void cs4231a_class_initfn (ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS (klass);
dc->realize = cs4231a_realizefn;
- dc->reset = cs4231a_reset;
+ device_class_set_legacy_reset(dc, cs4231a_reset);
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
dc->desc = "Crystal Semiconductor CS4231A";
dc->vmsd = &vmstate_cs4231a;
diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c
index 4ab61d3..9a508e7 100644
--- a/hw/audio/es1370.c
+++ b/hw/audio/es1370.c
@@ -888,7 +888,7 @@ static void es1370_class_init (ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
dc->desc = "ENSONIQ AudioPCI ES1370";
dc->vmsd = &vmstate_es1370;
- dc->reset = es1370_on_reset;
+ device_class_set_legacy_reset(dc, es1370_on_reset);
device_class_set_props(dc, es1370_properties);
}
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c
index b22e486..bc66150 100644
--- a/hw/audio/hda-codec.c
+++ b/hw/audio/hda-codec.c
@@ -472,6 +472,24 @@ static void hda_audio_set_amp(HDAAudioStream *st)
}
}
+static void hda_close_stream(HDAAudioState *a, HDAAudioStream *st)
+{
+ if (st->node == NULL) {
+ return;
+ }
+ if (a->use_timer) {
+ timer_free(st->buft);
+ st->buft = NULL;
+ }
+ if (st->output) {
+ AUD_close_out(&a->card, st->voice.out);
+ st->voice.out = NULL;
+ } else {
+ AUD_close_in(&a->card, st->voice.in);
+ st->voice.in = NULL;
+ }
+}
+
static void hda_audio_setup(HDAAudioStream *st)
{
bool use_timer = st->state->use_timer;
@@ -484,6 +502,7 @@ static void hda_audio_setup(HDAAudioStream *st)
trace_hda_audio_format(st->node->name, st->as.nchannels,
fmt2name[st->as.fmt], st->as.freq);
+ hda_close_stream(st->state, st);
if (st->output) {
if (use_timer) {
cb = hda_audio_output_cb;
@@ -741,23 +760,11 @@ static void hda_audio_init(HDACodecDevice *hda,
static void hda_audio_exit(HDACodecDevice *hda)
{
HDAAudioState *a = HDA_AUDIO(hda);
- HDAAudioStream *st;
int i;
dprint(a, 1, "%s\n", __func__);
for (i = 0; i < ARRAY_SIZE(a->st); i++) {
- st = a->st + i;
- if (st->node == NULL) {
- continue;
- }
- if (a->use_timer) {
- timer_del(st->buft);
- }
- if (st->output) {
- AUD_close_out(&a->card, st->voice.out);
- } else {
- AUD_close_in(&a->card, st->voice.in);
- }
+ hda_close_stream(a, a->st + i);
}
AUD_remove_card(&a->card);
}
@@ -910,7 +917,7 @@ static void hda_audio_base_class_init(ObjectClass *klass, void *data)
k->command = hda_audio_command;
k->stream = hda_audio_stream;
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
- dc->reset = hda_audio_reset;
+ device_class_set_legacy_reset(dc, hda_audio_reset);
dc->vmsd = &vmstate_hda_audio;
device_class_set_props(dc, hda_audio_properties);
}
diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c
index 9c54e60..6918e23 100644
--- a/hw/audio/intel-hda.c
+++ b/hw/audio/intel-hda.c
@@ -1231,7 +1231,7 @@ static void intel_hda_class_init(ObjectClass *klass, void *data)
k->exit = intel_hda_exit;
k->vendor_id = PCI_VENDOR_ID_INTEL;
k->class_id = PCI_CLASS_MULTIMEDIA_HD_AUDIO;
- dc->reset = intel_hda_reset;
+ device_class_set_legacy_reset(dc, intel_hda_reset);
dc->vmsd = &vmstate_intel_hda;
device_class_set_props(dc, intel_hda_properties);
}
diff --git a/hw/audio/marvell_88w8618.c b/hw/audio/marvell_88w8618.c
index cc28544..28f9af3 100644
--- a/hw/audio/marvell_88w8618.c
+++ b/hw/audio/marvell_88w8618.c
@@ -292,7 +292,7 @@ static void mv88w8618_audio_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = mv88w8618_audio_realize;
- dc->reset = mv88w8618_audio_reset;
+ device_class_set_legacy_reset(dc, mv88w8618_audio_reset);
dc->vmsd = &mv88w8618_audio_vmsd;
dc->user_creatable = false;
}
diff --git a/hw/audio/pl041.c b/hw/audio/pl041.c
index b435208..eb96dc2 100644
--- a/hw/audio/pl041.c
+++ b/hw/audio/pl041.c
@@ -639,7 +639,7 @@ static void pl041_device_class_init(ObjectClass *klass, void *data)
dc->realize = pl041_realize;
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
- dc->reset = pl041_device_reset;
+ device_class_set_legacy_reset(dc, pl041_device_reset);
dc->vmsd = &vmstate_pl041;
device_class_set_props(dc, pl041_device_properties);
}
diff --git a/hw/audio/soundhw.c b/hw/audio/soundhw.c
index b387b0e..d18fd9f 100644
--- a/hw/audio/soundhw.c
+++ b/hw/audio/soundhw.c
@@ -88,7 +88,8 @@ void select_soundhw(const char *name, const char *audiodev)
struct soundhw *c;
if (selected) {
- error_setg(&error_fatal, "only one -soundhw option is allowed");
+ error_report("only one -soundhw option is allowed");
+ exit(1);
}
for (c = soundhw; c->name; ++c) {
diff --git a/hw/audio/trace-events b/hw/audio/trace-events
index b1870ff..b8ef572 100644
--- a/hw/audio/trace-events
+++ b/hw/audio/trace-events
@@ -41,7 +41,6 @@ asc_update_irq(int irq, int a, int b) "set IRQ to %d (A: 0x%x B: 0x%x)"
#virtio-snd.c
virtio_snd_get_config(void *vdev, uint32_t jacks, uint32_t streams, uint32_t chmaps) "snd %p: get_config jacks=%"PRIu32" streams=%"PRIu32" chmaps=%"PRIu32""
-virtio_snd_set_config(void *vdev, uint32_t jacks, uint32_t new_jacks, uint32_t streams, uint32_t new_streams, uint32_t chmaps, uint32_t new_chmaps) "snd %p: set_config jacks from %"PRIu32"->%"PRIu32", streams from %"PRIu32"->%"PRIu32", chmaps from %"PRIu32"->%"PRIu32
virtio_snd_get_features(void *vdev, uint64_t features) "snd %p: get_features 0x%"PRIx64
virtio_snd_vm_state_running(void) "vm state running"
virtio_snd_vm_state_stopped(void) "vm state stopped"
diff --git a/hw/audio/via-ac97.c b/hw/audio/via-ac97.c
index 4c127a1..85243e6 100644
--- a/hw/audio/via-ac97.c
+++ b/hw/audio/via-ac97.c
@@ -478,7 +478,7 @@ static void via_ac97_class_init(ObjectClass *klass, void *data)
device_class_set_props(dc, via_ac97_properties);
set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
dc->desc = "VIA AC97";
- dc->reset = via_ac97_reset;
+ device_class_set_legacy_reset(dc, via_ac97_reset);
/* Reason: Part of a south bridge chip */
dc->user_creatable = false;
}
diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 5993f4f..c5581d7 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -20,7 +20,6 @@
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "qemu/lockable.h"
-#include "exec/tswap.h"
#include "sysemu/runstate.h"
#include "trace.h"
#include "qapi/error.h"
@@ -108,29 +107,6 @@ virtio_snd_get_config(VirtIODevice *vdev, uint8_t *config)
}
static void
-virtio_snd_set_config(VirtIODevice *vdev, const uint8_t *config)
-{
- VirtIOSound *s = VIRTIO_SND(vdev);
- const virtio_snd_config *sndconfig =
- (const virtio_snd_config *)config;
-
-
- trace_virtio_snd_set_config(vdev,
- s->snd_conf.jacks,
- sndconfig->jacks,
- s->snd_conf.streams,
- sndconfig->streams,
- s->snd_conf.chmaps,
- sndconfig->chmaps);
-
- memcpy(&s->snd_conf, sndconfig, sizeof(virtio_snd_config));
- le32_to_cpus(&s->snd_conf.jacks);
- le32_to_cpus(&s->snd_conf.streams);
- le32_to_cpus(&s->snd_conf.chmaps);
-
-}
-
-static void
virtio_snd_pcm_buffer_free(VirtIOSoundPCMBuffer *buffer)
{
g_free(buffer->elem);
@@ -282,11 +258,13 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
error_report("Number of channels is not supported.");
return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
}
- if (!(supported_formats & BIT(params->format))) {
+ if (params->format >= sizeof(supported_formats) * BITS_PER_BYTE ||
+ !(supported_formats & BIT(params->format))) {
error_report("Stream format is not supported.");
return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
}
- if (!(supported_rates & BIT(params->rate))) {
+ if (params->rate >= sizeof(supported_rates) * BITS_PER_BYTE ||
+ !(supported_rates & BIT(params->rate))) {
error_report("Stream rate is not supported.");
return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
}
@@ -1261,7 +1239,7 @@ static void virtio_snd_pcm_in_cb(void *data, int available)
{
VirtIOSoundPCMStream *stream = data;
VirtIOSoundPCMBuffer *buffer;
- size_t size;
+ size_t size, max_size;
WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
while (!QSIMPLEQ_EMPTY(&stream->queue)) {
@@ -1275,7 +1253,12 @@ static void virtio_snd_pcm_in_cb(void *data, int available)
continue;
}
+ max_size = iov_size(buffer->elem->in_sg, buffer->elem->in_num);
for (;;) {
+ if (buffer->size >= max_size) {
+ return_rx_buffer(stream, buffer);
+ break;
+ }
size = AUD_read(stream->voice.in,
buffer->data + buffer->size,
MIN(available, (stream->params.period_bytes -
@@ -1393,7 +1376,6 @@ static void virtio_snd_class_init(ObjectClass *klass, void *data)
vdc->realize = virtio_snd_realize;
vdc->unrealize = virtio_snd_unrealize;
vdc->get_config = virtio_snd_get_config;
- vdc->set_config = virtio_snd_set_config;
vdc->get_features = get_features;
vdc->reset = virtio_snd_reset;
vdc->legacy_features = 0;
diff --git a/hw/block/Kconfig b/hw/block/Kconfig
index 9e8f28f..a898e04 100644
--- a/hw/block/Kconfig
+++ b/hw/block/Kconfig
@@ -22,15 +22,6 @@ config PFLASH_CFI01
config PFLASH_CFI02
bool
-config ECC
- bool
-
-config ONENAND
- bool
-
-config TC58128
- bool
-
config VIRTIO_BLK
bool
default y
diff --git a/hw/block/ecc.c b/hw/block/ecc.c
deleted file mode 100644
index ed889a4..0000000
--- a/hw/block/ecc.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Calculate Error-correcting Codes. Used by NAND Flash controllers
- * (not by NAND chips).
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPL v2.
- *
- * 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 "migration/vmstate.h"
-#include "hw/block/flash.h"
-
-/*
- * Pre-calculated 256-way 1 byte column parity. Table borrowed from Linux.
- */
-static const uint8_t nand_ecc_precalc_table[] = {
- 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
- 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
- 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
- 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
- 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
- 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
- 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
- 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
- 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
- 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
- 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
- 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
- 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
- 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
- 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
- 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
- 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
- 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
- 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
- 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
- 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
- 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
- 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
- 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
- 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
- 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
- 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
- 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
- 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
- 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
- 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
- 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
-};
-
-/* Update ECC parity count. */
-uint8_t ecc_digest(ECCState *s, uint8_t sample)
-{
- uint8_t idx = nand_ecc_precalc_table[sample];
-
- s->cp ^= idx & 0x3f;
- if (idx & 0x40) {
- s->lp[0] ^= ~s->count;
- s->lp[1] ^= s->count;
- }
- s->count ++;
-
- return sample;
-}
-
-/* Reinitialise the counters. */
-void ecc_reset(ECCState *s)
-{
- s->lp[0] = 0x0000;
- s->lp[1] = 0x0000;
- s->cp = 0x00;
- s->count = 0;
-}
-
-/* Save/restore */
-const VMStateDescription vmstate_ecc_state = {
- .name = "ecc-state",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT8(cp, ECCState),
- VMSTATE_UINT16_ARRAY(lp, ECCState, 2),
- VMSTATE_UINT16(count, ECCState),
- VMSTATE_END_OF_LIST(),
- },
-};
diff --git a/hw/block/fdc-isa.c b/hw/block/fdc-isa.c
index e43dc53..5ed3c18 100644
--- a/hw/block/fdc-isa.c
+++ b/hw/block/fdc-isa.c
@@ -147,6 +147,8 @@ static void isa_fdc_get_drive_max_chs(FloppyDriveType type, uint8_t *maxc,
*maxs = fdf->last_sect;
}
}
+ /* fd_formats must contain at least one entry per FloppyDriveType */
+ assert(*maxc);
(*maxc)--;
}
@@ -305,7 +307,7 @@ static void isabus_fdc_class_init(ObjectClass *klass, void *data)
dc->desc = "virtual floppy controller";
dc->realize = isabus_fdc_realize;
dc->fw_name = "fdc";
- dc->reset = fdctrl_external_reset_isa;
+ device_class_set_legacy_reset(dc, fdctrl_external_reset_isa);
dc->vmsd = &vmstate_isa_fdc;
adevc->build_dev_aml = build_fdc_aml;
device_class_set_props(dc, isa_fdc_properties);
diff --git a/hw/block/fdc-sysbus.c b/hw/block/fdc-sysbus.c
index 035bc08..e1ddbf3 100644
--- a/hw/block/fdc-sysbus.c
+++ b/hw/block/fdc-sysbus.c
@@ -181,7 +181,7 @@ static void sysbus_fdc_common_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = sysbus_fdc_realize;
- dc->reset = fdctrl_external_reset_sysbus;
+ device_class_set_legacy_reset(dc, fdctrl_external_reset_sysbus);
dc->vmsd = &vmstate_sysbus_fdc;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
}
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index 9e99107..e2e84f8 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -61,7 +61,8 @@ typedef struct FlashPartInfo {
*/
uint8_t id[SPI_NOR_MAX_ID_LEN];
uint8_t id_len;
- /* there is confusion between manufacturers as to what a sector is. In this
+ /*
+ * there is confusion between manufacturers as to what a sector is. In this
* device model, a "sector" is the size that is erased by the ERASE_SECTOR
* command (opcode 0xd8).
*/
@@ -168,7 +169,7 @@ typedef struct FlashPartInfo {
/*
* Spansion read mode command length in bytes,
* the mode is currently not supported.
-*/
+ */
#define SPANSION_CONTINUOUS_READ_MODE_CMD_LEN 1
#define WINBOND_CONTINUOUS_READ_MODE_CMD_LEN 1
@@ -189,7 +190,8 @@ static const FlashPartInfo known_devices[] = {
{ INFO("at45db081d", 0x1f2500, 0, 64 << 10, 16, ER_4K) },
- /* Atmel EEPROMS - it is assumed, that don't care bit in command
+ /*
+ * Atmel EEPROMS - it is assumed, that don't care bit in command
* is set to 0. Block protection is not supported.
*/
{ INFO("at25128a-nonjedec", 0x0, 0, 1, 131072, EEPROM) },
@@ -266,7 +268,8 @@ static const FlashPartInfo known_devices[] = {
{ INFO("n25q512ax3", 0x20ba20, 0x1000, 64 << 10, 1024, ER_4K) },
{ INFO("mt25ql512ab", 0x20ba20, 0x1044, 64 << 10, 1024, ER_4K | ER_32K) },
{ INFO_STACKED("mt35xu01g", 0x2c5b1b, 0x104100, 128 << 10, 1024,
- ER_4K | ER_32K, 2) },
+ ER_4K | ER_32K, 2),
+ .sfdp_read = m25p80_sfdp_mt35xu01g },
{ INFO_STACKED("mt35xu02gbba", 0x2c5b1c, 0x104100, 128 << 10, 2048,
ER_4K | ER_32K, 4),
.sfdp_read = m25p80_sfdp_mt35xu02g },
@@ -274,10 +277,13 @@ static const FlashPartInfo known_devices[] = {
{ INFO_STACKED("n25q00a", 0x20bb21, 0x1000, 64 << 10, 2048, ER_4K, 4) },
{ INFO_STACKED("mt25ql01g", 0x20ba21, 0x1040, 64 << 10, 2048, ER_4K, 2) },
{ INFO_STACKED("mt25qu01g", 0x20bb21, 0x1040, 64 << 10, 2048, ER_4K, 2) },
- { INFO_STACKED("mt25ql02g", 0x20ba22, 0x1040, 64 << 10, 4096, ER_4K | ER_32K, 2) },
- { INFO_STACKED("mt25qu02g", 0x20bb22, 0x1040, 64 << 10, 4096, ER_4K | ER_32K, 2) },
+ { INFO_STACKED("mt25ql02g", 0x20ba22, 0x1040, 64 << 10, 4096,
+ ER_4K | ER_32K, 2) },
+ { INFO_STACKED("mt25qu02g", 0x20bb22, 0x1040, 64 << 10, 4096,
+ ER_4K | ER_32K, 2) },
- /* Spansion -- single (large) sector size only, at least
+ /*
+ * Spansion -- single (large) sector size only, at least
* for the chips listed here (without boot sectors).
*/
{ INFO("s25sl032p", 0x010215, 0x4d00, 64 << 10, 64, ER_4K) },
@@ -350,13 +356,17 @@ static const FlashPartInfo known_devices[] = {
{ INFO("w25x64", 0xef3017, 0, 64 << 10, 128, ER_4K) },
{ INFO("w25q64", 0xef4017, 0, 64 << 10, 128, ER_4K) },
{ INFO("w25q80", 0xef5014, 0, 64 << 10, 16, ER_4K) },
- { INFO("w25q80bl", 0xef4014, 0, 64 << 10, 16, ER_4K) },
+ { INFO("w25q80bl", 0xef4014, 0, 64 << 10, 16, ER_4K),
+ .sfdp_read = m25p80_sfdp_w25q80bl },
{ INFO("w25q256", 0xef4019, 0, 64 << 10, 512, ER_4K),
.sfdp_read = m25p80_sfdp_w25q256 },
{ INFO("w25q512jv", 0xef4020, 0, 64 << 10, 1024, ER_4K),
.sfdp_read = m25p80_sfdp_w25q512jv },
{ INFO("w25q01jvq", 0xef4021, 0, 64 << 10, 2048, ER_4K),
.sfdp_read = m25p80_sfdp_w25q01jvq },
+
+ /* Microchip */
+ { INFO("25csm04", 0x29cc00, 0x100, 64 << 10, 8, 0) },
};
typedef enum {
@@ -421,6 +431,11 @@ typedef enum {
RDCR_EQIO = 0x35,
RSTQIO = 0xf5,
+ /*
+ * Winbond: 0x31 - write status register 2
+ */
+ WRSR2 = 0x31,
+
RNVCR = 0xB5,
WNVCR = 0xB1,
@@ -545,7 +560,8 @@ static void blk_sync_complete(void *opaque, int ret)
qemu_iovec_destroy(iov);
g_free(iov);
- /* do nothing. Masters do not directly interact with the backing store,
+ /*
+ * do nothing. Masters do not directly interact with the backing store,
* only the working copy so no mutexing required.
*/
}
@@ -811,6 +827,15 @@ static void complete_collecting_data(Flash *s)
s->write_enable = false;
}
break;
+ case WRSR2:
+ switch (get_man(s)) {
+ case MAN_WINBOND:
+ s->quad_enable = !!(s->data[0] & 0x02);
+ break;
+ default:
+ break;
+ }
+ break;
case BRWR:
case EXTEND_ADDR_WRITE:
s->ear = s->data[0];
@@ -1270,7 +1295,31 @@ static void decode_new_cmd(Flash *s, uint32_t value)
}
s->pos = 0;
break;
+ case WRSR2:
+ /*
+ * If WP# is low and status_register_write_disabled is high,
+ * status register writes are disabled.
+ * This is also called "hardware protected mode" (HPM). All other
+ * combinations of the two states are called "software protected mode"
+ * (SPM), and status register writes are permitted.
+ */
+ if ((s->wp_level == 0 && s->status_register_write_disabled)
+ || !s->write_enable) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "M25P80: Status register 2 write is disabled!\n");
+ break;
+ }
+ switch (get_man(s)) {
+ case MAN_WINBOND:
+ s->needed_bytes = 1;
+ s->state = STATE_COLLECTING_DATA;
+ s->pos = 0;
+ break;
+ default:
+ break;
+ }
+ break;
case WRDI:
s->write_enable = false;
if (get_man(s) == MAN_SST) {
@@ -1821,7 +1870,7 @@ static void m25p80_class_init(ObjectClass *klass, void *data)
k->cs_polarity = SSI_CS_LOW;
dc->vmsd = &vmstate_m25p80;
device_class_set_props(dc, m25p80_properties);
- dc->reset = m25p80_reset;
+ device_class_set_legacy_reset(dc, m25p80_reset);
mc->pi = data;
}
@@ -1839,7 +1888,7 @@ static void m25p80_register_types(void)
type_register_static(&m25p80_info);
for (i = 0; i < ARRAY_SIZE(known_devices); ++i) {
- TypeInfo ti = {
+ const TypeInfo ti = {
.name = known_devices[i].part_name,
.parent = TYPE_M25P80,
.class_init = m25p80_class_init,
diff --git a/hw/block/m25p80_sfdp.c b/hw/block/m25p80_sfdp.c
index 6ee2cfa..a03a291 100644
--- a/hw/block/m25p80_sfdp.c
+++ b/hw/block/m25p80_sfdp.c
@@ -57,6 +57,43 @@ static const uint8_t sfdp_n25q256a[] = {
};
define_sfdp_read(n25q256a);
+static const uint8_t sfdp_mt35xu01g[] = {
+ 0x53, 0x46, 0x44, 0x50, 0x06, 0x01, 0x01, 0xff,
+ 0x00, 0x06, 0x01, 0x10, 0x30, 0x00, 0x00, 0xff,
+ 0x84, 0x00, 0x01, 0x02, 0x80, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xe5, 0x20, 0x8a, 0xff, 0xff, 0xff, 0xff, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0x0c, 0x20, 0x11, 0xd8,
+ 0x0f, 0x52, 0x00, 0x00, 0x24, 0x5a, 0x99, 0x00,
+ 0x8b, 0x8e, 0x03, 0xe1, 0xac, 0x01, 0x27, 0x38,
+ 0x7a, 0x75, 0x7a, 0x75, 0xfb, 0xbd, 0xd5, 0x5c,
+ 0x00, 0x00, 0x70, 0xff, 0x81, 0xb0, 0x38, 0x36,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x43, 0x0e, 0xff, 0xff, 0x21, 0xdc, 0x5c, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+define_sfdp_read(mt35xu01g);
+
static const uint8_t sfdp_mt35xu02g[] = {
0x53, 0x46, 0x44, 0x50, 0x06, 0x01, 0x01, 0xff,
0x00, 0x06, 0x01, 0x10, 0x30, 0x00, 0x00, 0xff,
@@ -367,6 +404,42 @@ static const uint8_t sfdp_w25q01jvq[] = {
};
define_sfdp_read(w25q01jvq);
+static const uint8_t sfdp_w25q80bl[] = {
+ 0x53, 0x46, 0x44, 0x50, 0x05, 0x01, 0x00, 0xff,
+ 0x00, 0x05, 0x01, 0x10, 0x80, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xe5, 0x20, 0xf1, 0xff, 0xff, 0xff, 0x7f, 0x00,
+ 0x44, 0xeb, 0x08, 0x6b, 0x08, 0x3b, 0x42, 0xbb,
+ 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0x0c, 0x20, 0x0f, 0x52,
+ 0x10, 0xd8, 0x00, 0x00, 0x23, 0x02, 0xa6, 0x00,
+ 0x81, 0x6c, 0x14, 0xa7, 0xed, 0x61, 0x76, 0x33,
+ 0x7a, 0x75, 0x7a, 0x75, 0xf7, 0xa2, 0xd5, 0x5c,
+ 0x00, 0xf7, 0x1d, 0xff, 0xe9, 0x30, 0xc0, 0x80,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+define_sfdp_read(w25q80bl);
+
/*
* Integrated Silicon Solution (ISSI)
*/
diff --git a/hw/block/m25p80_sfdp.h b/hw/block/m25p80_sfdp.h
index 1733b56..3578568 100644
--- a/hw/block/m25p80_sfdp.h
+++ b/hw/block/m25p80_sfdp.h
@@ -16,6 +16,7 @@
#define M25P80_SFDP_MAX_SIZE (1 << 24)
uint8_t m25p80_sfdp_n25q256a(uint32_t addr);
+uint8_t m25p80_sfdp_mt35xu01g(uint32_t addr);
uint8_t m25p80_sfdp_mt35xu02g(uint32_t addr);
uint8_t m25p80_sfdp_mx25l25635e(uint32_t addr);
@@ -24,7 +25,7 @@ uint8_t m25p80_sfdp_mx66l1g45g(uint32_t addr);
uint8_t m25p80_sfdp_w25q256(uint32_t addr);
uint8_t m25p80_sfdp_w25q512jv(uint32_t addr);
-
+uint8_t m25p80_sfdp_w25q80bl(uint32_t addr);
uint8_t m25p80_sfdp_w25q01jvq(uint32_t addr);
uint8_t m25p80_sfdp_is25wp256(uint32_t addr);
diff --git a/hw/block/meson.build b/hw/block/meson.build
index 8aa4dc3..16a51bf 100644
--- a/hw/block/meson.build
+++ b/hw/block/meson.build
@@ -3,19 +3,16 @@ system_ss.add(files(
'cdrom.c',
'hd-geometry.c'
))
-system_ss.add(when: 'CONFIG_ECC', if_true: files('ecc.c'))
system_ss.add(when: 'CONFIG_FDC', if_true: files('fdc.c'))
system_ss.add(when: 'CONFIG_FDC_ISA', if_true: files('fdc-isa.c'))
system_ss.add(when: 'CONFIG_FDC_SYSBUS', if_true: files('fdc-sysbus.c'))
system_ss.add(when: 'CONFIG_NAND', if_true: files('nand.c'))
-system_ss.add(when: 'CONFIG_ONENAND', if_true: files('onenand.c'))
system_ss.add(when: 'CONFIG_PFLASH_CFI01', if_true: files('pflash_cfi01.c'))
system_ss.add(when: 'CONFIG_PFLASH_CFI02', if_true: files('pflash_cfi02.c'))
system_ss.add(when: 'CONFIG_SSI_M25P80', if_true: files('m25p80.c'))
system_ss.add(when: 'CONFIG_SSI_M25P80', if_true: files('m25p80_sfdp.c'))
system_ss.add(when: 'CONFIG_SWIM', if_true: files('swim.c'))
system_ss.add(when: 'CONFIG_XEN_BUS', if_true: files('xen-block.c'))
-system_ss.add(when: 'CONFIG_TC58128', if_true: files('tc58128.c'))
specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c', 'virtio-blk-common.c'))
specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c', 'virtio-blk-common.c'))
diff --git a/hw/block/nand.c b/hw/block/nand.c
index e2433c2..ac0a5d2 100644
--- a/hw/block/nand.c
+++ b/hw/block/nand.c
@@ -457,7 +457,7 @@ static void nand_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = nand_realize;
- dc->reset = nand_reset;
+ device_class_set_legacy_reset(dc, nand_reset);
dc->vmsd = &vmstate_nand;
device_class_set_props(dc, nand_properties);
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
diff --git a/hw/block/onenand.c b/hw/block/onenand.c
deleted file mode 100644
index d8a6944..0000000
--- a/hw/block/onenand.c
+++ /dev/null
@@ -1,872 +0,0 @@
-/*
- * OneNAND flash memories emulation.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/block/flash.h"
-#include "hw/irq.h"
-#include "hw/qdev-properties.h"
-#include "hw/qdev-properties-system.h"
-#include "sysemu/block-backend.h"
-#include "exec/memory.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "qemu/error-report.h"
-#include "qemu/log.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-/* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */
-#define PAGE_SHIFT 11
-
-/* Fixed */
-#define BLOCK_SHIFT (PAGE_SHIFT + 6)
-
-#define TYPE_ONE_NAND "onenand"
-OBJECT_DECLARE_SIMPLE_TYPE(OneNANDState, ONE_NAND)
-
-struct OneNANDState {
- SysBusDevice parent_obj;
-
- struct {
- uint16_t man;
- uint16_t dev;
- uint16_t ver;
- } id;
- int shift;
- hwaddr base;
- qemu_irq intr;
- qemu_irq rdy;
- BlockBackend *blk;
- BlockBackend *blk_cur;
- uint8_t *image;
- uint8_t *otp;
- uint8_t *current;
- MemoryRegion ram;
- MemoryRegion mapped_ram;
- uint8_t current_direction;
- uint8_t *boot[2];
- uint8_t *data[2][2];
- MemoryRegion iomem;
- MemoryRegion container;
- int cycle;
- int otpmode;
-
- uint16_t addr[8];
- uint16_t unladdr[8];
- int bufaddr;
- int count;
- uint16_t command;
- uint16_t config[2];
- uint16_t status;
- uint16_t intstatus;
- uint16_t wpstatus;
-
- ECCState ecc;
-
- int density_mask;
- int secs;
- int secs_cur;
- int blocks;
- uint8_t *blockwp;
-};
-
-enum {
- ONEN_BUF_BLOCK = 0,
- ONEN_BUF_BLOCK2 = 1,
- ONEN_BUF_DEST_BLOCK = 2,
- ONEN_BUF_DEST_PAGE = 3,
- ONEN_BUF_PAGE = 7,
-};
-
-enum {
- ONEN_ERR_CMD = 1 << 10,
- ONEN_ERR_ERASE = 1 << 11,
- ONEN_ERR_PROG = 1 << 12,
- ONEN_ERR_LOAD = 1 << 13,
-};
-
-enum {
- ONEN_INT_RESET = 1 << 4,
- ONEN_INT_ERASE = 1 << 5,
- ONEN_INT_PROG = 1 << 6,
- ONEN_INT_LOAD = 1 << 7,
- ONEN_INT = 1 << 15,
-};
-
-enum {
- ONEN_LOCK_LOCKTIGHTEN = 1 << 0,
- ONEN_LOCK_LOCKED = 1 << 1,
- ONEN_LOCK_UNLOCKED = 1 << 2,
-};
-
-static void onenand_mem_setup(OneNANDState *s)
-{
- /* XXX: We should use IO_MEM_ROMD but we broke it earlier...
- * Both 0x0000 ... 0x01ff and 0x8000 ... 0x800f can be used to
- * write boot commands. Also take note of the BWPS bit. */
- memory_region_init(&s->container, OBJECT(s), "onenand",
- 0x10000 << s->shift);
- memory_region_add_subregion(&s->container, 0, &s->iomem);
- memory_region_init_alias(&s->mapped_ram, OBJECT(s), "onenand-mapped-ram",
- &s->ram, 0x0200 << s->shift,
- 0xbe00 << s->shift);
- memory_region_add_subregion_overlap(&s->container,
- 0x0200 << s->shift,
- &s->mapped_ram,
- 1);
-}
-
-static void onenand_intr_update(OneNANDState *s)
-{
- qemu_set_irq(s->intr, ((s->intstatus >> 15) ^ (~s->config[0] >> 6)) & 1);
-}
-
-static int onenand_pre_save(void *opaque)
-{
- OneNANDState *s = opaque;
- if (s->current == s->otp) {
- s->current_direction = 1;
- } else if (s->current == s->image) {
- s->current_direction = 2;
- } else {
- s->current_direction = 0;
- }
-
- return 0;
-}
-
-static int onenand_post_load(void *opaque, int version_id)
-{
- OneNANDState *s = opaque;
- switch (s->current_direction) {
- case 0:
- break;
- case 1:
- s->current = s->otp;
- break;
- case 2:
- s->current = s->image;
- break;
- default:
- return -1;
- }
- onenand_intr_update(s);
- return 0;
-}
-
-static const VMStateDescription vmstate_onenand = {
- .name = "onenand",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_save = onenand_pre_save,
- .post_load = onenand_post_load,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT8(current_direction, OneNANDState),
- VMSTATE_INT32(cycle, OneNANDState),
- VMSTATE_INT32(otpmode, OneNANDState),
- VMSTATE_UINT16_ARRAY(addr, OneNANDState, 8),
- VMSTATE_UINT16_ARRAY(unladdr, OneNANDState, 8),
- VMSTATE_INT32(bufaddr, OneNANDState),
- VMSTATE_INT32(count, OneNANDState),
- VMSTATE_UINT16(command, OneNANDState),
- VMSTATE_UINT16_ARRAY(config, OneNANDState, 2),
- VMSTATE_UINT16(status, OneNANDState),
- VMSTATE_UINT16(intstatus, OneNANDState),
- VMSTATE_UINT16(wpstatus, OneNANDState),
- VMSTATE_INT32(secs_cur, OneNANDState),
- VMSTATE_PARTIAL_VBUFFER(blockwp, OneNANDState, blocks),
- VMSTATE_UINT8(ecc.cp, OneNANDState),
- VMSTATE_UINT16_ARRAY(ecc.lp, OneNANDState, 2),
- VMSTATE_UINT16(ecc.count, OneNANDState),
- VMSTATE_BUFFER_POINTER_UNSAFE(otp, OneNANDState, 0,
- ((64 + 2) << PAGE_SHIFT)),
- VMSTATE_END_OF_LIST()
- }
-};
-
-/* Hot reset (Reset OneNAND command) or warm reset (RP pin low) */
-static void onenand_reset(OneNANDState *s, int cold)
-{
- memset(&s->addr, 0, sizeof(s->addr));
- s->command = 0;
- s->count = 1;
- s->bufaddr = 0;
- s->config[0] = 0x40c0;
- s->config[1] = 0x0000;
- onenand_intr_update(s);
- qemu_irq_raise(s->rdy);
- s->status = 0x0000;
- s->intstatus = cold ? 0x8080 : 0x8010;
- s->unladdr[0] = 0;
- s->unladdr[1] = 0;
- s->wpstatus = 0x0002;
- s->cycle = 0;
- s->otpmode = 0;
- s->blk_cur = s->blk;
- s->current = s->image;
- s->secs_cur = s->secs;
-
- if (cold) {
- /* Lock the whole flash */
- memset(s->blockwp, ONEN_LOCK_LOCKED, s->blocks);
-
- if (s->blk_cur && blk_pread(s->blk_cur, 0, 8 << BDRV_SECTOR_BITS,
- s->boot[0], 0) < 0) {
- hw_error("%s: Loading the BootRAM failed.\n", __func__);
- }
- }
-}
-
-static void onenand_system_reset(DeviceState *dev)
-{
- OneNANDState *s = ONE_NAND(dev);
-
- onenand_reset(s, 1);
-}
-
-static inline int onenand_load_main(OneNANDState *s, int sec, int secn,
- void *dest)
-{
- assert(UINT32_MAX >> BDRV_SECTOR_BITS > sec);
- assert(UINT32_MAX >> BDRV_SECTOR_BITS > secn);
- if (s->blk_cur) {
- return blk_pread(s->blk_cur, sec << BDRV_SECTOR_BITS,
- secn << BDRV_SECTOR_BITS, dest, 0) < 0;
- } else if (sec + secn > s->secs_cur) {
- return 1;
- }
-
- memcpy(dest, s->current + (sec << 9), secn << 9);
-
- return 0;
-}
-
-static inline int onenand_prog_main(OneNANDState *s, int sec, int secn,
- void *src)
-{
- int result = 0;
-
- if (secn > 0) {
- uint32_t size = secn << BDRV_SECTOR_BITS;
- uint32_t offset = sec << BDRV_SECTOR_BITS;
- assert(UINT32_MAX >> BDRV_SECTOR_BITS > sec);
- assert(UINT32_MAX >> BDRV_SECTOR_BITS > secn);
- const uint8_t *sp = (const uint8_t *)src;
- uint8_t *dp = 0;
- if (s->blk_cur) {
- dp = g_malloc(size);
- if (!dp || blk_pread(s->blk_cur, offset, size, dp, 0) < 0) {
- result = 1;
- }
- } else {
- if (sec + secn > s->secs_cur) {
- result = 1;
- } else {
- dp = (uint8_t *)s->current + offset;
- }
- }
- if (!result) {
- uint32_t i;
- for (i = 0; i < size; i++) {
- dp[i] &= sp[i];
- }
- if (s->blk_cur) {
- result = blk_pwrite(s->blk_cur, offset, size, dp, 0) < 0;
- }
- }
- if (dp && s->blk_cur) {
- g_free(dp);
- }
- }
-
- return result;
-}
-
-static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
- void *dest)
-{
- uint8_t buf[512];
-
- if (s->blk_cur) {
- uint32_t offset = (s->secs_cur + (sec >> 5)) << BDRV_SECTOR_BITS;
- if (blk_pread(s->blk_cur, offset, BDRV_SECTOR_SIZE, buf, 0) < 0) {
- return 1;
- }
- memcpy(dest, buf + ((sec & 31) << 4), secn << 4);
- } else if (sec + secn > s->secs_cur) {
- return 1;
- } else {
- memcpy(dest, s->current + (s->secs_cur << 9) + (sec << 4), secn << 4);
- }
-
- return 0;
-}
-
-static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn,
- void *src)
-{
- int result = 0;
- if (secn > 0) {
- const uint8_t *sp = (const uint8_t *)src;
- uint8_t *dp = 0, *dpp = 0;
- uint32_t offset = (s->secs_cur + (sec >> 5)) << BDRV_SECTOR_BITS;
- assert(UINT32_MAX >> BDRV_SECTOR_BITS > s->secs_cur + (sec >> 5));
- if (s->blk_cur) {
- dp = g_malloc(512);
- if (!dp
- || blk_pread(s->blk_cur, offset, BDRV_SECTOR_SIZE, dp, 0) < 0) {
- result = 1;
- } else {
- dpp = dp + ((sec & 31) << 4);
- }
- } else {
- if (sec + secn > s->secs_cur) {
- result = 1;
- } else {
- dpp = s->current + (s->secs_cur << 9) + (sec << 4);
- }
- }
- if (!result) {
- uint32_t i;
- for (i = 0; i < (secn << 4); i++) {
- dpp[i] &= sp[i];
- }
- if (s->blk_cur) {
- result = blk_pwrite(s->blk_cur, offset, BDRV_SECTOR_SIZE, dp,
- 0) < 0;
- }
- }
- g_free(dp);
- }
- return result;
-}
-
-static inline int onenand_erase(OneNANDState *s, int sec, int num)
-{
- uint8_t *blankbuf, *tmpbuf;
-
- blankbuf = g_malloc(512);
- tmpbuf = g_malloc(512);
- memset(blankbuf, 0xff, 512);
- for (; num > 0; num--, sec++) {
- if (s->blk_cur) {
- int erasesec = s->secs_cur + (sec >> 5);
- if (blk_pwrite(s->blk_cur, sec << BDRV_SECTOR_BITS,
- BDRV_SECTOR_SIZE, blankbuf, 0) < 0) {
- goto fail;
- }
- if (blk_pread(s->blk_cur, erasesec << BDRV_SECTOR_BITS,
- BDRV_SECTOR_SIZE, tmpbuf, 0) < 0) {
- goto fail;
- }
- memcpy(tmpbuf + ((sec & 31) << 4), blankbuf, 1 << 4);
- if (blk_pwrite(s->blk_cur, erasesec << BDRV_SECTOR_BITS,
- BDRV_SECTOR_SIZE, tmpbuf, 0) < 0) {
- goto fail;
- }
- } else {
- if (sec + 1 > s->secs_cur) {
- goto fail;
- }
- memcpy(s->current + (sec << 9), blankbuf, 512);
- memcpy(s->current + (s->secs_cur << 9) + (sec << 4),
- blankbuf, 1 << 4);
- }
- }
-
- g_free(tmpbuf);
- g_free(blankbuf);
- return 0;
-
-fail:
- g_free(tmpbuf);
- g_free(blankbuf);
- return 1;
-}
-
-static void onenand_command(OneNANDState *s)
-{
- int b;
- int sec;
- void *buf;
-#define SETADDR(block, page) \
- sec = (s->addr[page] & 3) + \
- ((((s->addr[page] >> 2) & 0x3f) + \
- (((s->addr[block] & 0xfff) | \
- (s->addr[block] >> 15 ? s->density_mask : 0)) \
- << 6)) \
- << (PAGE_SHIFT - 9));
-#define SETBUF_M() \
- buf = (s->bufaddr & 8) ? s->data[(s->bufaddr >> 2) & 1][0] : s->boot[0]; \
- buf += (s->bufaddr & 3) << 9;
-#define SETBUF_S() \
- buf = (s->bufaddr & 8) ? \
- s->data[(s->bufaddr >> 2) & 1][1] : s->boot[1]; \
- buf += (s->bufaddr & 3) << 4;
-
- switch (s->command) {
- case 0x00: /* Load single/multiple sector data unit into buffer */
- SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
-
- SETBUF_M()
- if (onenand_load_main(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
-
-#if 0
- SETBUF_S()
- if (onenand_load_spare(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
-#endif
-
- /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
- * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
- * then we need two split the read/write into two chunks.
- */
- s->intstatus |= ONEN_INT | ONEN_INT_LOAD;
- break;
- case 0x13: /* Load single/multiple spare sector into buffer */
- SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
-
- SETBUF_S()
- if (onenand_load_spare(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
-
- /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
- * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
- * then we need two split the read/write into two chunks.
- */
- s->intstatus |= ONEN_INT | ONEN_INT_LOAD;
- break;
- case 0x80: /* Program single/multiple sector data unit from buffer */
- SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
-
- SETBUF_M()
- if (onenand_prog_main(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
-
-#if 0
- SETBUF_S()
- if (onenand_prog_spare(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
-#endif
-
- /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
- * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
- * then we need two split the read/write into two chunks.
- */
- s->intstatus |= ONEN_INT | ONEN_INT_PROG;
- break;
- case 0x1a: /* Program single/multiple spare area sector from buffer */
- SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
-
- SETBUF_S()
- if (onenand_prog_spare(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
-
- /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
- * or if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
- * then we need two split the read/write into two chunks.
- */
- s->intstatus |= ONEN_INT | ONEN_INT_PROG;
- break;
- case 0x1b: /* Copy-back program */
- SETBUF_S()
-
- SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
- if (onenand_load_main(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
-
- SETADDR(ONEN_BUF_DEST_BLOCK, ONEN_BUF_DEST_PAGE)
- if (onenand_prog_main(s, sec, s->count, buf))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
-
- /* TODO: spare areas */
-
- s->intstatus |= ONEN_INT | ONEN_INT_PROG;
- break;
-
- case 0x23: /* Unlock NAND array block(s) */
- s->intstatus |= ONEN_INT;
-
- /* XXX the previous (?) area should be locked automatically */
- for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
- if (b >= s->blocks) {
- s->status |= ONEN_ERR_CMD;
- break;
- }
- if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
- break;
-
- s->wpstatus = s->blockwp[b] = ONEN_LOCK_UNLOCKED;
- }
- break;
- case 0x27: /* Unlock All NAND array blocks */
- s->intstatus |= ONEN_INT;
-
- for (b = 0; b < s->blocks; b ++) {
- if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
- break;
-
- s->wpstatus = s->blockwp[b] = ONEN_LOCK_UNLOCKED;
- }
- break;
-
- case 0x2a: /* Lock NAND array block(s) */
- s->intstatus |= ONEN_INT;
-
- for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
- if (b >= s->blocks) {
- s->status |= ONEN_ERR_CMD;
- break;
- }
- if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
- break;
-
- s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKED;
- }
- break;
- case 0x2c: /* Lock-tight NAND array block(s) */
- s->intstatus |= ONEN_INT;
-
- for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
- if (b >= s->blocks) {
- s->status |= ONEN_ERR_CMD;
- break;
- }
- if (s->blockwp[b] == ONEN_LOCK_UNLOCKED)
- continue;
-
- s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKTIGHTEN;
- }
- break;
-
- case 0x71: /* Erase-Verify-Read */
- s->intstatus |= ONEN_INT;
- break;
- case 0x95: /* Multi-block erase */
- qemu_irq_pulse(s->intr);
- /* Fall through. */
- case 0x94: /* Block erase */
- sec = ((s->addr[ONEN_BUF_BLOCK] & 0xfff) |
- (s->addr[ONEN_BUF_BLOCK] >> 15 ? s->density_mask : 0))
- << (BLOCK_SHIFT - 9);
- if (onenand_erase(s, sec, 1 << (BLOCK_SHIFT - 9)))
- s->status |= ONEN_ERR_CMD | ONEN_ERR_ERASE;
-
- s->intstatus |= ONEN_INT | ONEN_INT_ERASE;
- break;
- case 0xb0: /* Erase suspend */
- break;
- case 0x30: /* Erase resume */
- s->intstatus |= ONEN_INT | ONEN_INT_ERASE;
- break;
-
- case 0xf0: /* Reset NAND Flash core */
- onenand_reset(s, 0);
- break;
- case 0xf3: /* Reset OneNAND */
- onenand_reset(s, 0);
- break;
-
- case 0x65: /* OTP Access */
- s->intstatus |= ONEN_INT;
- s->blk_cur = NULL;
- s->current = s->otp;
- s->secs_cur = 1 << (BLOCK_SHIFT - 9);
- s->addr[ONEN_BUF_BLOCK] = 0;
- s->otpmode = 1;
- break;
-
- default:
- s->status |= ONEN_ERR_CMD;
- s->intstatus |= ONEN_INT;
- qemu_log_mask(LOG_GUEST_ERROR, "unknown OneNAND command %x\n",
- s->command);
- }
-
- onenand_intr_update(s);
-}
-
-static uint64_t onenand_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- OneNANDState *s = (OneNANDState *) opaque;
- int offset = addr >> s->shift;
-
- switch (offset) {
- case 0x0000 ... 0xbffe:
- return lduw_le_p(s->boot[0] + addr);
-
- case 0xf000: /* Manufacturer ID */
- return s->id.man;
- case 0xf001: /* Device ID */
- return s->id.dev;
- case 0xf002: /* Version ID */
- return s->id.ver;
- /* TODO: get the following values from a real chip! */
- case 0xf003: /* Data Buffer size */
- return 1 << PAGE_SHIFT;
- case 0xf004: /* Boot Buffer size */
- return 0x200;
- case 0xf005: /* Amount of buffers */
- return 1 | (2 << 8);
- case 0xf006: /* Technology */
- return 0;
-
- case 0xf100 ... 0xf107: /* Start addresses */
- return s->addr[offset - 0xf100];
-
- case 0xf200: /* Start buffer */
- return (s->bufaddr << 8) | ((s->count - 1) & (1 << (PAGE_SHIFT - 10)));
-
- case 0xf220: /* Command */
- return s->command;
- case 0xf221: /* System Configuration 1 */
- return s->config[0] & 0xffe0;
- case 0xf222: /* System Configuration 2 */
- return s->config[1];
-
- case 0xf240: /* Controller Status */
- return s->status;
- case 0xf241: /* Interrupt */
- return s->intstatus;
- case 0xf24c: /* Unlock Start Block Address */
- return s->unladdr[0];
- case 0xf24d: /* Unlock End Block Address */
- return s->unladdr[1];
- case 0xf24e: /* Write Protection Status */
- return s->wpstatus;
-
- case 0xff00: /* ECC Status */
- return 0x00;
- case 0xff01: /* ECC Result of main area data */
- case 0xff02: /* ECC Result of spare area data */
- case 0xff03: /* ECC Result of main area data */
- case 0xff04: /* ECC Result of spare area data */
- qemu_log_mask(LOG_UNIMP,
- "onenand: ECC result registers unimplemented\n");
- return 0x0000;
- }
-
- qemu_log_mask(LOG_GUEST_ERROR, "read of unknown OneNAND register 0x%x\n",
- offset);
- return 0;
-}
-
-static void onenand_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- OneNANDState *s = (OneNANDState *) opaque;
- int offset = addr >> s->shift;
- int sec;
-
- switch (offset) {
- case 0x0000 ... 0x01ff:
- case 0x8000 ... 0x800f:
- if (s->cycle) {
- s->cycle = 0;
-
- if (value == 0x0000) {
- SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
- onenand_load_main(s, sec,
- 1 << (PAGE_SHIFT - 9), s->data[0][0]);
- s->addr[ONEN_BUF_PAGE] += 4;
- s->addr[ONEN_BUF_PAGE] &= 0xff;
- }
- break;
- }
-
- switch (value) {
- case 0x00f0: /* Reset OneNAND */
- onenand_reset(s, 0);
- break;
-
- case 0x00e0: /* Load Data into Buffer */
- s->cycle = 1;
- break;
-
- case 0x0090: /* Read Identification Data */
- memset(s->boot[0], 0, 3 << s->shift);
- s->boot[0][0 << s->shift] = s->id.man & 0xff;
- s->boot[0][1 << s->shift] = s->id.dev & 0xff;
- s->boot[0][2 << s->shift] = s->wpstatus & 0xff;
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "unknown OneNAND boot command %" PRIx64 "\n",
- value);
- }
- break;
-
- case 0xf100 ... 0xf107: /* Start addresses */
- s->addr[offset - 0xf100] = value;
- break;
-
- case 0xf200: /* Start buffer */
- s->bufaddr = (value >> 8) & 0xf;
- if (PAGE_SHIFT == 11)
- s->count = (value & 3) ?: 4;
- else if (PAGE_SHIFT == 10)
- s->count = (value & 1) ?: 2;
- break;
-
- case 0xf220: /* Command */
- if (s->intstatus & (1 << 15))
- break;
- s->command = value;
- onenand_command(s);
- break;
- case 0xf221: /* System Configuration 1 */
- s->config[0] = value;
- onenand_intr_update(s);
- qemu_set_irq(s->rdy, (s->config[0] >> 7) & 1);
- break;
- case 0xf222: /* System Configuration 2 */
- s->config[1] = value;
- break;
-
- case 0xf241: /* Interrupt */
- s->intstatus &= value;
- if ((1 << 15) & ~s->intstatus)
- s->status &= ~(ONEN_ERR_CMD | ONEN_ERR_ERASE |
- ONEN_ERR_PROG | ONEN_ERR_LOAD);
- onenand_intr_update(s);
- break;
- case 0xf24c: /* Unlock Start Block Address */
- s->unladdr[0] = value & (s->blocks - 1);
- /* For some reason we have to set the end address to by default
- * be same as start because the software forgets to write anything
- * in there. */
- s->unladdr[1] = value & (s->blocks - 1);
- break;
- case 0xf24d: /* Unlock End Block Address */
- s->unladdr[1] = value & (s->blocks - 1);
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "write to unknown OneNAND register 0x%x\n",
- offset);
- }
-}
-
-static const MemoryRegionOps onenand_ops = {
- .read = onenand_read,
- .write = onenand_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void onenand_realize(DeviceState *dev, Error **errp)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- OneNANDState *s = ONE_NAND(dev);
- uint32_t size = 1 << (24 + ((s->id.dev >> 4) & 7));
- void *ram;
- Error *local_err = NULL;
-
- s->base = (hwaddr)-1;
- s->rdy = NULL;
- s->blocks = size >> BLOCK_SHIFT;
- s->secs = size >> 9;
- s->blockwp = g_malloc(s->blocks);
- s->density_mask = (s->id.dev & 0x08)
- ? (1 << (6 + ((s->id.dev >> 4) & 7))) : 0;
- memory_region_init_io(&s->iomem, OBJECT(s), &onenand_ops, s, "onenand",
- 0x10000 << s->shift);
- if (!s->blk) {
- s->image = memset(g_malloc(size + (size >> 5)),
- 0xff, size + (size >> 5));
- } else {
- if (!blk_supports_write_perm(s->blk)) {
- error_setg(errp, "Can't use a read-only drive");
- return;
- }
- blk_set_perm(s->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE,
- BLK_PERM_ALL, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
- s->blk_cur = s->blk;
- }
- s->otp = memset(g_malloc((64 + 2) << PAGE_SHIFT),
- 0xff, (64 + 2) << PAGE_SHIFT);
- memory_region_init_ram_nomigrate(&s->ram, OBJECT(s), "onenand.ram",
- 0xc000 << s->shift, &error_fatal);
- vmstate_register_ram_global(&s->ram);
- ram = memory_region_get_ram_ptr(&s->ram);
- s->boot[0] = ram + (0x0000 << s->shift);
- s->boot[1] = ram + (0x8000 << s->shift);
- s->data[0][0] = ram + ((0x0200 + (0 << (PAGE_SHIFT - 1))) << s->shift);
- s->data[0][1] = ram + ((0x8010 + (0 << (PAGE_SHIFT - 6))) << s->shift);
- s->data[1][0] = ram + ((0x0200 + (1 << (PAGE_SHIFT - 1))) << s->shift);
- s->data[1][1] = ram + ((0x8010 + (1 << (PAGE_SHIFT - 6))) << s->shift);
- onenand_mem_setup(s);
- sysbus_init_irq(sbd, &s->intr);
- sysbus_init_mmio(sbd, &s->container);
- vmstate_register(VMSTATE_IF(dev),
- ((s->shift & 0x7f) << 24)
- | ((s->id.man & 0xff) << 16)
- | ((s->id.dev & 0xff) << 8)
- | (s->id.ver & 0xff),
- &vmstate_onenand, s);
-}
-
-static Property onenand_properties[] = {
- DEFINE_PROP_UINT16("manufacturer_id", OneNANDState, id.man, 0),
- DEFINE_PROP_UINT16("device_id", OneNANDState, id.dev, 0),
- DEFINE_PROP_UINT16("version_id", OneNANDState, id.ver, 0),
- DEFINE_PROP_INT32("shift", OneNANDState, shift, 0),
- DEFINE_PROP_DRIVE("drive", OneNANDState, blk),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void onenand_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = onenand_realize;
- dc->reset = onenand_system_reset;
- device_class_set_props(dc, onenand_properties);
-}
-
-static const TypeInfo onenand_info = {
- .name = TYPE_ONE_NAND,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(OneNANDState),
- .class_init = onenand_class_init,
-};
-
-static void onenand_register_types(void)
-{
- type_register_static(&onenand_info);
-}
-
-void *onenand_raw_otp(DeviceState *onenand_device)
-{
- OneNANDState *s = ONE_NAND(onenand_device);
-
- return s->otp;
-}
-
-type_init(onenand_register_types)
diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
index c8f1cf5..7b6ec64 100644
--- a/hw/block/pflash_cfi01.c
+++ b/hw/block/pflash_cfi01.c
@@ -614,6 +614,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset,
if (!pfl->counter) {
trace_pflash_write(pfl->name, "block write finished");
pfl->wcycle++;
+ break;
}
pfl->counter--;
@@ -939,7 +940,7 @@ static void pflash_cfi01_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = pflash_cfi01_system_reset;
+ device_class_set_legacy_reset(dc, pflash_cfi01_system_reset);
dc->realize = pflash_cfi01_realize;
device_class_set_props(dc, pflash_cfi01_properties);
dc->vmsd = &vmstate_pflash;
diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 2314142..8393f26 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -974,7 +974,7 @@ static void pflash_cfi02_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = pflash_cfi02_realize;
- dc->reset = pflash_cfi02_reset;
+ device_class_set_legacy_reset(dc, pflash_cfi02_reset);
dc->unrealize = pflash_cfi02_unrealize;
device_class_set_props(dc, pflash_cfi02_properties);
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
diff --git a/hw/block/swim.c b/hw/block/swim.c
index 44761c1..64992eb 100644
--- a/hw/block/swim.c
+++ b/hw/block/swim.c
@@ -556,7 +556,7 @@ static void sysbus_swim_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = sysbus_swim_realize;
- dc->reset = sysbus_swim_reset;
+ device_class_set_legacy_reset(dc, sysbus_swim_reset);
dc->vmsd = &vmstate_sysbus_swim;
}
diff --git a/hw/block/tc58128.c b/hw/block/tc58128.c
deleted file mode 100644
index 0984e37..0000000
--- a/hw/block/tc58128.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * TC58128 NAND EEPROM emulation
- *
- * Copyright (c) 2005 Samuel Tardieu
- *
- * 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 (including the next
- * paragraph) 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.
- *
- * SPDX-License-Identifier: MIT
- */
-#include "qemu/osdep.h"
-#include "qemu/units.h"
-#include "hw/sh4/sh.h"
-#include "hw/loader.h"
-#include "sysemu/qtest.h"
-#include "qemu/error-report.h"
-
-#define CE1 0x0100
-#define CE2 0x0200
-#define RE 0x0400
-#define WE 0x0800
-#define ALE 0x1000
-#define CLE 0x2000
-#define RDY1 0x4000
-#define RDY2 0x8000
-#define RDY(n) ((n) == 0 ? RDY1 : RDY2)
-
-typedef enum { WAIT, READ1, READ2, READ3 } state_t;
-
-typedef struct {
- uint8_t *flash_contents;
- state_t state;
- uint32_t address;
- uint8_t address_cycle;
-} tc58128_dev;
-
-static tc58128_dev tc58128_devs[2];
-
-#define FLASH_SIZE (16 * MiB)
-
-static void init_dev(tc58128_dev * dev, const char *filename)
-{
- int ret, blocks;
-
- dev->state = WAIT;
- dev->flash_contents = g_malloc(FLASH_SIZE);
- memset(dev->flash_contents, 0xff, FLASH_SIZE);
- if (filename) {
- /* Load flash image skipping the first block */
- ret = load_image_size(filename, dev->flash_contents + 528 * 32,
- FLASH_SIZE - 528 * 32);
- if (ret < 0) {
- if (!qtest_enabled()) {
- error_report("Could not load flash image %s", filename);
- exit(1);
- }
- } else {
- /* Build first block with number of blocks */
- blocks = DIV_ROUND_UP(ret, 528 * 32);
- dev->flash_contents[0] = blocks & 0xff;
- dev->flash_contents[1] = (blocks >> 8) & 0xff;
- dev->flash_contents[2] = (blocks >> 16) & 0xff;
- dev->flash_contents[3] = (blocks >> 24) & 0xff;
- fprintf(stderr, "loaded %d bytes for %s into flash\n", ret,
- filename);
- }
- }
-}
-
-static void handle_command(tc58128_dev * dev, uint8_t command)
-{
- switch (command) {
- case 0xff:
- fprintf(stderr, "reset flash device\n");
- dev->state = WAIT;
- break;
- case 0x00:
- fprintf(stderr, "read mode 1\n");
- dev->state = READ1;
- dev->address_cycle = 0;
- break;
- case 0x01:
- fprintf(stderr, "read mode 2\n");
- dev->state = READ2;
- dev->address_cycle = 0;
- break;
- case 0x50:
- fprintf(stderr, "read mode 3\n");
- dev->state = READ3;
- dev->address_cycle = 0;
- break;
- default:
- fprintf(stderr, "unknown flash command 0x%02x\n", command);
- abort();
- }
-}
-
-static void handle_address(tc58128_dev * dev, uint8_t data)
-{
- switch (dev->state) {
- case READ1:
- case READ2:
- case READ3:
- switch (dev->address_cycle) {
- case 0:
- dev->address = data;
- if (dev->state == READ2)
- dev->address |= 0x100;
- else if (dev->state == READ3)
- dev->address |= 0x200;
- break;
- case 1:
- dev->address += data * 528 * 0x100;
- break;
- case 2:
- dev->address += data * 528;
- fprintf(stderr, "address pointer in flash: 0x%08x\n",
- dev->address);
- break;
- default:
- /* Invalid data */
- abort();
- }
- dev->address_cycle++;
- break;
- default:
- abort();
- }
-}
-
-static uint8_t handle_read(tc58128_dev * dev)
-{
-#if 0
- if (dev->address % 0x100000 == 0)
- fprintf(stderr, "reading flash at address 0x%08x\n", dev->address);
-#endif
- return dev->flash_contents[dev->address++];
-}
-
-/* We never mark the device as busy, so interrupts cannot be triggered
- XXXXX */
-
-static int tc58128_cb(uint16_t porta, uint16_t portb,
- uint16_t * periph_pdtra, uint16_t * periph_portadir,
- uint16_t * periph_pdtrb, uint16_t * periph_portbdir)
-{
- int dev;
-
- if ((porta & CE1) == 0)
- dev = 0;
- else if ((porta & CE2) == 0)
- dev = 1;
- else
- return 0; /* No device selected */
-
- if ((porta & RE) && (porta & WE)) {
- /* Nothing to do, assert ready and return to input state */
- *periph_portadir &= 0xff00;
- *periph_portadir |= RDY(dev);
- *periph_pdtra |= RDY(dev);
- return 1;
- }
-
- if (porta & CLE) {
- /* Command */
- assert((porta & WE) == 0);
- handle_command(&tc58128_devs[dev], porta & 0x00ff);
- } else if (porta & ALE) {
- assert((porta & WE) == 0);
- handle_address(&tc58128_devs[dev], porta & 0x00ff);
- } else if ((porta & RE) == 0) {
- *periph_portadir |= 0x00ff;
- *periph_pdtra &= 0xff00;
- *periph_pdtra |= handle_read(&tc58128_devs[dev]);
- } else {
- abort();
- }
- return 1;
-}
-
-static sh7750_io_device tc58128 = {
- RE | WE, /* Port A triggers */
- 0, /* Port B triggers */
- tc58128_cb /* Callback */
-};
-
-int tc58128_init(struct SH7750State *s, const char *zone1, const char *zone2)
-{
- if (!qtest_enabled()) {
- warn_report_once("The TC58128 flash device is deprecated");
- }
- init_dev(&tc58128_devs[0], zone1);
- init_dev(&tc58128_devs[1], zone2);
- return sh7750_register_io_device(s, &tc58128);
-}
diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c
index fdbc30b..5b7f46b 100644
--- a/hw/block/vhost-user-blk.c
+++ b/hw/block/vhost-user-blk.c
@@ -51,6 +51,7 @@ static const int user_feature_bits[] = {
VIRTIO_F_RING_PACKED,
VIRTIO_F_IOMMU_PLATFORM,
VIRTIO_F_RING_RESET,
+ VIRTIO_F_IN_ORDER,
VIRTIO_F_NOTIFICATION_DATA,
VHOST_INVALID_FEATURE_BIT
};
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 73bdfd6..9166d79 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -700,7 +700,7 @@ static int virtio_blk_handle_zone_mgmt(VirtIOBlockReq *req, BlockZoneOp op)
} else {
if (bs->bl.zone_size > capacity - offset) {
/* The zoned device allows the last smaller zone. */
- len = capacity - bs->bl.zone_size * (bs->bl.nr_zones - 1);
+ len = capacity - bs->bl.zone_size * (bs->bl.nr_zones - 1ull);
} else {
len = bs->bl.zone_size;
}
@@ -1060,7 +1060,7 @@ static void virtio_blk_dma_restart_cb(void *opaque, bool running,
VirtIOBlock *s = opaque;
uint16_t num_queues = s->conf.num_queues;
g_autofree VirtIOBlockReq **vq_rq = NULL;
- VirtIOBlockReq *rq;
+ VirtIOBlockReq *rq = NULL;
if (!running) {
return;
diff --git a/hw/char/Kconfig b/hw/char/Kconfig
index 4fd74ea..4b73a80 100644
--- a/hw/char/Kconfig
+++ b/hw/char/Kconfig
@@ -21,6 +21,10 @@ config SERIAL_ISA
depends on ISA_BUS
select SERIAL
+config SERIAL_MM
+ bool
+ select SERIAL
+
config SERIAL_PCI
bool
default y if PCI_DEVICES
diff --git a/hw/char/avr_usart.c b/hw/char/avr_usart.c
index 5bcf9db..3aff01c 100644
--- a/hw/char/avr_usart.c
+++ b/hw/char/avr_usart.c
@@ -86,7 +86,7 @@ static void update_char_mask(AVRUsartState *usart)
usart->char_mask = 0b11111111;
break;
default:
- assert(0);
+ g_assert_not_reached();
}
}
@@ -300,7 +300,7 @@ static void avr_usart_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = avr_usart_reset;
+ device_class_set_legacy_reset(dc, avr_usart_reset);
device_class_set_props(dc, avr_usart_properties);
dc->realize = avr_usart_realize;
}
diff --git a/hw/char/bcm2835_aux.c b/hw/char/bcm2835_aux.c
index 83990e2..fca2f27 100644
--- a/hw/char/bcm2835_aux.c
+++ b/hw/char/bcm2835_aux.c
@@ -138,7 +138,7 @@ static uint64_t bcm2835_aux_read(void *opaque, hwaddr offset, unsigned size)
res = 0x30e; /* space in the output buffer, empty tx fifo, idle tx/rx */
if (s->read_count > 0) {
res |= 0x1; /* data in input buffer */
- assert(s->read_count < BCM2835_AUX_RX_FIFO_LEN);
+ assert(s->read_count <= BCM2835_AUX_RX_FIFO_LEN);
res |= ((uint32_t)s->read_count) << 16; /* rx fifo fill level */
}
return res;
diff --git a/hw/char/cmsdk-apb-uart.c b/hw/char/cmsdk-apb-uart.c
index d07cca1..467e40b 100644
--- a/hw/char/cmsdk-apb-uart.c
+++ b/hw/char/cmsdk-apb-uart.c
@@ -389,7 +389,7 @@ static void cmsdk_apb_uart_class_init(ObjectClass *klass, void *data)
dc->realize = cmsdk_apb_uart_realize;
dc->vmsd = &cmsdk_apb_uart_vmstate;
- dc->reset = cmsdk_apb_uart_reset;
+ device_class_set_legacy_reset(dc, cmsdk_apb_uart_reset);
device_class_set_props(dc, cmsdk_apb_uart_properties);
}
diff --git a/hw/char/digic-uart.c b/hw/char/digic-uart.c
index ef2d762..5b04abe 100644
--- a/hw/char/digic-uart.c
+++ b/hw/char/digic-uart.c
@@ -182,7 +182,7 @@ static void digic_uart_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = digic_uart_realize;
- dc->reset = digic_uart_reset;
+ device_class_set_legacy_reset(dc, digic_uart_reset);
dc->vmsd = &vmstate_digic_uart;
device_class_set_props(dc, digic_uart_properties);
}
diff --git a/hw/char/escc.c b/hw/char/escc.c
index d450d70..b1b1bbe 100644
--- a/hw/char/escc.c
+++ b/hw/char/escc.c
@@ -287,6 +287,7 @@ static void escc_reset_chn(ESCCChannelState *s)
s->rxint = s->txint = 0;
s->rxint_under_svc = s->txint_under_svc = 0;
s->e0_mode = s->led_mode = s->caps_lock_mode = s->num_lock_mode = 0;
+ s->sunmouse_dx = s->sunmouse_dy = s->sunmouse_buttons = 0;
clear_queue(s);
}
@@ -952,53 +953,96 @@ static void handle_kbd_command(ESCCChannelState *s, int val)
}
}
-static void sunmouse_event(void *opaque,
- int dx, int dy, int dz, int buttons_state)
+static void sunmouse_handle_event(DeviceState *dev, QemuConsole *src,
+ InputEvent *evt)
{
- ESCCChannelState *s = opaque;
- int ch;
+ ESCCChannelState *s = (ESCCChannelState *)dev;
+ InputMoveEvent *move;
+ InputBtnEvent *btn;
+ static const int bmap[INPUT_BUTTON__MAX] = {
+ [INPUT_BUTTON_LEFT] = 0x4,
+ [INPUT_BUTTON_MIDDLE] = 0x2,
+ [INPUT_BUTTON_RIGHT] = 0x1,
+ };
+
+ switch (evt->type) {
+ case INPUT_EVENT_KIND_REL:
+ move = evt->u.rel.data;
+ if (move->axis == INPUT_AXIS_X) {
+ s->sunmouse_dx += move->value;
+ } else if (move->axis == INPUT_AXIS_Y) {
+ s->sunmouse_dy -= move->value;
+ }
+ break;
- trace_escc_sunmouse_event(dx, dy, buttons_state);
- ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
+ case INPUT_EVENT_KIND_BTN:
+ btn = evt->u.btn.data;
+ if (bmap[btn->button]) {
+ if (btn->down) {
+ s->sunmouse_buttons |= bmap[btn->button];
+ } else {
+ s->sunmouse_buttons &= ~bmap[btn->button];
+ }
+ /* Indicate we have a supported button event */
+ s->sunmouse_buttons |= 0x80;
+ }
+ break;
- if (buttons_state & MOUSE_EVENT_LBUTTON) {
- ch ^= 0x4;
- }
- if (buttons_state & MOUSE_EVENT_MBUTTON) {
- ch ^= 0x2;
+ default:
+ /* keep gcc happy */
+ break;
}
- if (buttons_state & MOUSE_EVENT_RBUTTON) {
- ch ^= 0x1;
+}
+
+static void sunmouse_sync(DeviceState *dev)
+{
+ ESCCChannelState *s = (ESCCChannelState *)dev;
+ int ch;
+
+ if (s->sunmouse_dx == 0 && s->sunmouse_dy == 0 &&
+ (s->sunmouse_buttons & 0x80) == 0) {
+ /* Nothing to do after button event filter */
+ return;
}
+ /* Clear our button event flag */
+ s->sunmouse_buttons &= ~0x80;
+ trace_escc_sunmouse_event(s->sunmouse_dx, s->sunmouse_dy,
+ s->sunmouse_buttons);
+ ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
+ ch ^= s->sunmouse_buttons;
put_queue(s, ch);
- ch = dx;
-
+ ch = s->sunmouse_dx;
if (ch > 127) {
ch = 127;
} else if (ch < -127) {
ch = -127;
}
-
put_queue(s, ch & 0xff);
+ s->sunmouse_dx -= ch;
- ch = -dy;
-
+ ch = s->sunmouse_dy;
if (ch > 127) {
ch = 127;
} else if (ch < -127) {
ch = -127;
}
-
put_queue(s, ch & 0xff);
+ s->sunmouse_dy -= ch;
/* MSC protocol specifies two extra motion bytes */
-
put_queue(s, 0);
put_queue(s, 0);
}
+static const QemuInputHandler sunmouse_handler = {
+ .name = "QEMU Sun Mouse",
+ .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
+ .event = sunmouse_handle_event,
+ .sync = sunmouse_sync,
+};
+
static void escc_init1(Object *obj)
{
ESCCState *s = ESCC(obj);
@@ -1036,8 +1080,8 @@ static void escc_realize(DeviceState *dev, Error **errp)
}
if (s->chn[0].type == escc_mouse) {
- qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0,
- "QEMU Sun Mouse");
+ s->chn[0].hs = qemu_input_handler_register((DeviceState *)(&s->chn[0]),
+ &sunmouse_handler);
}
if (s->chn[1].type == escc_kbd) {
s->chn[1].hs = qemu_input_handler_register((DeviceState *)(&s->chn[1]),
@@ -1062,7 +1106,7 @@ static void escc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = escc_reset;
+ device_class_set_legacy_reset(dc, escc_reset);
dc->realize = escc_realize;
dc->vmsd = &vmstate_escc;
device_class_set_props(dc, escc_properties);
diff --git a/hw/char/etraxfs_ser.c b/hw/char/etraxfs_ser.c
deleted file mode 100644
index 8d6422d..0000000
--- a/hw/char/etraxfs_ser.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * QEMU ETRAX System Emulator
- *
- * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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/irq.h"
-#include "hw/qdev-properties.h"
-#include "hw/qdev-properties-system.h"
-#include "hw/sysbus.h"
-#include "chardev/char-fe.h"
-#include "qemu/log.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-#define D(x)
-
-#define RW_TR_CTRL (0x00 / 4)
-#define RW_TR_DMA_EN (0x04 / 4)
-#define RW_REC_CTRL (0x08 / 4)
-#define RW_DOUT (0x1c / 4)
-#define RS_STAT_DIN (0x20 / 4)
-#define R_STAT_DIN (0x24 / 4)
-#define RW_INTR_MASK (0x2c / 4)
-#define RW_ACK_INTR (0x30 / 4)
-#define R_INTR (0x34 / 4)
-#define R_MASKED_INTR (0x38 / 4)
-#define R_MAX (0x3c / 4)
-
-#define STAT_DAV 16
-#define STAT_TR_IDLE 22
-#define STAT_TR_RDY 24
-
-#define TYPE_ETRAX_FS_SERIAL "etraxfs-serial"
-typedef struct ETRAXSerial ETRAXSerial;
-DECLARE_INSTANCE_CHECKER(ETRAXSerial, ETRAX_SERIAL,
- TYPE_ETRAX_FS_SERIAL)
-
-struct ETRAXSerial {
- SysBusDevice parent_obj;
-
- MemoryRegion mmio;
- CharBackend chr;
- qemu_irq irq;
-
- int pending_tx;
-
- uint8_t rx_fifo[16];
- unsigned int rx_fifo_pos;
- unsigned int rx_fifo_len;
-
- /* Control registers. */
- uint32_t regs[R_MAX];
-};
-
-static void ser_update_irq(ETRAXSerial *s)
-{
-
- if (s->rx_fifo_len) {
- s->regs[R_INTR] |= 8;
- } else {
- s->regs[R_INTR] &= ~8;
- }
-
- s->regs[R_MASKED_INTR] = s->regs[R_INTR] & s->regs[RW_INTR_MASK];
- qemu_set_irq(s->irq, !!s->regs[R_MASKED_INTR]);
-}
-
-static uint64_t
-ser_read(void *opaque, hwaddr addr, unsigned int size)
-{
- ETRAXSerial *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr)
- {
- case R_STAT_DIN:
- r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
- if (s->rx_fifo_len) {
- r |= 1 << STAT_DAV;
- }
- r |= 1 << STAT_TR_RDY;
- r |= 1 << STAT_TR_IDLE;
- break;
- case RS_STAT_DIN:
- r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
- if (s->rx_fifo_len) {
- r |= 1 << STAT_DAV;
- s->rx_fifo_len--;
- }
- r |= 1 << STAT_TR_RDY;
- r |= 1 << STAT_TR_IDLE;
- break;
- default:
- r = s->regs[addr];
- D(qemu_log("%s " HWADDR_FMT_plx "=%x\n", __func__, addr, r));
- break;
- }
- return r;
-}
-
-static void
-ser_write(void *opaque, hwaddr addr,
- uint64_t val64, unsigned int size)
-{
- ETRAXSerial *s = opaque;
- uint32_t value = val64;
- unsigned char ch = val64;
-
- D(qemu_log("%s " HWADDR_FMT_plx "=%x\n", __func__, addr, value));
- addr >>= 2;
- switch (addr)
- {
- case RW_DOUT:
- /* XXX this blocks entire thread. Rewrite to use
- * qemu_chr_fe_write and background I/O callbacks */
- qemu_chr_fe_write_all(&s->chr, &ch, 1);
- s->regs[R_INTR] |= 3;
- s->pending_tx = 1;
- s->regs[addr] = value;
- break;
- case RW_ACK_INTR:
- if (s->pending_tx) {
- value &= ~1;
- s->pending_tx = 0;
- D(qemu_log("fixedup value=%x r_intr=%x\n",
- value, s->regs[R_INTR]));
- }
- s->regs[addr] = value;
- s->regs[R_INTR] &= ~value;
- D(printf("r_intr=%x\n", s->regs[R_INTR]));
- break;
- default:
- s->regs[addr] = value;
- break;
- }
- ser_update_irq(s);
-}
-
-static const MemoryRegionOps ser_ops = {
- .read = ser_read,
- .write = ser_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4
- }
-};
-
-static Property etraxfs_ser_properties[] = {
- DEFINE_PROP_CHR("chardev", ETRAXSerial, chr),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void serial_receive(void *opaque, const uint8_t *buf, int size)
-{
- ETRAXSerial *s = opaque;
- int i;
-
- /* Got a byte. */
- if (s->rx_fifo_len >= 16) {
- D(qemu_log("WARNING: UART dropped char.\n"));
- return;
- }
-
- for (i = 0; i < size; i++) {
- s->rx_fifo[s->rx_fifo_pos] = buf[i];
- s->rx_fifo_pos++;
- s->rx_fifo_pos &= 15;
- s->rx_fifo_len++;
- }
-
- ser_update_irq(s);
-}
-
-static int serial_can_receive(void *opaque)
-{
- ETRAXSerial *s = opaque;
-
- /* Is the receiver enabled? */
- if (!(s->regs[RW_REC_CTRL] & (1 << 3))) {
- return 0;
- }
-
- return sizeof(s->rx_fifo) - s->rx_fifo_len;
-}
-
-static void serial_event(void *opaque, QEMUChrEvent event)
-{
-
-}
-
-static void etraxfs_ser_reset(DeviceState *d)
-{
- ETRAXSerial *s = ETRAX_SERIAL(d);
-
- /* transmitter begins ready and idle. */
- s->regs[RS_STAT_DIN] |= (1 << STAT_TR_RDY);
- s->regs[RS_STAT_DIN] |= (1 << STAT_TR_IDLE);
-
- s->regs[RW_REC_CTRL] = 0x10000;
-
-}
-
-static void etraxfs_ser_init(Object *obj)
-{
- ETRAXSerial *s = ETRAX_SERIAL(obj);
- SysBusDevice *dev = SYS_BUS_DEVICE(obj);
-
- sysbus_init_irq(dev, &s->irq);
- memory_region_init_io(&s->mmio, obj, &ser_ops, s,
- "etraxfs-serial", R_MAX * 4);
- sysbus_init_mmio(dev, &s->mmio);
-}
-
-static void etraxfs_ser_realize(DeviceState *dev, Error **errp)
-{
- ETRAXSerial *s = ETRAX_SERIAL(dev);
-
- qemu_chr_fe_set_handlers(&s->chr,
- serial_can_receive, serial_receive,
- serial_event, NULL, s, NULL, true);
-}
-
-static void etraxfs_ser_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = etraxfs_ser_reset;
- device_class_set_props(dc, etraxfs_ser_properties);
- dc->realize = etraxfs_ser_realize;
-}
-
-static const TypeInfo etraxfs_ser_info = {
- .name = TYPE_ETRAX_FS_SERIAL,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(ETRAXSerial),
- .instance_init = etraxfs_ser_init,
- .class_init = etraxfs_ser_class_init,
-};
-
-static void etraxfs_serial_register_types(void)
-{
- type_register_static(&etraxfs_ser_info);
-}
-
-type_init(etraxfs_serial_register_types)
diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c
index 8cdd42e..d9e732f 100644
--- a/hw/char/exynos4210_uart.c
+++ b/hw/char/exynos4210_uart.c
@@ -717,7 +717,7 @@ static void exynos4210_uart_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = exynos4210_uart_realize;
- dc->reset = exynos4210_uart_reset;
+ device_class_set_legacy_reset(dc, exynos4210_uart_reset);
device_class_set_props(dc, exynos4210_uart_properties);
dc->vmsd = &vmstate_exynos4210_uart;
}
diff --git a/hw/char/goldfish_tty.c b/hw/char/goldfish_tty.c
index f8ff043..d1917b8 100644
--- a/hw/char/goldfish_tty.c
+++ b/hw/char/goldfish_tty.c
@@ -16,6 +16,7 @@
#include "qemu/log.h"
#include "trace.h"
#include "exec/address-spaces.h"
+#include "sysemu/dma.h"
#include "hw/char/goldfish_tty.h"
#define GOLDFISH_TTY_VERSION 1
@@ -69,7 +70,6 @@ static uint64_t goldfish_tty_read(void *opaque, hwaddr addr,
static void goldfish_tty_cmd(GoldfishTTYState *s, uint32_t cmd)
{
uint32_t to_copy;
- uint8_t *buf;
uint8_t data_out[GOLFISH_TTY_BUFFER_SIZE];
int len;
uint64_t ptr;
@@ -97,8 +97,8 @@ static void goldfish_tty_cmd(GoldfishTTYState *s, uint32_t cmd)
while (len) {
to_copy = MIN(GOLFISH_TTY_BUFFER_SIZE, len);
- address_space_rw(&address_space_memory, ptr,
- MEMTXATTRS_UNSPECIFIED, data_out, to_copy, 0);
+ dma_memory_read_relaxed(&address_space_memory, ptr,
+ data_out, to_copy);
qemu_chr_fe_write_all(&s->chr, data_out, to_copy);
len -= to_copy;
@@ -109,9 +109,9 @@ static void goldfish_tty_cmd(GoldfishTTYState *s, uint32_t cmd)
len = s->data_len;
ptr = s->data_ptr;
while (len && !fifo8_is_empty(&s->rx_fifo)) {
- buf = (uint8_t *)fifo8_pop_buf(&s->rx_fifo, len, &to_copy);
- address_space_rw(&address_space_memory, ptr,
- MEMTXATTRS_UNSPECIFIED, buf, to_copy, 1);
+ const uint8_t *buf = fifo8_pop_bufptr(&s->rx_fifo, len, &to_copy);
+
+ dma_memory_write_relaxed(&address_space_memory, ptr, buf, to_copy);
len -= to_copy;
ptr += to_copy;
@@ -262,7 +262,7 @@ static void goldfish_tty_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
device_class_set_props(dc, goldfish_tty_properties);
- dc->reset = goldfish_tty_reset;
+ device_class_set_legacy_reset(dc, goldfish_tty_reset);
dc->realize = goldfish_tty_realize;
dc->unrealize = goldfish_tty_unrealize;
dc->vmsd = &vmstate_goldfish_tty;
diff --git a/hw/char/grlib_apbuart.c b/hw/char/grlib_apbuart.c
index 515b65b..d0032b4 100644
--- a/hw/char/grlib_apbuart.c
+++ b/hw/char/grlib_apbuart.c
@@ -287,7 +287,7 @@ static void grlib_apbuart_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = grlib_apbuart_realize;
- dc->reset = grlib_apbuart_reset;
+ device_class_set_legacy_reset(dc, grlib_apbuart_reset);
device_class_set_props(dc, grlib_apbuart_properties);
}
diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
index 63aae6d..589177f 100644
--- a/hw/char/ibex_uart.c
+++ b/hw/char/ibex_uart.c
@@ -547,7 +547,7 @@ static void ibex_uart_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = ibex_uart_reset;
+ device_class_set_legacy_reset(dc, ibex_uart_reset);
dc->realize = ibex_uart_realize;
dc->vmsd = &vmstate_ibex_uart;
device_class_set_props(dc, ibex_uart_properties);
diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c
index ba37be6..22c9080 100644
--- a/hw/char/imx_serial.c
+++ b/hw/char/imx_serial.c
@@ -449,7 +449,7 @@ static void imx_serial_class_init(ObjectClass *klass, void *data)
dc->realize = imx_serial_realize;
dc->vmsd = &vmstate_imx_serial;
- dc->reset = imx_serial_reset_at_boot;
+ device_class_set_legacy_reset(dc, imx_serial_reset_at_boot);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
dc->desc = "i.MX series UART";
device_class_set_props(dc, imx_serial_properties);
diff --git a/hw/char/mcf_uart.c b/hw/char/mcf_uart.c
index f9cbc9b..ad15e28 100644
--- a/hw/char/mcf_uart.c
+++ b/hw/char/mcf_uart.c
@@ -322,7 +322,7 @@ static void mcf_uart_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = mcf_uart_realize;
- dc->reset = mcf_uart_reset;
+ device_class_set_legacy_reset(dc, mcf_uart_reset);
device_class_set_props(dc, mcf_uart_properties);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
diff --git a/hw/char/mchp_pfsoc_mmuart.c b/hw/char/mchp_pfsoc_mmuart.c
index e7908bb..3c3224c 100644
--- a/hw/char/mchp_pfsoc_mmuart.c
+++ b/hw/char/mchp_pfsoc_mmuart.c
@@ -126,7 +126,7 @@ static void mchp_pfsoc_mmuart_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = mchp_pfsoc_mmuart_realize;
- dc->reset = mchp_pfsoc_mmuart_reset;
+ device_class_set_legacy_reset(dc, mchp_pfsoc_mmuart_reset);
dc->vmsd = &mchp_pfsoc_mmuart_vmstate;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
}
diff --git a/hw/char/meson.build b/hw/char/meson.build
index e5b13b6..1750834 100644
--- a/hw/char/meson.build
+++ b/hw/char/meson.build
@@ -1,7 +1,6 @@
system_ss.add(when: 'CONFIG_CADENCE', if_true: files('cadence_uart.c'))
system_ss.add(when: 'CONFIG_CMSDK_APB_UART', if_true: files('cmsdk-apb-uart.c'))
system_ss.add(when: 'CONFIG_ESCC', if_true: files('escc.c'))
-system_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_ser.c'))
system_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_apbuart.c'))
system_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_uart.c'))
system_ss.add(when: 'CONFIG_IMX', if_true: files('imx_serial.c'))
@@ -14,6 +13,7 @@ system_ss.add(when: 'CONFIG_PL011', if_true: files('pl011.c'))
system_ss.add(when: 'CONFIG_SCLPCONSOLE', if_true: files('sclpconsole.c', 'sclpconsole-lm.c'))
system_ss.add(when: 'CONFIG_SERIAL', if_true: files('serial.c'))
system_ss.add(when: 'CONFIG_SERIAL_ISA', if_true: files('serial-isa.c'))
+system_ss.add(when: 'CONFIG_SERIAL_MM', if_true: files('serial-mm.c'))
system_ss.add(when: 'CONFIG_SERIAL_PCI', if_true: files('serial-pci.c'))
system_ss.add(when: 'CONFIG_SERIAL_PCI_MULTI', if_true: files('serial-pci-multi.c'))
system_ss.add(when: 'CONFIG_SHAKTI_UART', if_true: files('shakti_uart.c'))
diff --git a/hw/char/nrf51_uart.c b/hw/char/nrf51_uart.c
index c2cd6bb..04da3f8 100644
--- a/hw/char/nrf51_uart.c
+++ b/hw/char/nrf51_uart.c
@@ -313,7 +313,7 @@ static void nrf51_uart_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = nrf51_uart_reset;
+ device_class_set_legacy_reset(dc, nrf51_uart_reset);
dc->realize = nrf51_uart_realize;
device_class_set_props(dc, nrf51_uart_properties);
dc->vmsd = &nrf51_uart_vmstate;
diff --git a/hw/char/omap_uart.c b/hw/char/omap_uart.c
index c2ef4c1..07fb868 100644
--- a/hw/char/omap_uart.c
+++ b/hw/char/omap_uart.c
@@ -20,7 +20,7 @@
#include "qemu/osdep.h"
#include "chardev/char.h"
#include "hw/arm/omap.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "exec/address-spaces.h"
/* UARTs */
@@ -28,7 +28,6 @@ struct omap_uart_s {
MemoryRegion iomem;
hwaddr base;
SerialMM *serial; /* TODO */
- struct omap_target_agent_s *ta;
omap_clk fclk;
qemu_irq irq;
@@ -36,8 +35,6 @@ struct omap_uart_s {
uint8_t syscontrol;
uint8_t wkup;
uint8_t cfps;
- uint8_t mdr[2];
- uint8_t scr;
uint8_t clksel;
};
@@ -66,113 +63,3 @@ struct omap_uart_s *omap_uart_init(hwaddr base,
DEVICE_NATIVE_ENDIAN);
return s;
}
-
-static uint64_t omap_uart_read(void *opaque, hwaddr addr, unsigned size)
-{
- struct omap_uart_s *s = opaque;
-
- if (size == 4) {
- return omap_badwidth_read8(opaque, addr);
- }
-
- switch (addr) {
- case 0x20: /* MDR1 */
- return s->mdr[0];
- case 0x24: /* MDR2 */
- return s->mdr[1];
- case 0x40: /* SCR */
- return s->scr;
- case 0x44: /* SSR */
- return 0x0;
- case 0x48: /* EBLR (OMAP2) */
- return s->eblr;
- case 0x4C: /* OSC_12M_SEL (OMAP1) */
- return s->clksel;
- case 0x50: /* MVR */
- return 0x30;
- case 0x54: /* SYSC (OMAP2) */
- return s->syscontrol;
- case 0x58: /* SYSS (OMAP2) */
- return 1;
- case 0x5c: /* WER (OMAP2) */
- return s->wkup;
- case 0x60: /* CFPS (OMAP2) */
- return s->cfps;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_uart_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_uart_s *s = opaque;
-
- if (size == 4) {
- omap_badwidth_write8(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x20: /* MDR1 */
- s->mdr[0] = value & 0x7f;
- break;
- case 0x24: /* MDR2 */
- s->mdr[1] = value & 0xff;
- break;
- case 0x40: /* SCR */
- s->scr = value & 0xff;
- break;
- case 0x48: /* EBLR (OMAP2) */
- s->eblr = value & 0xff;
- break;
- case 0x4C: /* OSC_12M_SEL (OMAP1) */
- s->clksel = value & 1;
- break;
- case 0x44: /* SSR */
- case 0x50: /* MVR */
- case 0x58: /* SYSS (OMAP2) */
- OMAP_RO_REG(addr);
- break;
- case 0x54: /* SYSC (OMAP2) */
- s->syscontrol = value & 0x1d;
- if (value & 2) {
- omap_uart_reset(s);
- }
- break;
- case 0x5c: /* WER (OMAP2) */
- s->wkup = value & 0x7f;
- break;
- case 0x60: /* CFPS (OMAP2) */
- s->cfps = value & 0xff;
- break;
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_uart_ops = {
- .read = omap_uart_read,
- .write = omap_uart_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_uart_s *omap2_uart_init(MemoryRegion *sysmem,
- struct omap_target_agent_s *ta,
- qemu_irq irq, omap_clk fclk, omap_clk iclk,
- qemu_irq txdma, qemu_irq rxdma,
- const char *label, Chardev *chr)
-{
- hwaddr base = omap_l4_attach(ta, 0, NULL);
- struct omap_uart_s *s = omap_uart_init(base, irq,
- fclk, iclk, txdma, rxdma, label, chr);
-
- memory_region_init_io(&s->iomem, NULL, &omap_uart_ops, s, "omap.uart", 0x100);
-
- s->ta = ta;
-
- memory_region_add_subregion(sysmem, base + 0x20, &s->iomem);
-
- return s;
-}
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
index f8078aa..0fd1334 100644
--- a/hw/char/pl011.c
+++ b/hw/char/pl011.c
@@ -85,13 +85,15 @@ DeviceState *pl011_create(hwaddr addr, qemu_irq irq, Chardev *chr)
#define CR_OUT1 (1 << 12)
#define CR_RTS (1 << 11)
#define CR_DTR (1 << 10)
+#define CR_TXE (1 << 8)
#define CR_LBE (1 << 7)
+#define CR_UARTEN (1 << 0)
/* Integer Baud Rate Divider, UARTIBRD */
-#define IBRD_MASK 0x3f
+#define IBRD_MASK 0xffff
/* Fractional Baud Rate Divider, UARTFBRD */
-#define FBRD_MASK 0xffff
+#define FBRD_MASK 0x3f
static const unsigned char pl011_id_arm[8] =
{ 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
@@ -138,6 +140,11 @@ static void pl011_update(PL011State *s)
}
}
+static bool pl011_loopback_enabled(PL011State *s)
+{
+ return !!(s->cr & CR_LBE);
+}
+
static bool pl011_is_fifo_enabled(PL011State *s)
{
return (s->lcr & LCR_FEN) != 0;
@@ -149,41 +156,126 @@ static inline unsigned pl011_get_fifo_depth(PL011State *s)
return pl011_is_fifo_enabled(s) ? PL011_FIFO_DEPTH : 1;
}
-static inline void pl011_reset_fifo(PL011State *s)
+static inline void pl011_reset_rx_fifo(PL011State *s)
{
s->read_count = 0;
s->read_pos = 0;
/* Reset FIFO flags */
- s->flags &= ~(PL011_FLAG_RXFF | PL011_FLAG_TXFF);
- s->flags |= PL011_FLAG_RXFE | PL011_FLAG_TXFE;
+ s->flags &= ~PL011_FLAG_RXFF;
+ s->flags |= PL011_FLAG_RXFE;
+}
+
+static inline void pl011_reset_tx_fifo(PL011State *s)
+{
+ /* Reset FIFO flags */
+ s->flags &= ~PL011_FLAG_TXFF;
+ s->flags |= PL011_FLAG_TXFE;
+}
+
+static void pl011_fifo_rx_put(void *opaque, uint32_t value)
+{
+ PL011State *s = (PL011State *)opaque;
+ int slot;
+ unsigned pipe_depth;
+
+ pipe_depth = pl011_get_fifo_depth(s);
+ slot = (s->read_pos + s->read_count) & (pipe_depth - 1);
+ s->read_fifo[slot] = value;
+ s->read_count++;
+ s->flags &= ~PL011_FLAG_RXFE;
+ trace_pl011_fifo_rx_put(value, s->read_count);
+ if (s->read_count == pipe_depth) {
+ trace_pl011_fifo_rx_full();
+ s->flags |= PL011_FLAG_RXFF;
+ }
+ if (s->read_count == s->read_trigger) {
+ s->int_level |= INT_RX;
+ pl011_update(s);
+ }
+}
+
+static void pl011_loopback_tx(PL011State *s, uint32_t value)
+{
+ if (!pl011_loopback_enabled(s)) {
+ return;
+ }
+
+ /*
+ * Caveat:
+ *
+ * In real hardware, TX loopback happens at the serial-bit level
+ * and then reassembled by the RX logics back into bytes and placed
+ * into the RX fifo. That is, loopback happens after TX fifo.
+ *
+ * Because the real hardware TX fifo is time-drained at the frame
+ * rate governed by the configured serial format, some loopback
+ * bytes in TX fifo may still be able to get into the RX fifo
+ * that could be full at times while being drained at software
+ * pace.
+ *
+ * In such scenario, the RX draining pace is the major factor
+ * deciding which loopback bytes get into the RX fifo, unless
+ * hardware flow-control is enabled.
+ *
+ * For simplicity, the above described is not emulated.
+ */
+ pl011_fifo_rx_put(s, value);
+}
+
+static void pl011_write_txdata(PL011State *s, uint8_t data)
+{
+ if (!(s->cr & CR_UARTEN)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "PL011 data written to disabled UART\n");
+ }
+ if (!(s->cr & CR_TXE)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "PL011 data written to disabled TX UART\n");
+ }
+
+ /*
+ * XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks
+ */
+ qemu_chr_fe_write_all(&s->chr, &data, 1);
+ pl011_loopback_tx(s, data);
+ s->int_level |= INT_TX;
+ pl011_update(s);
+}
+
+static uint32_t pl011_read_rxdata(PL011State *s)
+{
+ uint32_t c;
+
+ s->flags &= ~PL011_FLAG_RXFF;
+ c = s->read_fifo[s->read_pos];
+ if (s->read_count > 0) {
+ s->read_count--;
+ s->read_pos = (s->read_pos + 1) & (pl011_get_fifo_depth(s) - 1);
+ }
+ if (s->read_count == 0) {
+ s->flags |= PL011_FLAG_RXFE;
+ }
+ if (s->read_count == s->read_trigger - 1) {
+ s->int_level &= ~INT_RX;
+ }
+ trace_pl011_read_fifo(s->read_count);
+ s->rsr = c >> 8;
+ pl011_update(s);
+ qemu_chr_fe_accept_input(&s->chr);
+ return c;
}
static uint64_t pl011_read(void *opaque, hwaddr offset,
unsigned size)
{
PL011State *s = (PL011State *)opaque;
- uint32_t c;
uint64_t r;
switch (offset >> 2) {
case 0: /* UARTDR */
- s->flags &= ~PL011_FLAG_RXFF;
- c = s->read_fifo[s->read_pos];
- if (s->read_count > 0) {
- s->read_count--;
- s->read_pos = (s->read_pos + 1) & (pl011_get_fifo_depth(s) - 1);
- }
- if (s->read_count == 0) {
- s->flags |= PL011_FLAG_RXFE;
- }
- if (s->read_count == s->read_trigger - 1)
- s->int_level &= ~ INT_RX;
- trace_pl011_read_fifo(s->read_count);
- s->rsr = c >> 8;
- pl011_update(s);
- qemu_chr_fe_accept_input(&s->chr);
- r = c;
+ r = pl011_read_rxdata(s);
break;
case 1: /* UARTRSR */
r = s->rsr;
@@ -268,11 +360,6 @@ static void pl011_trace_baudrate_change(const PL011State *s)
s->ibrd, s->fbrd);
}
-static bool pl011_loopback_enabled(PL011State *s)
-{
- return !!(s->cr & CR_LBE);
-}
-
static void pl011_loopback_mdmctrl(PL011State *s)
{
uint32_t cr, fr, il;
@@ -314,36 +401,6 @@ static void pl011_loopback_mdmctrl(PL011State *s)
pl011_update(s);
}
-static void pl011_put_fifo(void *opaque, uint32_t value);
-
-static void pl011_loopback_tx(PL011State *s, uint32_t value)
-{
- if (!pl011_loopback_enabled(s)) {
- return;
- }
-
- /*
- * Caveat:
- *
- * In real hardware, TX loopback happens at the serial-bit level
- * and then reassembled by the RX logics back into bytes and placed
- * into the RX fifo. That is, loopback happens after TX fifo.
- *
- * Because the real hardware TX fifo is time-drained at the frame
- * rate governed by the configured serial format, some loopback
- * bytes in TX fifo may still be able to get into the RX fifo
- * that could be full at times while being drained at software
- * pace.
- *
- * In such scenario, the RX draining pace is the major factor
- * deciding which loopback bytes get into the RX fifo, unless
- * hardware flow-control is enabled.
- *
- * For simplicity, the above described is not emulated.
- */
- pl011_put_fifo(s, value);
-}
-
static void pl011_loopback_break(PL011State *s, int brk_enable)
{
if (brk_enable) {
@@ -361,14 +418,8 @@ static void pl011_write(void *opaque, hwaddr offset,
switch (offset >> 2) {
case 0: /* UARTDR */
- /* ??? Check if transmitter is enabled. */
ch = value;
- /* 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);
- pl011_loopback_tx(s, ch);
- s->int_level |= INT_TX;
- pl011_update(s);
+ pl011_write_txdata(s, ch);
break;
case 1: /* UARTRSR/UARTECR */
s->rsr = 0;
@@ -390,7 +441,8 @@ static void pl011_write(void *opaque, hwaddr offset,
case 11: /* UARTLCR_H */
/* Reset the FIFO state on FIFO enable or disable */
if ((s->lcr ^ value) & LCR_FEN) {
- pl011_reset_fifo(s);
+ pl011_reset_rx_fifo(s);
+ pl011_reset_tx_fifo(s);
}
if ((s->lcr ^ value) & LCR_BRK) {
int break_enable = value & LCR_BRK;
@@ -440,28 +492,6 @@ static int pl011_can_receive(void *opaque)
return r;
}
-static void pl011_put_fifo(void *opaque, uint32_t value)
-{
- PL011State *s = (PL011State *)opaque;
- int slot;
- unsigned pipe_depth;
-
- pipe_depth = pl011_get_fifo_depth(s);
- slot = (s->read_pos + s->read_count) & (pipe_depth - 1);
- s->read_fifo[slot] = value;
- s->read_count++;
- s->flags &= ~PL011_FLAG_RXFE;
- trace_pl011_put_fifo(value, s->read_count);
- if (s->read_count == pipe_depth) {
- trace_pl011_put_fifo_full();
- s->flags |= PL011_FLAG_RXFF;
- }
- if (s->read_count == s->read_trigger) {
- s->int_level |= INT_RX;
- pl011_update(s);
- }
-}
-
static void pl011_receive(void *opaque, const uint8_t *buf, int size)
{
/*
@@ -473,13 +503,13 @@ static void pl011_receive(void *opaque, const uint8_t *buf, int size)
return;
}
- pl011_put_fifo(opaque, *buf);
+ pl011_fifo_rx_put(opaque, *buf);
}
static void pl011_event(void *opaque, QEMUChrEvent event)
{
if (event == CHR_EVENT_BREAK && !pl011_loopback_enabled(opaque)) {
- pl011_put_fifo(opaque, DR_BE);
+ pl011_fifo_rx_put(opaque, DR_BE);
}
}
@@ -549,7 +579,7 @@ static const VMStateDescription vmstate_pl011 = {
.minimum_version_id = 2,
.post_load = pl011_post_load,
.fields = (const VMStateField[]) {
- VMSTATE_UINT32(readbuff, PL011State),
+ VMSTATE_UNUSED(sizeof(uint32_t)),
VMSTATE_UINT32(flags, PL011State),
VMSTATE_UINT32(lcr, PL011State),
VMSTATE_UINT32(rsr, PL011State),
@@ -621,7 +651,8 @@ static void pl011_reset(DeviceState *dev)
s->ifl = 0x12;
s->cr = 0x300;
s->flags = 0;
- pl011_reset_fifo(s);
+ pl011_reset_rx_fifo(s);
+ pl011_reset_tx_fifo(s);
}
static void pl011_class_init(ObjectClass *oc, void *data)
@@ -629,7 +660,7 @@ static void pl011_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = pl011_realize;
- dc->reset = pl011_reset;
+ device_class_set_legacy_reset(dc, pl011_reset);
dc->vmsd = &vmstate_pl011;
device_class_set_props(dc, pl011_properties);
}
diff --git a/hw/char/renesas_sci.c b/hw/char/renesas_sci.c
index 5cb7335..7ce0408 100644
--- a/hw/char/renesas_sci.c
+++ b/hw/char/renesas_sci.c
@@ -331,7 +331,7 @@ static void rsci_class_init(ObjectClass *klass, void *data)
dc->realize = rsci_realize;
dc->vmsd = &vmstate_rsci;
- dc->reset = rsci_reset;
+ device_class_set_legacy_reset(dc, rsci_reset);
device_class_set_props(dc, rsci_properties);
}
diff --git a/hw/char/riscv_htif.c b/hw/char/riscv_htif.c
index 9bef60d..54fd55c 100644
--- a/hw/char/riscv_htif.c
+++ b/hw/char/riscv_htif.c
@@ -24,7 +24,6 @@
#include "qapi/error.h"
#include "qemu/log.h"
#include "hw/char/riscv_htif.h"
-#include "hw/char/serial.h"
#include "chardev/char.h"
#include "chardev/char-fe.h"
#include "qemu/timer.h"
diff --git a/hw/char/sclpconsole-lm.c b/hw/char/sclpconsole-lm.c
index 7719f43..4fe1c4d 100644
--- a/hw/char/sclpconsole-lm.c
+++ b/hw/char/sclpconsole-lm.c
@@ -346,7 +346,7 @@ static void console_class_init(ObjectClass *klass, void *data)
SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
device_class_set_props(dc, console_properties);
- dc->reset = console_reset;
+ device_class_set_legacy_reset(dc, console_reset);
dc->vmsd = &vmstate_sclplmconsole;
ec->init = console_init;
ec->get_send_mask = send_mask;
diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c
index 5d630b0..e6d49e8 100644
--- a/hw/char/sclpconsole.c
+++ b/hw/char/sclpconsole.c
@@ -262,7 +262,7 @@ static void console_class_init(ObjectClass *klass, void *data)
SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
device_class_set_props(dc, console_properties);
- dc->reset = console_reset;
+ device_class_set_legacy_reset(dc, console_reset);
dc->vmsd = &vmstate_sclpconsole;
ec->init = console_init;
ec->get_send_mask = send_mask;
diff --git a/hw/char/serial-isa.c b/hw/char/serial-isa.c
index 329b352..b562ec9 100644
--- a/hw/char/serial-isa.c
+++ b/hw/char/serial-isa.c
@@ -29,6 +29,7 @@
#include "sysemu/sysemu.h"
#include "hw/acpi/acpi_aml_interface.h"
#include "hw/char/serial.h"
+#include "hw/char/serial-isa.h"
#include "hw/isa/isa.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
diff --git a/hw/char/serial-mm.c b/hw/char/serial-mm.c
new file mode 100644
index 0000000..2f67776
--- /dev/null
+++ b/hw/char/serial-mm.c
@@ -0,0 +1,157 @@
+/*
+ * QEMU 16550A UART emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2008 Citrix Systems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/char/serial-mm.h"
+#include "exec/cpu-common.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "hw/qdev-properties.h"
+
+static uint64_t serial_mm_read(void *opaque, hwaddr addr, unsigned size)
+{
+ SerialMM *s = SERIAL_MM(opaque);
+ return serial_io_ops.read(&s->serial, addr >> s->regshift, 1);
+}
+
+static void serial_mm_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ SerialMM *s = SERIAL_MM(opaque);
+ value &= 255;
+ serial_io_ops.write(&s->serial, addr >> s->regshift, value, 1);
+}
+
+static const MemoryRegionOps serial_mm_ops[3] = {
+ [DEVICE_NATIVE_ENDIAN] = {
+ .read = serial_mm_read,
+ .write = serial_mm_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid.max_access_size = 8,
+ .impl.max_access_size = 8,
+ },
+ [DEVICE_LITTLE_ENDIAN] = {
+ .read = serial_mm_read,
+ .write = serial_mm_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid.max_access_size = 8,
+ .impl.max_access_size = 8,
+ },
+ [DEVICE_BIG_ENDIAN] = {
+ .read = serial_mm_read,
+ .write = serial_mm_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid.max_access_size = 8,
+ .impl.max_access_size = 8,
+ },
+};
+
+static void serial_mm_realize(DeviceState *dev, Error **errp)
+{
+ SerialMM *smm = SERIAL_MM(dev);
+ SerialState *s = &smm->serial;
+
+ if (!qdev_realize(DEVICE(s), NULL, errp)) {
+ return;
+ }
+
+ memory_region_init_io(&s->io, OBJECT(dev),
+ &serial_mm_ops[smm->endianness], smm, "serial",
+ 8 << smm->regshift);
+ sysbus_init_mmio(SYS_BUS_DEVICE(smm), &s->io);
+ sysbus_init_irq(SYS_BUS_DEVICE(smm), &smm->serial.irq);
+}
+
+static const VMStateDescription vmstate_serial_mm = {
+ .name = "serial",
+ .version_id = 3,
+ .minimum_version_id = 2,
+ .fields = (const VMStateField[]) {
+ VMSTATE_STRUCT(serial, SerialMM, 0, vmstate_serial, SerialState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+SerialMM *serial_mm_init(MemoryRegion *address_space,
+ hwaddr base, int regshift,
+ qemu_irq irq, int baudbase,
+ Chardev *chr, enum device_endian end)
+{
+ SerialMM *smm = SERIAL_MM(qdev_new(TYPE_SERIAL_MM));
+ MemoryRegion *mr;
+
+ qdev_prop_set_uint8(DEVICE(smm), "regshift", regshift);
+ qdev_prop_set_uint32(DEVICE(smm), "baudbase", baudbase);
+ qdev_prop_set_chr(DEVICE(smm), "chardev", chr);
+ qdev_set_legacy_instance_id(DEVICE(smm), base, 2);
+ qdev_prop_set_uint8(DEVICE(smm), "endianness", end);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(smm), &error_fatal);
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(smm), 0, irq);
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(smm), 0);
+ memory_region_add_subregion(address_space, base, mr);
+
+ return smm;
+}
+
+static void serial_mm_instance_init(Object *o)
+{
+ SerialMM *smm = SERIAL_MM(o);
+
+ object_initialize_child(o, "serial", &smm->serial, TYPE_SERIAL);
+
+ qdev_alias_all_properties(DEVICE(&smm->serial), o);
+}
+
+static Property serial_mm_properties[] = {
+ /*
+ * Set the spacing between adjacent memory-mapped UART registers.
+ * Each register will be at (1 << regshift) bytes after the previous one.
+ */
+ DEFINE_PROP_UINT8("regshift", SerialMM, regshift, 0),
+ DEFINE_PROP_UINT8("endianness", SerialMM, endianness, DEVICE_NATIVE_ENDIAN),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void serial_mm_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ device_class_set_props(dc, serial_mm_properties);
+ dc->realize = serial_mm_realize;
+ dc->vmsd = &vmstate_serial_mm;
+}
+
+static const TypeInfo types[] = {
+ {
+ .name = TYPE_SERIAL_MM,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .class_init = serial_mm_class_init,
+ .instance_init = serial_mm_instance_init,
+ .instance_size = sizeof(SerialMM),
+ },
+};
+
+DEFINE_TYPES(types)
diff --git a/hw/char/serial.c b/hw/char/serial.c
index d8b2db5..b50a8a1 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -951,13 +951,6 @@ static void serial_unrealize(DeviceState *dev)
qemu_unregister_reset(serial_reset, s);
}
-/* Change the main reference oscillator frequency. */
-void serial_set_frequency(SerialState *s, uint32_t frequency)
-{
- s->baudbase = frequency;
- serial_update_parameters(s);
-}
-
const MemoryRegionOps serial_io_ops = {
.read = serial_ioport_read,
.write = serial_ioport_write,
@@ -996,135 +989,9 @@ static const TypeInfo serial_info = {
.class_init = serial_class_init,
};
-/* Memory mapped interface */
-static uint64_t serial_mm_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- SerialMM *s = SERIAL_MM(opaque);
- return serial_ioport_read(&s->serial, addr >> s->regshift, 1);
-}
-
-static void serial_mm_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- SerialMM *s = SERIAL_MM(opaque);
- value &= 255;
- serial_ioport_write(&s->serial, addr >> s->regshift, value, 1);
-}
-
-static const MemoryRegionOps serial_mm_ops[3] = {
- [DEVICE_NATIVE_ENDIAN] = {
- .read = serial_mm_read,
- .write = serial_mm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid.max_access_size = 8,
- .impl.max_access_size = 8,
- },
- [DEVICE_LITTLE_ENDIAN] = {
- .read = serial_mm_read,
- .write = serial_mm_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid.max_access_size = 8,
- .impl.max_access_size = 8,
- },
- [DEVICE_BIG_ENDIAN] = {
- .read = serial_mm_read,
- .write = serial_mm_write,
- .endianness = DEVICE_BIG_ENDIAN,
- .valid.max_access_size = 8,
- .impl.max_access_size = 8,
- },
-};
-
-static void serial_mm_realize(DeviceState *dev, Error **errp)
-{
- SerialMM *smm = SERIAL_MM(dev);
- SerialState *s = &smm->serial;
-
- if (!qdev_realize(DEVICE(s), NULL, errp)) {
- return;
- }
-
- memory_region_init_io(&s->io, OBJECT(dev),
- &serial_mm_ops[smm->endianness], smm, "serial",
- 8 << smm->regshift);
- sysbus_init_mmio(SYS_BUS_DEVICE(smm), &s->io);
- sysbus_init_irq(SYS_BUS_DEVICE(smm), &smm->serial.irq);
-}
-
-static const VMStateDescription vmstate_serial_mm = {
- .name = "serial",
- .version_id = 3,
- .minimum_version_id = 2,
- .fields = (const VMStateField[]) {
- VMSTATE_STRUCT(serial, SerialMM, 0, vmstate_serial, SerialState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-SerialMM *serial_mm_init(MemoryRegion *address_space,
- hwaddr base, int regshift,
- qemu_irq irq, int baudbase,
- Chardev *chr, enum device_endian end)
-{
- SerialMM *smm = SERIAL_MM(qdev_new(TYPE_SERIAL_MM));
- MemoryRegion *mr;
-
- qdev_prop_set_uint8(DEVICE(smm), "regshift", regshift);
- qdev_prop_set_uint32(DEVICE(smm), "baudbase", baudbase);
- qdev_prop_set_chr(DEVICE(smm), "chardev", chr);
- qdev_set_legacy_instance_id(DEVICE(smm), base, 2);
- qdev_prop_set_uint8(DEVICE(smm), "endianness", end);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(smm), &error_fatal);
-
- sysbus_connect_irq(SYS_BUS_DEVICE(smm), 0, irq);
- mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(smm), 0);
- memory_region_add_subregion(address_space, base, mr);
-
- return smm;
-}
-
-static void serial_mm_instance_init(Object *o)
-{
- SerialMM *smm = SERIAL_MM(o);
-
- object_initialize_child(o, "serial", &smm->serial, TYPE_SERIAL);
-
- qdev_alias_all_properties(DEVICE(&smm->serial), o);
-}
-
-static Property serial_mm_properties[] = {
- /*
- * Set the spacing between adjacent memory-mapped UART registers.
- * Each register will be at (1 << regshift) bytes after the
- * previous one.
- */
- DEFINE_PROP_UINT8("regshift", SerialMM, regshift, 0),
- DEFINE_PROP_UINT8("endianness", SerialMM, endianness, DEVICE_NATIVE_ENDIAN),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void serial_mm_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- device_class_set_props(dc, serial_mm_properties);
- dc->realize = serial_mm_realize;
- dc->vmsd = &vmstate_serial_mm;
-}
-
-static const TypeInfo serial_mm_info = {
- .name = TYPE_SERIAL_MM,
- .parent = TYPE_SYS_BUS_DEVICE,
- .class_init = serial_mm_class_init,
- .instance_init = serial_mm_instance_init,
- .instance_size = sizeof(SerialMM),
-};
-
static void serial_register_types(void)
{
type_register_static(&serial_info);
- type_register_static(&serial_mm_info);
}
type_init(serial_register_types)
diff --git a/hw/char/sh_serial.c b/hw/char/sh_serial.c
index 355886e..429b256 100644
--- a/hw/char/sh_serial.c
+++ b/hw/char/sh_serial.c
@@ -459,7 +459,7 @@ static void sh_serial_class_init(ObjectClass *oc, void *data)
device_class_set_props(dc, sh_serial_properties);
dc->realize = sh_serial_realize;
- dc->reset = sh_serial_reset;
+ device_class_set_legacy_reset(dc, sh_serial_reset);
/* Reason: part of SuperH CPU/SoC, needs to be wired up */
dc->user_creatable = false;
}
diff --git a/hw/char/shakti_uart.c b/hw/char/shakti_uart.c
index 98b142c..4a71953 100644
--- a/hw/char/shakti_uart.c
+++ b/hw/char/shakti_uart.c
@@ -165,7 +165,7 @@ static Property shakti_uart_properties[] = {
static void shakti_uart_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = shakti_uart_reset;
+ device_class_set_legacy_reset(dc, shakti_uart_reset);
dc->realize = shakti_uart_realize;
device_class_set_props(dc, shakti_uart_properties);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c
index 8753afe..17b5b1f 100644
--- a/hw/char/stm32f2xx_usart.c
+++ b/hw/char/stm32f2xx_usart.c
@@ -228,7 +228,7 @@ static void stm32f2xx_usart_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = stm32f2xx_usart_reset;
+ device_class_set_legacy_reset(dc, stm32f2xx_usart_reset);
device_class_set_props(dc, stm32f2xx_usart_properties);
dc->realize = stm32f2xx_usart_realize;
}
diff --git a/hw/char/stm32l4x5_usart.c b/hw/char/stm32l4x5_usart.c
index fc5dcac..3cf200c 100644
--- a/hw/char/stm32l4x5_usart.c
+++ b/hw/char/stm32l4x5_usart.c
@@ -154,6 +154,21 @@ REG32(RDR, 0x24)
REG32(TDR, 0x28)
FIELD(TDR, TDR, 0, 9)
+static void stm32l4x5_update_isr(Stm32l4x5UsartBaseState *s)
+{
+ if (s->cr1 & R_CR1_TE_MASK) {
+ s->isr |= R_ISR_TEACK_MASK;
+ } else {
+ s->isr &= ~R_ISR_TEACK_MASK;
+ }
+
+ if (s->cr1 & R_CR1_RE_MASK) {
+ s->isr |= R_ISR_REACK_MASK;
+ } else {
+ s->isr &= ~R_ISR_REACK_MASK;
+ }
+}
+
static void stm32l4x5_update_irq(Stm32l4x5UsartBaseState *s)
{
if (((s->isr & R_ISR_WUF_MASK) && (s->cr3 & R_CR3_WUFIE_MASK)) ||
@@ -456,6 +471,7 @@ static void stm32l4x5_usart_base_write(void *opaque, hwaddr addr,
case A_CR1:
s->cr1 = value;
stm32l4x5_update_params(s);
+ stm32l4x5_update_isr(s);
stm32l4x5_update_irq(s);
return;
case A_CR2:
diff --git a/hw/char/trace-events b/hw/char/trace-events
index 8875758..59e1f73 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -58,8 +58,8 @@ pl011_read(uint32_t addr, uint32_t value, const char *regname) "addr 0x%03x valu
pl011_read_fifo(int read_count) "FIFO read, read_count now %d"
pl011_write(uint32_t addr, uint32_t value, const char *regname) "addr 0x%03x value 0x%08x reg %s"
pl011_can_receive(uint32_t lcr, int read_count, int r) "LCR 0x%08x read_count %d returning %d"
-pl011_put_fifo(uint32_t c, int read_count) "new char 0x%x read_count now %d"
-pl011_put_fifo_full(void) "FIFO now full, RXFF set"
+pl011_fifo_rx_put(uint32_t c, int read_count) "new char 0x%02x read_count now %d"
+pl011_fifo_rx_full(void) "RX FIFO now full, RXFF set"
pl011_baudrate_change(unsigned int baudrate, uint64_t clock, uint32_t ibrd, uint32_t fbrd) "new baudrate %u (clk: %" PRIu64 "hz, ibrd: %" PRIu32 ", fbrd: %" PRIu32 ")"
# cmsdk-apb-uart.c
diff --git a/hw/char/xilinx_uartlite.c b/hw/char/xilinx_uartlite.c
index 180bb97..f325084 100644
--- a/hw/char/xilinx_uartlite.c
+++ b/hw/char/xilinx_uartlite.c
@@ -234,7 +234,7 @@ static void xilinx_uartlite_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = xilinx_uartlite_reset;
+ device_class_set_legacy_reset(dc, xilinx_uartlite_reset);
dc->realize = xilinx_uartlite_realize;
device_class_set_props(dc, xilinx_uartlite_properties);
}
diff --git a/hw/core/clock.c b/hw/core/clock.c
index e212865..cbe7b1b 100644
--- a/hw/core/clock.c
+++ b/hw/core/clock.c
@@ -13,6 +13,8 @@
#include "qemu/osdep.h"
#include "qemu/cutils.h"
+#include "qapi/visitor.h"
+#include "sysemu/qtest.h"
#include "hw/clock.h"
#include "trace.h"
@@ -158,6 +160,15 @@ bool clock_set_mul_div(Clock *clk, uint32_t multiplier, uint32_t divider)
return true;
}
+static void clock_period_prop_get(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ Clock *clk = CLOCK(obj);
+ uint64_t period = clock_get(clk);
+ visit_type_uint64(v, name, &period, errp);
+}
+
+
static void clock_initfn(Object *obj)
{
Clock *clk = CLOCK(obj);
@@ -166,6 +177,11 @@ static void clock_initfn(Object *obj)
clk->divider = 1;
QLIST_INIT(&clk->children);
+
+ if (qtest_enabled()) {
+ object_property_add(obj, "qtest-clock-period", "uint64",
+ clock_period_prop_get, NULL, NULL, NULL);
+ }
}
static void clock_finalizefn(Object *obj)
diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c
index d2e3e45..09c7903 100644
--- a/hw/core/cpu-common.c
+++ b/hw/core/cpu-common.c
@@ -24,6 +24,7 @@
#include "sysemu/hw_accel.h"
#include "qemu/log.h"
#include "qemu/main-loop.h"
+#include "qemu/lockcnt.h"
#include "exec/log.h"
#include "exec/gdbstub.h"
#include "sysemu/tcg.h"
@@ -282,7 +283,10 @@ static void cpu_common_finalize(Object *obj)
}
#endif
free_queued_cpu_work(cpu);
- g_array_free(cpu->gdb_regs, TRUE);
+ /* If cleanup didn't happen in context to gdb_unregister_coprocessor_all */
+ if (cpu->gdb_regs) {
+ g_array_free(cpu->gdb_regs, TRUE);
+ }
qemu_lockcnt_destroy(&cpu->in_ioctl_lock);
qemu_mutex_destroy(&cpu->work_mutex);
qemu_cond_destroy(cpu->halt_cond);
diff --git a/hw/core/irq.c b/hw/core/irq.c
index 3f14e2d..7d5b003 100644
--- a/hw/core/irq.c
+++ b/hw/core/irq.c
@@ -26,16 +26,6 @@
#include "hw/irq.h"
#include "qom/object.h"
-OBJECT_DECLARE_SIMPLE_TYPE(IRQState, IRQ)
-
-struct IRQState {
- Object parent_obj;
-
- qemu_irq_handler handler;
- void *opaque;
- int n;
-};
-
void qemu_set_irq(qemu_irq irq, int level)
{
if (!irq)
@@ -44,6 +34,21 @@ void qemu_set_irq(qemu_irq irq, int level)
irq->handler(irq->opaque, irq->n, level);
}
+static void init_irq_fields(IRQState *irq, qemu_irq_handler handler,
+ void *opaque, int n)
+{
+ irq->handler = handler;
+ irq->opaque = opaque;
+ irq->n = n;
+}
+
+void qemu_init_irq(IRQState *irq, qemu_irq_handler handler, void *opaque,
+ int n)
+{
+ object_initialize(irq, sizeof(*irq), TYPE_IRQ);
+ init_irq_fields(irq, handler, opaque, n);
+}
+
qemu_irq *qemu_extend_irqs(qemu_irq *old, int n_old, qemu_irq_handler handler,
void *opaque, int n)
{
@@ -67,13 +72,8 @@ qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n)
qemu_irq qemu_allocate_irq(qemu_irq_handler handler, void *opaque, int n)
{
- IRQState *irq;
-
- irq = IRQ(object_new(TYPE_IRQ));
- irq->handler = handler;
- irq->opaque = opaque;
- irq->n = n;
-
+ IRQState *irq = IRQ(object_new(TYPE_IRQ));
+ init_irq_fields(irq, handler, opaque, n);
return irq;
}
diff --git a/hw/core/machine.c b/hw/core/machine.c
index bc38cad..adaba17 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -34,9 +34,13 @@
#include "hw/virtio/virtio-iommu.h"
#include "audio/audio.h"
+GlobalProperty hw_compat_9_1[] = {};
+const size_t hw_compat_9_1_len = G_N_ELEMENTS(hw_compat_9_1);
+
GlobalProperty hw_compat_9_0[] = {
{"arm-cpu", "backcompat-cntfrq", "true" },
- {"scsi-disk-base", "migrate-emulated-scsi-request", "false" },
+ { "scsi-hd", "migrate-emulated-scsi-request", "false" },
+ { "scsi-cd", "migrate-emulated-scsi-request", "false" },
{"vfio-pci", "skip-vsc-check", "false" },
{ "virtio-pci", "x-pcie-pm-no-soft-reset", "off" },
{"sd-card", "spec_version", "2" },
@@ -1004,6 +1008,12 @@ static void machine_class_init(ObjectClass *oc, void *data)
/* Default 128 MB as guest ram size */
mc->default_ram_size = 128 * MiB;
mc->rom_file_has_mr = true;
+ /*
+ * SMBIOS 3.1.0 7.18.5 Memory Device ā€” Extended Size
+ * use max possible value that could be encoded into
+ * 'Extended Size' field (2047Tb).
+ */
+ mc->smbios_memory_device_size = 2047 * TiB;
/* numa node memory size aligned on 8MB by default.
* On Linux, each node's border has to be 8MB aligned
diff --git a/hw/core/numa.c b/hw/core/numa.c
index f8ce332..1b5f44b 100644
--- a/hw/core/numa.c
+++ b/hw/core/numa.c
@@ -249,7 +249,7 @@ void parse_numa_hmat_lb(NumaState *numa_state, NumaHmatLBOptions *node,
lb_data.initiator = node->initiator;
lb_data.target = node->target;
- if (node->data_type <= HMATLB_DATA_TYPE_WRITE_LATENCY) {
+ if (node->data_type <= HMAT_LB_DATA_TYPE_WRITE_LATENCY) {
/* Input latency data */
if (!node->has_latency) {
@@ -313,7 +313,7 @@ void parse_numa_hmat_lb(NumaState *numa_state, NumaHmatLBOptions *node,
numa_info[node->target].lb_info_provided |= BIT(0);
}
lb_data.data = node->latency;
- } else if (node->data_type >= HMATLB_DATA_TYPE_ACCESS_BANDWIDTH) {
+ } else if (node->data_type >= HMAT_LB_DATA_TYPE_ACCESS_BANDWIDTH) {
/* Input bandwidth data */
if (!node->has_bandwidth) {
error_setg(errp, "Missing 'bandwidth' option");
@@ -380,7 +380,7 @@ void parse_numa_hmat_lb(NumaState *numa_state, NumaHmatLBOptions *node,
}
lb_data.data = node->bandwidth;
} else {
- assert(0);
+ g_assert_not_reached();
}
g_array_append_val(hmat_lb->list, lb_data);
diff --git a/hw/core/or-irq.c b/hw/core/or-irq.c
index 13907df..b25468e 100644
--- a/hw/core/or-irq.c
+++ b/hw/core/or-irq.c
@@ -124,7 +124,7 @@ static void or_irq_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = or_irq_reset;
+ device_class_set_legacy_reset(dc, or_irq_reset);
device_class_set_props(dc, or_irq_properties);
dc->realize = or_irq_realize;
dc->vmsd = &vmstate_or_irq;
diff --git a/hw/core/platform-bus.c b/hw/core/platform-bus.c
index b8487b2..dc58bf5 100644
--- a/hw/core/platform-bus.c
+++ b/hw/core/platform-bus.c
@@ -145,9 +145,12 @@ static void platform_bus_map_mmio(PlatformBusDevice *pbus, SysBusDevice *sbdev,
* the target device's memory region
*/
for (off = 0; off < pbus->mmio_size; off += alignment) {
- if (!memory_region_find(&pbus->mmio, off, size).mr) {
+ MemoryRegion *mr = memory_region_find(&pbus->mmio, off, size).mr;
+ if (!mr) {
found_region = true;
break;
+ } else {
+ memory_region_unref(mr);
}
}
diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c
index b151759..1d8964d 100644
--- a/hw/core/ptimer.c
+++ b/hw/core/ptimer.c
@@ -83,7 +83,7 @@ static void ptimer_reload(ptimer_state *s, int delta_adjust)
delta = s->delta = s->limit;
}
- if (s->period == 0) {
+ if (s->period == 0 && s->period_frac == 0) {
if (!qtest_enabled()) {
fprintf(stderr, "Timer with period zero, disabling\n");
}
@@ -309,7 +309,7 @@ void ptimer_run(ptimer_state *s, int oneshot)
assert(s->in_transaction);
- if (was_disabled && s->period == 0) {
+ if (was_disabled && s->period == 0 && s->period_frac == 0) {
if (!qtest_enabled()) {
fprintf(stderr, "Timer with period zero, disabling\n");
}
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index f13350b..35deef0 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -588,18 +588,14 @@ const PropertyInfo qdev_prop_losttickpolicy = {
static void set_blocksize(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
uint32_t *ptr = object_field_prop_ptr(obj, prop);
uint64_t value;
- Error *local_err = NULL;
if (!visit_type_size(v, name, &value, errp)) {
return;
}
- check_block_size(dev->id ? : "", name, value, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ if (!check_block_size(name, value, errp)) {
return;
}
*ptr = value;
@@ -659,7 +655,7 @@ const PropertyInfo qdev_prop_fdc_drive_type = {
const PropertyInfo qdev_prop_multifd_compression = {
.name = "MultiFDCompression",
.description = "multifd_compression values, "
- "none/zlib/zstd/qpl/uadk",
+ "none/zlib/zstd/qpl/uadk/qatzip",
.enum_table = &MultiFDCompression_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
@@ -1188,12 +1184,12 @@ const PropertyInfo qdev_prop_uuid = {
/* --- s390 cpu entitlement policy --- */
-QEMU_BUILD_BUG_ON(sizeof(CpuS390Entitlement) != sizeof(int));
+QEMU_BUILD_BUG_ON(sizeof(S390CpuEntitlement) != sizeof(int));
const PropertyInfo qdev_prop_cpus390entitlement = {
- .name = "CpuS390Entitlement",
+ .name = "S390CpuEntitlement",
.description = "low/medium (default)/high",
- .enum_table = &CpuS390Entitlement_lookup,
+ .enum_table = &S390CpuEntitlement_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
.set_default_value = qdev_propinfo_set_default_value_enum,
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index f3a996f..db36f54 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -747,57 +747,6 @@ device_vmstate_if_get_id(VMStateIf *obj)
return qdev_get_dev_path(dev);
}
-/**
- * device_phases_reset:
- * Transition reset method for devices to allow moving
- * smoothly from legacy reset method to multi-phases
- */
-static void device_phases_reset(DeviceState *dev)
-{
- ResettableClass *rc = RESETTABLE_GET_CLASS(dev);
-
- if (rc->phases.enter) {
- rc->phases.enter(OBJECT(dev), RESET_TYPE_COLD);
- }
- if (rc->phases.hold) {
- rc->phases.hold(OBJECT(dev), RESET_TYPE_COLD);
- }
- if (rc->phases.exit) {
- rc->phases.exit(OBJECT(dev), RESET_TYPE_COLD);
- }
-}
-
-static void device_transitional_reset(Object *obj)
-{
- DeviceClass *dc = DEVICE_GET_CLASS(obj);
-
- /*
- * This will call either @device_phases_reset (for multi-phases transitioned
- * devices) or a device's specific method for not-yet transitioned devices.
- * In both case, it does not reset children.
- */
- if (dc->reset) {
- dc->reset(DEVICE(obj));
- }
-}
-
-/**
- * device_get_transitional_reset:
- * check if the device's class is ready for multi-phase
- */
-static ResettableTrFunction device_get_transitional_reset(Object *obj)
-{
- DeviceClass *dc = DEVICE_GET_CLASS(obj);
- if (dc->reset != device_phases_reset) {
- /*
- * dc->reset has been overridden by a subclass,
- * the device is not ready for multi phase yet.
- */
- return device_transitional_reset;
- }
- return NULL;
-}
-
static void device_class_init(ObjectClass *class, void *data)
{
DeviceClass *dc = DEVICE_CLASS(class);
@@ -819,20 +768,12 @@ static void device_class_init(ObjectClass *class, void *data)
rc->child_foreach = device_reset_child_foreach;
/*
- * @device_phases_reset is put as the default reset method below, allowing
- * to do the multi-phase transition from base classes to leaf classes. It
- * allows a legacy-reset Device class to extend a multi-phases-reset
- * Device class for the following reason:
- * + If a base class B has been moved to multi-phase, then it does not
- * override this default reset method and may have defined phase methods.
- * + A child class C (extending class B) which uses
- * device_class_set_parent_reset() (or similar means) to override the
- * reset method will still work as expected. @device_phases_reset function
- * will be registered as the parent reset method and effectively call
- * parent reset phases.
+ * A NULL legacy_reset implies a three-phase reset device. Devices can
+ * only be reset using three-phase aware mechanisms, but we still support
+ * for transitional purposes leaf classes which set the old legacy_reset
+ * method via device_class_set_legacy_reset().
*/
- dc->reset = device_phases_reset;
- rc->get_transitional_function = device_get_transitional_reset;
+ dc->legacy_reset = NULL;
object_class_property_add_bool(class, "realized",
device_get_realized, device_set_realized);
@@ -844,12 +785,30 @@ static void device_class_init(ObjectClass *class, void *data)
offsetof(DeviceState, parent_bus), NULL, 0);
}
-void device_class_set_parent_reset(DeviceClass *dc,
- DeviceReset dev_reset,
- DeviceReset *parent_reset)
+static void do_legacy_reset(Object *obj, ResetType type)
{
- *parent_reset = dc->reset;
- dc->reset = dev_reset;
+ DeviceClass *dc = DEVICE_GET_CLASS(obj);
+
+ dc->legacy_reset(DEVICE(obj));
+}
+
+void device_class_set_legacy_reset(DeviceClass *dc, DeviceReset dev_reset)
+{
+ /*
+ * A legacy DeviceClass::reset has identical semantics to the
+ * three-phase "hold" method, with no "enter" or "exit"
+ * behaviour. Classes that use this legacy function must be leaf
+ * classes that do not chain up to their parent class reset.
+ * There is no mechanism for resetting a device that does not
+ * use the three-phase APIs, so the only place which calls
+ * the legacy_reset hook is do_legacy_reset().
+ */
+ ResettableClass *rc = RESETTABLE_CLASS(dc);
+
+ rc->phases.enter = NULL;
+ rc->phases.hold = do_legacy_reset;
+ rc->phases.exit = NULL;
+ dc->legacy_reset = dev_reset;
}
void device_class_set_parent_realize(DeviceClass *dc,
diff --git a/hw/core/reset.c b/hw/core/reset.c
index 58dfc8d..14a2639 100644
--- a/hw/core/reset.c
+++ b/hw/core/reset.c
@@ -170,11 +170,8 @@ void qemu_unregister_resettable(Object *obj)
resettable_container_remove(get_root_reset_container(), obj);
}
-void qemu_devices_reset(ShutdownCause reason)
+void qemu_devices_reset(ResetType type)
{
- ResetType type = (reason == SHUTDOWN_CAUSE_SNAPSHOT_LOAD) ?
- RESET_TYPE_SNAPSHOT_LOAD : RESET_TYPE_COLD;
-
/* Reset the simulation */
resettable_reset(OBJECT(get_root_reset_container()), type);
}
diff --git a/hw/core/resettable.c b/hw/core/resettable.c
index 6dd3e3d..5cdb4a4 100644
--- a/hw/core/resettable.c
+++ b/hw/core/resettable.c
@@ -93,20 +93,6 @@ static void resettable_child_foreach(ResettableClass *rc, Object *obj,
}
}
-/**
- * resettable_get_tr_func:
- * helper to fetch transitional reset callback if any.
- */
-static ResettableTrFunction resettable_get_tr_func(ResettableClass *rc,
- Object *obj)
-{
- ResettableTrFunction tr_func = NULL;
- if (rc->get_transitional_function) {
- tr_func = rc->get_transitional_function(obj);
- }
- return tr_func;
-}
-
static void resettable_phase_enter(Object *obj, void *opaque, ResetType type)
{
ResettableClass *rc = RESETTABLE_GET_CLASS(obj);
@@ -146,7 +132,7 @@ static void resettable_phase_enter(Object *obj, void *opaque, ResetType type)
if (action_needed) {
trace_resettable_phase_enter_exec(obj, obj_typename, type,
!!rc->phases.enter);
- if (rc->phases.enter && !resettable_get_tr_func(rc, obj)) {
+ if (rc->phases.enter) {
rc->phases.enter(obj, type);
}
s->hold_phase_pending = true;
@@ -171,12 +157,8 @@ static void resettable_phase_hold(Object *obj, void *opaque, ResetType type)
/* exec hold phase */
if (s->hold_phase_pending) {
s->hold_phase_pending = false;
- ResettableTrFunction tr_func = resettable_get_tr_func(rc, obj);
trace_resettable_phase_hold_exec(obj, obj_typename, !!rc->phases.hold);
- if (tr_func) {
- trace_resettable_transitional_function(obj, obj_typename);
- tr_func(obj);
- } else if (rc->phases.hold) {
+ if (rc->phases.hold) {
rc->phases.hold(obj, type);
}
}
@@ -199,7 +181,7 @@ static void resettable_phase_exit(Object *obj, void *opaque, ResetType type)
assert(s->count > 0);
if (--s->count == 0) {
trace_resettable_phase_exit_exec(obj, obj_typename, !!rc->phases.exit);
- if (rc->phases.exit && !resettable_get_tr_func(rc, obj)) {
+ if (rc->phases.exit) {
rc->phases.exit(obj, type);
}
}
diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c
index ad34fb7..e64d99c 100644
--- a/hw/core/sysbus.c
+++ b/hw/core/sysbus.c
@@ -154,16 +154,6 @@ static void sysbus_mmio_map_common(SysBusDevice *dev, int n, hwaddr addr,
}
}
-void sysbus_mmio_unmap(SysBusDevice *dev, int n)
-{
- assert(n >= 0 && n < dev->num_mmio);
-
- if (dev->mmio[n].addr != (hwaddr)-1) {
- memory_region_del_subregion(get_system_memory(), dev->mmio[n].memory);
- dev->mmio[n].addr = (hwaddr)-1;
- }
-}
-
void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr)
{
sysbus_mmio_map_common(dev, n, addr, false, 0);
diff --git a/hw/core/uboot_image.h b/hw/core/uboot_image.h
index 18ac293..e4dcfb0 100644
--- a/hw/core/uboot_image.h
+++ b/hw/core/uboot_image.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* (C) Copyright 2008 Semihalf
*
diff --git a/hw/cris/Kconfig b/hw/cris/Kconfig
deleted file mode 100644
index 26c7eef..0000000
--- a/hw/cris/Kconfig
+++ /dev/null
@@ -1,11 +0,0 @@
-config AXIS
- bool
- default y
- depends on CRIS
- select ETRAXFS
- select PFLASH_CFI02
- select NAND
-
-config ETRAXFS
- bool
- select PTIMER
diff --git a/hw/cris/axis_dev88.c b/hw/cris/axis_dev88.c
deleted file mode 100644
index 5556634..0000000
--- a/hw/cris/axis_dev88.c
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * QEMU model for the AXIS devboard 88.
- *
- * Copyright (c) 2009 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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/units.h"
-#include "qapi/error.h"
-#include "cpu.h"
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include "hw/block/flash.h"
-#include "hw/boards.h"
-#include "hw/cris/etraxfs.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "boot.h"
-#include "sysemu/qtest.h"
-#include "sysemu/sysemu.h"
-
-#define D(x)
-#define DNAND(x)
-
-struct nand_state_t
-{
- DeviceState *nand;
- MemoryRegion iomem;
- unsigned int rdy:1;
- unsigned int ale:1;
- unsigned int cle:1;
- unsigned int ce:1;
-};
-
-static struct nand_state_t nand_state;
-static uint64_t nand_read(void *opaque, hwaddr addr, unsigned size)
-{
- struct nand_state_t *s = opaque;
- uint32_t r;
- int rdy;
-
- r = nand_getio(s->nand);
- nand_getpins(s->nand, &rdy);
- s->rdy = rdy;
-
- DNAND(printf("%s addr=%x r=%x\n", __func__, addr, r));
- return r;
-}
-
-static void
-nand_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- struct nand_state_t *s = opaque;
- int rdy;
-
- DNAND(printf("%s addr=%x v=%x\n", __func__, addr, (unsigned)value));
- nand_setpins(s->nand, s->cle, s->ale, s->ce, 1, 0);
- nand_setio(s->nand, value);
- nand_getpins(s->nand, &rdy);
- s->rdy = rdy;
-}
-
-static const MemoryRegionOps nand_ops = {
- .read = nand_read,
- .write = nand_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct tempsensor_t
-{
- unsigned int shiftreg;
- unsigned int count;
- enum {
- ST_OUT, ST_IN, ST_Z
- } state;
-
- uint16_t regs[3];
-};
-
-static void tempsensor_clkedge(struct tempsensor_t *s,
- unsigned int clk, unsigned int data_in)
-{
- D(printf("%s clk=%d state=%d sr=%x\n", __func__,
- clk, s->state, s->shiftreg));
- if (s->count == 0) {
- s->count = 16;
- s->state = ST_OUT;
- }
- switch (s->state) {
- case ST_OUT:
- /* Output reg is clocked at negedge. */
- if (!clk) {
- s->count--;
- s->shiftreg <<= 1;
- if (s->count == 0) {
- s->shiftreg = 0;
- s->state = ST_IN;
- s->count = 16;
- }
- }
- break;
- case ST_Z:
- if (clk) {
- s->count--;
- if (s->count == 0) {
- s->shiftreg = 0;
- s->state = ST_OUT;
- s->count = 16;
- }
- }
- break;
- case ST_IN:
- /* Indata is sampled at posedge. */
- if (clk) {
- s->count--;
- s->shiftreg <<= 1;
- s->shiftreg |= data_in & 1;
- if (s->count == 0) {
- D(printf("%s cfgreg=%x\n", __func__, s->shiftreg));
- s->regs[0] = s->shiftreg;
- s->state = ST_OUT;
- s->count = 16;
-
- if ((s->regs[0] & 0xff) == 0) {
- /* 25 degrees celsius. */
- s->shiftreg = 0x0b9f;
- } else if ((s->regs[0] & 0xff) == 0xff) {
- /* Sensor ID, 0x8100 LM70. */
- s->shiftreg = 0x8100;
- } else
- printf("Invalid tempsens state %x\n", s->regs[0]);
- }
- }
- break;
- }
-}
-
-
-#define RW_PA_DOUT 0x00
-#define R_PA_DIN 0x01
-#define RW_PA_OE 0x02
-#define RW_PD_DOUT 0x10
-#define R_PD_DIN 0x11
-#define RW_PD_OE 0x12
-
-static struct gpio_state_t
-{
- MemoryRegion iomem;
- struct nand_state_t *nand;
- struct tempsensor_t tempsensor;
- uint32_t regs[0x5c / 4];
-} gpio_state;
-
-static uint64_t gpio_read(void *opaque, hwaddr addr, unsigned size)
-{
- struct gpio_state_t *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr)
- {
- case R_PA_DIN:
- r = s->regs[RW_PA_DOUT] & s->regs[RW_PA_OE];
-
- /* Encode pins from the nand. */
- r |= s->nand->rdy << 7;
- break;
- case R_PD_DIN:
- r = s->regs[RW_PD_DOUT] & s->regs[RW_PD_OE];
-
- /* Encode temp sensor pins. */
- r |= (!!(s->tempsensor.shiftreg & 0x10000)) << 4;
- break;
-
- default:
- r = s->regs[addr];
- break;
- }
- return r;
- D(printf("%s %x=%x\n", __func__, addr, r));
-}
-
-static void gpio_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- struct gpio_state_t *s = opaque;
- D(printf("%s %x=%x\n", __func__, addr, (unsigned)value));
-
- addr >>= 2;
- switch (addr)
- {
- case RW_PA_DOUT:
- /* Decode nand pins. */
- s->nand->ale = !!(value & (1 << 6));
- s->nand->cle = !!(value & (1 << 5));
- s->nand->ce = !!(value & (1 << 4));
-
- s->regs[addr] = value;
- break;
-
- case RW_PD_DOUT:
- /* Temp sensor clk. */
- if ((s->regs[addr] ^ value) & 2)
- tempsensor_clkedge(&s->tempsensor, !!(value & 2),
- !!(value & 16));
- s->regs[addr] = value;
- break;
-
- default:
- s->regs[addr] = value;
- break;
- }
-}
-
-static const MemoryRegionOps gpio_ops = {
- .read = gpio_read,
- .write = gpio_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-#define INTMEM_SIZE (128 * KiB)
-
-static struct cris_load_info li;
-
-static
-void axisdev88_init(MachineState *machine)
-{
- const char *kernel_filename = machine->kernel_filename;
- const char *kernel_cmdline = machine->kernel_cmdline;
- CRISCPU *cpu;
- DeviceState *dev;
- SysBusDevice *s;
- DriveInfo *nand;
- qemu_irq irq[30], nmi[2];
- void *etraxfs_dmac;
- struct etraxfs_dma_client *dma_eth;
- int i;
- MemoryRegion *address_space_mem = get_system_memory();
- MemoryRegion *phys_intmem = g_new(MemoryRegion, 1);
-
- /* init CPUs */
- cpu = CRIS_CPU(cpu_create(machine->cpu_type));
-
- memory_region_add_subregion(address_space_mem, 0x40000000, machine->ram);
-
- /* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the
- internal memory. */
- memory_region_init_ram(phys_intmem, NULL, "axisdev88.chipram",
- INTMEM_SIZE, &error_fatal);
- memory_region_add_subregion(address_space_mem, 0x38000000, phys_intmem);
-
- /* Attach a NAND flash to CS1. */
- nand = drive_get(IF_MTD, 0, 0);
- nand_state.nand = nand_init(nand ? blk_by_legacy_dinfo(nand) : NULL,
- NAND_MFR_STMICRO, 0x39);
- memory_region_init_io(&nand_state.iomem, NULL, &nand_ops, &nand_state,
- "nand", 0x05000000);
- memory_region_add_subregion(address_space_mem, 0x10000000,
- &nand_state.iomem);
-
- gpio_state.nand = &nand_state;
- memory_region_init_io(&gpio_state.iomem, NULL, &gpio_ops, &gpio_state,
- "gpio", 0x5c);
- memory_region_add_subregion(address_space_mem, 0x3001a000,
- &gpio_state.iomem);
-
-
- dev = qdev_new("etraxfs-pic");
- s = SYS_BUS_DEVICE(dev);
- sysbus_realize_and_unref(s, &error_fatal);
- sysbus_mmio_map(s, 0, 0x3001c000);
- sysbus_connect_irq(s, 0, qdev_get_gpio_in(DEVICE(cpu), CRIS_CPU_IRQ));
- sysbus_connect_irq(s, 1, qdev_get_gpio_in(DEVICE(cpu), CRIS_CPU_NMI));
- for (i = 0; i < 30; i++) {
- irq[i] = qdev_get_gpio_in(dev, i);
- }
- nmi[0] = qdev_get_gpio_in(dev, 30);
- nmi[1] = qdev_get_gpio_in(dev, 31);
-
- etraxfs_dmac = etraxfs_dmac_init(0x30000000, 10);
- for (i = 0; i < 10; i++) {
- /* On ETRAX, odd numbered channels are inputs. */
- etraxfs_dmac_connect(etraxfs_dmac, i, irq + 7 + i, i & 1);
- }
-
- /* Add the two ethernet blocks. */
- dma_eth = g_malloc0(sizeof dma_eth[0] * 4); /* Allocate 4 channels. */
-
- etraxfs_eth_init(0x30034000, 1, &dma_eth[0], &dma_eth[1]);
- /* The DMA Connector block is missing, hardwire things for now. */
- etraxfs_dmac_connect_client(etraxfs_dmac, 0, &dma_eth[0]);
- etraxfs_dmac_connect_client(etraxfs_dmac, 1, &dma_eth[1]);
-
- if (qemu_find_nic_info("etraxfs-eth", true, "fseth")) {
- etraxfs_eth_init(0x30036000, 2, &dma_eth[2], &dma_eth[3]);
- etraxfs_dmac_connect_client(etraxfs_dmac, 6, &dma_eth[2]);
- etraxfs_dmac_connect_client(etraxfs_dmac, 7, &dma_eth[3]);
- }
-
- /* 2 timers. */
- sysbus_create_varargs("etraxfs-timer", 0x3001e000, irq[0x1b], nmi[1], NULL);
- sysbus_create_varargs("etraxfs-timer", 0x3005e000, irq[0x1b], nmi[1], NULL);
-
- for (i = 0; i < 4; i++) {
- etraxfs_ser_create(0x30026000 + i * 0x2000, irq[0x14 + i], serial_hd(i));
- }
-
- if (kernel_filename) {
- li.image_filename = kernel_filename;
- li.cmdline = kernel_cmdline;
- li.ram_size = machine->ram_size;
- cris_load_image(cpu, &li);
- } else if (!qtest_enabled()) {
- fprintf(stderr, "Kernel image must be specified\n");
- exit(1);
- }
-}
-
-static void axisdev88_machine_init(MachineClass *mc)
-{
- mc->desc = "AXIS devboard 88";
- mc->init = axisdev88_init;
- mc->is_default = true;
- mc->default_cpu_type = CRIS_CPU_TYPE_NAME("crisv32");
- mc->default_ram_id = "axisdev88.ram";
-}
-
-DEFINE_MACHINE("axis-dev88", axisdev88_machine_init)
diff --git a/hw/cris/boot.c b/hw/cris/boot.c
deleted file mode 100644
index 9fa09cf..0000000
--- a/hw/cris/boot.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * CRIS image loading.
- *
- * Copyright (c) 2010 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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 "cpu.h"
-#include "hw/loader.h"
-#include "elf.h"
-#include "boot.h"
-#include "qemu/cutils.h"
-#include "sysemu/reset.h"
-
-static void main_cpu_reset(void *opaque)
-{
- CRISCPU *cpu = opaque;
- CPUCRISState *env = &cpu->env;
- struct cris_load_info *li;
-
- li = env->load_info;
-
- cpu_reset(CPU(cpu));
-
- if (!li) {
- /* nothing more to do. */
- return;
- }
-
- env->pc = li->entry;
-
- if (li->image_filename) {
- env->regs[8] = 0x56902387; /* RAM boot magic. */
- env->regs[9] = 0x40004000 + li->image_size;
- }
-
- if (li->cmdline) {
- /* Let the kernel know we are modifying the cmdline. */
- env->regs[10] = 0x87109563;
- env->regs[11] = 0x40000000;
- }
-}
-
-static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
-{
- return addr - 0x80000000LL;
-}
-
-void cris_load_image(CRISCPU *cpu, struct cris_load_info *li)
-{
- CPUCRISState *env = &cpu->env;
- uint64_t entry;
- int kcmdline_len;
- int image_size;
-
- env->load_info = li;
- /* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis
- devboard SDK. */
- image_size = load_elf(li->image_filename, NULL,
- translate_kernel_address, NULL,
- &entry, NULL, NULL, NULL, 0, EM_CRIS, 0, 0);
- li->entry = entry;
- if (image_size < 0) {
- /* Takes a kimage from the axis devboard SDK. */
- image_size = load_image_targphys(li->image_filename, 0x40004000,
- li->ram_size);
- li->entry = 0x40004000;
- }
-
- if (image_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- li->image_filename);
- exit(1);
- }
-
- if (li->cmdline && (kcmdline_len = strlen(li->cmdline))) {
- if (kcmdline_len > 256) {
- fprintf(stderr, "Too long CRIS kernel cmdline (max 256)\n");
- exit(1);
- }
- pstrcpy_targphys("cmdline", 0x40000000, 256, li->cmdline);
- }
- qemu_register_reset(main_cpu_reset, cpu);
-}
diff --git a/hw/cris/boot.h b/hw/cris/boot.h
deleted file mode 100644
index 9f1e0e3..0000000
--- a/hw/cris/boot.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef HW_CRIS_BOOT_H
-#define HW_CRIS_BOOT_H
-
-struct cris_load_info
-{
- const char *image_filename;
- const char *cmdline;
- int image_size;
- ram_addr_t ram_size;
-
- hwaddr entry;
-};
-
-void cris_load_image(CRISCPU *cpu, struct cris_load_info *li);
-
-#endif
diff --git a/hw/cris/meson.build b/hw/cris/meson.build
deleted file mode 100644
index dc808a4..0000000
--- a/hw/cris/meson.build
+++ /dev/null
@@ -1,5 +0,0 @@
-cris_ss = ss.source_set()
-cris_ss.add(files('boot.c'))
-cris_ss.add(when: 'CONFIG_AXIS', if_true: files('axis_dev88.c'))
-
-hw_arch += {'cris': cris_ss}
diff --git a/hw/cxl/cxl-events.c b/hw/cxl/cxl-events.c
index d397718..12dee2e 100644
--- a/hw/cxl/cxl-events.c
+++ b/hw/cxl/cxl-events.c
@@ -139,6 +139,19 @@ bool cxl_event_insert(CXLDeviceState *cxlds, CXLEventLogType log_type,
return cxl_event_count(log) == 1;
}
+void cxl_discard_all_event_records(CXLDeviceState *cxlds)
+{
+ CXLEventLogType log_type;
+ CXLEventLog *log;
+
+ for (log_type = 0; log_type < CXL_EVENT_TYPE_MAX; log_type++) {
+ log = &cxlds->event_logs[log_type];
+ while (!cxl_event_empty(log)) {
+ cxl_event_delete_head(cxlds, log_type, log);
+ }
+ }
+}
+
CXLRetCode cxl_event_get_records(CXLDeviceState *cxlds, CXLGetEventPayload *pl,
uint8_t log_type, int max_recs,
size_t *len)
diff --git a/hw/cxl/cxl-host.c b/hw/cxl/cxl-host.c
index c5f5fcf..e9f2543 100644
--- a/hw/cxl/cxl-host.c
+++ b/hw/cxl/cxl-host.c
@@ -315,7 +315,8 @@ static void machine_set_cxl(Object *obj, Visitor *v, const char *name,
static void machine_get_cfmw(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
- CXLFixedMemoryWindowOptionsList **list = opaque;
+ CXLState *state = opaque;
+ CXLFixedMemoryWindowOptionsList **list = &state->cfmw_list;
visit_type_CXLFixedMemoryWindowOptionsList(v, name, list, errp);
}
diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c
index 74eeb6f..9258e48 100644
--- a/hw/cxl/cxl-mailbox-utils.c
+++ b/hw/cxl/cxl-mailbox-utils.c
@@ -12,6 +12,7 @@
#include "hw/pci/msix.h"
#include "hw/cxl/cxl.h"
#include "hw/cxl/cxl_events.h"
+#include "hw/cxl/cxl_mailbox.h"
#include "hw/pci/pci.h"
#include "hw/pci-bridge/cxl_upstream_port.h"
#include "qemu/cutils.h"
@@ -62,12 +63,18 @@ enum {
#define SET_INTERRUPT_POLICY 0x3
FIRMWARE_UPDATE = 0x02,
#define GET_INFO 0x0
+ #define TRANSFER 0x1
+ #define ACTIVATE 0x2
TIMESTAMP = 0x03,
#define GET 0x0
#define SET 0x1
LOGS = 0x04,
#define GET_SUPPORTED 0x0
#define GET_LOG 0x1
+ FEATURES = 0x05,
+ #define GET_SUPPORTED 0x0
+ #define GET_FEATURE 0x1
+ #define SET_FEATURE 0x2
IDENTIFY = 0x40,
#define MEMORY_DEVICE 0x0
CCLS = 0x41,
@@ -83,6 +90,9 @@ enum {
#define GET_POISON_LIST 0x0
#define INJECT_POISON 0x1
#define CLEAR_POISON 0x2
+ #define GET_SCAN_MEDIA_CAPABILITIES 0x3
+ #define SCAN_MEDIA 0x4
+ #define GET_SCAN_MEDIA_RESULTS 0x5
DCD_CONFIG = 0x48,
#define GET_DC_CONFIG 0x0
#define GET_DYN_CAP_EXT_LIST 0x1
@@ -235,7 +245,6 @@ static CXLRetCode cmd_events_get_records(const struct cxl_cmd *cmd,
log_type = payload_in[0];
pl = (CXLGetEventPayload *)payload_out;
- memset(pl, 0, sizeof(*pl));
max_recs = (cxlds->payload_size - CXL_EVENT_PAYLOAD_HDR_SIZE) /
CXL_EVENT_RECORD_SIZE;
@@ -273,7 +282,6 @@ static CXLRetCode cmd_events_get_interrupt_policy(const struct cxl_cmd *cmd,
CXLEventLog *log;
policy = (CXLEventInterruptPolicy *)payload_out;
- memset(policy, 0, sizeof(*policy));
log = &cxlds->event_logs[CXL_EVENT_TYPE_INFO];
if (log->irq_enabled) {
@@ -372,7 +380,6 @@ static CXLRetCode cmd_infostat_identify(const struct cxl_cmd *cmd,
QEMU_BUILD_BUG_ON(sizeof(*is_identify) != 18);
is_identify = (void *)payload_out;
- memset(is_identify, 0, sizeof(*is_identify));
is_identify->pcie_vid = class->vendor_id;
is_identify->pcie_did = class->device_id;
if (object_dynamic_cast(OBJECT(cci->d), TYPE_CXL_USP)) {
@@ -606,7 +613,6 @@ static CXLRetCode cmd_infostat_bg_op_sts(const struct cxl_cmd *cmd,
QEMU_BUILD_BUG_ON(sizeof(*bg_op_status) != 8);
bg_op_status = (void *)payload_out;
- memset(bg_op_status, 0, sizeof(*bg_op_status));
bg_op_status->status = cci->bg.complete_pct << 1;
if (cci->bg.runtime > 0) {
bg_op_status->status |= 1U << 0;
@@ -618,6 +624,9 @@ static CXLRetCode cmd_infostat_bg_op_sts(const struct cxl_cmd *cmd,
return CXL_MBOX_SUCCESS;
}
+#define CXL_FW_SLOTS 2
+#define CXL_FW_SIZE 0x02000000 /* 32 mb */
+
/* CXL r3.1 Section 8.2.9.3.1: Get FW Info (Opcode 0200h) */
static CXLRetCode cmd_firmware_update_get_info(const struct cxl_cmd *cmd,
uint8_t *payload_in,
@@ -647,17 +656,193 @@ static CXLRetCode cmd_firmware_update_get_info(const struct cxl_cmd *cmd,
}
fw_info = (void *)payload_out;
- memset(fw_info, 0, sizeof(*fw_info));
- fw_info->slots_supported = 2;
- fw_info->slot_info = BIT(0) | BIT(3);
- fw_info->caps = 0;
- pstrcpy(fw_info->fw_rev1, sizeof(fw_info->fw_rev1), "BWFW VERSION 0");
+ fw_info->slots_supported = CXL_FW_SLOTS;
+ fw_info->slot_info = (cci->fw.active_slot & 0x7) |
+ ((cci->fw.staged_slot & 0x7) << 3);
+ fw_info->caps = BIT(0); /* online update supported */
+
+ if (cci->fw.slot[0]) {
+ pstrcpy(fw_info->fw_rev1, sizeof(fw_info->fw_rev1), "BWFW VERSION 0");
+ }
+ if (cci->fw.slot[1]) {
+ pstrcpy(fw_info->fw_rev2, sizeof(fw_info->fw_rev2), "BWFW VERSION 1");
+ }
*len_out = sizeof(*fw_info);
return CXL_MBOX_SUCCESS;
}
+/* CXL r3.1 section 8.2.9.3.2: Transfer FW (Opcode 0201h) */
+#define CXL_FW_XFER_ALIGNMENT 128
+
+#define CXL_FW_XFER_ACTION_FULL 0x0
+#define CXL_FW_XFER_ACTION_INIT 0x1
+#define CXL_FW_XFER_ACTION_CONTINUE 0x2
+#define CXL_FW_XFER_ACTION_END 0x3
+#define CXL_FW_XFER_ACTION_ABORT 0x4
+
+static CXLRetCode cmd_firmware_update_transfer(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ struct {
+ uint8_t action;
+ uint8_t slot;
+ uint8_t rsvd1[2];
+ uint32_t offset;
+ uint8_t rsvd2[0x78];
+ uint8_t data[];
+ } QEMU_PACKED *fw_transfer = (void *)payload_in;
+ size_t offset, length;
+
+ if (fw_transfer->action == CXL_FW_XFER_ACTION_ABORT) {
+ /*
+ * At this point there aren't any on-going transfers
+ * running in the bg - this is serialized before this
+ * call altogether. Just mark the state machine and
+ * disregard any other input.
+ */
+ cci->fw.transferring = false;
+ return CXL_MBOX_SUCCESS;
+ }
+
+ offset = fw_transfer->offset * CXL_FW_XFER_ALIGNMENT;
+ length = len - sizeof(*fw_transfer);
+ if (offset + length > CXL_FW_SIZE) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+
+ if (cci->fw.transferring) {
+ if (fw_transfer->action == CXL_FW_XFER_ACTION_FULL ||
+ fw_transfer->action == CXL_FW_XFER_ACTION_INIT) {
+ return CXL_MBOX_FW_XFER_IN_PROGRESS;
+ }
+ /*
+ * Abort partitioned package transfer if over 30 secs
+ * between parts. As opposed to the explicit ABORT action,
+ * semantically treat this condition as an error - as
+ * if a part action were passed without a previous INIT.
+ */
+ if (difftime(time(NULL), cci->fw.last_partxfer) > 30.0) {
+ cci->fw.transferring = false;
+ return CXL_MBOX_INVALID_INPUT;
+ }
+ } else if (fw_transfer->action == CXL_FW_XFER_ACTION_CONTINUE ||
+ fw_transfer->action == CXL_FW_XFER_ACTION_END) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+
+ /* allow back-to-back retransmission */
+ if ((offset != cci->fw.prev_offset || length != cci->fw.prev_len) &&
+ (fw_transfer->action == CXL_FW_XFER_ACTION_CONTINUE ||
+ fw_transfer->action == CXL_FW_XFER_ACTION_END)) {
+ /* verify no overlaps */
+ if (offset < cci->fw.prev_offset + cci->fw.prev_len) {
+ return CXL_MBOX_FW_XFER_OUT_OF_ORDER;
+ }
+ }
+
+ switch (fw_transfer->action) {
+ case CXL_FW_XFER_ACTION_FULL: /* ignores offset */
+ case CXL_FW_XFER_ACTION_END:
+ if (fw_transfer->slot == 0 ||
+ fw_transfer->slot == cci->fw.active_slot ||
+ fw_transfer->slot > CXL_FW_SLOTS) {
+ return CXL_MBOX_FW_INVALID_SLOT;
+ }
+
+ /* mark the slot used upon bg completion */
+ break;
+ case CXL_FW_XFER_ACTION_INIT:
+ if (offset != 0) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+
+ cci->fw.transferring = true;
+ cci->fw.prev_offset = offset;
+ cci->fw.prev_len = length;
+ break;
+ case CXL_FW_XFER_ACTION_CONTINUE:
+ cci->fw.prev_offset = offset;
+ cci->fw.prev_len = length;
+ break;
+ default:
+ return CXL_MBOX_INVALID_INPUT;
+ }
+
+ if (fw_transfer->action == CXL_FW_XFER_ACTION_FULL) {
+ cci->bg.runtime = 10 * 1000UL;
+ } else {
+ cci->bg.runtime = 2 * 1000UL;
+ }
+ /* keep relevant context for bg completion */
+ cci->fw.curr_action = fw_transfer->action;
+ cci->fw.curr_slot = fw_transfer->slot;
+ *len_out = 0;
+
+ return CXL_MBOX_BG_STARTED;
+}
+
+static void __do_firmware_xfer(CXLCCI *cci)
+{
+ switch (cci->fw.curr_action) {
+ case CXL_FW_XFER_ACTION_FULL:
+ case CXL_FW_XFER_ACTION_END:
+ cci->fw.slot[cci->fw.curr_slot - 1] = true;
+ cci->fw.transferring = false;
+ break;
+ case CXL_FW_XFER_ACTION_INIT:
+ case CXL_FW_XFER_ACTION_CONTINUE:
+ time(&cci->fw.last_partxfer);
+ break;
+ default:
+ break;
+ }
+}
+
+/* CXL r3.1 section 8.2.9.3.3: Activate FW (Opcode 0202h) */
+static CXLRetCode cmd_firmware_update_activate(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ struct {
+ uint8_t action;
+ uint8_t slot;
+ } QEMU_PACKED *fw_activate = (void *)payload_in;
+ QEMU_BUILD_BUG_ON(sizeof(*fw_activate) != 0x2);
+
+ if (fw_activate->slot == 0 ||
+ fw_activate->slot == cci->fw.active_slot ||
+ fw_activate->slot > CXL_FW_SLOTS) {
+ return CXL_MBOX_FW_INVALID_SLOT;
+ }
+
+ /* ensure that an actual fw package is there */
+ if (!cci->fw.slot[fw_activate->slot - 1]) {
+ return CXL_MBOX_FW_INVALID_SLOT;
+ }
+
+ switch (fw_activate->action) {
+ case 0: /* online */
+ cci->fw.active_slot = fw_activate->slot;
+ break;
+ case 1: /* reset */
+ cci->fw.staged_slot = fw_activate->slot;
+ break;
+ default:
+ return CXL_MBOX_INVALID_INPUT;
+ }
+
+ return CXL_MBOX_SUCCESS;
+}
+
/* CXL r3.1 Section 8.2.9.4.1: Get Timestamp (Opcode 0300h) */
static CXLRetCode cmd_timestamp_get(const struct cxl_cmd *cmd,
uint8_t *payload_in,
@@ -768,6 +953,388 @@ static CXLRetCode cmd_logs_get_log(const struct cxl_cmd *cmd,
return CXL_MBOX_SUCCESS;
}
+/* CXL r3.1 section 8.2.9.6: Features */
+/*
+ * Get Supported Features output payload
+ * CXL r3.1 section 8.2.9.6.1 Table 8-96
+ */
+typedef struct CXLSupportedFeatureHeader {
+ uint16_t entries;
+ uint16_t nsuppfeats_dev;
+ uint32_t reserved;
+} QEMU_PACKED CXLSupportedFeatureHeader;
+
+/*
+ * Get Supported Features Supported Feature Entry
+ * CXL r3.1 section 8.2.9.6.1 Table 8-97
+ */
+typedef struct CXLSupportedFeatureEntry {
+ QemuUUID uuid;
+ uint16_t feat_index;
+ uint16_t get_feat_size;
+ uint16_t set_feat_size;
+ uint32_t attr_flags;
+ uint8_t get_feat_version;
+ uint8_t set_feat_version;
+ uint16_t set_feat_effects;
+ uint8_t rsvd[18];
+} QEMU_PACKED CXLSupportedFeatureEntry;
+
+/*
+ * Get Supported Features Supported Feature Entry
+ * CXL rev 3.1 section 8.2.9.6.1 Table 8-97
+ */
+/* Supported Feature Entry : attribute flags */
+#define CXL_FEAT_ENTRY_ATTR_FLAG_CHANGABLE BIT(0)
+#define CXL_FEAT_ENTRY_ATTR_FLAG_DEEPEST_RESET_PERSISTENCE_MASK GENMASK(3, 1)
+#define CXL_FEAT_ENTRY_ATTR_FLAG_PERSIST_ACROSS_FIRMWARE_UPDATE BIT(4)
+#define CXL_FEAT_ENTRY_ATTR_FLAG_SUPPORT_DEFAULT_SELECTION BIT(5)
+#define CXL_FEAT_ENTRY_ATTR_FLAG_SUPPORT_SAVED_SELECTION BIT(6)
+
+/* Supported Feature Entry : set feature effects */
+#define CXL_FEAT_ENTRY_SFE_CONFIG_CHANGE_COLD_RESET BIT(0)
+#define CXL_FEAT_ENTRY_SFE_IMMEDIATE_CONFIG_CHANGE BIT(1)
+#define CXL_FEAT_ENTRY_SFE_IMMEDIATE_DATA_CHANGE BIT(2)
+#define CXL_FEAT_ENTRY_SFE_IMMEDIATE_POLICY_CHANGE BIT(3)
+#define CXL_FEAT_ENTRY_SFE_IMMEDIATE_LOG_CHANGE BIT(4)
+#define CXL_FEAT_ENTRY_SFE_SECURITY_STATE_CHANGE BIT(5)
+#define CXL_FEAT_ENTRY_SFE_BACKGROUND_OPERATION BIT(6)
+#define CXL_FEAT_ENTRY_SFE_SUPPORT_SECONDARY_MAILBOX BIT(7)
+#define CXL_FEAT_ENTRY_SFE_SUPPORT_ABORT_BACKGROUND_OPERATION BIT(8)
+#define CXL_FEAT_ENTRY_SFE_CEL_VALID BIT(9)
+#define CXL_FEAT_ENTRY_SFE_CONFIG_CHANGE_CONV_RESET BIT(10)
+#define CXL_FEAT_ENTRY_SFE_CONFIG_CHANGE_CXL_RESET BIT(11)
+
+enum CXL_SUPPORTED_FEATURES_LIST {
+ CXL_FEATURE_PATROL_SCRUB = 0,
+ CXL_FEATURE_ECS,
+ CXL_FEATURE_MAX
+};
+
+/* Get Feature CXL 3.1 Spec 8.2.9.6.2 */
+/*
+ * Get Feature input payload
+ * CXL r3.1 section 8.2.9.6.2 Table 8-99
+ */
+/* Get Feature : Payload in selection */
+enum CXL_GET_FEATURE_SELECTION {
+ CXL_GET_FEATURE_SEL_CURRENT_VALUE,
+ CXL_GET_FEATURE_SEL_DEFAULT_VALUE,
+ CXL_GET_FEATURE_SEL_SAVED_VALUE,
+ CXL_GET_FEATURE_SEL_MAX
+};
+
+/* Set Feature CXL 3.1 Spec 8.2.9.6.3 */
+/*
+ * Set Feature input payload
+ * CXL r3.1 section 8.2.9.6.3 Table 8-101
+ */
+typedef struct CXLSetFeatureInHeader {
+ QemuUUID uuid;
+ uint32_t flags;
+ uint16_t offset;
+ uint8_t version;
+ uint8_t rsvd[9];
+} QEMU_PACKED QEMU_ALIGNED(16) CXLSetFeatureInHeader;
+
+/* Set Feature : Payload in flags */
+#define CXL_SET_FEATURE_FLAG_DATA_TRANSFER_MASK 0x7
+enum CXL_SET_FEATURE_FLAG_DATA_TRANSFER {
+ CXL_SET_FEATURE_FLAG_FULL_DATA_TRANSFER,
+ CXL_SET_FEATURE_FLAG_INITIATE_DATA_TRANSFER,
+ CXL_SET_FEATURE_FLAG_CONTINUE_DATA_TRANSFER,
+ CXL_SET_FEATURE_FLAG_FINISH_DATA_TRANSFER,
+ CXL_SET_FEATURE_FLAG_ABORT_DATA_TRANSFER,
+ CXL_SET_FEATURE_FLAG_DATA_TRANSFER_MAX
+};
+#define CXL_SET_FEAT_DATA_SAVED_ACROSS_RESET BIT(3)
+
+/* CXL r3.1 section 8.2.9.9.11.1: Device Patrol Scrub Control Feature */
+static const QemuUUID patrol_scrub_uuid = {
+ .data = UUID(0x96dad7d6, 0xfde8, 0x482b, 0xa7, 0x33,
+ 0x75, 0x77, 0x4e, 0x06, 0xdb, 0x8a)
+};
+
+typedef struct CXLMemPatrolScrubSetFeature {
+ CXLSetFeatureInHeader hdr;
+ CXLMemPatrolScrubWriteAttrs feat_data;
+} QEMU_PACKED QEMU_ALIGNED(16) CXLMemPatrolScrubSetFeature;
+
+/*
+ * CXL r3.1 section 8.2.9.9.11.2:
+ * DDR5 Error Check Scrub (ECS) Control Feature
+ */
+static const QemuUUID ecs_uuid = {
+ .data = UUID(0xe5b13f22, 0x2328, 0x4a14, 0xb8, 0xba,
+ 0xb9, 0x69, 0x1e, 0x89, 0x33, 0x86)
+};
+
+typedef struct CXLMemECSSetFeature {
+ CXLSetFeatureInHeader hdr;
+ CXLMemECSWriteAttrs feat_data[];
+} QEMU_PACKED QEMU_ALIGNED(16) CXLMemECSSetFeature;
+
+/* CXL r3.1 section 8.2.9.6.1: Get Supported Features (Opcode 0500h) */
+static CXLRetCode cmd_features_get_supported(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ struct {
+ uint32_t count;
+ uint16_t start_index;
+ uint16_t reserved;
+ } QEMU_PACKED QEMU_ALIGNED(16) * get_feats_in = (void *)payload_in;
+
+ struct {
+ CXLSupportedFeatureHeader hdr;
+ CXLSupportedFeatureEntry feat_entries[];
+ } QEMU_PACKED QEMU_ALIGNED(16) * get_feats_out = (void *)payload_out;
+ uint16_t index, req_entries;
+ uint16_t entry;
+
+ if (!object_dynamic_cast(OBJECT(cci->d), TYPE_CXL_TYPE3)) {
+ return CXL_MBOX_UNSUPPORTED;
+ }
+ if (get_feats_in->count < sizeof(CXLSupportedFeatureHeader) ||
+ get_feats_in->start_index >= CXL_FEATURE_MAX) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+
+ req_entries = (get_feats_in->count -
+ sizeof(CXLSupportedFeatureHeader)) /
+ sizeof(CXLSupportedFeatureEntry);
+ req_entries = MIN(req_entries,
+ (CXL_FEATURE_MAX - get_feats_in->start_index));
+
+ for (entry = 0, index = get_feats_in->start_index;
+ entry < req_entries; index++) {
+ switch (index) {
+ case CXL_FEATURE_PATROL_SCRUB:
+ /* Fill supported feature entry for device patrol scrub control */
+ get_feats_out->feat_entries[entry++] =
+ (struct CXLSupportedFeatureEntry) {
+ .uuid = patrol_scrub_uuid,
+ .feat_index = index,
+ .get_feat_size = sizeof(CXLMemPatrolScrubReadAttrs),
+ .set_feat_size = sizeof(CXLMemPatrolScrubWriteAttrs),
+ .attr_flags = CXL_FEAT_ENTRY_ATTR_FLAG_CHANGABLE,
+ .get_feat_version = CXL_MEMDEV_PS_GET_FEATURE_VERSION,
+ .set_feat_version = CXL_MEMDEV_PS_SET_FEATURE_VERSION,
+ .set_feat_effects = CXL_FEAT_ENTRY_SFE_IMMEDIATE_CONFIG_CHANGE |
+ CXL_FEAT_ENTRY_SFE_CEL_VALID,
+ };
+ break;
+ case CXL_FEATURE_ECS:
+ /* Fill supported feature entry for device DDR5 ECS control */
+ get_feats_out->feat_entries[entry++] =
+ (struct CXLSupportedFeatureEntry) {
+ .uuid = ecs_uuid,
+ .feat_index = index,
+ .get_feat_size = CXL_ECS_NUM_MEDIA_FRUS *
+ sizeof(CXLMemECSReadAttrs),
+ .set_feat_size = CXL_ECS_NUM_MEDIA_FRUS *
+ sizeof(CXLMemECSWriteAttrs),
+ .attr_flags = CXL_FEAT_ENTRY_ATTR_FLAG_CHANGABLE,
+ .get_feat_version = CXL_ECS_GET_FEATURE_VERSION,
+ .set_feat_version = CXL_ECS_SET_FEATURE_VERSION,
+ .set_feat_effects = CXL_FEAT_ENTRY_SFE_IMMEDIATE_CONFIG_CHANGE |
+ CXL_FEAT_ENTRY_SFE_CEL_VALID,
+ };
+ break;
+ default:
+ __builtin_unreachable();
+ }
+ }
+ get_feats_out->hdr.nsuppfeats_dev = CXL_FEATURE_MAX;
+ get_feats_out->hdr.entries = req_entries;
+ *len_out = sizeof(CXLSupportedFeatureHeader) +
+ req_entries * sizeof(CXLSupportedFeatureEntry);
+
+ return CXL_MBOX_SUCCESS;
+}
+
+/* CXL r3.1 section 8.2.9.6.2: Get Feature (Opcode 0501h) */
+static CXLRetCode cmd_features_get_feature(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ struct {
+ QemuUUID uuid;
+ uint16_t offset;
+ uint16_t count;
+ uint8_t selection;
+ } QEMU_PACKED QEMU_ALIGNED(16) * get_feature;
+ uint16_t bytes_to_copy = 0;
+ CXLType3Dev *ct3d;
+ CXLSetFeatureInfo *set_feat_info;
+
+ if (!object_dynamic_cast(OBJECT(cci->d), TYPE_CXL_TYPE3)) {
+ return CXL_MBOX_UNSUPPORTED;
+ }
+
+ ct3d = CXL_TYPE3(cci->d);
+ get_feature = (void *)payload_in;
+
+ set_feat_info = &ct3d->set_feat_info;
+ if (qemu_uuid_is_equal(&get_feature->uuid, &set_feat_info->uuid)) {
+ return CXL_MBOX_FEATURE_TRANSFER_IN_PROGRESS;
+ }
+
+ if (get_feature->selection != CXL_GET_FEATURE_SEL_CURRENT_VALUE) {
+ return CXL_MBOX_UNSUPPORTED;
+ }
+ if (get_feature->offset + get_feature->count > cci->payload_max) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+
+ if (qemu_uuid_is_equal(&get_feature->uuid, &patrol_scrub_uuid)) {
+ if (get_feature->offset >= sizeof(CXLMemPatrolScrubReadAttrs)) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+ bytes_to_copy = sizeof(CXLMemPatrolScrubReadAttrs) -
+ get_feature->offset;
+ bytes_to_copy = MIN(bytes_to_copy, get_feature->count);
+ memcpy(payload_out,
+ (uint8_t *)&ct3d->patrol_scrub_attrs + get_feature->offset,
+ bytes_to_copy);
+ } else if (qemu_uuid_is_equal(&get_feature->uuid, &ecs_uuid)) {
+ if (get_feature->offset >= CXL_ECS_NUM_MEDIA_FRUS *
+ sizeof(CXLMemECSReadAttrs)) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+ bytes_to_copy = CXL_ECS_NUM_MEDIA_FRUS *
+ sizeof(CXLMemECSReadAttrs) -
+ get_feature->offset;
+ bytes_to_copy = MIN(bytes_to_copy, get_feature->count);
+ memcpy(payload_out,
+ (uint8_t *)&ct3d->ecs_attrs + get_feature->offset,
+ bytes_to_copy);
+ } else {
+ return CXL_MBOX_UNSUPPORTED;
+ }
+
+ *len_out = bytes_to_copy;
+
+ return CXL_MBOX_SUCCESS;
+}
+
+/* CXL r3.1 section 8.2.9.6.3: Set Feature (Opcode 0502h) */
+static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ CXLSetFeatureInHeader *hdr = (void *)payload_in;
+ CXLMemPatrolScrubWriteAttrs *ps_write_attrs;
+ CXLMemPatrolScrubSetFeature *ps_set_feature;
+ CXLMemECSWriteAttrs *ecs_write_attrs;
+ CXLMemECSSetFeature *ecs_set_feature;
+ CXLSetFeatureInfo *set_feat_info;
+ uint16_t bytes_to_copy = 0;
+ uint8_t data_transfer_flag;
+ CXLType3Dev *ct3d;
+ uint16_t count;
+
+
+ if (!object_dynamic_cast(OBJECT(cci->d), TYPE_CXL_TYPE3)) {
+ return CXL_MBOX_UNSUPPORTED;
+ }
+ ct3d = CXL_TYPE3(cci->d);
+ set_feat_info = &ct3d->set_feat_info;
+
+ if (!qemu_uuid_is_null(&set_feat_info->uuid) &&
+ !qemu_uuid_is_equal(&hdr->uuid, &set_feat_info->uuid)) {
+ return CXL_MBOX_FEATURE_TRANSFER_IN_PROGRESS;
+ }
+ if (hdr->flags & CXL_SET_FEAT_DATA_SAVED_ACROSS_RESET) {
+ set_feat_info->data_saved_across_reset = true;
+ } else {
+ set_feat_info->data_saved_across_reset = false;
+ }
+
+ data_transfer_flag =
+ hdr->flags & CXL_SET_FEATURE_FLAG_DATA_TRANSFER_MASK;
+ if (data_transfer_flag == CXL_SET_FEATURE_FLAG_INITIATE_DATA_TRANSFER) {
+ set_feat_info->uuid = hdr->uuid;
+ set_feat_info->data_size = 0;
+ }
+ set_feat_info->data_transfer_flag = data_transfer_flag;
+ set_feat_info->data_offset = hdr->offset;
+ bytes_to_copy = len_in - sizeof(CXLSetFeatureInHeader);
+
+ if (qemu_uuid_is_equal(&hdr->uuid, &patrol_scrub_uuid)) {
+ if (hdr->version != CXL_MEMDEV_PS_SET_FEATURE_VERSION) {
+ return CXL_MBOX_UNSUPPORTED;
+ }
+
+ ps_set_feature = (void *)payload_in;
+ ps_write_attrs = &ps_set_feature->feat_data;
+ memcpy((uint8_t *)&ct3d->patrol_scrub_wr_attrs + hdr->offset,
+ ps_write_attrs,
+ bytes_to_copy);
+ set_feat_info->data_size += bytes_to_copy;
+
+ if (data_transfer_flag == CXL_SET_FEATURE_FLAG_FULL_DATA_TRANSFER ||
+ data_transfer_flag == CXL_SET_FEATURE_FLAG_FINISH_DATA_TRANSFER) {
+ ct3d->patrol_scrub_attrs.scrub_cycle &= ~0xFF;
+ ct3d->patrol_scrub_attrs.scrub_cycle |=
+ ct3d->patrol_scrub_wr_attrs.scrub_cycle_hr & 0xFF;
+ ct3d->patrol_scrub_attrs.scrub_flags &= ~0x1;
+ ct3d->patrol_scrub_attrs.scrub_flags |=
+ ct3d->patrol_scrub_wr_attrs.scrub_flags & 0x1;
+ }
+ } else if (qemu_uuid_is_equal(&hdr->uuid,
+ &ecs_uuid)) {
+ if (hdr->version != CXL_ECS_SET_FEATURE_VERSION) {
+ return CXL_MBOX_UNSUPPORTED;
+ }
+
+ ecs_set_feature = (void *)payload_in;
+ ecs_write_attrs = ecs_set_feature->feat_data;
+ memcpy((uint8_t *)ct3d->ecs_wr_attrs + hdr->offset,
+ ecs_write_attrs,
+ bytes_to_copy);
+ set_feat_info->data_size += bytes_to_copy;
+
+ if (data_transfer_flag == CXL_SET_FEATURE_FLAG_FULL_DATA_TRANSFER ||
+ data_transfer_flag == CXL_SET_FEATURE_FLAG_FINISH_DATA_TRANSFER) {
+ for (count = 0; count < CXL_ECS_NUM_MEDIA_FRUS; count++) {
+ ct3d->ecs_attrs[count].ecs_log_cap =
+ ct3d->ecs_wr_attrs[count].ecs_log_cap;
+ ct3d->ecs_attrs[count].ecs_config =
+ ct3d->ecs_wr_attrs[count].ecs_config & 0x1F;
+ }
+ }
+ } else {
+ return CXL_MBOX_UNSUPPORTED;
+ }
+
+ if (data_transfer_flag == CXL_SET_FEATURE_FLAG_FULL_DATA_TRANSFER ||
+ data_transfer_flag == CXL_SET_FEATURE_FLAG_FINISH_DATA_TRANSFER ||
+ data_transfer_flag == CXL_SET_FEATURE_FLAG_ABORT_DATA_TRANSFER) {
+ memset(&set_feat_info->uuid, 0, sizeof(QemuUUID));
+ if (qemu_uuid_is_equal(&hdr->uuid, &patrol_scrub_uuid)) {
+ memset(&ct3d->patrol_scrub_wr_attrs, 0, set_feat_info->data_size);
+ } else if (qemu_uuid_is_equal(&hdr->uuid, &ecs_uuid)) {
+ memset(ct3d->ecs_wr_attrs, 0, set_feat_info->data_size);
+ }
+ set_feat_info->data_transfer_flag = 0;
+ set_feat_info->data_saved_across_reset = false;
+ set_feat_info->data_offset = 0;
+ set_feat_info->data_size = 0;
+ }
+
+ return CXL_MBOX_SUCCESS;
+}
+
/* CXL r3.1 Section 8.2.9.9.1.1: Identify Memory Device (Opcode 4000h) */
static CXLRetCode cmd_identify_memory_device(const struct cxl_cmd *cmd,
uint8_t *payload_in,
@@ -805,7 +1372,6 @@ static CXLRetCode cmd_identify_memory_device(const struct cxl_cmd *cmd,
}
id = (void *)payload_out;
- memset(id, 0, sizeof(*id));
snprintf(id->fw_revision, 0x10, "BWFW VERSION %02d", 0);
@@ -953,6 +1519,7 @@ static void __do_sanitization(CXLType3Dev *ct3d)
memset(lsa, 0, memory_region_size(mr));
}
}
+ cxl_discard_all_event_records(&ct3d->cxl_dstate);
}
/*
@@ -1086,8 +1653,8 @@ static CXLRetCode cmd_media_get_poison_list(const struct cxl_cmd *cmd,
QLIST_FOREACH(ent, poison_list, node) {
/* Check for no overlap */
- if (ent->start >= query_start + query_length ||
- ent->start + ent->length <= query_start) {
+ if (!ranges_overlap(ent->start, ent->length,
+ query_start, query_length)) {
continue;
}
record_count++;
@@ -1095,13 +1662,12 @@ static CXLRetCode cmd_media_get_poison_list(const struct cxl_cmd *cmd,
out_pl_len = sizeof(*out) + record_count * sizeof(out->records[0]);
assert(out_pl_len <= CXL_MAILBOX_MAX_PAYLOAD_SIZE);
- memset(out, 0, out_pl_len);
QLIST_FOREACH(ent, poison_list, node) {
uint64_t start, stop;
/* Check for no overlap */
- if (ent->start >= query_start + query_length ||
- ent->start + ent->length <= query_start) {
+ if (!ranges_overlap(ent->start, ent->length,
+ query_start, query_length)) {
continue;
}
@@ -1117,6 +1683,10 @@ static CXLRetCode cmd_media_get_poison_list(const struct cxl_cmd *cmd,
out->flags = (1 << 1);
stq_le_p(&out->overflow_timestamp, ct3d->poison_list_overflow_ts);
}
+ if (scan_media_running(cci)) {
+ out->flags |= (1 << 2);
+ }
+
stw_le_p(&out->count, record_count);
*len_out = out_pl_len;
return CXL_MBOX_SUCCESS;
@@ -1146,6 +1716,16 @@ static CXLRetCode cmd_media_inject_poison(const struct cxl_cmd *cmd,
return CXL_MBOX_SUCCESS;
}
}
+ /*
+ * Freeze the list if there is an on-going scan media operation.
+ */
+ if (scan_media_running(cci)) {
+ /*
+ * XXX: Spec is ambiguous - is this case considered
+ * a successful return despite not adding to the list?
+ */
+ goto success;
+ }
if (ct3d->poison_list_cnt == CXL_POISON_LIST_LIMIT) {
return CXL_MBOX_INJECT_POISON_LIMIT;
@@ -1161,6 +1741,7 @@ static CXLRetCode cmd_media_inject_poison(const struct cxl_cmd *cmd,
*/
QLIST_INSERT_HEAD(poison_list, p, node);
ct3d->poison_list_cnt++;
+success:
*len_out = 0;
return CXL_MBOX_SUCCESS;
@@ -1200,6 +1781,17 @@ static CXLRetCode cmd_media_clear_poison(const struct cxl_cmd *cmd,
}
}
+ /*
+ * Freeze the list if there is an on-going scan media operation.
+ */
+ if (scan_media_running(cci)) {
+ /*
+ * XXX: Spec is ambiguous - is this case considered
+ * a successful return despite not removing from the list?
+ */
+ goto success;
+ }
+
QLIST_FOREACH(ent, poison_list, node) {
/*
* Test for contained in entry. Simpler than general case
@@ -1210,7 +1802,7 @@ static CXLRetCode cmd_media_clear_poison(const struct cxl_cmd *cmd,
}
}
if (!ent) {
- return CXL_MBOX_SUCCESS;
+ goto success;
}
QLIST_REMOVE(ent, node);
@@ -1247,8 +1839,258 @@ static CXLRetCode cmd_media_clear_poison(const struct cxl_cmd *cmd,
}
/* Any fragments have been added, free original entry */
g_free(ent);
+success:
+ *len_out = 0;
+
+ return CXL_MBOX_SUCCESS;
+}
+
+/*
+ * CXL r3.1 section 8.2.9.9.4.4: Get Scan Media Capabilities
+ */
+static CXLRetCode
+cmd_media_get_scan_media_capabilities(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ struct get_scan_media_capabilities_pl {
+ uint64_t pa;
+ uint64_t length;
+ } QEMU_PACKED;
+
+ struct get_scan_media_capabilities_out_pl {
+ uint32_t estimated_runtime_ms;
+ };
+
+ CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
+ CXLDeviceState *cxl_dstate = &ct3d->cxl_dstate;
+ struct get_scan_media_capabilities_pl *in = (void *)payload_in;
+ struct get_scan_media_capabilities_out_pl *out = (void *)payload_out;
+ uint64_t query_start;
+ uint64_t query_length;
+
+ query_start = ldq_le_p(&in->pa);
+ /* 64 byte alignment required */
+ if (query_start & 0x3f) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+ query_length = ldq_le_p(&in->length) * CXL_CACHE_LINE_SIZE;
+
+ if (query_start + query_length > cxl_dstate->static_mem_size) {
+ return CXL_MBOX_INVALID_PA;
+ }
+
+ /*
+ * Just use 400 nanosecond access/read latency + 100 ns for
+ * the cost of updating the poison list. For small enough
+ * chunks return at least 1 ms.
+ */
+ stl_le_p(&out->estimated_runtime_ms,
+ MAX(1, query_length * (0.0005L / 64)));
+
+ *len_out = sizeof(*out);
+ return CXL_MBOX_SUCCESS;
+}
+
+static void __do_scan_media(CXLType3Dev *ct3d)
+{
+ CXLPoison *ent;
+ unsigned int results_cnt = 0;
+
+ QLIST_FOREACH(ent, &ct3d->scan_media_results, node) {
+ results_cnt++;
+ }
+
+ /* only scan media may clear the overflow */
+ if (ct3d->poison_list_overflowed &&
+ ct3d->poison_list_cnt == results_cnt) {
+ cxl_clear_poison_list_overflowed(ct3d);
+ }
+ /* scan media has run since last conventional reset */
+ ct3d->scan_media_hasrun = true;
+}
+
+/*
+ * CXL r3.1 section 8.2.9.9.4.5: Scan Media
+ */
+static CXLRetCode cmd_media_scan_media(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ struct scan_media_pl {
+ uint64_t pa;
+ uint64_t length;
+ uint8_t flags;
+ } QEMU_PACKED;
+
+ struct scan_media_pl *in = (void *)payload_in;
+ CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
+ CXLDeviceState *cxl_dstate = &ct3d->cxl_dstate;
+ uint64_t query_start;
+ uint64_t query_length;
+ CXLPoison *ent, *next;
+
+ query_start = ldq_le_p(&in->pa);
+ /* 64 byte alignment required */
+ if (query_start & 0x3f) {
+ return CXL_MBOX_INVALID_INPUT;
+ }
+ query_length = ldq_le_p(&in->length) * CXL_CACHE_LINE_SIZE;
+
+ if (query_start + query_length > cxl_dstate->static_mem_size) {
+ return CXL_MBOX_INVALID_PA;
+ }
+ if (ct3d->dc.num_regions && query_start + query_length >=
+ cxl_dstate->static_mem_size + ct3d->dc.total_capacity) {
+ return CXL_MBOX_INVALID_PA;
+ }
+
+ if (in->flags == 0) { /* TODO */
+ qemu_log_mask(LOG_UNIMP,
+ "Scan Media Event Log is unsupported\n");
+ }
+
+ /* any previous results are discarded upon a new Scan Media */
+ QLIST_FOREACH_SAFE(ent, &ct3d->scan_media_results, node, next) {
+ QLIST_REMOVE(ent, node);
+ g_free(ent);
+ }
+
+ /* kill the poison list - it will be recreated */
+ if (ct3d->poison_list_overflowed) {
+ QLIST_FOREACH_SAFE(ent, &ct3d->poison_list, node, next) {
+ QLIST_REMOVE(ent, node);
+ g_free(ent);
+ ct3d->poison_list_cnt--;
+ }
+ }
+
+ /*
+ * Scan the backup list and move corresponding entries
+ * into the results list, updating the poison list
+ * when possible.
+ */
+ QLIST_FOREACH_SAFE(ent, &ct3d->poison_list_bkp, node, next) {
+ CXLPoison *res;
+
+ if (ent->start >= query_start + query_length ||
+ ent->start + ent->length <= query_start) {
+ continue;
+ }
+
+ /*
+ * If a Get Poison List cmd comes in while this
+ * scan is being done, it will see the new complete
+ * list, while setting the respective flag.
+ */
+ if (ct3d->poison_list_cnt < CXL_POISON_LIST_LIMIT) {
+ CXLPoison *p = g_new0(CXLPoison, 1);
+
+ p->start = ent->start;
+ p->length = ent->length;
+ p->type = ent->type;
+ QLIST_INSERT_HEAD(&ct3d->poison_list, p, node);
+ ct3d->poison_list_cnt++;
+ }
+
+ res = g_new0(CXLPoison, 1);
+ res->start = ent->start;
+ res->length = ent->length;
+ res->type = ent->type;
+ QLIST_INSERT_HEAD(&ct3d->scan_media_results, res, node);
+
+ QLIST_REMOVE(ent, node);
+ g_free(ent);
+ }
+
+ cci->bg.runtime = MAX(1, query_length * (0.0005L / 64));
*len_out = 0;
+ return CXL_MBOX_BG_STARTED;
+}
+
+/*
+ * CXL r3.1 section 8.2.9.9.4.6: Get Scan Media Results
+ */
+static CXLRetCode cmd_media_get_scan_media_results(const struct cxl_cmd *cmd,
+ uint8_t *payload_in,
+ size_t len_in,
+ uint8_t *payload_out,
+ size_t *len_out,
+ CXLCCI *cci)
+{
+ struct get_scan_media_results_out_pl {
+ uint64_t dpa_restart;
+ uint64_t length;
+ uint8_t flags;
+ uint8_t rsvd1;
+ uint16_t count;
+ uint8_t rsvd2[0xc];
+ struct {
+ uint64_t addr;
+ uint32_t length;
+ uint32_t resv;
+ } QEMU_PACKED records[];
+ } QEMU_PACKED;
+
+ struct get_scan_media_results_out_pl *out = (void *)payload_out;
+ CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
+ CXLPoisonList *scan_media_results = &ct3d->scan_media_results;
+ CXLPoison *ent, *next;
+ uint16_t total_count = 0, record_count = 0, i = 0;
+ uint16_t out_pl_len;
+
+ if (!ct3d->scan_media_hasrun) {
+ return CXL_MBOX_UNSUPPORTED;
+ }
+
+ /*
+ * Calculate limits, all entries are within the same address range of the
+ * last scan media call.
+ */
+ QLIST_FOREACH(ent, scan_media_results, node) {
+ size_t rec_size = record_count * sizeof(out->records[0]);
+
+ if (sizeof(*out) + rec_size < CXL_MAILBOX_MAX_PAYLOAD_SIZE) {
+ record_count++;
+ }
+ total_count++;
+ }
+
+ out_pl_len = sizeof(*out) + record_count * sizeof(out->records[0]);
+ assert(out_pl_len <= CXL_MAILBOX_MAX_PAYLOAD_SIZE);
+
+ memset(out, 0, out_pl_len);
+ QLIST_FOREACH_SAFE(ent, scan_media_results, node, next) {
+ uint64_t start, stop;
+
+ if (i == record_count) {
+ break;
+ }
+
+ start = ROUND_DOWN(ent->start, 64ull);
+ stop = ROUND_DOWN(ent->start, 64ull) + ent->length;
+ stq_le_p(&out->records[i].addr, start);
+ stl_le_p(&out->records[i].length, (stop - start) / CXL_CACHE_LINE_SIZE);
+ i++;
+
+ /* consume the returning entry */
+ QLIST_REMOVE(ent, node);
+ g_free(ent);
+ }
+
+ stw_le_p(&out->count, record_count);
+ if (total_count > record_count) {
+ out->flags = (1 << 0); /* More Media Error Records */
+ }
+
+ *len_out = out_pl_len;
return CXL_MBOX_SUCCESS;
}
@@ -1822,40 +2664,51 @@ static CXLRetCode cmd_dcd_release_dyn_cap(const struct cxl_cmd *cmd,
return CXL_MBOX_SUCCESS;
}
-#define IMMEDIATE_CONFIG_CHANGE (1 << 1)
-#define IMMEDIATE_DATA_CHANGE (1 << 2)
-#define IMMEDIATE_POLICY_CHANGE (1 << 3)
-#define IMMEDIATE_LOG_CHANGE (1 << 4)
-#define SECURITY_STATE_CHANGE (1 << 5)
-#define BACKGROUND_OPERATION (1 << 6)
-
static const struct cxl_cmd cxl_cmd_set[256][256] = {
[EVENTS][GET_RECORDS] = { "EVENTS_GET_RECORDS",
cmd_events_get_records, 1, 0 },
[EVENTS][CLEAR_RECORDS] = { "EVENTS_CLEAR_RECORDS",
- cmd_events_clear_records, ~0, IMMEDIATE_LOG_CHANGE },
+ cmd_events_clear_records, ~0, CXL_MBOX_IMMEDIATE_LOG_CHANGE },
[EVENTS][GET_INTERRUPT_POLICY] = { "EVENTS_GET_INTERRUPT_POLICY",
cmd_events_get_interrupt_policy, 0, 0 },
[EVENTS][SET_INTERRUPT_POLICY] = { "EVENTS_SET_INTERRUPT_POLICY",
cmd_events_set_interrupt_policy,
- ~0, IMMEDIATE_CONFIG_CHANGE },
+ ~0, CXL_MBOX_IMMEDIATE_CONFIG_CHANGE },
[FIRMWARE_UPDATE][GET_INFO] = { "FIRMWARE_UPDATE_GET_INFO",
cmd_firmware_update_get_info, 0, 0 },
+ [FIRMWARE_UPDATE][TRANSFER] = { "FIRMWARE_UPDATE_TRANSFER",
+ cmd_firmware_update_transfer, ~0, CXL_MBOX_BACKGROUND_OPERATION },
+ [FIRMWARE_UPDATE][ACTIVATE] = { "FIRMWARE_UPDATE_ACTIVATE",
+ cmd_firmware_update_activate, 2, CXL_MBOX_BACKGROUND_OPERATION },
[TIMESTAMP][GET] = { "TIMESTAMP_GET", cmd_timestamp_get, 0, 0 },
[TIMESTAMP][SET] = { "TIMESTAMP_SET", cmd_timestamp_set,
- 8, IMMEDIATE_POLICY_CHANGE },
+ 8, CXL_MBOX_IMMEDIATE_POLICY_CHANGE },
[LOGS][GET_SUPPORTED] = { "LOGS_GET_SUPPORTED", cmd_logs_get_supported,
0, 0 },
[LOGS][GET_LOG] = { "LOGS_GET_LOG", cmd_logs_get_log, 0x18, 0 },
+ [FEATURES][GET_SUPPORTED] = { "FEATURES_GET_SUPPORTED",
+ cmd_features_get_supported, 0x8, 0 },
+ [FEATURES][GET_FEATURE] = { "FEATURES_GET_FEATURE",
+ cmd_features_get_feature, 0x15, 0 },
+ [FEATURES][SET_FEATURE] = { "FEATURES_SET_FEATURE",
+ cmd_features_set_feature,
+ ~0,
+ (CXL_MBOX_IMMEDIATE_CONFIG_CHANGE |
+ CXL_MBOX_IMMEDIATE_DATA_CHANGE |
+ CXL_MBOX_IMMEDIATE_POLICY_CHANGE |
+ CXL_MBOX_IMMEDIATE_LOG_CHANGE |
+ CXL_MBOX_SECURITY_STATE_CHANGE)},
[IDENTIFY][MEMORY_DEVICE] = { "IDENTIFY_MEMORY_DEVICE",
cmd_identify_memory_device, 0, 0 },
[CCLS][GET_PARTITION_INFO] = { "CCLS_GET_PARTITION_INFO",
cmd_ccls_get_partition_info, 0, 0 },
[CCLS][GET_LSA] = { "CCLS_GET_LSA", cmd_ccls_get_lsa, 8, 0 },
[CCLS][SET_LSA] = { "CCLS_SET_LSA", cmd_ccls_set_lsa,
- ~0, IMMEDIATE_CONFIG_CHANGE | IMMEDIATE_DATA_CHANGE },
+ ~0, CXL_MBOX_IMMEDIATE_CONFIG_CHANGE | CXL_MBOX_IMMEDIATE_DATA_CHANGE },
[SANITIZE][OVERWRITE] = { "SANITIZE_OVERWRITE", cmd_sanitize_overwrite, 0,
- IMMEDIATE_DATA_CHANGE | SECURITY_STATE_CHANGE | BACKGROUND_OPERATION },
+ (CXL_MBOX_IMMEDIATE_DATA_CHANGE |
+ CXL_MBOX_SECURITY_STATE_CHANGE |
+ CXL_MBOX_BACKGROUND_OPERATION)},
[PERSISTENT_MEM][GET_SECURITY_STATE] = { "GET_SECURITY_STATE",
cmd_get_security_state, 0, 0 },
[MEDIA_AND_POISON][GET_POISON_LIST] = { "MEDIA_AND_POISON_GET_POISON_LIST",
@@ -1864,6 +2717,14 @@ static const struct cxl_cmd cxl_cmd_set[256][256] = {
cmd_media_inject_poison, 8, 0 },
[MEDIA_AND_POISON][CLEAR_POISON] = { "MEDIA_AND_POISON_CLEAR_POISON",
cmd_media_clear_poison, 72, 0 },
+ [MEDIA_AND_POISON][GET_SCAN_MEDIA_CAPABILITIES] = {
+ "MEDIA_AND_POISON_GET_SCAN_MEDIA_CAPABILITIES",
+ cmd_media_get_scan_media_capabilities, 16, 0 },
+ [MEDIA_AND_POISON][SCAN_MEDIA] = { "MEDIA_AND_POISON_SCAN_MEDIA",
+ cmd_media_scan_media, 17, CXL_MBOX_BACKGROUND_OPERATION },
+ [MEDIA_AND_POISON][GET_SCAN_MEDIA_RESULTS] = {
+ "MEDIA_AND_POISON_GET_SCAN_MEDIA_RESULTS",
+ cmd_media_get_scan_media_results, 0, 0 },
};
static const struct cxl_cmd cxl_cmd_set_dcd[256][256] = {
@@ -1874,10 +2735,10 @@ static const struct cxl_cmd cxl_cmd_set_dcd[256][256] = {
8, 0 },
[DCD_CONFIG][ADD_DYN_CAP_RSP] = {
"DCD_ADD_DYNAMIC_CAPACITY_RESPONSE", cmd_dcd_add_dyn_cap_rsp,
- ~0, IMMEDIATE_DATA_CHANGE },
+ ~0, CXL_MBOX_IMMEDIATE_DATA_CHANGE },
[DCD_CONFIG][RELEASE_DYN_CAP] = {
"DCD_RELEASE_DYNAMIC_CAPACITY", cmd_dcd_release_dyn_cap,
- ~0, IMMEDIATE_DATA_CHANGE },
+ ~0, CXL_MBOX_IMMEDIATE_DATA_CHANGE },
};
static const struct cxl_cmd cxl_cmd_set_sw[256][256] = {
@@ -1885,8 +2746,8 @@ static const struct cxl_cmd cxl_cmd_set_sw[256][256] = {
[INFOSTAT][BACKGROUND_OPERATION_STATUS] = { "BACKGROUND_OPERATION_STATUS",
cmd_infostat_bg_op_sts, 0, 0 },
[TIMESTAMP][GET] = { "TIMESTAMP_GET", cmd_timestamp_get, 0, 0 },
- [TIMESTAMP][SET] = { "TIMESTAMP_SET", cmd_timestamp_set, 0,
- IMMEDIATE_POLICY_CHANGE },
+ [TIMESTAMP][SET] = { "TIMESTAMP_SET", cmd_timestamp_set, 8,
+ CXL_MBOX_IMMEDIATE_POLICY_CHANGE },
[LOGS][GET_SUPPORTED] = { "LOGS_GET_SUPPORTED", cmd_logs_get_supported, 0,
0 },
[LOGS][GET_LOG] = { "LOGS_GET_LOG", cmd_logs_get_log, 0x18, 0 },
@@ -1913,6 +2774,7 @@ int cxl_process_cci_message(CXLCCI *cci, uint8_t set, uint8_t cmd,
int ret;
const struct cxl_cmd *cxl_cmd;
opcode_handler h;
+ CXLDeviceState *cxl_dstate;
*len_out = 0;
cxl_cmd = &cci->cxl_cmd_set[set][cmd];
@@ -1928,28 +2790,34 @@ int cxl_process_cci_message(CXLCCI *cci, uint8_t set, uint8_t cmd,
}
/* Only one bg command at a time */
- if ((cxl_cmd->effect & BACKGROUND_OPERATION) &&
+ if ((cxl_cmd->effect & CXL_MBOX_BACKGROUND_OPERATION) &&
cci->bg.runtime > 0) {
return CXL_MBOX_BUSY;
}
- /* forbid any selected commands while overwriting */
- if (sanitize_running(cci)) {
- if (h == cmd_events_get_records ||
- h == cmd_ccls_get_partition_info ||
- h == cmd_ccls_set_lsa ||
- h == cmd_ccls_get_lsa ||
- h == cmd_logs_get_log ||
- h == cmd_media_get_poison_list ||
- h == cmd_media_inject_poison ||
- h == cmd_media_clear_poison ||
- h == cmd_sanitize_overwrite) {
- return CXL_MBOX_MEDIA_DISABLED;
+ /* forbid any selected commands while the media is disabled */
+ if (object_dynamic_cast(OBJECT(cci->d), TYPE_CXL_TYPE3)) {
+ cxl_dstate = &CXL_TYPE3(cci->d)->cxl_dstate;
+
+ if (cxl_dev_media_disabled(cxl_dstate)) {
+ if (h == cmd_events_get_records ||
+ h == cmd_ccls_get_partition_info ||
+ h == cmd_ccls_set_lsa ||
+ h == cmd_ccls_get_lsa ||
+ h == cmd_logs_get_log ||
+ h == cmd_media_get_poison_list ||
+ h == cmd_media_inject_poison ||
+ h == cmd_media_clear_poison ||
+ h == cmd_sanitize_overwrite ||
+ h == cmd_firmware_update_transfer ||
+ h == cmd_firmware_update_activate) {
+ return CXL_MBOX_MEDIA_DISABLED;
+ }
}
}
ret = (*h)(cxl_cmd, pl_in, len_in, pl_out, len_out, cci);
- if ((cxl_cmd->effect & BACKGROUND_OPERATION) &&
+ if ((cxl_cmd->effect & CXL_MBOX_BACKGROUND_OPERATION) &&
ret == CXL_MBOX_BG_STARTED) {
*bg_started = true;
} else {
@@ -1987,6 +2855,9 @@ static void bg_timercb(void *opaque)
cci->bg.complete_pct = 100;
cci->bg.ret_code = ret;
switch (cci->bg.opcode) {
+ case 0x0201: /* fw transfer */
+ __do_firmware_xfer(cci);
+ break;
case 0x4400: /* sanitize */
{
CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
@@ -1995,8 +2866,13 @@ static void bg_timercb(void *opaque)
cxl_dev_enable_media(&ct3d->cxl_dstate);
}
break;
- case 0x4304: /* TODO: scan media */
+ case 0x4304: /* scan media */
+ {
+ CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
+
+ __do_scan_media(ct3d);
break;
+ }
default:
__builtin_unreachable();
break;
@@ -2053,6 +2929,10 @@ void cxl_init_cci(CXLCCI *cci, size_t payload_max)
cci->bg.runtime = 0;
cci->bg.timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
bg_timercb, cci);
+
+ memset(&cci->fw, 0, sizeof(cci->fw));
+ cci->fw.active_slot = 1;
+ cci->fw.slot[cci->fw.active_slot - 1] = true;
}
static void cxl_copy_cci_commands(CXLCCI *cci, const struct cxl_cmd (*cxl_cmds)[256])
diff --git a/hw/cxl/switch-mailbox-cci.c b/hw/cxl/switch-mailbox-cci.c
index ba399c6..4f41944 100644
--- a/hw/cxl/switch-mailbox-cci.c
+++ b/hw/cxl/switch-mailbox-cci.c
@@ -89,7 +89,7 @@ static void cswmbcci_class_init(ObjectClass *oc, void *data)
pc->device_id = 0xa123;
pc->revision = 0;
dc->desc = "CXL Switch Mailbox CCI";
- dc->reset = cswmbcci_reset;
+ device_class_set_legacy_reset(dc, cswmbcci_reset);
device_class_set_props(dc, cxl_switch_cci_props);
}
diff --git a/hw/display/Kconfig b/hw/display/Kconfig
index a4552c8..2250c74 100644
--- a/hw/display/Kconfig
+++ b/hw/display/Kconfig
@@ -66,9 +66,6 @@ config BOCHS_DISPLAY
select VGA
select EDID
-config BLIZZARD
- bool
-
config FRAMEBUFFER
bool
@@ -76,7 +73,7 @@ config SM501
bool
select I2C
select DDC
- select SERIAL
+ select SERIAL_MM
select USB_OHCI_SYSBUS
config TCX
diff --git a/hw/display/artist.c b/hw/display/artist.c
index d913453..5790b7a 100644
--- a/hw/display/artist.c
+++ b/hw/display/artist.c
@@ -1491,7 +1491,7 @@ static void artist_class_init(ObjectClass *klass, void *data)
dc->realize = artist_realizefn;
dc->vmsd = &vmstate_artist;
- dc->reset = artist_reset;
+ device_class_set_legacy_reset(dc, artist_reset);
device_class_set_props(dc, artist_properties);
}
diff --git a/hw/display/ati.c b/hw/display/ati.c
index b1f94f5..593a253 100644
--- a/hw/display/ati.c
+++ b/hw/display/ati.c
@@ -1055,7 +1055,7 @@ static void ati_vga_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- dc->reset = ati_vga_reset;
+ device_class_set_legacy_reset(dc, ati_vga_reset);
device_class_set_props(dc, ati_vga_properties);
dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c
index 650db3d..7005d5b 100644
--- a/hw/display/bcm2835_fb.c
+++ b/hw/display/bcm2835_fb.c
@@ -449,7 +449,7 @@ static void bcm2835_fb_class_init(ObjectClass *klass, void *data)
device_class_set_props(dc, bcm2835_fb_props);
dc->realize = bcm2835_fb_realize;
- dc->reset = bcm2835_fb_reset;
+ device_class_set_legacy_reset(dc, bcm2835_fb_reset);
dc->vmsd = &vmstate_bcm2835_fb;
}
diff --git a/hw/display/blizzard.c b/hw/display/blizzard.c
deleted file mode 100644
index 030abbe..0000000
--- a/hw/display/blizzard.c
+++ /dev/null
@@ -1,1026 +0,0 @@
-/*
- * Epson S1D13744/S1D13745 (Blizzard/Hailstorm/Tornado) LCD/TV controller.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/bitops.h"
-#include "ui/console.h"
-#include "hw/display/blizzard.h"
-#include "ui/pixel_ops.h"
-
-typedef void (*blizzard_fn_t)(uint8_t *, const uint8_t *, unsigned int);
-
-typedef struct {
- uint8_t reg;
- uint32_t addr;
- int swallow;
-
- int pll;
- int pll_range;
- int pll_ctrl;
- uint8_t pll_mode;
- uint8_t clksel;
- int memenable;
- int memrefresh;
- uint8_t timing[3];
- int priority;
-
- uint8_t lcd_config;
- int x;
- int y;
- int skipx;
- int skipy;
- uint8_t hndp;
- uint8_t vndp;
- uint8_t hsync;
- uint8_t vsync;
- uint8_t pclk;
- uint8_t u;
- uint8_t v;
- uint8_t yrc[2];
- int ix[2];
- int iy[2];
- int ox[2];
- int oy[2];
-
- int enable;
- int blank;
- int bpp;
- int invalidate;
- int mx[2];
- int my[2];
- uint8_t mode;
- uint8_t effect;
- uint8_t iformat;
- uint8_t source;
- QemuConsole *con;
- blizzard_fn_t *line_fn_tab[2];
- void *fb;
-
- uint8_t hssi_config[3];
- uint8_t tv_config;
- uint8_t tv_timing[4];
- uint8_t vbi;
- uint8_t tv_x;
- uint8_t tv_y;
- uint8_t tv_test;
- uint8_t tv_filter_config;
- uint8_t tv_filter_idx;
- uint8_t tv_filter_coeff[0x20];
- uint8_t border_r;
- uint8_t border_g;
- uint8_t border_b;
- uint8_t gamma_config;
- uint8_t gamma_idx;
- uint8_t gamma_lut[0x100];
- uint8_t matrix_ena;
- uint8_t matrix_coeff[0x12];
- uint8_t matrix_r;
- uint8_t matrix_g;
- uint8_t matrix_b;
- uint8_t pm;
- uint8_t status;
- uint8_t rgbgpio_dir;
- uint8_t rgbgpio;
- uint8_t gpio_dir;
- uint8_t gpio;
- uint8_t gpio_edge[2];
- uint8_t gpio_irq;
- uint8_t gpio_pdown;
-
- struct {
- int x;
- int y;
- int dx;
- int dy;
- int len;
- int buflen;
- void *buf;
- void *data;
- uint16_t *ptr;
- int angle;
- int pitch;
- blizzard_fn_t line_fn;
- } data;
-} BlizzardState;
-
-/* Bytes(!) per pixel */
-static const int blizzard_iformat_bpp[0x10] = {
- 0,
- 2, /* RGB 5:6:5*/
- 3, /* RGB 6:6:6 mode 1 */
- 3, /* RGB 8:8:8 mode 1 */
- 0, 0,
- 4, /* RGB 6:6:6 mode 2 */
- 4, /* RGB 8:8:8 mode 2 */
- 0, /* YUV 4:2:2 */
- 0, /* YUV 4:2:0 */
- 0, 0, 0, 0, 0, 0,
-};
-
-static void blizzard_window(BlizzardState *s)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- uint8_t *src, *dst;
- int bypp[2];
- int bypl[3];
- int y;
- blizzard_fn_t fn = s->data.line_fn;
-
- if (!fn)
- return;
- if (s->mx[0] > s->data.x)
- s->mx[0] = s->data.x;
- if (s->my[0] > s->data.y)
- s->my[0] = s->data.y;
- if (s->mx[1] < s->data.x + s->data.dx)
- s->mx[1] = s->data.x + s->data.dx;
- if (s->my[1] < s->data.y + s->data.dy)
- s->my[1] = s->data.y + s->data.dy;
-
- bypp[0] = s->bpp;
- bypp[1] = surface_bytes_per_pixel(surface);
- bypl[0] = bypp[0] * s->data.pitch;
- bypl[1] = bypp[1] * s->x;
- bypl[2] = bypp[0] * s->data.dx;
-
- src = s->data.data;
- dst = s->fb + bypl[1] * s->data.y + bypp[1] * s->data.x;
- for (y = s->data.dy; y > 0; y --, src += bypl[0], dst += bypl[1])
- fn(dst, src, bypl[2]);
-}
-
-static int blizzard_transfer_setup(BlizzardState *s)
-{
- if (s->source > 3 || !s->bpp ||
- s->ix[1] < s->ix[0] || s->iy[1] < s->iy[0])
- return 0;
-
- s->data.angle = s->effect & 3;
- s->data.line_fn = s->line_fn_tab[!!s->data.angle][s->iformat];
- s->data.x = s->ix[0];
- s->data.y = s->iy[0];
- s->data.dx = s->ix[1] - s->ix[0] + 1;
- s->data.dy = s->iy[1] - s->iy[0] + 1;
- s->data.len = s->bpp * s->data.dx * s->data.dy;
- s->data.pitch = s->data.dx;
- if (s->data.len > s->data.buflen) {
- s->data.buf = g_realloc(s->data.buf, s->data.len);
- s->data.buflen = s->data.len;
- }
- s->data.ptr = s->data.buf;
- s->data.data = s->data.buf;
- s->data.len /= 2;
- return 1;
-}
-
-static void blizzard_reset(BlizzardState *s)
-{
- s->reg = 0;
- s->swallow = 0;
-
- s->pll = 9;
- s->pll_range = 1;
- s->pll_ctrl = 0x14;
- s->pll_mode = 0x32;
- s->clksel = 0x00;
- s->memenable = 0;
- s->memrefresh = 0x25c;
- s->timing[0] = 0x3f;
- s->timing[1] = 0x13;
- s->timing[2] = 0x21;
- s->priority = 0;
-
- s->lcd_config = 0x74;
- s->x = 8;
- s->y = 1;
- s->skipx = 0;
- s->skipy = 0;
- s->hndp = 3;
- s->vndp = 2;
- s->hsync = 1;
- s->vsync = 1;
- s->pclk = 0x80;
-
- s->ix[0] = 0;
- s->ix[1] = 0;
- s->iy[0] = 0;
- s->iy[1] = 0;
- s->ox[0] = 0;
- s->ox[1] = 0;
- s->oy[0] = 0;
- s->oy[1] = 0;
-
- s->yrc[0] = 0x00;
- s->yrc[1] = 0x30;
- s->u = 0;
- s->v = 0;
-
- s->iformat = 3;
- s->source = 0;
- s->bpp = blizzard_iformat_bpp[s->iformat];
-
- s->hssi_config[0] = 0x00;
- s->hssi_config[1] = 0x00;
- s->hssi_config[2] = 0x01;
- s->tv_config = 0x00;
- s->tv_timing[0] = 0x00;
- s->tv_timing[1] = 0x00;
- s->tv_timing[2] = 0x00;
- s->tv_timing[3] = 0x00;
- s->vbi = 0x10;
- s->tv_x = 0x14;
- s->tv_y = 0x03;
- s->tv_test = 0x00;
- s->tv_filter_config = 0x80;
- s->tv_filter_idx = 0x00;
- s->border_r = 0x10;
- s->border_g = 0x80;
- s->border_b = 0x80;
- s->gamma_config = 0x00;
- s->gamma_idx = 0x00;
- s->matrix_ena = 0x00;
- memset(&s->matrix_coeff, 0, sizeof(s->matrix_coeff));
- s->matrix_r = 0x00;
- s->matrix_g = 0x00;
- s->matrix_b = 0x00;
- s->pm = 0x02;
- s->status = 0x00;
- s->rgbgpio_dir = 0x00;
- s->gpio_dir = 0x00;
- s->gpio_edge[0] = 0x00;
- s->gpio_edge[1] = 0x00;
- s->gpio_irq = 0x00;
- s->gpio_pdown = 0xff;
-}
-
-static inline void blizzard_invalidate_display(void *opaque) {
- BlizzardState *s = (BlizzardState *) opaque;
-
- s->invalidate = 1;
-}
-
-static uint16_t blizzard_reg_read(void *opaque, uint8_t reg)
-{
- BlizzardState *s = (BlizzardState *) opaque;
-
- switch (reg) {
- case 0x00: /* Revision Code */
- return 0xa5;
-
- case 0x02: /* Configuration Readback */
- return 0x83; /* Macrovision OK, CNF[2:0] = 3 */
-
- case 0x04: /* PLL M-Divider */
- return (s->pll - 1) | (1 << 7);
- case 0x06: /* PLL Lock Range Control */
- return s->pll_range;
- case 0x08: /* PLL Lock Synthesis Control 0 */
- return s->pll_ctrl & 0xff;
- case 0x0a: /* PLL Lock Synthesis Control 1 */
- return s->pll_ctrl >> 8;
- case 0x0c: /* PLL Mode Control 0 */
- return s->pll_mode;
-
- case 0x0e: /* Clock-Source Select */
- return s->clksel;
-
- case 0x10: /* Memory Controller Activate */
- case 0x14: /* Memory Controller Bank 0 Status Flag */
- return s->memenable;
-
- case 0x18: /* Auto-Refresh Interval Setting 0 */
- return s->memrefresh & 0xff;
- case 0x1a: /* Auto-Refresh Interval Setting 1 */
- return s->memrefresh >> 8;
-
- case 0x1c: /* Power-On Sequence Timing Control */
- return s->timing[0];
- case 0x1e: /* Timing Control 0 */
- return s->timing[1];
- case 0x20: /* Timing Control 1 */
- return s->timing[2];
-
- case 0x24: /* Arbitration Priority Control */
- return s->priority;
-
- case 0x28: /* LCD Panel Configuration */
- return s->lcd_config;
-
- case 0x2a: /* LCD Horizontal Display Width */
- return s->x >> 3;
- case 0x2c: /* LCD Horizontal Non-display Period */
- return s->hndp;
- case 0x2e: /* LCD Vertical Display Height 0 */
- return s->y & 0xff;
- case 0x30: /* LCD Vertical Display Height 1 */
- return s->y >> 8;
- case 0x32: /* LCD Vertical Non-display Period */
- return s->vndp;
- case 0x34: /* LCD HS Pulse-width */
- return s->hsync;
- case 0x36: /* LCd HS Pulse Start Position */
- return s->skipx >> 3;
- case 0x38: /* LCD VS Pulse-width */
- return s->vsync;
- case 0x3a: /* LCD VS Pulse Start Position */
- return s->skipy;
-
- case 0x3c: /* PCLK Polarity */
- return s->pclk;
-
- case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */
- return s->hssi_config[0];
- case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */
- return s->hssi_config[1];
- case 0x42: /* High-speed Serial Interface Tx Mode */
- return s->hssi_config[2];
- case 0x44: /* TV Display Configuration */
- return s->tv_config;
- case 0x46 ... 0x4c: /* TV Vertical Blanking Interval Data bits */
- return s->tv_timing[(reg - 0x46) >> 1];
- case 0x4e: /* VBI: Closed Caption / XDS Control / Status */
- return s->vbi;
- case 0x50: /* TV Horizontal Start Position */
- return s->tv_x;
- case 0x52: /* TV Vertical Start Position */
- return s->tv_y;
- case 0x54: /* TV Test Pattern Setting */
- return s->tv_test;
- case 0x56: /* TV Filter Setting */
- return s->tv_filter_config;
- case 0x58: /* TV Filter Coefficient Index */
- return s->tv_filter_idx;
- case 0x5a: /* TV Filter Coefficient Data */
- if (s->tv_filter_idx < 0x20)
- return s->tv_filter_coeff[s->tv_filter_idx ++];
- return 0;
-
- case 0x60: /* Input YUV/RGB Translate Mode 0 */
- return s->yrc[0];
- case 0x62: /* Input YUV/RGB Translate Mode 1 */
- return s->yrc[1];
- case 0x64: /* U Data Fix */
- return s->u;
- case 0x66: /* V Data Fix */
- return s->v;
-
- case 0x68: /* Display Mode */
- return s->mode;
-
- case 0x6a: /* Special Effects */
- return s->effect;
-
- case 0x6c: /* Input Window X Start Position 0 */
- return s->ix[0] & 0xff;
- case 0x6e: /* Input Window X Start Position 1 */
- return s->ix[0] >> 3;
- case 0x70: /* Input Window Y Start Position 0 */
- return s->ix[0] & 0xff;
- case 0x72: /* Input Window Y Start Position 1 */
- return s->ix[0] >> 3;
- case 0x74: /* Input Window X End Position 0 */
- return s->ix[1] & 0xff;
- case 0x76: /* Input Window X End Position 1 */
- return s->ix[1] >> 3;
- case 0x78: /* Input Window Y End Position 0 */
- return s->ix[1] & 0xff;
- case 0x7a: /* Input Window Y End Position 1 */
- return s->ix[1] >> 3;
- case 0x7c: /* Output Window X Start Position 0 */
- return s->ox[0] & 0xff;
- case 0x7e: /* Output Window X Start Position 1 */
- return s->ox[0] >> 3;
- case 0x80: /* Output Window Y Start Position 0 */
- return s->oy[0] & 0xff;
- case 0x82: /* Output Window Y Start Position 1 */
- return s->oy[0] >> 3;
- case 0x84: /* Output Window X End Position 0 */
- return s->ox[1] & 0xff;
- case 0x86: /* Output Window X End Position 1 */
- return s->ox[1] >> 3;
- case 0x88: /* Output Window Y End Position 0 */
- return s->oy[1] & 0xff;
- case 0x8a: /* Output Window Y End Position 1 */
- return s->oy[1] >> 3;
-
- case 0x8c: /* Input Data Format */
- return s->iformat;
- case 0x8e: /* Data Source Select */
- return s->source;
- case 0x90: /* Display Memory Data Port */
- return 0;
-
- case 0xa8: /* Border Color 0 */
- return s->border_r;
- case 0xaa: /* Border Color 1 */
- return s->border_g;
- case 0xac: /* Border Color 2 */
- return s->border_b;
-
- case 0xb4: /* Gamma Correction Enable */
- return s->gamma_config;
- case 0xb6: /* Gamma Correction Table Index */
- return s->gamma_idx;
- case 0xb8: /* Gamma Correction Table Data */
- return s->gamma_lut[s->gamma_idx ++];
-
- case 0xba: /* 3x3 Matrix Enable */
- return s->matrix_ena;
- case 0xbc ... 0xde: /* Coefficient Registers */
- return s->matrix_coeff[(reg - 0xbc) >> 1];
- case 0xe0: /* 3x3 Matrix Red Offset */
- return s->matrix_r;
- case 0xe2: /* 3x3 Matrix Green Offset */
- return s->matrix_g;
- case 0xe4: /* 3x3 Matrix Blue Offset */
- return s->matrix_b;
-
- case 0xe6: /* Power-save */
- return s->pm;
- case 0xe8: /* Non-display Period Control / Status */
- return s->status | (1 << 5);
- case 0xea: /* RGB Interface Control */
- return s->rgbgpio_dir;
- case 0xec: /* RGB Interface Status */
- return s->rgbgpio;
- case 0xee: /* General-purpose IO Pins Configuration */
- return s->gpio_dir;
- case 0xf0: /* General-purpose IO Pins Status / Control */
- return s->gpio;
- case 0xf2: /* GPIO Positive Edge Interrupt Trigger */
- return s->gpio_edge[0];
- case 0xf4: /* GPIO Negative Edge Interrupt Trigger */
- return s->gpio_edge[1];
- case 0xf6: /* GPIO Interrupt Status */
- return s->gpio_irq;
- case 0xf8: /* GPIO Pull-down Control */
- return s->gpio_pdown;
-
- default:
- fprintf(stderr, "%s: unknown register %02x\n", __func__, reg);
- return 0;
- }
-}
-
-static void blizzard_reg_write(void *opaque, uint8_t reg, uint16_t value)
-{
- BlizzardState *s = (BlizzardState *) opaque;
-
- switch (reg) {
- case 0x04: /* PLL M-Divider */
- s->pll = (value & 0x3f) + 1;
- break;
- case 0x06: /* PLL Lock Range Control */
- s->pll_range = value & 3;
- break;
- case 0x08: /* PLL Lock Synthesis Control 0 */
- s->pll_ctrl &= 0xf00;
- s->pll_ctrl |= (value << 0) & 0x0ff;
- break;
- case 0x0a: /* PLL Lock Synthesis Control 1 */
- s->pll_ctrl &= 0x0ff;
- s->pll_ctrl |= (value << 8) & 0xf00;
- break;
- case 0x0c: /* PLL Mode Control 0 */
- s->pll_mode = value & 0x77;
- if ((value & 3) == 0 || (value & 3) == 3)
- fprintf(stderr, "%s: wrong PLL Control bits (%i)\n",
- __func__, value & 3);
- break;
-
- case 0x0e: /* Clock-Source Select */
- s->clksel = value & 0xff;
- break;
-
- case 0x10: /* Memory Controller Activate */
- s->memenable = value & 1;
- break;
- case 0x14: /* Memory Controller Bank 0 Status Flag */
- break;
-
- case 0x18: /* Auto-Refresh Interval Setting 0 */
- s->memrefresh &= 0xf00;
- s->memrefresh |= (value << 0) & 0x0ff;
- break;
- case 0x1a: /* Auto-Refresh Interval Setting 1 */
- s->memrefresh &= 0x0ff;
- s->memrefresh |= (value << 8) & 0xf00;
- break;
-
- case 0x1c: /* Power-On Sequence Timing Control */
- s->timing[0] = value & 0x7f;
- break;
- case 0x1e: /* Timing Control 0 */
- s->timing[1] = value & 0x17;
- break;
- case 0x20: /* Timing Control 1 */
- s->timing[2] = value & 0x35;
- break;
-
- case 0x24: /* Arbitration Priority Control */
- s->priority = value & 1;
- break;
-
- case 0x28: /* LCD Panel Configuration */
- s->lcd_config = value & 0xff;
- if (value & (1 << 7))
- fprintf(stderr, "%s: data swap not supported!\n", __func__);
- break;
-
- case 0x2a: /* LCD Horizontal Display Width */
- s->x = value << 3;
- break;
- case 0x2c: /* LCD Horizontal Non-display Period */
- s->hndp = value & 0xff;
- break;
- case 0x2e: /* LCD Vertical Display Height 0 */
- s->y &= 0x300;
- s->y |= (value << 0) & 0x0ff;
- break;
- case 0x30: /* LCD Vertical Display Height 1 */
- s->y &= 0x0ff;
- s->y |= (value << 8) & 0x300;
- break;
- case 0x32: /* LCD Vertical Non-display Period */
- s->vndp = value & 0xff;
- break;
- case 0x34: /* LCD HS Pulse-width */
- s->hsync = value & 0xff;
- break;
- case 0x36: /* LCD HS Pulse Start Position */
- s->skipx = value & 0xff;
- break;
- case 0x38: /* LCD VS Pulse-width */
- s->vsync = value & 0xbf;
- break;
- case 0x3a: /* LCD VS Pulse Start Position */
- s->skipy = value & 0xff;
- break;
-
- case 0x3c: /* PCLK Polarity */
- s->pclk = value & 0x82;
- /* Affects calculation of s->hndp, s->hsync and s->skipx. */
- break;
-
- case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */
- s->hssi_config[0] = value;
- break;
- case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */
- s->hssi_config[1] = value;
- if (((value >> 4) & 3) == 3)
- fprintf(stderr, "%s: Illegal active-data-links value\n",
- __func__);
- break;
- case 0x42: /* High-speed Serial Interface Tx Mode */
- s->hssi_config[2] = value & 0xbd;
- break;
-
- case 0x44: /* TV Display Configuration */
- s->tv_config = value & 0xfe;
- break;
- case 0x46 ... 0x4c: /* TV Vertical Blanking Interval Data bits 0 */
- s->tv_timing[(reg - 0x46) >> 1] = value;
- break;
- case 0x4e: /* VBI: Closed Caption / XDS Control / Status */
- s->vbi = value;
- break;
- case 0x50: /* TV Horizontal Start Position */
- s->tv_x = value;
- break;
- case 0x52: /* TV Vertical Start Position */
- s->tv_y = value & 0x7f;
- break;
- case 0x54: /* TV Test Pattern Setting */
- s->tv_test = value;
- break;
- case 0x56: /* TV Filter Setting */
- s->tv_filter_config = value & 0xbf;
- break;
- case 0x58: /* TV Filter Coefficient Index */
- s->tv_filter_idx = value & 0x1f;
- break;
- case 0x5a: /* TV Filter Coefficient Data */
- if (s->tv_filter_idx < 0x20)
- s->tv_filter_coeff[s->tv_filter_idx ++] = value;
- break;
-
- case 0x60: /* Input YUV/RGB Translate Mode 0 */
- s->yrc[0] = value & 0xb0;
- break;
- case 0x62: /* Input YUV/RGB Translate Mode 1 */
- s->yrc[1] = value & 0x30;
- break;
- case 0x64: /* U Data Fix */
- s->u = value & 0xff;
- break;
- case 0x66: /* V Data Fix */
- s->v = value & 0xff;
- break;
-
- case 0x68: /* Display Mode */
- if ((s->mode ^ value) & 3)
- s->invalidate = 1;
- s->mode = value & 0xb7;
- s->enable = value & 1;
- s->blank = (value >> 1) & 1;
- if (value & (1 << 4))
- fprintf(stderr, "%s: Macrovision enable attempt!\n", __func__);
- break;
-
- case 0x6a: /* Special Effects */
- s->effect = value & 0xfb;
- break;
-
- case 0x6c: /* Input Window X Start Position 0 */
- s->ix[0] &= 0x300;
- s->ix[0] |= (value << 0) & 0x0ff;
- break;
- case 0x6e: /* Input Window X Start Position 1 */
- s->ix[0] &= 0x0ff;
- s->ix[0] |= (value << 8) & 0x300;
- break;
- case 0x70: /* Input Window Y Start Position 0 */
- s->iy[0] &= 0x300;
- s->iy[0] |= (value << 0) & 0x0ff;
- break;
- case 0x72: /* Input Window Y Start Position 1 */
- s->iy[0] &= 0x0ff;
- s->iy[0] |= (value << 8) & 0x300;
- break;
- case 0x74: /* Input Window X End Position 0 */
- s->ix[1] &= 0x300;
- s->ix[1] |= (value << 0) & 0x0ff;
- break;
- case 0x76: /* Input Window X End Position 1 */
- s->ix[1] &= 0x0ff;
- s->ix[1] |= (value << 8) & 0x300;
- break;
- case 0x78: /* Input Window Y End Position 0 */
- s->iy[1] &= 0x300;
- s->iy[1] |= (value << 0) & 0x0ff;
- break;
- case 0x7a: /* Input Window Y End Position 1 */
- s->iy[1] &= 0x0ff;
- s->iy[1] |= (value << 8) & 0x300;
- break;
- case 0x7c: /* Output Window X Start Position 0 */
- s->ox[0] &= 0x300;
- s->ox[0] |= (value << 0) & 0x0ff;
- break;
- case 0x7e: /* Output Window X Start Position 1 */
- s->ox[0] &= 0x0ff;
- s->ox[0] |= (value << 8) & 0x300;
- break;
- case 0x80: /* Output Window Y Start Position 0 */
- s->oy[0] &= 0x300;
- s->oy[0] |= (value << 0) & 0x0ff;
- break;
- case 0x82: /* Output Window Y Start Position 1 */
- s->oy[0] &= 0x0ff;
- s->oy[0] |= (value << 8) & 0x300;
- break;
- case 0x84: /* Output Window X End Position 0 */
- s->ox[1] &= 0x300;
- s->ox[1] |= (value << 0) & 0x0ff;
- break;
- case 0x86: /* Output Window X End Position 1 */
- s->ox[1] &= 0x0ff;
- s->ox[1] |= (value << 8) & 0x300;
- break;
- case 0x88: /* Output Window Y End Position 0 */
- s->oy[1] &= 0x300;
- s->oy[1] |= (value << 0) & 0x0ff;
- break;
- case 0x8a: /* Output Window Y End Position 1 */
- s->oy[1] &= 0x0ff;
- s->oy[1] |= (value << 8) & 0x300;
- break;
-
- case 0x8c: /* Input Data Format */
- s->iformat = value & 0xf;
- s->bpp = blizzard_iformat_bpp[s->iformat];
- if (!s->bpp)
- fprintf(stderr, "%s: Illegal or unsupported input format %x\n",
- __func__, s->iformat);
- break;
- case 0x8e: /* Data Source Select */
- s->source = value & 7;
- /* Currently all windows will be "destructive overlays". */
- if ((!(s->effect & (1 << 3)) && (s->ix[0] != s->ox[0] ||
- s->iy[0] != s->oy[0] ||
- s->ix[1] != s->ox[1] ||
- s->iy[1] != s->oy[1])) ||
- !((s->ix[1] - s->ix[0]) & (s->iy[1] - s->iy[0]) &
- (s->ox[1] - s->ox[0]) & (s->oy[1] - s->oy[0]) & 1))
- fprintf(stderr, "%s: Illegal input/output window positions\n",
- __func__);
-
- blizzard_transfer_setup(s);
- break;
-
- case 0x90: /* Display Memory Data Port */
- if (!s->data.len && !blizzard_transfer_setup(s))
- break;
-
- *s->data.ptr ++ = value;
- if (-- s->data.len == 0)
- blizzard_window(s);
- break;
-
- case 0xa8: /* Border Color 0 */
- s->border_r = value;
- break;
- case 0xaa: /* Border Color 1 */
- s->border_g = value;
- break;
- case 0xac: /* Border Color 2 */
- s->border_b = value;
- break;
-
- case 0xb4: /* Gamma Correction Enable */
- s->gamma_config = value & 0x87;
- break;
- case 0xb6: /* Gamma Correction Table Index */
- s->gamma_idx = value;
- break;
- case 0xb8: /* Gamma Correction Table Data */
- s->gamma_lut[s->gamma_idx ++] = value;
- break;
-
- case 0xba: /* 3x3 Matrix Enable */
- s->matrix_ena = value & 1;
- break;
- case 0xbc ... 0xde: /* Coefficient Registers */
- s->matrix_coeff[(reg - 0xbc) >> 1] = value & ((reg & 2) ? 0x80 : 0xff);
- break;
- case 0xe0: /* 3x3 Matrix Red Offset */
- s->matrix_r = value;
- break;
- case 0xe2: /* 3x3 Matrix Green Offset */
- s->matrix_g = value;
- break;
- case 0xe4: /* 3x3 Matrix Blue Offset */
- s->matrix_b = value;
- break;
-
- case 0xe6: /* Power-save */
- s->pm = value & 0x83;
- if (value & s->mode & 1)
- fprintf(stderr, "%s: The display must be disabled before entering "
- "Standby Mode\n", __func__);
- break;
- case 0xe8: /* Non-display Period Control / Status */
- s->status = value & 0x1b;
- break;
- case 0xea: /* RGB Interface Control */
- s->rgbgpio_dir = value & 0x8f;
- break;
- case 0xec: /* RGB Interface Status */
- s->rgbgpio = value & 0xcf;
- break;
- case 0xee: /* General-purpose IO Pins Configuration */
- s->gpio_dir = value;
- break;
- case 0xf0: /* General-purpose IO Pins Status / Control */
- s->gpio = value;
- break;
- case 0xf2: /* GPIO Positive Edge Interrupt Trigger */
- s->gpio_edge[0] = value;
- break;
- case 0xf4: /* GPIO Negative Edge Interrupt Trigger */
- s->gpio_edge[1] = value;
- break;
- case 0xf6: /* GPIO Interrupt Status */
- s->gpio_irq &= value;
- break;
- case 0xf8: /* GPIO Pull-down Control */
- s->gpio_pdown = value;
- break;
-
- default:
- fprintf(stderr, "%s: unknown register %02x\n", __func__, reg);
- break;
- }
-}
-
-uint16_t s1d13745_read(void *opaque, int dc)
-{
- BlizzardState *s = (BlizzardState *) opaque;
- uint16_t value = blizzard_reg_read(s, s->reg);
-
- if (s->swallow -- > 0)
- return 0;
- if (dc)
- s->reg ++;
-
- return value;
-}
-
-void s1d13745_write(void *opaque, int dc, uint16_t value)
-{
- BlizzardState *s = (BlizzardState *) opaque;
-
- if (s->swallow -- > 0)
- return;
- if (dc) {
- blizzard_reg_write(s, s->reg, value);
-
- if (s->reg != 0x90 && s->reg != 0x5a && s->reg != 0xb8)
- s->reg += 2;
- } else
- s->reg = value & 0xff;
-}
-
-void s1d13745_write_block(void *opaque, int dc,
- void *buf, size_t len, int pitch)
-{
- BlizzardState *s = (BlizzardState *) opaque;
-
- while (len > 0) {
- if (s->reg == 0x90 && dc &&
- (s->data.len || blizzard_transfer_setup(s)) &&
- len >= (s->data.len << 1)) {
- len -= s->data.len << 1;
- s->data.len = 0;
- s->data.data = buf;
- if (pitch)
- s->data.pitch = pitch;
- blizzard_window(s);
- s->data.data = s->data.buf;
- continue;
- }
-
- s1d13745_write(opaque, dc, *(uint16_t *) buf);
- len -= 2;
- buf += 2;
- }
-}
-
-static void blizzard_update_display(void *opaque)
-{
- BlizzardState *s = (BlizzardState *) opaque;
- DisplaySurface *surface = qemu_console_surface(s->con);
- int y, bypp, bypl, bwidth;
- uint8_t *src, *dst;
-
- if (!s->enable)
- return;
-
- if (s->x != surface_width(surface) || s->y != surface_height(surface)) {
- s->invalidate = 1;
- qemu_console_resize(s->con, s->x, s->y);
- surface = qemu_console_surface(s->con);
- }
-
- if (s->invalidate) {
- s->invalidate = 0;
-
- if (s->blank) {
- bypp = surface_bytes_per_pixel(surface);
- memset(surface_data(surface), 0, bypp * s->x * s->y);
- return;
- }
-
- s->mx[0] = 0;
- s->mx[1] = s->x;
- s->my[0] = 0;
- s->my[1] = s->y;
- }
-
- if (s->mx[1] <= s->mx[0])
- return;
-
- bypp = surface_bytes_per_pixel(surface);
- bypl = bypp * s->x;
- bwidth = bypp * (s->mx[1] - s->mx[0]);
- y = s->my[0];
- src = s->fb + bypl * y + bypp * s->mx[0];
- dst = surface_data(surface) + bypl * y + bypp * s->mx[0];
- for (; y < s->my[1]; y ++, src += bypl, dst += bypl)
- memcpy(dst, src, bwidth);
-
- dpy_gfx_update(s->con, s->mx[0], s->my[0],
- s->mx[1] - s->mx[0], y - s->my[0]);
-
- s->mx[0] = s->x;
- s->mx[1] = 0;
- s->my[0] = s->y;
- s->my[1] = 0;
-}
-
-static void blizzard_draw_line16_32(uint32_t *dest,
- const uint16_t *src, unsigned int width)
-{
- uint16_t data;
- unsigned int r, g, b;
- const uint16_t *end = (const void *) src + width;
- while (src < end) {
- data = *src ++;
- b = extract16(data, 0, 5) << 3;
- g = extract16(data, 5, 6) << 2;
- r = extract16(data, 11, 5) << 3;
- *dest++ = rgb_to_pixel32(r, g, b);
- }
-}
-
-static void blizzard_draw_line24mode1_32(uint32_t *dest,
- const uint8_t *src, unsigned int width)
-{
- /* TODO: check if SDL 24-bit planes are not in the same format and
- * if so, use memcpy */
- unsigned int r[2], g[2], b[2];
- const uint8_t *end = src + width;
- while (src < end) {
- g[0] = *src ++;
- r[0] = *src ++;
- r[1] = *src ++;
- b[0] = *src ++;
- *dest++ = rgb_to_pixel32(r[0], g[0], b[0]);
- b[1] = *src ++;
- g[1] = *src ++;
- *dest++ = rgb_to_pixel32(r[1], g[1], b[1]);
- }
-}
-
-static void blizzard_draw_line24mode2_32(uint32_t *dest,
- const uint8_t *src, unsigned int width)
-{
- unsigned int r, g, b;
- const uint8_t *end = src + width;
- while (src < end) {
- r = *src ++;
- src ++;
- b = *src ++;
- g = *src ++;
- *dest++ = rgb_to_pixel32(r, g, b);
- }
-}
-
-/* No rotation */
-static blizzard_fn_t blizzard_draw_fn_32[0x10] = {
- NULL,
- /* RGB 5:6:5*/
- (blizzard_fn_t) blizzard_draw_line16_32,
- /* RGB 6:6:6 mode 1 */
- (blizzard_fn_t) blizzard_draw_line24mode1_32,
- /* RGB 8:8:8 mode 1 */
- (blizzard_fn_t) blizzard_draw_line24mode1_32,
- NULL, NULL,
- /* RGB 6:6:6 mode 2 */
- (blizzard_fn_t) blizzard_draw_line24mode2_32,
- /* RGB 8:8:8 mode 2 */
- (blizzard_fn_t) blizzard_draw_line24mode2_32,
- /* YUV 4:2:2 */
- NULL,
- /* YUV 4:2:0 */
- NULL,
- NULL, NULL, NULL, NULL, NULL, NULL,
-};
-
-/* 90deg, 180deg and 270deg rotation */
-static blizzard_fn_t blizzard_draw_fn_r_32[0x10] = {
- /* TODO */
- [0 ... 0xf] = NULL,
-};
-
-static const GraphicHwOps blizzard_ops = {
- .invalidate = blizzard_invalidate_display,
- .gfx_update = blizzard_update_display,
-};
-
-void *s1d13745_init(qemu_irq gpio_int)
-{
- BlizzardState *s = g_malloc0(sizeof(*s));
- DisplaySurface *surface;
-
- s->fb = g_malloc(0x180000);
-
- s->con = graphic_console_init(NULL, 0, &blizzard_ops, s);
- surface = qemu_console_surface(s->con);
-
- assert(surface_bits_per_pixel(surface) == 32);
-
- s->line_fn_tab[0] = blizzard_draw_fn_32;
- s->line_fn_tab[1] = blizzard_draw_fn_r_32;
-
- blizzard_reset(s);
-
- return s;
-}
diff --git a/hw/display/cg3.c b/hw/display/cg3.c
index b271faa..95f8f98 100644
--- a/hw/display/cg3.c
+++ b/hw/display/cg3.c
@@ -374,7 +374,7 @@ static void cg3_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = cg3_realizefn;
- dc->reset = cg3_reset;
+ device_class_set_legacy_reset(dc, cg3_reset);
dc->vmsd = &vmstate_cg3;
device_class_set_props(dc, cg3_properties);
}
diff --git a/hw/display/dm163.c b/hw/display/dm163.c
index f92aee3..75a91f6 100644
--- a/hw/display/dm163.c
+++ b/hw/display/dm163.c
@@ -271,7 +271,7 @@ static uint32_t *update_display_of_row(DM163State *s, uint32_t *dest,
unsigned row)
{
for (unsigned _ = 0; _ < LED_SQUARE_SIZE; _++) {
- for (int x = 0; x < RGB_MATRIX_NUM_COLS * LED_SQUARE_SIZE; x++) {
+ for (int x = RGB_MATRIX_NUM_COLS * LED_SQUARE_SIZE - 1; x >= 0; x--) {
/* UI layer guarantees that there's 32 bits per pixel (Mar 2024) */
*dest++ = s->buffer[s->buffer_idx_of_row[row]][x / LED_SQUARE_SIZE];
}
diff --git a/hw/display/dpcd.c b/hw/display/dpcd.c
index aab1b1a..108faf7 100644
--- a/hw/display/dpcd.c
+++ b/hw/display/dpcd.c
@@ -145,7 +145,7 @@ static void dpcd_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
- dc->reset = dpcd_reset;
+ device_class_set_legacy_reset(dc, dpcd_reset);
dc->vmsd = &vmstate_dpcd;
}
diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c
index 5712558..f3d8249 100644
--- a/hw/display/exynos4210_fimd.c
+++ b/hw/display/exynos4210_fimd.c
@@ -1964,7 +1964,7 @@ static void exynos4210_fimd_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &exynos4210_fimd_vmstate;
- dc->reset = exynos4210_fimd_reset;
+ device_class_set_legacy_reset(dc, exynos4210_fimd_reset);
dc->realize = exynos4210_fimd_realize;
device_class_set_props(dc, exynos4210_fimd_properties);
}
diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c
index e08ec3f..fa2f184 100644
--- a/hw/display/g364fb.c
+++ b/hw/display/g364fb.c
@@ -534,7 +534,7 @@ static void g364fb_sysbus_class_init(ObjectClass *klass, void *data)
dc->realize = g364fb_sysbus_realize;
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
dc->desc = "G364 framebuffer";
- dc->reset = g364fb_sysbus_reset;
+ device_class_set_legacy_reset(dc, g364fb_sysbus_reset);
dc->vmsd = &vmstate_g364fb_sysbus;
device_class_set_props(dc, g364fb_sysbus_properties);
}
diff --git a/hw/display/i2c-ddc.c b/hw/display/i2c-ddc.c
index 3f9d1e1..465b003 100644
--- a/hw/display/i2c-ddc.c
+++ b/hw/display/i2c-ddc.c
@@ -105,7 +105,7 @@ static void i2c_ddc_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
I2CSlaveClass *isc = I2C_SLAVE_CLASS(oc);
- dc->reset = i2c_ddc_reset;
+ device_class_set_legacy_reset(dc, i2c_ddc_reset);
dc->vmsd = &vmstate_i2c_ddc;
device_class_set_props(dc, i2c_ddc_properties);
isc->event = i2c_ddc_event;
diff --git a/hw/display/jazz_led.c b/hw/display/jazz_led.c
index 534f15d..1448488 100644
--- a/hw/display/jazz_led.c
+++ b/hw/display/jazz_led.c
@@ -300,7 +300,7 @@ static void jazz_led_class_init(ObjectClass *klass, void *data)
dc->desc = "Jazz LED display",
dc->vmsd = &vmstate_jazz_led;
- dc->reset = jazz_led_reset;
+ device_class_set_legacy_reset(dc, jazz_led_reset);
dc->realize = jazz_led_realize;
}
diff --git a/hw/display/macfb.c b/hw/display/macfb.c
index 1ace341..a5b4a49 100644
--- a/hw/display/macfb.c
+++ b/hw/display/macfb.c
@@ -802,7 +802,7 @@ static void macfb_sysbus_class_init(ObjectClass *klass, void *data)
dc->realize = macfb_sysbus_realize;
dc->desc = "SysBus Macintosh framebuffer";
- dc->reset = macfb_sysbus_reset;
+ device_class_set_legacy_reset(dc, macfb_sysbus_reset);
dc->vmsd = &vmstate_macfb_sysbus;
device_class_set_props(dc, macfb_sysbus_properties);
}
@@ -817,7 +817,7 @@ static void macfb_nubus_class_init(ObjectClass *klass, void *data)
device_class_set_parent_unrealize(dc, macfb_nubus_unrealize,
&ndc->parent_unrealize);
dc->desc = "Nubus Macintosh framebuffer";
- dc->reset = macfb_nubus_reset;
+ device_class_set_legacy_reset(dc, macfb_nubus_reset);
dc->vmsd = &vmstate_macfb_nubus;
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
device_class_set_props(dc, macfb_nubus_properties);
diff --git a/hw/display/meson.build b/hw/display/meson.build
index 7db05ea..20a9497 100644
--- a/hw/display/meson.build
+++ b/hw/display/meson.build
@@ -22,13 +22,9 @@ system_ss.add(when: 'CONFIG_VGA_MMIO', if_true: files('vga-mmio.c'))
system_ss.add(when: 'CONFIG_VMWARE_VGA', if_true: files('vmware_vga.c'))
system_ss.add(when: 'CONFIG_BOCHS_DISPLAY', if_true: files('bochs-display.c'))
-system_ss.add(when: 'CONFIG_BLIZZARD', if_true: files('blizzard.c'))
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_fimd.c'))
system_ss.add(when: 'CONFIG_FRAMEBUFFER', if_true: files('framebuffer.c'))
-system_ss.add(when: 'CONFIG_ZAURUS', if_true: files('tc6393xb.c'))
-system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_dss.c'))
-system_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_lcd.c'))
system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_fb.c'))
system_ss.add(when: 'CONFIG_SM501', if_true: files('sm501.c'))
system_ss.add(when: 'CONFIG_TCX', if_true: files('tcx.c'))
diff --git a/hw/display/omap_dss.c b/hw/display/omap_dss.c
deleted file mode 100644
index f33fc76..0000000
--- a/hw/display/omap_dss.c
+++ /dev/null
@@ -1,1093 +0,0 @@
-/*
- * OMAP2 Display Subsystem.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/log.h"
-#include "hw/hw.h"
-#include "hw/irq.h"
-#include "ui/console.h"
-#include "hw/arm/omap.h"
-
-struct omap_dss_s {
- qemu_irq irq;
- qemu_irq drq;
- DisplayState *state;
- MemoryRegion iomem_diss1, iomem_disc1, iomem_rfbi1, iomem_venc1, iomem_im3;
-
- int autoidle;
- int control;
- int enable;
-
- struct omap_dss_panel_s {
- int enable;
- int nx;
- int ny;
-
- int x;
- int y;
- } dig, lcd;
-
- struct {
- uint32_t idlemode;
- uint32_t irqst;
- uint32_t irqen;
- uint32_t control;
- uint32_t config;
- uint32_t capable;
- uint32_t timing[4];
- int line;
- uint32_t bg[2];
- uint32_t trans[2];
-
- struct omap_dss_plane_s {
- int enable;
- int bpp;
- int posx;
- int posy;
- int nx;
- int ny;
-
- hwaddr addr[3];
-
- uint32_t attr;
- uint32_t tresh;
- int rowinc;
- int colinc;
- int wininc;
- } l[3];
-
- int invalidate;
- uint16_t palette[256];
- } dispc;
-
- struct {
- int idlemode;
- uint32_t control;
- int enable;
- int pixels;
- int busy;
- int skiplines;
- uint16_t rxbuf;
- uint32_t config[2];
- uint32_t time[4];
- uint32_t data[6];
- uint16_t vsync;
- uint16_t hsync;
- struct rfbi_chip_s *chip[2];
- } rfbi;
-};
-
-static void omap_dispc_interrupt_update(struct omap_dss_s *s)
-{
- qemu_set_irq(s->irq, s->dispc.irqst & s->dispc.irqen);
-}
-
-static void omap_rfbi_reset(struct omap_dss_s *s)
-{
- s->rfbi.idlemode = 0;
- s->rfbi.control = 2;
- s->rfbi.enable = 0;
- s->rfbi.pixels = 0;
- s->rfbi.skiplines = 0;
- s->rfbi.busy = 0;
- s->rfbi.config[0] = 0x00310000;
- s->rfbi.config[1] = 0x00310000;
- s->rfbi.time[0] = 0;
- s->rfbi.time[1] = 0;
- s->rfbi.time[2] = 0;
- s->rfbi.time[3] = 0;
- s->rfbi.data[0] = 0;
- s->rfbi.data[1] = 0;
- s->rfbi.data[2] = 0;
- s->rfbi.data[3] = 0;
- s->rfbi.data[4] = 0;
- s->rfbi.data[5] = 0;
- s->rfbi.vsync = 0;
- s->rfbi.hsync = 0;
-}
-
-void omap_dss_reset(struct omap_dss_s *s)
-{
- s->autoidle = 0;
- s->control = 0;
- s->enable = 0;
-
- s->dig.enable = 0;
- s->dig.nx = 1;
- s->dig.ny = 1;
-
- s->lcd.enable = 0;
- s->lcd.nx = 1;
- s->lcd.ny = 1;
-
- s->dispc.idlemode = 0;
- s->dispc.irqst = 0;
- s->dispc.irqen = 0;
- s->dispc.control = 0;
- s->dispc.config = 0;
- s->dispc.capable = 0x161;
- s->dispc.timing[0] = 0;
- s->dispc.timing[1] = 0;
- s->dispc.timing[2] = 0;
- s->dispc.timing[3] = 0;
- s->dispc.line = 0;
- s->dispc.bg[0] = 0;
- s->dispc.bg[1] = 0;
- s->dispc.trans[0] = 0;
- s->dispc.trans[1] = 0;
-
- s->dispc.l[0].enable = 0;
- s->dispc.l[0].bpp = 0;
- s->dispc.l[0].addr[0] = 0;
- s->dispc.l[0].addr[1] = 0;
- s->dispc.l[0].addr[2] = 0;
- s->dispc.l[0].posx = 0;
- s->dispc.l[0].posy = 0;
- s->dispc.l[0].nx = 1;
- s->dispc.l[0].ny = 1;
- s->dispc.l[0].attr = 0;
- s->dispc.l[0].tresh = 0;
- s->dispc.l[0].rowinc = 1;
- s->dispc.l[0].colinc = 1;
- s->dispc.l[0].wininc = 0;
-
- omap_rfbi_reset(s);
- omap_dispc_interrupt_update(s);
-}
-
-static uint64_t omap_diss_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_dss_s *s = opaque;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* DSS_REVISIONNUMBER */
- return 0x20;
-
- case 0x10: /* DSS_SYSCONFIG */
- return s->autoidle;
-
- case 0x14: /* DSS_SYSSTATUS */
- return 1; /* RESETDONE */
-
- case 0x40: /* DSS_CONTROL */
- return s->control;
-
- case 0x50: /* DSS_PSA_LCD_REG_1 */
- case 0x54: /* DSS_PSA_LCD_REG_2 */
- case 0x58: /* DSS_PSA_VIDEO_REG */
- /* TODO: fake some values when appropriate s->control bits are set */
- return 0;
-
- case 0x5c: /* DSS_STATUS */
- return 1 + (s->control & 1);
-
- default:
- break;
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_diss_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_dss_s *s = opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* DSS_REVISIONNUMBER */
- case 0x14: /* DSS_SYSSTATUS */
- case 0x50: /* DSS_PSA_LCD_REG_1 */
- case 0x54: /* DSS_PSA_LCD_REG_2 */
- case 0x58: /* DSS_PSA_VIDEO_REG */
- case 0x5c: /* DSS_STATUS */
- OMAP_RO_REG(addr);
- break;
-
- case 0x10: /* DSS_SYSCONFIG */
- if (value & 2) /* SOFTRESET */
- omap_dss_reset(s);
- s->autoidle = value & 1;
- break;
-
- case 0x40: /* DSS_CONTROL */
- s->control = value & 0x3dd;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_diss_ops = {
- .read = omap_diss_read,
- .write = omap_diss_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t omap_disc_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_dss_s *s = opaque;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x000: /* DISPC_REVISION */
- return 0x20;
-
- case 0x010: /* DISPC_SYSCONFIG */
- return s->dispc.idlemode;
-
- case 0x014: /* DISPC_SYSSTATUS */
- return 1; /* RESETDONE */
-
- case 0x018: /* DISPC_IRQSTATUS */
- return s->dispc.irqst;
-
- case 0x01c: /* DISPC_IRQENABLE */
- return s->dispc.irqen;
-
- case 0x040: /* DISPC_CONTROL */
- return s->dispc.control;
-
- case 0x044: /* DISPC_CONFIG */
- return s->dispc.config;
-
- case 0x048: /* DISPC_CAPABLE */
- return s->dispc.capable;
-
- case 0x04c: /* DISPC_DEFAULT_COLOR0 */
- return s->dispc.bg[0];
- case 0x050: /* DISPC_DEFAULT_COLOR1 */
- return s->dispc.bg[1];
- case 0x054: /* DISPC_TRANS_COLOR0 */
- return s->dispc.trans[0];
- case 0x058: /* DISPC_TRANS_COLOR1 */
- return s->dispc.trans[1];
-
- case 0x05c: /* DISPC_LINE_STATUS */
- return 0x7ff;
- case 0x060: /* DISPC_LINE_NUMBER */
- return s->dispc.line;
-
- case 0x064: /* DISPC_TIMING_H */
- return s->dispc.timing[0];
- case 0x068: /* DISPC_TIMING_V */
- return s->dispc.timing[1];
- case 0x06c: /* DISPC_POL_FREQ */
- return s->dispc.timing[2];
- case 0x070: /* DISPC_DIVISOR */
- return s->dispc.timing[3];
-
- case 0x078: /* DISPC_SIZE_DIG */
- return ((s->dig.ny - 1) << 16) | (s->dig.nx - 1);
- case 0x07c: /* DISPC_SIZE_LCD */
- return ((s->lcd.ny - 1) << 16) | (s->lcd.nx - 1);
-
- case 0x080: /* DISPC_GFX_BA0 */
- return s->dispc.l[0].addr[0];
- case 0x084: /* DISPC_GFX_BA1 */
- return s->dispc.l[0].addr[1];
- case 0x088: /* DISPC_GFX_POSITION */
- return (s->dispc.l[0].posy << 16) | s->dispc.l[0].posx;
- case 0x08c: /* DISPC_GFX_SIZE */
- return ((s->dispc.l[0].ny - 1) << 16) | (s->dispc.l[0].nx - 1);
- case 0x0a0: /* DISPC_GFX_ATTRIBUTES */
- return s->dispc.l[0].attr;
- case 0x0a4: /* DISPC_GFX_FIFO_TRESHOLD */
- return s->dispc.l[0].tresh;
- case 0x0a8: /* DISPC_GFX_FIFO_SIZE_STATUS */
- return 256;
- case 0x0ac: /* DISPC_GFX_ROW_INC */
- return s->dispc.l[0].rowinc;
- case 0x0b0: /* DISPC_GFX_PIXEL_INC */
- return s->dispc.l[0].colinc;
- case 0x0b4: /* DISPC_GFX_WINDOW_SKIP */
- return s->dispc.l[0].wininc;
- case 0x0b8: /* DISPC_GFX_TABLE_BA */
- return s->dispc.l[0].addr[2];
-
- case 0x0bc: /* DISPC_VID1_BA0 */
- case 0x0c0: /* DISPC_VID1_BA1 */
- case 0x0c4: /* DISPC_VID1_POSITION */
- case 0x0c8: /* DISPC_VID1_SIZE */
- case 0x0cc: /* DISPC_VID1_ATTRIBUTES */
- case 0x0d0: /* DISPC_VID1_FIFO_TRESHOLD */
- case 0x0d4: /* DISPC_VID1_FIFO_SIZE_STATUS */
- case 0x0d8: /* DISPC_VID1_ROW_INC */
- case 0x0dc: /* DISPC_VID1_PIXEL_INC */
- case 0x0e0: /* DISPC_VID1_FIR */
- case 0x0e4: /* DISPC_VID1_PICTURE_SIZE */
- case 0x0e8: /* DISPC_VID1_ACCU0 */
- case 0x0ec: /* DISPC_VID1_ACCU1 */
- case 0x0f0 ... 0x140: /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
- case 0x14c: /* DISPC_VID2_BA0 */
- case 0x150: /* DISPC_VID2_BA1 */
- case 0x154: /* DISPC_VID2_POSITION */
- case 0x158: /* DISPC_VID2_SIZE */
- case 0x15c: /* DISPC_VID2_ATTRIBUTES */
- case 0x160: /* DISPC_VID2_FIFO_TRESHOLD */
- case 0x164: /* DISPC_VID2_FIFO_SIZE_STATUS */
- case 0x168: /* DISPC_VID2_ROW_INC */
- case 0x16c: /* DISPC_VID2_PIXEL_INC */
- case 0x170: /* DISPC_VID2_FIR */
- case 0x174: /* DISPC_VID2_PICTURE_SIZE */
- case 0x178: /* DISPC_VID2_ACCU0 */
- case 0x17c: /* DISPC_VID2_ACCU1 */
- case 0x180 ... 0x1d0: /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
- case 0x1d4: /* DISPC_DATA_CYCLE1 */
- case 0x1d8: /* DISPC_DATA_CYCLE2 */
- case 0x1dc: /* DISPC_DATA_CYCLE3 */
- return 0;
-
- default:
- break;
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_disc_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_dss_s *s = opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x010: /* DISPC_SYSCONFIG */
- if (value & 2) /* SOFTRESET */
- omap_dss_reset(s);
- s->dispc.idlemode = value & 0x301b;
- break;
-
- case 0x018: /* DISPC_IRQSTATUS */
- s->dispc.irqst &= ~value;
- omap_dispc_interrupt_update(s);
- break;
-
- case 0x01c: /* DISPC_IRQENABLE */
- s->dispc.irqen = value & 0xffff;
- omap_dispc_interrupt_update(s);
- break;
-
- case 0x040: /* DISPC_CONTROL */
- s->dispc.control = value & 0x07ff9fff;
- s->dig.enable = (value >> 1) & 1;
- s->lcd.enable = (value >> 0) & 1;
- if (value & (1 << 12)) /* OVERLAY_OPTIMIZATION */
- if (!((s->dispc.l[1].attr | s->dispc.l[2].attr) & 1)) {
- fprintf(stderr, "%s: Overlay Optimization when no overlay "
- "region effectively exists leads to "
- "unpredictable behaviour!\n", __func__);
- }
- if (value & (1 << 6)) { /* GODIGITAL */
- /* XXX: Shadowed fields are:
- * s->dispc.config
- * s->dispc.capable
- * s->dispc.bg[0]
- * s->dispc.bg[1]
- * s->dispc.trans[0]
- * s->dispc.trans[1]
- * s->dispc.line
- * s->dispc.timing[0]
- * s->dispc.timing[1]
- * s->dispc.timing[2]
- * s->dispc.timing[3]
- * s->lcd.nx
- * s->lcd.ny
- * s->dig.nx
- * s->dig.ny
- * s->dispc.l[0].addr[0]
- * s->dispc.l[0].addr[1]
- * s->dispc.l[0].addr[2]
- * s->dispc.l[0].posx
- * s->dispc.l[0].posy
- * s->dispc.l[0].nx
- * s->dispc.l[0].ny
- * s->dispc.l[0].tresh
- * s->dispc.l[0].rowinc
- * s->dispc.l[0].colinc
- * s->dispc.l[0].wininc
- * All they need to be loaded here from their shadow registers.
- */
- }
- if (value & (1 << 5)) { /* GOLCD */
- /* XXX: Likewise for LCD here. */
- }
- s->dispc.invalidate = 1;
- break;
-
- case 0x044: /* DISPC_CONFIG */
- s->dispc.config = value & 0x3fff;
- /* XXX:
- * bits 2:1 (LOADMODE) reset to 0 after set to 1 and palette loaded
- * bits 2:1 (LOADMODE) reset to 2 after set to 3 and palette loaded
- */
- s->dispc.invalidate = 1;
- break;
-
- case 0x048: /* DISPC_CAPABLE */
- s->dispc.capable = value & 0x3ff;
- break;
-
- case 0x04c: /* DISPC_DEFAULT_COLOR0 */
- s->dispc.bg[0] = value & 0xffffff;
- s->dispc.invalidate = 1;
- break;
- case 0x050: /* DISPC_DEFAULT_COLOR1 */
- s->dispc.bg[1] = value & 0xffffff;
- s->dispc.invalidate = 1;
- break;
- case 0x054: /* DISPC_TRANS_COLOR0 */
- s->dispc.trans[0] = value & 0xffffff;
- s->dispc.invalidate = 1;
- break;
- case 0x058: /* DISPC_TRANS_COLOR1 */
- s->dispc.trans[1] = value & 0xffffff;
- s->dispc.invalidate = 1;
- break;
-
- case 0x060: /* DISPC_LINE_NUMBER */
- s->dispc.line = value & 0x7ff;
- break;
-
- case 0x064: /* DISPC_TIMING_H */
- s->dispc.timing[0] = value & 0x0ff0ff3f;
- break;
- case 0x068: /* DISPC_TIMING_V */
- s->dispc.timing[1] = value & 0x0ff0ff3f;
- break;
- case 0x06c: /* DISPC_POL_FREQ */
- s->dispc.timing[2] = value & 0x0003ffff;
- break;
- case 0x070: /* DISPC_DIVISOR */
- s->dispc.timing[3] = value & 0x00ff00ff;
- break;
-
- case 0x078: /* DISPC_SIZE_DIG */
- s->dig.nx = ((value >> 0) & 0x7ff) + 1; /* PPL */
- s->dig.ny = ((value >> 16) & 0x7ff) + 1; /* LPP */
- s->dispc.invalidate = 1;
- break;
- case 0x07c: /* DISPC_SIZE_LCD */
- s->lcd.nx = ((value >> 0) & 0x7ff) + 1; /* PPL */
- s->lcd.ny = ((value >> 16) & 0x7ff) + 1; /* LPP */
- s->dispc.invalidate = 1;
- break;
- case 0x080: /* DISPC_GFX_BA0 */
- s->dispc.l[0].addr[0] = (hwaddr) value;
- s->dispc.invalidate = 1;
- break;
- case 0x084: /* DISPC_GFX_BA1 */
- s->dispc.l[0].addr[1] = (hwaddr) value;
- s->dispc.invalidate = 1;
- break;
- case 0x088: /* DISPC_GFX_POSITION */
- s->dispc.l[0].posx = ((value >> 0) & 0x7ff); /* GFXPOSX */
- s->dispc.l[0].posy = ((value >> 16) & 0x7ff); /* GFXPOSY */
- s->dispc.invalidate = 1;
- break;
- case 0x08c: /* DISPC_GFX_SIZE */
- s->dispc.l[0].nx = ((value >> 0) & 0x7ff) + 1; /* GFXSIZEX */
- s->dispc.l[0].ny = ((value >> 16) & 0x7ff) + 1; /* GFXSIZEY */
- s->dispc.invalidate = 1;
- break;
- case 0x0a0: /* DISPC_GFX_ATTRIBUTES */
- s->dispc.l[0].attr = value & 0x7ff;
- if (value & (3 << 9))
- fprintf(stderr, "%s: Big-endian pixel format not supported\n",
- __func__);
- s->dispc.l[0].enable = value & 1;
- s->dispc.l[0].bpp = (value >> 1) & 0xf;
- s->dispc.invalidate = 1;
- break;
- case 0x0a4: /* DISPC_GFX_FIFO_TRESHOLD */
- s->dispc.l[0].tresh = value & 0x01ff01ff;
- break;
- case 0x0ac: /* DISPC_GFX_ROW_INC */
- s->dispc.l[0].rowinc = value;
- s->dispc.invalidate = 1;
- break;
- case 0x0b0: /* DISPC_GFX_PIXEL_INC */
- s->dispc.l[0].colinc = value;
- s->dispc.invalidate = 1;
- break;
- case 0x0b4: /* DISPC_GFX_WINDOW_SKIP */
- s->dispc.l[0].wininc = value;
- break;
- case 0x0b8: /* DISPC_GFX_TABLE_BA */
- s->dispc.l[0].addr[2] = (hwaddr) value;
- s->dispc.invalidate = 1;
- break;
-
- case 0x0bc: /* DISPC_VID1_BA0 */
- case 0x0c0: /* DISPC_VID1_BA1 */
- case 0x0c4: /* DISPC_VID1_POSITION */
- case 0x0c8: /* DISPC_VID1_SIZE */
- case 0x0cc: /* DISPC_VID1_ATTRIBUTES */
- case 0x0d0: /* DISPC_VID1_FIFO_TRESHOLD */
- case 0x0d8: /* DISPC_VID1_ROW_INC */
- case 0x0dc: /* DISPC_VID1_PIXEL_INC */
- case 0x0e0: /* DISPC_VID1_FIR */
- case 0x0e4: /* DISPC_VID1_PICTURE_SIZE */
- case 0x0e8: /* DISPC_VID1_ACCU0 */
- case 0x0ec: /* DISPC_VID1_ACCU1 */
- case 0x0f0 ... 0x140: /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
- case 0x14c: /* DISPC_VID2_BA0 */
- case 0x150: /* DISPC_VID2_BA1 */
- case 0x154: /* DISPC_VID2_POSITION */
- case 0x158: /* DISPC_VID2_SIZE */
- case 0x15c: /* DISPC_VID2_ATTRIBUTES */
- case 0x160: /* DISPC_VID2_FIFO_TRESHOLD */
- case 0x168: /* DISPC_VID2_ROW_INC */
- case 0x16c: /* DISPC_VID2_PIXEL_INC */
- case 0x170: /* DISPC_VID2_FIR */
- case 0x174: /* DISPC_VID2_PICTURE_SIZE */
- case 0x178: /* DISPC_VID2_ACCU0 */
- case 0x17c: /* DISPC_VID2_ACCU1 */
- case 0x180 ... 0x1d0: /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
- case 0x1d4: /* DISPC_DATA_CYCLE1 */
- case 0x1d8: /* DISPC_DATA_CYCLE2 */
- case 0x1dc: /* DISPC_DATA_CYCLE3 */
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_disc_ops = {
- .read = omap_disc_read,
- .write = omap_disc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_rfbi_transfer_stop(struct omap_dss_s *s)
-{
- if (!s->rfbi.busy)
- return;
-
- /* TODO: in non-Bypass mode we probably need to just deassert the DRQ. */
-
- s->rfbi.busy = 0;
-}
-
-static void omap_rfbi_transfer_start(struct omap_dss_s *s)
-{
- void *data;
- hwaddr len;
- hwaddr data_addr;
- int pitch;
- static void *bounce_buffer;
- static hwaddr bounce_len;
-
- if (!s->rfbi.enable || s->rfbi.busy)
- return;
-
- if (s->rfbi.control & (1 << 1)) { /* BYPASS */
- /* TODO: in non-Bypass mode we probably need to just assert the
- * DRQ and wait for DMA to write the pixels. */
- qemu_log_mask(LOG_UNIMP, "%s: Bypass mode unimplemented\n", __func__);
- return;
- }
-
- if (!(s->dispc.control & (1 << 11))) /* RFBIMODE */
- return;
- /* TODO: check that LCD output is enabled in DISPC. */
-
- s->rfbi.busy = 1;
-
- len = s->rfbi.pixels * 2;
-
- data_addr = s->dispc.l[0].addr[0];
- data = cpu_physical_memory_map(data_addr, &len, false);
- if (data && len != s->rfbi.pixels * 2) {
- cpu_physical_memory_unmap(data, len, 0, 0);
- data = NULL;
- len = s->rfbi.pixels * 2;
- }
- if (!data) {
- if (len > bounce_len) {
- bounce_buffer = g_realloc(bounce_buffer, len);
- }
- data = bounce_buffer;
- cpu_physical_memory_read(data_addr, data, len);
- }
-
- /* TODO bpp */
- s->rfbi.pixels = 0;
-
- /* TODO: negative values */
- pitch = s->dispc.l[0].nx + (s->dispc.l[0].rowinc - 1) / 2;
-
- if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
- s->rfbi.chip[0]->block(s->rfbi.chip[0]->opaque, 1, data, len, pitch);
- if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
- s->rfbi.chip[1]->block(s->rfbi.chip[1]->opaque, 1, data, len, pitch);
-
- if (data != bounce_buffer) {
- cpu_physical_memory_unmap(data, len, 0, len);
- }
-
- omap_rfbi_transfer_stop(s);
-
- /* TODO */
- s->dispc.irqst |= 1; /* FRAMEDONE */
- omap_dispc_interrupt_update(s);
-}
-
-static uint64_t omap_rfbi_read(void *opaque, hwaddr addr, unsigned size)
-{
- struct omap_dss_s *s = opaque;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* RFBI_REVISION */
- return 0x10;
-
- case 0x10: /* RFBI_SYSCONFIG */
- return s->rfbi.idlemode;
-
- case 0x14: /* RFBI_SYSSTATUS */
- return 1 | (s->rfbi.busy << 8); /* RESETDONE */
-
- case 0x40: /* RFBI_CONTROL */
- return s->rfbi.control;
-
- case 0x44: /* RFBI_PIXELCNT */
- return s->rfbi.pixels;
-
- case 0x48: /* RFBI_LINE_NUMBER */
- return s->rfbi.skiplines;
-
- case 0x58: /* RFBI_READ */
- case 0x5c: /* RFBI_STATUS */
- return s->rfbi.rxbuf;
-
- case 0x60: /* RFBI_CONFIG0 */
- return s->rfbi.config[0];
- case 0x64: /* RFBI_ONOFF_TIME0 */
- return s->rfbi.time[0];
- case 0x68: /* RFBI_CYCLE_TIME0 */
- return s->rfbi.time[1];
- case 0x6c: /* RFBI_DATA_CYCLE1_0 */
- return s->rfbi.data[0];
- case 0x70: /* RFBI_DATA_CYCLE2_0 */
- return s->rfbi.data[1];
- case 0x74: /* RFBI_DATA_CYCLE3_0 */
- return s->rfbi.data[2];
-
- case 0x78: /* RFBI_CONFIG1 */
- return s->rfbi.config[1];
- case 0x7c: /* RFBI_ONOFF_TIME1 */
- return s->rfbi.time[2];
- case 0x80: /* RFBI_CYCLE_TIME1 */
- return s->rfbi.time[3];
- case 0x84: /* RFBI_DATA_CYCLE1_1 */
- return s->rfbi.data[3];
- case 0x88: /* RFBI_DATA_CYCLE2_1 */
- return s->rfbi.data[4];
- case 0x8c: /* RFBI_DATA_CYCLE3_1 */
- return s->rfbi.data[5];
-
- case 0x90: /* RFBI_VSYNC_WIDTH */
- return s->rfbi.vsync;
- case 0x94: /* RFBI_HSYNC_WIDTH */
- return s->rfbi.hsync;
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_rfbi_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_dss_s *s = opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x10: /* RFBI_SYSCONFIG */
- if (value & 2) /* SOFTRESET */
- omap_rfbi_reset(s);
- s->rfbi.idlemode = value & 0x19;
- break;
-
- case 0x40: /* RFBI_CONTROL */
- s->rfbi.control = value & 0xf;
- s->rfbi.enable = value & 1;
- if (value & (1 << 4) && /* ITE */
- !(s->rfbi.config[0] & s->rfbi.config[1] & 0xc))
- omap_rfbi_transfer_start(s);
- break;
-
- case 0x44: /* RFBI_PIXELCNT */
- s->rfbi.pixels = value;
- break;
-
- case 0x48: /* RFBI_LINE_NUMBER */
- s->rfbi.skiplines = value & 0x7ff;
- break;
-
- case 0x4c: /* RFBI_CMD */
- if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
- s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 0, value & 0xffff);
- if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
- s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 0, value & 0xffff);
- break;
- case 0x50: /* RFBI_PARAM */
- if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
- s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
- if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
- s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
- break;
- case 0x54: /* RFBI_DATA */
- /* TODO: take into account the format set up in s->rfbi.config[?] and
- * s->rfbi.data[?], but special-case the most usual scenario so that
- * speed doesn't suffer. */
- if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) {
- s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
- s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value >> 16);
- }
- if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) {
- s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
- s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value >> 16);
- }
- if (!-- s->rfbi.pixels)
- omap_rfbi_transfer_stop(s);
- break;
- case 0x58: /* RFBI_READ */
- if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
- s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 1);
- else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
- s->rfbi.rxbuf = s->rfbi.chip[1]->read(s->rfbi.chip[1]->opaque, 1);
- if (!-- s->rfbi.pixels)
- omap_rfbi_transfer_stop(s);
- break;
-
- case 0x5c: /* RFBI_STATUS */
- if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
- s->rfbi.rxbuf = s->rfbi.chip[0]->read(s->rfbi.chip[0]->opaque, 0);
- else if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
- s->rfbi.rxbuf = s->rfbi.chip[1]->read(s->rfbi.chip[1]->opaque, 0);
- if (!-- s->rfbi.pixels)
- omap_rfbi_transfer_stop(s);
- break;
-
- case 0x60: /* RFBI_CONFIG0 */
- s->rfbi.config[0] = value & 0x003f1fff;
- break;
-
- case 0x64: /* RFBI_ONOFF_TIME0 */
- s->rfbi.time[0] = value & 0x3fffffff;
- break;
- case 0x68: /* RFBI_CYCLE_TIME0 */
- s->rfbi.time[1] = value & 0x0fffffff;
- break;
- case 0x6c: /* RFBI_DATA_CYCLE1_0 */
- s->rfbi.data[0] = value & 0x0f1f0f1f;
- break;
- case 0x70: /* RFBI_DATA_CYCLE2_0 */
- s->rfbi.data[1] = value & 0x0f1f0f1f;
- break;
- case 0x74: /* RFBI_DATA_CYCLE3_0 */
- s->rfbi.data[2] = value & 0x0f1f0f1f;
- break;
- case 0x78: /* RFBI_CONFIG1 */
- s->rfbi.config[1] = value & 0x003f1fff;
- break;
-
- case 0x7c: /* RFBI_ONOFF_TIME1 */
- s->rfbi.time[2] = value & 0x3fffffff;
- break;
- case 0x80: /* RFBI_CYCLE_TIME1 */
- s->rfbi.time[3] = value & 0x0fffffff;
- break;
- case 0x84: /* RFBI_DATA_CYCLE1_1 */
- s->rfbi.data[3] = value & 0x0f1f0f1f;
- break;
- case 0x88: /* RFBI_DATA_CYCLE2_1 */
- s->rfbi.data[4] = value & 0x0f1f0f1f;
- break;
- case 0x8c: /* RFBI_DATA_CYCLE3_1 */
- s->rfbi.data[5] = value & 0x0f1f0f1f;
- break;
-
- case 0x90: /* RFBI_VSYNC_WIDTH */
- s->rfbi.vsync = value & 0xffff;
- break;
- case 0x94: /* RFBI_HSYNC_WIDTH */
- s->rfbi.hsync = value & 0xffff;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_rfbi_ops = {
- .read = omap_rfbi_read,
- .write = omap_rfbi_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t omap_venc_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* REV_ID */
- case 0x04: /* STATUS */
- case 0x08: /* F_CONTROL */
- case 0x10: /* VIDOUT_CTRL */
- case 0x14: /* SYNC_CTRL */
- case 0x1c: /* LLEN */
- case 0x20: /* FLENS */
- case 0x24: /* HFLTR_CTRL */
- case 0x28: /* CC_CARR_WSS_CARR */
- case 0x2c: /* C_PHASE */
- case 0x30: /* GAIN_U */
- case 0x34: /* GAIN_V */
- case 0x38: /* GAIN_Y */
- case 0x3c: /* BLACK_LEVEL */
- case 0x40: /* BLANK_LEVEL */
- case 0x44: /* X_COLOR */
- case 0x48: /* M_CONTROL */
- case 0x4c: /* BSTAMP_WSS_DATA */
- case 0x50: /* S_CARR */
- case 0x54: /* LINE21 */
- case 0x58: /* LN_SEL */
- case 0x5c: /* L21__WC_CTL */
- case 0x60: /* HTRIGGER_VTRIGGER */
- case 0x64: /* SAVID__EAVID */
- case 0x68: /* FLEN__FAL */
- case 0x6c: /* LAL__PHASE_RESET */
- case 0x70: /* HS_INT_START_STOP_X */
- case 0x74: /* HS_EXT_START_STOP_X */
- case 0x78: /* VS_INT_START_X */
- case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */
- case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */
- case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */
- case 0x88: /* VS_EXT_STOP_Y */
- case 0x90: /* AVID_START_STOP_X */
- case 0x94: /* AVID_START_STOP_Y */
- case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */
- case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */
- case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
- case 0xb0: /* TVDETGP_INT_START_STOP_X */
- case 0xb4: /* TVDETGP_INT_START_STOP_Y */
- case 0xb8: /* GEN_CTRL */
- case 0xc4: /* DAC_TST__DAC_A */
- case 0xc8: /* DAC_B__DAC_C */
- return 0;
-
- default:
- break;
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_venc_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, size);
- return;
- }
-
- switch (addr) {
- case 0x08: /* F_CONTROL */
- case 0x10: /* VIDOUT_CTRL */
- case 0x14: /* SYNC_CTRL */
- case 0x1c: /* LLEN */
- case 0x20: /* FLENS */
- case 0x24: /* HFLTR_CTRL */
- case 0x28: /* CC_CARR_WSS_CARR */
- case 0x2c: /* C_PHASE */
- case 0x30: /* GAIN_U */
- case 0x34: /* GAIN_V */
- case 0x38: /* GAIN_Y */
- case 0x3c: /* BLACK_LEVEL */
- case 0x40: /* BLANK_LEVEL */
- case 0x44: /* X_COLOR */
- case 0x48: /* M_CONTROL */
- case 0x4c: /* BSTAMP_WSS_DATA */
- case 0x50: /* S_CARR */
- case 0x54: /* LINE21 */
- case 0x58: /* LN_SEL */
- case 0x5c: /* L21__WC_CTL */
- case 0x60: /* HTRIGGER_VTRIGGER */
- case 0x64: /* SAVID__EAVID */
- case 0x68: /* FLEN__FAL */
- case 0x6c: /* LAL__PHASE_RESET */
- case 0x70: /* HS_INT_START_STOP_X */
- case 0x74: /* HS_EXT_START_STOP_X */
- case 0x78: /* VS_INT_START_X */
- case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */
- case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */
- case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */
- case 0x88: /* VS_EXT_STOP_Y */
- case 0x90: /* AVID_START_STOP_X */
- case 0x94: /* AVID_START_STOP_Y */
- case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */
- case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */
- case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
- case 0xb0: /* TVDETGP_INT_START_STOP_X */
- case 0xb4: /* TVDETGP_INT_START_STOP_Y */
- case 0xb8: /* GEN_CTRL */
- case 0xc4: /* DAC_TST__DAC_A */
- case 0xc8: /* DAC_B__DAC_C */
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_venc_ops = {
- .read = omap_venc_read,
- .write = omap_venc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t omap_im3_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x0a8: /* SBIMERRLOGA */
- case 0x0b0: /* SBIMERRLOG */
- case 0x190: /* SBIMSTATE */
- case 0x198: /* SBTMSTATE_L */
- case 0x19c: /* SBTMSTATE_H */
- case 0x1a8: /* SBIMCONFIG_L */
- case 0x1ac: /* SBIMCONFIG_H */
- case 0x1f8: /* SBID_L */
- case 0x1fc: /* SBID_H */
- return 0;
-
- default:
- break;
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_im3_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x0b0: /* SBIMERRLOG */
- case 0x190: /* SBIMSTATE */
- case 0x198: /* SBTMSTATE_L */
- case 0x19c: /* SBTMSTATE_H */
- case 0x1a8: /* SBIMCONFIG_L */
- case 0x1ac: /* SBIMCONFIG_H */
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_im3_ops = {
- .read = omap_im3_read,
- .write = omap_im3_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
- MemoryRegion *sysmem,
- hwaddr l3_base,
- qemu_irq irq, qemu_irq drq,
- omap_clk fck1, omap_clk fck2, omap_clk ck54m,
- omap_clk ick1, omap_clk ick2)
-{
- struct omap_dss_s *s = g_new0(struct omap_dss_s, 1);
-
- s->irq = irq;
- s->drq = drq;
- omap_dss_reset(s);
-
- memory_region_init_io(&s->iomem_diss1, NULL, &omap_diss_ops, s, "omap.diss1",
- omap_l4_region_size(ta, 0));
- memory_region_init_io(&s->iomem_disc1, NULL, &omap_disc_ops, s, "omap.disc1",
- omap_l4_region_size(ta, 1));
- memory_region_init_io(&s->iomem_rfbi1, NULL, &omap_rfbi_ops, s, "omap.rfbi1",
- omap_l4_region_size(ta, 2));
- memory_region_init_io(&s->iomem_venc1, NULL, &omap_venc_ops, s, "omap.venc1",
- omap_l4_region_size(ta, 3));
- memory_region_init_io(&s->iomem_im3, NULL, &omap_im3_ops, s,
- "omap.im3", 0x1000);
-
- omap_l4_attach(ta, 0, &s->iomem_diss1);
- omap_l4_attach(ta, 1, &s->iomem_disc1);
- omap_l4_attach(ta, 2, &s->iomem_rfbi1);
- omap_l4_attach(ta, 3, &s->iomem_venc1);
- memory_region_add_subregion(sysmem, l3_base, &s->iomem_im3);
-
-#if 0
- s->state = graphic_console_init(omap_update_display,
- omap_invalidate_display, omap_screen_dump, s);
-#endif
-
- return s;
-}
-
-void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip)
-{
- if (cs < 0 || cs > 1)
- hw_error("%s: wrong CS %i\n", __func__, cs);
- s->rfbi.chip[cs] = chip;
-}
diff --git a/hw/display/pxa2xx_lcd.c b/hw/display/pxa2xx_lcd.c
deleted file mode 100644
index a9d0d98..0000000
--- a/hw/display/pxa2xx_lcd.c
+++ /dev/null
@@ -1,1451 +0,0 @@
-/*
- * Intel XScale PXA255/270 LCDC emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPLv2.
- *
- * 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/log.h"
-#include "hw/irq.h"
-#include "migration/vmstate.h"
-#include "ui/console.h"
-#include "hw/arm/pxa.h"
-#include "ui/pixel_ops.h"
-#include "hw/boards.h"
-/* FIXME: For graphic_rotate. Should probably be done in common code. */
-#include "sysemu/sysemu.h"
-#include "framebuffer.h"
-
-struct DMAChannel {
- uint32_t branch;
- uint8_t up;
- uint8_t palette[1024];
- uint8_t pbuffer[1024];
- void (*redraw)(PXA2xxLCDState *s, hwaddr addr,
- int *miny, int *maxy);
-
- uint32_t descriptor;
- uint32_t source;
- uint32_t id;
- uint32_t command;
-};
-
-struct PXA2xxLCDState {
- MemoryRegion *sysmem;
- MemoryRegion iomem;
- MemoryRegionSection fbsection;
- qemu_irq irq;
- int irqlevel;
-
- int invalidated;
- QemuConsole *con;
- int dest_width;
- int xres, yres;
- int pal_for;
- int transp;
- enum {
- pxa_lcdc_2bpp = 1,
- pxa_lcdc_4bpp = 2,
- pxa_lcdc_8bpp = 3,
- pxa_lcdc_16bpp = 4,
- pxa_lcdc_18bpp = 5,
- pxa_lcdc_18pbpp = 6,
- pxa_lcdc_19bpp = 7,
- pxa_lcdc_19pbpp = 8,
- pxa_lcdc_24bpp = 9,
- pxa_lcdc_25bpp = 10,
- } bpp;
-
- uint32_t control[6];
- uint32_t status[2];
- uint32_t ovl1c[2];
- uint32_t ovl2c[2];
- uint32_t ccr;
- uint32_t cmdcr;
- uint32_t trgbr;
- uint32_t tcr;
- uint32_t liidr;
- uint8_t bscntr;
-
- struct DMAChannel dma_ch[7];
-
- qemu_irq vsync_cb;
- int orientation;
-};
-
-typedef struct QEMU_PACKED {
- uint32_t fdaddr;
- uint32_t fsaddr;
- uint32_t fidr;
- uint32_t ldcmd;
-} PXAFrameDescriptor;
-
-#define LCCR0 0x000 /* LCD Controller Control register 0 */
-#define LCCR1 0x004 /* LCD Controller Control register 1 */
-#define LCCR2 0x008 /* LCD Controller Control register 2 */
-#define LCCR3 0x00c /* LCD Controller Control register 3 */
-#define LCCR4 0x010 /* LCD Controller Control register 4 */
-#define LCCR5 0x014 /* LCD Controller Control register 5 */
-
-#define FBR0 0x020 /* DMA Channel 0 Frame Branch register */
-#define FBR1 0x024 /* DMA Channel 1 Frame Branch register */
-#define FBR2 0x028 /* DMA Channel 2 Frame Branch register */
-#define FBR3 0x02c /* DMA Channel 3 Frame Branch register */
-#define FBR4 0x030 /* DMA Channel 4 Frame Branch register */
-#define FBR5 0x110 /* DMA Channel 5 Frame Branch register */
-#define FBR6 0x114 /* DMA Channel 6 Frame Branch register */
-
-#define LCSR1 0x034 /* LCD Controller Status register 1 */
-#define LCSR0 0x038 /* LCD Controller Status register 0 */
-#define LIIDR 0x03c /* LCD Controller Interrupt ID register */
-
-#define TRGBR 0x040 /* TMED RGB Seed register */
-#define TCR 0x044 /* TMED Control register */
-
-#define OVL1C1 0x050 /* Overlay 1 Control register 1 */
-#define OVL1C2 0x060 /* Overlay 1 Control register 2 */
-#define OVL2C1 0x070 /* Overlay 2 Control register 1 */
-#define OVL2C2 0x080 /* Overlay 2 Control register 2 */
-#define CCR 0x090 /* Cursor Control register */
-
-#define CMDCR 0x100 /* Command Control register */
-#define PRSR 0x104 /* Panel Read Status register */
-
-#define PXA_LCDDMA_CHANS 7
-#define DMA_FDADR 0x00 /* Frame Descriptor Address register */
-#define DMA_FSADR 0x04 /* Frame Source Address register */
-#define DMA_FIDR 0x08 /* Frame ID register */
-#define DMA_LDCMD 0x0c /* Command register */
-
-/* LCD Buffer Strength Control register */
-#define BSCNTR 0x04000054
-
-/* Bitfield masks */
-#define LCCR0_ENB (1 << 0)
-#define LCCR0_CMS (1 << 1)
-#define LCCR0_SDS (1 << 2)
-#define LCCR0_LDM (1 << 3)
-#define LCCR0_SOFM0 (1 << 4)
-#define LCCR0_IUM (1 << 5)
-#define LCCR0_EOFM0 (1 << 6)
-#define LCCR0_PAS (1 << 7)
-#define LCCR0_DPD (1 << 9)
-#define LCCR0_DIS (1 << 10)
-#define LCCR0_QDM (1 << 11)
-#define LCCR0_PDD (0xff << 12)
-#define LCCR0_BSM0 (1 << 20)
-#define LCCR0_OUM (1 << 21)
-#define LCCR0_LCDT (1 << 22)
-#define LCCR0_RDSTM (1 << 23)
-#define LCCR0_CMDIM (1 << 24)
-#define LCCR0_OUC (1 << 25)
-#define LCCR0_LDDALT (1 << 26)
-#define LCCR1_PPL(x) ((x) & 0x3ff)
-#define LCCR2_LPP(x) ((x) & 0x3ff)
-#define LCCR3_API (15 << 16)
-#define LCCR3_BPP(x) ((((x) >> 24) & 7) | (((x) >> 26) & 8))
-#define LCCR3_PDFOR(x) (((x) >> 30) & 3)
-#define LCCR4_K1(x) (((x) >> 0) & 7)
-#define LCCR4_K2(x) (((x) >> 3) & 7)
-#define LCCR4_K3(x) (((x) >> 6) & 7)
-#define LCCR4_PALFOR(x) (((x) >> 15) & 3)
-#define LCCR5_SOFM(ch) (1 << (ch - 1))
-#define LCCR5_EOFM(ch) (1 << (ch + 7))
-#define LCCR5_BSM(ch) (1 << (ch + 15))
-#define LCCR5_IUM(ch) (1 << (ch + 23))
-#define OVLC1_EN (1 << 31)
-#define CCR_CEN (1 << 31)
-#define FBR_BRA (1 << 0)
-#define FBR_BINT (1 << 1)
-#define FBR_SRCADDR (0xfffffff << 4)
-#define LCSR0_LDD (1 << 0)
-#define LCSR0_SOF0 (1 << 1)
-#define LCSR0_BER (1 << 2)
-#define LCSR0_ABC (1 << 3)
-#define LCSR0_IU0 (1 << 4)
-#define LCSR0_IU1 (1 << 5)
-#define LCSR0_OU (1 << 6)
-#define LCSR0_QD (1 << 7)
-#define LCSR0_EOF0 (1 << 8)
-#define LCSR0_BS0 (1 << 9)
-#define LCSR0_SINT (1 << 10)
-#define LCSR0_RDST (1 << 11)
-#define LCSR0_CMDINT (1 << 12)
-#define LCSR0_BERCH(x) (((x) & 7) << 28)
-#define LCSR1_SOF(ch) (1 << (ch - 1))
-#define LCSR1_EOF(ch) (1 << (ch + 7))
-#define LCSR1_BS(ch) (1 << (ch + 15))
-#define LCSR1_IU(ch) (1 << (ch + 23))
-#define LDCMD_LENGTH(x) ((x) & 0x001ffffc)
-#define LDCMD_EOFINT (1 << 21)
-#define LDCMD_SOFINT (1 << 22)
-#define LDCMD_PAL (1 << 26)
-
-/* Size of a pixel in the QEMU UI output surface, in bytes */
-#define DEST_PIXEL_WIDTH 4
-
-/* Line drawing code to handle the various possible guest pixel formats */
-
-# define SKIP_PIXEL(to) do { to += deststep; } while (0)
-# define COPY_PIXEL(to, from) \
- do { \
- *(uint32_t *) to = from; \
- SKIP_PIXEL(to); \
- } while (0)
-
-#if HOST_BIG_ENDIAN
-# define SWAP_WORDS 1
-#endif
-
-#define FN_2(x) FN(x + 1) FN(x)
-#define FN_4(x) FN_2(x + 2) FN_2(x)
-
-static void pxa2xx_draw_line2(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t *palette = opaque;
- uint32_t data;
- while (width > 0) {
- data = *(uint32_t *) src;
-#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 2)) & 3]);
-#ifdef SWAP_WORDS
- FN_4(12)
- FN_4(8)
- FN_4(4)
- FN_4(0)
-#else
- FN_4(0)
- FN_4(4)
- FN_4(8)
- FN_4(12)
-#endif
-#undef FN
- width -= 16;
- src += 4;
- }
-}
-
-static void pxa2xx_draw_line4(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t *palette = opaque;
- uint32_t data;
- while (width > 0) {
- data = *(uint32_t *) src;
-#define FN(x) COPY_PIXEL(dest, palette[(data >> ((x) * 4)) & 0xf]);
-#ifdef SWAP_WORDS
- FN_2(6)
- FN_2(4)
- FN_2(2)
- FN_2(0)
-#else
- FN_2(0)
- FN_2(2)
- FN_2(4)
- FN_2(6)
-#endif
-#undef FN
- width -= 8;
- src += 4;
- }
-}
-
-static void pxa2xx_draw_line8(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t *palette = opaque;
- uint32_t data;
- while (width > 0) {
- data = *(uint32_t *) src;
-#define FN(x) COPY_PIXEL(dest, palette[(data >> (x)) & 0xff]);
-#ifdef SWAP_WORDS
- FN(24)
- FN(16)
- FN(8)
- FN(0)
-#else
- FN(0)
- FN(8)
- FN(16)
- FN(24)
-#endif
-#undef FN
- width -= 4;
- src += 4;
- }
-}
-
-static void pxa2xx_draw_line16(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
- b = (data & 0x1f) << 3;
- data >>= 5;
- g = (data & 0x3f) << 2;
- data >>= 6;
- r = (data & 0x1f) << 3;
- data >>= 5;
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- b = (data & 0x1f) << 3;
- data >>= 5;
- g = (data & 0x3f) << 2;
- data >>= 6;
- r = (data & 0x1f) << 3;
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- width -= 2;
- src += 4;
- }
-}
-
-static void pxa2xx_draw_line16t(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
- b = (data & 0x1f) << 3;
- data >>= 5;
- g = (data & 0x1f) << 3;
- data >>= 5;
- r = (data & 0x1f) << 3;
- data >>= 5;
- if (data & 1) {
- SKIP_PIXEL(dest);
- } else {
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- }
- data >>= 1;
- b = (data & 0x1f) << 3;
- data >>= 5;
- g = (data & 0x1f) << 3;
- data >>= 5;
- r = (data & 0x1f) << 3;
- data >>= 5;
- if (data & 1) {
- SKIP_PIXEL(dest);
- } else {
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- }
- width -= 2;
- src += 4;
- }
-}
-
-static void pxa2xx_draw_line18(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
- b = (data & 0x3f) << 2;
- data >>= 6;
- g = (data & 0x3f) << 2;
- data >>= 6;
- r = (data & 0x3f) << 2;
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- width -= 1;
- src += 4;
- }
-}
-
-/* The wicked packed format */
-static void pxa2xx_draw_line18p(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t data[3];
- unsigned int r, g, b;
- while (width > 0) {
- data[0] = *(uint32_t *) src;
- src += 4;
- data[1] = *(uint32_t *) src;
- src += 4;
- data[2] = *(uint32_t *) src;
- src += 4;
-#ifdef SWAP_WORDS
- data[0] = bswap32(data[0]);
- data[1] = bswap32(data[1]);
- data[2] = bswap32(data[2]);
-#endif
- b = (data[0] & 0x3f) << 2;
- data[0] >>= 6;
- g = (data[0] & 0x3f) << 2;
- data[0] >>= 6;
- r = (data[0] & 0x3f) << 2;
- data[0] >>= 12;
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- b = (data[0] & 0x3f) << 2;
- data[0] >>= 6;
- g = ((data[1] & 0xf) << 4) | (data[0] << 2);
- data[1] >>= 4;
- r = (data[1] & 0x3f) << 2;
- data[1] >>= 12;
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- b = (data[1] & 0x3f) << 2;
- data[1] >>= 6;
- g = (data[1] & 0x3f) << 2;
- data[1] >>= 6;
- r = ((data[2] & 0x3) << 6) | (data[1] << 2);
- data[2] >>= 8;
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- b = (data[2] & 0x3f) << 2;
- data[2] >>= 6;
- g = (data[2] & 0x3f) << 2;
- data[2] >>= 6;
- r = data[2] << 2;
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- width -= 4;
- }
-}
-
-static void pxa2xx_draw_line19(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
- b = (data & 0x3f) << 2;
- data >>= 6;
- g = (data & 0x3f) << 2;
- data >>= 6;
- r = (data & 0x3f) << 2;
- data >>= 6;
- if (data & 1) {
- SKIP_PIXEL(dest);
- } else {
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- }
- width -= 1;
- src += 4;
- }
-}
-
-/* The wicked packed format */
-static void pxa2xx_draw_line19p(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t data[3];
- unsigned int r, g, b;
- while (width > 0) {
- data[0] = *(uint32_t *) src;
- src += 4;
- data[1] = *(uint32_t *) src;
- src += 4;
- data[2] = *(uint32_t *) src;
- src += 4;
-# ifdef SWAP_WORDS
- data[0] = bswap32(data[0]);
- data[1] = bswap32(data[1]);
- data[2] = bswap32(data[2]);
-# endif
- b = (data[0] & 0x3f) << 2;
- data[0] >>= 6;
- g = (data[0] & 0x3f) << 2;
- data[0] >>= 6;
- r = (data[0] & 0x3f) << 2;
- data[0] >>= 6;
- if (data[0] & 1) {
- SKIP_PIXEL(dest);
- } else {
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- }
- data[0] >>= 6;
- b = (data[0] & 0x3f) << 2;
- data[0] >>= 6;
- g = ((data[1] & 0xf) << 4) | (data[0] << 2);
- data[1] >>= 4;
- r = (data[1] & 0x3f) << 2;
- data[1] >>= 6;
- if (data[1] & 1) {
- SKIP_PIXEL(dest);
- } else {
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- }
- data[1] >>= 6;
- b = (data[1] & 0x3f) << 2;
- data[1] >>= 6;
- g = (data[1] & 0x3f) << 2;
- data[1] >>= 6;
- r = ((data[2] & 0x3) << 6) | (data[1] << 2);
- data[2] >>= 2;
- if (data[2] & 1) {
- SKIP_PIXEL(dest);
- } else {
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- }
- data[2] >>= 6;
- b = (data[2] & 0x3f) << 2;
- data[2] >>= 6;
- g = (data[2] & 0x3f) << 2;
- data[2] >>= 6;
- r = data[2] << 2;
- data[2] >>= 6;
- if (data[2] & 1) {
- SKIP_PIXEL(dest);
- } else {
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- }
- width -= 4;
- }
-}
-
-static void pxa2xx_draw_line24(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
- b = data & 0xff;
- data >>= 8;
- g = data & 0xff;
- data >>= 8;
- r = data & 0xff;
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- width -= 1;
- src += 4;
- }
-}
-
-static void pxa2xx_draw_line24t(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
- b = (data & 0x7f) << 1;
- data >>= 7;
- g = data & 0xff;
- data >>= 8;
- r = data & 0xff;
- data >>= 8;
- if (data & 1) {
- SKIP_PIXEL(dest);
- } else {
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- }
- width -= 1;
- src += 4;
- }
-}
-
-static void pxa2xx_draw_line25(void *opaque, uint8_t *dest, const uint8_t *src,
- int width, int deststep)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
- b = data & 0xff;
- data >>= 8;
- g = data & 0xff;
- data >>= 8;
- r = data & 0xff;
- data >>= 8;
- if (data & 1) {
- SKIP_PIXEL(dest);
- } else {
- COPY_PIXEL(dest, rgb_to_pixel32(r, g, b));
- }
- width -= 1;
- src += 4;
- }
-}
-
-/* Overlay planes disabled, no transparency */
-static drawfn pxa2xx_draw_fn_32[16] = {
- [0 ... 0xf] = NULL,
- [pxa_lcdc_2bpp] = pxa2xx_draw_line2,
- [pxa_lcdc_4bpp] = pxa2xx_draw_line4,
- [pxa_lcdc_8bpp] = pxa2xx_draw_line8,
- [pxa_lcdc_16bpp] = pxa2xx_draw_line16,
- [pxa_lcdc_18bpp] = pxa2xx_draw_line18,
- [pxa_lcdc_18pbpp] = pxa2xx_draw_line18p,
- [pxa_lcdc_24bpp] = pxa2xx_draw_line24,
-};
-
-/* Overlay planes enabled, transparency used */
-static drawfn pxa2xx_draw_fn_32t[16] = {
- [0 ... 0xf] = NULL,
- [pxa_lcdc_4bpp] = pxa2xx_draw_line4,
- [pxa_lcdc_8bpp] = pxa2xx_draw_line8,
- [pxa_lcdc_16bpp] = pxa2xx_draw_line16t,
- [pxa_lcdc_19bpp] = pxa2xx_draw_line19,
- [pxa_lcdc_19pbpp] = pxa2xx_draw_line19p,
- [pxa_lcdc_24bpp] = pxa2xx_draw_line24t,
- [pxa_lcdc_25bpp] = pxa2xx_draw_line25,
-};
-
-#undef COPY_PIXEL
-#undef SKIP_PIXEL
-
-#ifdef SWAP_WORDS
-# undef SWAP_WORDS
-#endif
-
-/* Route internal interrupt lines to the global IC */
-static void pxa2xx_lcdc_int_update(PXA2xxLCDState *s)
-{
- int level = 0;
- level |= (s->status[0] & LCSR0_LDD) && !(s->control[0] & LCCR0_LDM);
- level |= (s->status[0] & LCSR0_SOF0) && !(s->control[0] & LCCR0_SOFM0);
- level |= (s->status[0] & LCSR0_IU0) && !(s->control[0] & LCCR0_IUM);
- level |= (s->status[0] & LCSR0_IU1) && !(s->control[5] & LCCR5_IUM(1));
- level |= (s->status[0] & LCSR0_OU) && !(s->control[0] & LCCR0_OUM);
- level |= (s->status[0] & LCSR0_QD) && !(s->control[0] & LCCR0_QDM);
- level |= (s->status[0] & LCSR0_EOF0) && !(s->control[0] & LCCR0_EOFM0);
- level |= (s->status[0] & LCSR0_BS0) && !(s->control[0] & LCCR0_BSM0);
- level |= (s->status[0] & LCSR0_RDST) && !(s->control[0] & LCCR0_RDSTM);
- level |= (s->status[0] & LCSR0_CMDINT) && !(s->control[0] & LCCR0_CMDIM);
- level |= (s->status[1] & ~s->control[5]);
-
- qemu_set_irq(s->irq, !!level);
- s->irqlevel = level;
-}
-
-/* Set Branch Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_bs_set(PXA2xxLCDState *s, int ch)
-{
- int unmasked;
- if (ch == 0) {
- s->status[0] |= LCSR0_BS0;
- unmasked = !(s->control[0] & LCCR0_BSM0);
- } else {
- s->status[1] |= LCSR1_BS(ch);
- unmasked = !(s->control[5] & LCCR5_BSM(ch));
- }
-
- if (unmasked) {
- if (s->irqlevel)
- s->status[0] |= LCSR0_SINT;
- else
- s->liidr = s->dma_ch[ch].id;
- }
-}
-
-/* Set Start Of Frame Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_sof_set(PXA2xxLCDState *s, int ch)
-{
- int unmasked;
- if (!(s->dma_ch[ch].command & LDCMD_SOFINT))
- return;
-
- if (ch == 0) {
- s->status[0] |= LCSR0_SOF0;
- unmasked = !(s->control[0] & LCCR0_SOFM0);
- } else {
- s->status[1] |= LCSR1_SOF(ch);
- unmasked = !(s->control[5] & LCCR5_SOFM(ch));
- }
-
- if (unmasked) {
- if (s->irqlevel)
- s->status[0] |= LCSR0_SINT;
- else
- s->liidr = s->dma_ch[ch].id;
- }
-}
-
-/* Set End Of Frame Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_eof_set(PXA2xxLCDState *s, int ch)
-{
- int unmasked;
- if (!(s->dma_ch[ch].command & LDCMD_EOFINT))
- return;
-
- if (ch == 0) {
- s->status[0] |= LCSR0_EOF0;
- unmasked = !(s->control[0] & LCCR0_EOFM0);
- } else {
- s->status[1] |= LCSR1_EOF(ch);
- unmasked = !(s->control[5] & LCCR5_EOFM(ch));
- }
-
- if (unmasked) {
- if (s->irqlevel)
- s->status[0] |= LCSR0_SINT;
- else
- s->liidr = s->dma_ch[ch].id;
- }
-}
-
-/* Set Bus Error Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_ber_set(PXA2xxLCDState *s, int ch)
-{
- s->status[0] |= LCSR0_BERCH(ch) | LCSR0_BER;
- if (s->irqlevel)
- s->status[0] |= LCSR0_SINT;
- else
- s->liidr = s->dma_ch[ch].id;
-}
-
-/* Load new Frame Descriptors from DMA */
-static void pxa2xx_descriptor_load(PXA2xxLCDState *s)
-{
- PXAFrameDescriptor desc;
- hwaddr descptr;
- int i;
-
- for (i = 0; i < PXA_LCDDMA_CHANS; i ++) {
- s->dma_ch[i].source = 0;
-
- if (!s->dma_ch[i].up)
- continue;
-
- if (s->dma_ch[i].branch & FBR_BRA) {
- descptr = s->dma_ch[i].branch & FBR_SRCADDR;
- if (s->dma_ch[i].branch & FBR_BINT)
- pxa2xx_dma_bs_set(s, i);
- s->dma_ch[i].branch &= ~FBR_BRA;
- } else
- descptr = s->dma_ch[i].descriptor;
-
- if (!((descptr >= PXA2XX_SDRAM_BASE && descptr +
- sizeof(desc) <= PXA2XX_SDRAM_BASE + current_machine->ram_size) ||
- (descptr >= PXA2XX_INTERNAL_BASE && descptr + sizeof(desc) <=
- PXA2XX_INTERNAL_BASE + PXA2XX_INTERNAL_SIZE))) {
- continue;
- }
-
- cpu_physical_memory_read(descptr, &desc, sizeof(desc));
- s->dma_ch[i].descriptor = le32_to_cpu(desc.fdaddr);
- s->dma_ch[i].source = le32_to_cpu(desc.fsaddr);
- s->dma_ch[i].id = le32_to_cpu(desc.fidr);
- s->dma_ch[i].command = le32_to_cpu(desc.ldcmd);
- }
-}
-
-static uint64_t pxa2xx_lcdc_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
- int ch;
-
- switch (offset) {
- case LCCR0:
- return s->control[0];
- case LCCR1:
- return s->control[1];
- case LCCR2:
- return s->control[2];
- case LCCR3:
- return s->control[3];
- case LCCR4:
- return s->control[4];
- case LCCR5:
- return s->control[5];
-
- case OVL1C1:
- return s->ovl1c[0];
- case OVL1C2:
- return s->ovl1c[1];
- case OVL2C1:
- return s->ovl2c[0];
- case OVL2C2:
- return s->ovl2c[1];
-
- case CCR:
- return s->ccr;
-
- case CMDCR:
- return s->cmdcr;
-
- case TRGBR:
- return s->trgbr;
- case TCR:
- return s->tcr;
-
- case 0x200 ... 0x1000: /* DMA per-channel registers */
- ch = (offset - 0x200) >> 4;
- if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS))
- goto fail;
-
- switch (offset & 0xf) {
- case DMA_FDADR:
- return s->dma_ch[ch].descriptor;
- case DMA_FSADR:
- return s->dma_ch[ch].source;
- case DMA_FIDR:
- return s->dma_ch[ch].id;
- case DMA_LDCMD:
- return s->dma_ch[ch].command;
- default:
- goto fail;
- }
-
- case FBR0:
- return s->dma_ch[0].branch;
- case FBR1:
- return s->dma_ch[1].branch;
- case FBR2:
- return s->dma_ch[2].branch;
- case FBR3:
- return s->dma_ch[3].branch;
- case FBR4:
- return s->dma_ch[4].branch;
- case FBR5:
- return s->dma_ch[5].branch;
- case FBR6:
- return s->dma_ch[6].branch;
-
- case BSCNTR:
- return s->bscntr;
-
- case PRSR:
- return 0;
-
- case LCSR0:
- return s->status[0];
- case LCSR1:
- return s->status[1];
- case LIIDR:
- return s->liidr;
-
- default:
- fail:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
- __func__, offset);
- }
-
- return 0;
-}
-
-static void pxa2xx_lcdc_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
- int ch;
-
- switch (offset) {
- case LCCR0:
- /* ACK Quick Disable done */
- if ((s->control[0] & LCCR0_ENB) && !(value & LCCR0_ENB))
- s->status[0] |= LCSR0_QD;
-
- if (!(s->control[0] & LCCR0_LCDT) && (value & LCCR0_LCDT)) {
- qemu_log_mask(LOG_UNIMP,
- "%s: internal frame buffer unsupported\n", __func__);
- }
- if ((s->control[3] & LCCR3_API) &&
- (value & LCCR0_ENB) && !(value & LCCR0_LCDT))
- s->status[0] |= LCSR0_ABC;
-
- s->control[0] = value & 0x07ffffff;
- pxa2xx_lcdc_int_update(s);
-
- s->dma_ch[0].up = !!(value & LCCR0_ENB);
- s->dma_ch[1].up = (s->ovl1c[0] & OVLC1_EN) || (value & LCCR0_SDS);
- break;
-
- case LCCR1:
- s->control[1] = value;
- break;
-
- case LCCR2:
- s->control[2] = value;
- break;
-
- case LCCR3:
- s->control[3] = value & 0xefffffff;
- s->bpp = LCCR3_BPP(value);
- break;
-
- case LCCR4:
- s->control[4] = value & 0x83ff81ff;
- break;
-
- case LCCR5:
- s->control[5] = value & 0x3f3f3f3f;
- break;
-
- case OVL1C1:
- if (!(s->ovl1c[0] & OVLC1_EN) && (value & OVLC1_EN)) {
- qemu_log_mask(LOG_UNIMP, "%s: Overlay 1 not supported\n", __func__);
- }
- s->ovl1c[0] = value & 0x80ffffff;
- s->dma_ch[1].up = (value & OVLC1_EN) || (s->control[0] & LCCR0_SDS);
- break;
-
- case OVL1C2:
- s->ovl1c[1] = value & 0x000fffff;
- break;
-
- case OVL2C1:
- if (!(s->ovl2c[0] & OVLC1_EN) && (value & OVLC1_EN)) {
- qemu_log_mask(LOG_UNIMP, "%s: Overlay 2 not supported\n", __func__);
- }
- s->ovl2c[0] = value & 0x80ffffff;
- s->dma_ch[2].up = !!(value & OVLC1_EN);
- s->dma_ch[3].up = !!(value & OVLC1_EN);
- s->dma_ch[4].up = !!(value & OVLC1_EN);
- break;
-
- case OVL2C2:
- s->ovl2c[1] = value & 0x007fffff;
- break;
-
- case CCR:
- if (!(s->ccr & CCR_CEN) && (value & CCR_CEN)) {
- qemu_log_mask(LOG_UNIMP,
- "%s: Hardware cursor unimplemented\n", __func__);
- }
- s->ccr = value & 0x81ffffe7;
- s->dma_ch[5].up = !!(value & CCR_CEN);
- break;
-
- case CMDCR:
- s->cmdcr = value & 0xff;
- break;
-
- case TRGBR:
- s->trgbr = value & 0x00ffffff;
- break;
-
- case TCR:
- s->tcr = value & 0x7fff;
- break;
-
- case 0x200 ... 0x1000: /* DMA per-channel registers */
- ch = (offset - 0x200) >> 4;
- if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS))
- goto fail;
-
- switch (offset & 0xf) {
- case DMA_FDADR:
- s->dma_ch[ch].descriptor = value & 0xfffffff0;
- break;
-
- default:
- goto fail;
- }
- break;
-
- case FBR0:
- s->dma_ch[0].branch = value & 0xfffffff3;
- break;
- case FBR1:
- s->dma_ch[1].branch = value & 0xfffffff3;
- break;
- case FBR2:
- s->dma_ch[2].branch = value & 0xfffffff3;
- break;
- case FBR3:
- s->dma_ch[3].branch = value & 0xfffffff3;
- break;
- case FBR4:
- s->dma_ch[4].branch = value & 0xfffffff3;
- break;
- case FBR5:
- s->dma_ch[5].branch = value & 0xfffffff3;
- break;
- case FBR6:
- s->dma_ch[6].branch = value & 0xfffffff3;
- break;
-
- case BSCNTR:
- s->bscntr = value & 0xf;
- break;
-
- case PRSR:
- break;
-
- case LCSR0:
- s->status[0] &= ~(value & 0xfff);
- if (value & LCSR0_BER)
- s->status[0] &= ~LCSR0_BERCH(7);
- break;
-
- case LCSR1:
- s->status[1] &= ~(value & 0x3e3f3f);
- break;
-
- default:
- fail:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
- __func__, offset);
- }
-}
-
-static const MemoryRegionOps pxa2xx_lcdc_ops = {
- .read = pxa2xx_lcdc_read,
- .write = pxa2xx_lcdc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/* Load new palette for a given DMA channel, convert to internal format */
-static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int i, n, format, r, g, b, alpha;
- uint32_t *dest;
- uint8_t *src;
- s->pal_for = LCCR4_PALFOR(s->control[4]);
- format = s->pal_for;
-
- switch (bpp) {
- case pxa_lcdc_2bpp:
- n = 4;
- break;
- case pxa_lcdc_4bpp:
- n = 16;
- break;
- case pxa_lcdc_8bpp:
- n = 256;
- break;
- default:
- return;
- }
-
- src = (uint8_t *) s->dma_ch[ch].pbuffer;
- dest = (uint32_t *) s->dma_ch[ch].palette;
- alpha = r = g = b = 0;
-
- for (i = 0; i < n; i ++) {
- switch (format) {
- case 0: /* 16 bpp, no transparency */
- alpha = 0;
- if (s->control[0] & LCCR0_CMS) {
- r = g = b = *(uint16_t *) src & 0xff;
- }
- else {
- r = (*(uint16_t *) src & 0xf800) >> 8;
- g = (*(uint16_t *) src & 0x07e0) >> 3;
- b = (*(uint16_t *) src & 0x001f) << 3;
- }
- src += 2;
- break;
- case 1: /* 16 bpp plus transparency */
- alpha = *(uint32_t *) src & (1 << 24);
- if (s->control[0] & LCCR0_CMS)
- r = g = b = *(uint32_t *) src & 0xff;
- else {
- r = (*(uint32_t *) src & 0xf80000) >> 16;
- g = (*(uint32_t *) src & 0x00fc00) >> 8;
- b = (*(uint32_t *) src & 0x0000f8);
- }
- src += 4;
- break;
- case 2: /* 18 bpp plus transparency */
- alpha = *(uint32_t *) src & (1 << 24);
- if (s->control[0] & LCCR0_CMS)
- r = g = b = *(uint32_t *) src & 0xff;
- else {
- r = (*(uint32_t *) src & 0xfc0000) >> 16;
- g = (*(uint32_t *) src & 0x00fc00) >> 8;
- b = (*(uint32_t *) src & 0x0000fc);
- }
- src += 4;
- break;
- case 3: /* 24 bpp plus transparency */
- alpha = *(uint32_t *) src & (1 << 24);
- if (s->control[0] & LCCR0_CMS)
- r = g = b = *(uint32_t *) src & 0xff;
- else {
- r = (*(uint32_t *) src & 0xff0000) >> 16;
- g = (*(uint32_t *) src & 0x00ff00) >> 8;
- b = (*(uint32_t *) src & 0x0000ff);
- }
- src += 4;
- break;
- }
- switch (surface_bits_per_pixel(surface)) {
- case 8:
- *dest = rgb_to_pixel8(r, g, b) | alpha;
- break;
- case 15:
- *dest = rgb_to_pixel15(r, g, b) | alpha;
- break;
- case 16:
- *dest = rgb_to_pixel16(r, g, b) | alpha;
- break;
- case 24:
- *dest = rgb_to_pixel24(r, g, b) | alpha;
- break;
- case 32:
- *dest = rgb_to_pixel32(r, g, b) | alpha;
- break;
- }
- dest ++;
- }
-}
-
-static inline drawfn pxa2xx_drawfn(PXA2xxLCDState *s)
-{
- if (s->transp) {
- return pxa2xx_draw_fn_32t[s->bpp];
- } else {
- return pxa2xx_draw_fn_32[s->bpp];
- }
-}
-
-static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s,
- hwaddr addr, int *miny, int *maxy)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int src_width, dest_width;
- drawfn fn = pxa2xx_drawfn(s);
- if (!fn)
- return;
-
- src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */
- if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
- src_width *= 3;
- else if (s->bpp > pxa_lcdc_16bpp)
- src_width *= 4;
- else if (s->bpp > pxa_lcdc_8bpp)
- src_width *= 2;
-
- dest_width = s->xres * DEST_PIXEL_WIDTH;
- *miny = 0;
- if (s->invalidated) {
- framebuffer_update_memory_section(&s->fbsection, s->sysmem,
- addr, s->yres, src_width);
- }
- framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
- src_width, dest_width, DEST_PIXEL_WIDTH,
- s->invalidated,
- fn, s->dma_ch[0].palette, miny, maxy);
-}
-
-static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s,
- hwaddr addr, int *miny, int *maxy)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int src_width, dest_width;
- drawfn fn = pxa2xx_drawfn(s);
- if (!fn)
- return;
-
- src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */
- if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
- src_width *= 3;
- else if (s->bpp > pxa_lcdc_16bpp)
- src_width *= 4;
- else if (s->bpp > pxa_lcdc_8bpp)
- src_width *= 2;
-
- dest_width = s->yres * DEST_PIXEL_WIDTH;
- *miny = 0;
- if (s->invalidated) {
- framebuffer_update_memory_section(&s->fbsection, s->sysmem,
- addr, s->yres, src_width);
- }
- framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
- src_width, DEST_PIXEL_WIDTH, -dest_width,
- s->invalidated,
- fn, s->dma_ch[0].palette,
- miny, maxy);
-}
-
-static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s,
- hwaddr addr, int *miny, int *maxy)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int src_width, dest_width;
- drawfn fn = pxa2xx_drawfn(s);
- if (!fn) {
- return;
- }
-
- src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */
- if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) {
- src_width *= 3;
- } else if (s->bpp > pxa_lcdc_16bpp) {
- src_width *= 4;
- } else if (s->bpp > pxa_lcdc_8bpp) {
- src_width *= 2;
- }
-
- dest_width = s->xres * DEST_PIXEL_WIDTH;
- *miny = 0;
- if (s->invalidated) {
- framebuffer_update_memory_section(&s->fbsection, s->sysmem,
- addr, s->yres, src_width);
- }
- framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
- src_width, -dest_width, -DEST_PIXEL_WIDTH,
- s->invalidated,
- fn, s->dma_ch[0].palette, miny, maxy);
-}
-
-static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s,
- hwaddr addr, int *miny, int *maxy)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int src_width, dest_width;
- drawfn fn = pxa2xx_drawfn(s);
- if (!fn) {
- return;
- }
-
- src_width = (s->xres + 3) & ~3; /* Pad to a 4 pixels multiple */
- if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) {
- src_width *= 3;
- } else if (s->bpp > pxa_lcdc_16bpp) {
- src_width *= 4;
- } else if (s->bpp > pxa_lcdc_8bpp) {
- src_width *= 2;
- }
-
- dest_width = s->yres * DEST_PIXEL_WIDTH;
- *miny = 0;
- if (s->invalidated) {
- framebuffer_update_memory_section(&s->fbsection, s->sysmem,
- addr, s->yres, src_width);
- }
- framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
- src_width, -DEST_PIXEL_WIDTH, dest_width,
- s->invalidated,
- fn, s->dma_ch[0].palette,
- miny, maxy);
-}
-
-static void pxa2xx_lcdc_resize(PXA2xxLCDState *s)
-{
- int width, height;
- if (!(s->control[0] & LCCR0_ENB))
- return;
-
- width = LCCR1_PPL(s->control[1]) + 1;
- height = LCCR2_LPP(s->control[2]) + 1;
-
- if (width != s->xres || height != s->yres) {
- if (s->orientation == 90 || s->orientation == 270) {
- qemu_console_resize(s->con, height, width);
- } else {
- qemu_console_resize(s->con, width, height);
- }
- s->invalidated = 1;
- s->xres = width;
- s->yres = height;
- }
-}
-
-static void pxa2xx_update_display(void *opaque)
-{
- PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
- hwaddr fbptr;
- int miny, maxy;
- int ch;
- if (!(s->control[0] & LCCR0_ENB))
- return;
-
- pxa2xx_descriptor_load(s);
-
- pxa2xx_lcdc_resize(s);
- miny = s->yres;
- maxy = 0;
- s->transp = s->dma_ch[2].up || s->dma_ch[3].up;
- /* Note: With overlay planes the order depends on LCCR0 bit 25. */
- for (ch = 0; ch < PXA_LCDDMA_CHANS; ch ++)
- if (s->dma_ch[ch].up) {
- if (!s->dma_ch[ch].source) {
- pxa2xx_dma_ber_set(s, ch);
- continue;
- }
- fbptr = s->dma_ch[ch].source;
- if (!((fbptr >= PXA2XX_SDRAM_BASE &&
- fbptr <= PXA2XX_SDRAM_BASE + current_machine->ram_size) ||
- (fbptr >= PXA2XX_INTERNAL_BASE &&
- fbptr <= PXA2XX_INTERNAL_BASE + PXA2XX_INTERNAL_SIZE))) {
- pxa2xx_dma_ber_set(s, ch);
- continue;
- }
-
- if (s->dma_ch[ch].command & LDCMD_PAL) {
- cpu_physical_memory_read(fbptr, s->dma_ch[ch].pbuffer,
- MAX(LDCMD_LENGTH(s->dma_ch[ch].command),
- sizeof(s->dma_ch[ch].pbuffer)));
- pxa2xx_palette_parse(s, ch, s->bpp);
- } else {
- /* Do we need to reparse palette */
- if (LCCR4_PALFOR(s->control[4]) != s->pal_for)
- pxa2xx_palette_parse(s, ch, s->bpp);
-
- /* ACK frame start */
- pxa2xx_dma_sof_set(s, ch);
-
- s->dma_ch[ch].redraw(s, fbptr, &miny, &maxy);
- s->invalidated = 0;
-
- /* ACK frame completed */
- pxa2xx_dma_eof_set(s, ch);
- }
- }
-
- if (s->control[0] & LCCR0_DIS) {
- /* ACK last frame completed */
- s->control[0] &= ~LCCR0_ENB;
- s->status[0] |= LCSR0_LDD;
- }
-
- if (miny >= 0) {
- switch (s->orientation) {
- case 0:
- dpy_gfx_update(s->con, 0, miny, s->xres, maxy - miny + 1);
- break;
- case 90:
- dpy_gfx_update(s->con, miny, 0, maxy - miny + 1, s->xres);
- break;
- case 180:
- maxy = s->yres - maxy - 1;
- miny = s->yres - miny - 1;
- dpy_gfx_update(s->con, 0, maxy, s->xres, miny - maxy + 1);
- break;
- case 270:
- maxy = s->yres - maxy - 1;
- miny = s->yres - miny - 1;
- dpy_gfx_update(s->con, maxy, 0, miny - maxy + 1, s->xres);
- break;
- }
- }
- pxa2xx_lcdc_int_update(s);
-
- qemu_irq_raise(s->vsync_cb);
-}
-
-static void pxa2xx_invalidate_display(void *opaque)
-{
- PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
- s->invalidated = 1;
-}
-
-static void pxa2xx_lcdc_orientation(void *opaque, int angle)
-{
- PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
-
- switch (angle) {
- case 0:
- s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot0;
- break;
- case 90:
- s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot90;
- break;
- case 180:
- s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot180;
- break;
- case 270:
- s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot270;
- break;
- }
-
- s->orientation = angle;
- s->xres = s->yres = -1;
- pxa2xx_lcdc_resize(s);
-}
-
-static const VMStateDescription vmstate_dma_channel = {
- .name = "dma_channel",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32(branch, struct DMAChannel),
- VMSTATE_UINT8(up, struct DMAChannel),
- VMSTATE_BUFFER(pbuffer, struct DMAChannel),
- VMSTATE_UINT32(descriptor, struct DMAChannel),
- VMSTATE_UINT32(source, struct DMAChannel),
- VMSTATE_UINT32(id, struct DMAChannel),
- VMSTATE_UINT32(command, struct DMAChannel),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int pxa2xx_lcdc_post_load(void *opaque, int version_id)
-{
- PXA2xxLCDState *s = opaque;
-
- s->bpp = LCCR3_BPP(s->control[3]);
- s->xres = s->yres = s->pal_for = -1;
-
- return 0;
-}
-
-static const VMStateDescription vmstate_pxa2xx_lcdc = {
- .name = "pxa2xx_lcdc",
- .version_id = 0,
- .minimum_version_id = 0,
- .post_load = pxa2xx_lcdc_post_load,
- .fields = (const VMStateField[]) {
- VMSTATE_INT32(irqlevel, PXA2xxLCDState),
- VMSTATE_INT32(transp, PXA2xxLCDState),
- VMSTATE_UINT32_ARRAY(control, PXA2xxLCDState, 6),
- VMSTATE_UINT32_ARRAY(status, PXA2xxLCDState, 2),
- VMSTATE_UINT32_ARRAY(ovl1c, PXA2xxLCDState, 2),
- VMSTATE_UINT32_ARRAY(ovl2c, PXA2xxLCDState, 2),
- VMSTATE_UINT32(ccr, PXA2xxLCDState),
- VMSTATE_UINT32(cmdcr, PXA2xxLCDState),
- VMSTATE_UINT32(trgbr, PXA2xxLCDState),
- VMSTATE_UINT32(tcr, PXA2xxLCDState),
- VMSTATE_UINT32(liidr, PXA2xxLCDState),
- VMSTATE_UINT8(bscntr, PXA2xxLCDState),
- VMSTATE_STRUCT_ARRAY(dma_ch, PXA2xxLCDState, 7, 0,
- vmstate_dma_channel, struct DMAChannel),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const GraphicHwOps pxa2xx_ops = {
- .invalidate = pxa2xx_invalidate_display,
- .gfx_update = pxa2xx_update_display,
-};
-
-PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
- hwaddr base, qemu_irq irq)
-{
- PXA2xxLCDState *s;
-
- s = g_new0(PXA2xxLCDState, 1);
- s->invalidated = 1;
- s->irq = irq;
- s->sysmem = sysmem;
-
- pxa2xx_lcdc_orientation(s, graphic_rotate);
-
- memory_region_init_io(&s->iomem, NULL, &pxa2xx_lcdc_ops, s,
- "pxa2xx-lcd-controller", 0x00100000);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- s->con = graphic_console_init(NULL, 0, &pxa2xx_ops, s);
-
- vmstate_register(NULL, 0, &vmstate_pxa2xx_lcdc, s);
-
- return s;
-}
-
-void pxa2xx_lcd_vsync_notifier(PXA2xxLCDState *s, qemu_irq handler)
-{
- s->vsync_cb = handler;
-}
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index 7178dec..0c4b1c9 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -1301,8 +1301,8 @@ static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta,
};
uint64_t guest_start;
uint64_t guest_end;
- int pci_region;
- pcibus_t pci_start;
+ int pci_region = -1;
+ pcibus_t pci_start = PCI_BAR_UNMAPPED;
pcibus_t pci_end;
MemoryRegion *mr;
intptr_t virt_start;
@@ -2486,7 +2486,7 @@ static void qxl_pci_class_init(ObjectClass *klass, void *data)
k->vendor_id = REDHAT_PCI_VENDOR_ID;
k->device_id = QXL_DEVICE_ID_STABLE;
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
- dc->reset = qxl_reset_handler;
+ device_class_set_legacy_reset(dc, qxl_reset_handler);
dc->vmsd = &qxl_vmstate;
device_class_set_props(dc, qxl_properties);
}
diff --git a/hw/display/sii9022.c b/hw/display/sii9022.c
index 60c3f78..16f8cb4 100644
--- a/hw/display/sii9022.c
+++ b/hw/display/sii9022.c
@@ -175,7 +175,7 @@ static void sii9022_class_init(ObjectClass *klass, void *data)
k->event = sii9022_event;
k->recv = sii9022_rx;
k->send = sii9022_tx;
- dc->reset = sii9022_reset;
+ device_class_set_legacy_reset(dc, sii9022_reset);
dc->realize = sii9022_realize;
dc->vmsd = &vmstate_sii9022;
}
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index 26dc817..38d005c 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -29,7 +29,7 @@
#include "qemu/log.h"
#include "qemu/module.h"
#include "hw/usb/hcd-ohci.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "ui/console.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
@@ -2086,7 +2086,7 @@ static void sm501_sysbus_class_init(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
dc->desc = "SM501 Multimedia Companion";
device_class_set_props(dc, sm501_sysbus_properties);
- dc->reset = sm501_reset_sysbus;
+ device_class_set_legacy_reset(dc, sm501_reset_sysbus);
dc->vmsd = &vmstate_sm501_sysbus;
}
@@ -2181,7 +2181,7 @@ static void sm501_pci_class_init(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
dc->desc = "SM501 Display Controller";
device_class_set_props(dc, sm501_pci_properties);
- dc->reset = sm501_reset_pci;
+ device_class_set_legacy_reset(dc, sm501_reset_pci);
dc->hotpluggable = false;
dc->vmsd = &vmstate_sm501_pci;
}
diff --git a/hw/display/tc6393xb.c b/hw/display/tc6393xb.c
deleted file mode 100644
index c7beba4..0000000
--- a/hw/display/tc6393xb.c
+++ /dev/null
@@ -1,568 +0,0 @@
-/*
- * Toshiba TC6393XB I/O Controller.
- * Found in Sharp Zaurus SL-6000 (tosa) or some
- * Toshiba e-Series PDAs.
- *
- * Most features are currently unsupported!!!
- *
- * This code is licensed under the GNU GPL v2.
- *
- * 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 "qapi/error.h"
-#include "qemu/host-utils.h"
-#include "hw/irq.h"
-#include "hw/display/tc6393xb.h"
-#include "exec/memory.h"
-#include "hw/block/flash.h"
-#include "ui/console.h"
-#include "ui/pixel_ops.h"
-#include "sysemu/blockdev.h"
-
-#define IRQ_TC6393_NAND 0
-#define IRQ_TC6393_MMC 1
-#define IRQ_TC6393_OHCI 2
-#define IRQ_TC6393_SERIAL 3
-#define IRQ_TC6393_FB 4
-
-#define TC6393XB_NR_IRQS 8
-
-#define TC6393XB_GPIOS 16
-
-#define SCR_REVID 0x08 /* b Revision ID */
-#define SCR_ISR 0x50 /* b Interrupt Status */
-#define SCR_IMR 0x52 /* b Interrupt Mask */
-#define SCR_IRR 0x54 /* b Interrupt Routing */
-#define SCR_GPER 0x60 /* w GP Enable */
-#define SCR_GPI_SR(i) (0x64 + (i)) /* b3 GPI Status */
-#define SCR_GPI_IMR(i) (0x68 + (i)) /* b3 GPI INT Mask */
-#define SCR_GPI_EDER(i) (0x6c + (i)) /* b3 GPI Edge Detect Enable */
-#define SCR_GPI_LIR(i) (0x70 + (i)) /* b3 GPI Level Invert */
-#define SCR_GPO_DSR(i) (0x78 + (i)) /* b3 GPO Data Set */
-#define SCR_GPO_DOECR(i) (0x7c + (i)) /* b3 GPO Data OE Control */
-#define SCR_GP_IARCR(i) (0x80 + (i)) /* b3 GP Internal Active Register Control */
-#define SCR_GP_IARLCR(i) (0x84 + (i)) /* b3 GP INTERNAL Active Register Level Control */
-#define SCR_GPI_BCR(i) (0x88 + (i)) /* b3 GPI Buffer Control */
-#define SCR_GPA_IARCR 0x8c /* w GPa Internal Active Register Control */
-#define SCR_GPA_IARLCR 0x90 /* w GPa Internal Active Register Level Control */
-#define SCR_GPA_BCR 0x94 /* w GPa Buffer Control */
-#define SCR_CCR 0x98 /* w Clock Control */
-#define SCR_PLL2CR 0x9a /* w PLL2 Control */
-#define SCR_PLL1CR 0x9c /* l PLL1 Control */
-#define SCR_DIARCR 0xa0 /* b Device Internal Active Register Control */
-#define SCR_DBOCR 0xa1 /* b Device Buffer Off Control */
-#define SCR_FER 0xe0 /* b Function Enable */
-#define SCR_MCR 0xe4 /* w Mode Control */
-#define SCR_CONFIG 0xfc /* b Configuration Control */
-#define SCR_DEBUG 0xff /* b Debug */
-
-#define NAND_CFG_COMMAND 0x04 /* w Command */
-#define NAND_CFG_BASE 0x10 /* l Control Base Address */
-#define NAND_CFG_INTP 0x3d /* b Interrupt Pin */
-#define NAND_CFG_INTE 0x48 /* b Int Enable */
-#define NAND_CFG_EC 0x4a /* b Event Control */
-#define NAND_CFG_ICC 0x4c /* b Internal Clock Control */
-#define NAND_CFG_ECCC 0x5b /* b ECC Control */
-#define NAND_CFG_NFTC 0x60 /* b NAND Flash Transaction Control */
-#define NAND_CFG_NFM 0x61 /* b NAND Flash Monitor */
-#define NAND_CFG_NFPSC 0x62 /* b NAND Flash Power Supply Control */
-#define NAND_CFG_NFDC 0x63 /* b NAND Flash Detect Control */
-
-#define NAND_DATA 0x00 /* l Data */
-#define NAND_MODE 0x04 /* b Mode */
-#define NAND_STATUS 0x05 /* b Status */
-#define NAND_ISR 0x06 /* b Interrupt Status */
-#define NAND_IMR 0x07 /* b Interrupt Mask */
-
-#define NAND_MODE_WP 0x80
-#define NAND_MODE_CE 0x10
-#define NAND_MODE_ALE 0x02
-#define NAND_MODE_CLE 0x01
-#define NAND_MODE_ECC_MASK 0x60
-#define NAND_MODE_ECC_EN 0x20
-#define NAND_MODE_ECC_READ 0x40
-#define NAND_MODE_ECC_RST 0x60
-
-struct TC6393xbState {
- MemoryRegion iomem;
- qemu_irq irq;
- qemu_irq *sub_irqs;
- struct {
- uint8_t ISR;
- uint8_t IMR;
- uint8_t IRR;
- uint16_t GPER;
- uint8_t GPI_SR[3];
- uint8_t GPI_IMR[3];
- uint8_t GPI_EDER[3];
- uint8_t GPI_LIR[3];
- uint8_t GP_IARCR[3];
- uint8_t GP_IARLCR[3];
- uint8_t GPI_BCR[3];
- uint16_t GPA_IARCR;
- uint16_t GPA_IARLCR;
- uint16_t CCR;
- uint16_t PLL2CR;
- uint32_t PLL1CR;
- uint8_t DIARCR;
- uint8_t DBOCR;
- uint8_t FER;
- uint16_t MCR;
- uint8_t CONFIG;
- uint8_t DEBUG;
- } scr;
- uint32_t gpio_dir;
- uint32_t gpio_level;
- uint32_t prev_level;
- qemu_irq handler[TC6393XB_GPIOS];
- qemu_irq *gpio_in;
-
- struct {
- uint8_t mode;
- uint8_t isr;
- uint8_t imr;
- } nand;
- int nand_enable;
- uint32_t nand_phys;
- DeviceState *flash;
- ECCState ecc;
-
- QemuConsole *con;
- MemoryRegion vram;
- uint16_t *vram_ptr;
- uint32_t scr_width, scr_height; /* in pixels */
- qemu_irq l3v;
- unsigned blank : 1,
- blanked : 1;
-};
-
-static void tc6393xb_gpio_set(void *opaque, int line, int level)
-{
-// TC6393xbState *s = opaque;
-
- if (line > TC6393XB_GPIOS) {
- printf("%s: No GPIO pin %i\n", __func__, line);
- return;
- }
-
- // FIXME: how does the chip reflect the GPIO input level change?
-}
-
-static void tc6393xb_gpio_handler_update(TC6393xbState *s)
-{
- uint32_t level, diff;
- int bit;
-
- level = s->gpio_level & s->gpio_dir;
- level &= MAKE_64BIT_MASK(0, TC6393XB_GPIOS);
-
- for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
- bit = ctz32(diff);
- qemu_set_irq(s->handler[bit], (level >> bit) & 1);
- }
-
- s->prev_level = level;
-}
-
-qemu_irq tc6393xb_l3v_get(TC6393xbState *s)
-{
- return s->l3v;
-}
-
-static void tc6393xb_l3v(void *opaque, int line, int level)
-{
- TC6393xbState *s = opaque;
- s->blank = !level;
- fprintf(stderr, "L3V: %d\n", level);
-}
-
-static void tc6393xb_sub_irq(void *opaque, int line, int level) {
- TC6393xbState *s = opaque;
- uint8_t isr = s->scr.ISR;
- if (level)
- isr |= 1 << line;
- else
- isr &= ~(1 << line);
- s->scr.ISR = isr;
- qemu_set_irq(s->irq, isr & s->scr.IMR);
-}
-
-#define SCR_REG_B(N) \
- case SCR_ ##N: return s->scr.N
-#define SCR_REG_W(N) \
- case SCR_ ##N: return s->scr.N; \
- case SCR_ ##N + 1: return s->scr.N >> 8;
-#define SCR_REG_L(N) \
- case SCR_ ##N: return s->scr.N; \
- case SCR_ ##N + 1: return s->scr.N >> 8; \
- case SCR_ ##N + 2: return s->scr.N >> 16; \
- case SCR_ ##N + 3: return s->scr.N >> 24;
-#define SCR_REG_A(N) \
- case SCR_ ##N(0): return s->scr.N[0]; \
- case SCR_ ##N(1): return s->scr.N[1]; \
- case SCR_ ##N(2): return s->scr.N[2]
-
-static uint32_t tc6393xb_scr_readb(TC6393xbState *s, hwaddr addr)
-{
- switch (addr) {
- case SCR_REVID:
- return 3;
- case SCR_REVID+1:
- return 0;
- SCR_REG_B(ISR);
- SCR_REG_B(IMR);
- SCR_REG_B(IRR);
- SCR_REG_W(GPER);
- SCR_REG_A(GPI_SR);
- SCR_REG_A(GPI_IMR);
- SCR_REG_A(GPI_EDER);
- SCR_REG_A(GPI_LIR);
- case SCR_GPO_DSR(0):
- case SCR_GPO_DSR(1):
- case SCR_GPO_DSR(2):
- return (s->gpio_level >> ((addr - SCR_GPO_DSR(0)) * 8)) & 0xff;
- case SCR_GPO_DOECR(0):
- case SCR_GPO_DOECR(1):
- case SCR_GPO_DOECR(2):
- return (s->gpio_dir >> ((addr - SCR_GPO_DOECR(0)) * 8)) & 0xff;
- SCR_REG_A(GP_IARCR);
- SCR_REG_A(GP_IARLCR);
- SCR_REG_A(GPI_BCR);
- SCR_REG_W(GPA_IARCR);
- SCR_REG_W(GPA_IARLCR);
- SCR_REG_W(CCR);
- SCR_REG_W(PLL2CR);
- SCR_REG_L(PLL1CR);
- SCR_REG_B(DIARCR);
- SCR_REG_B(DBOCR);
- SCR_REG_B(FER);
- SCR_REG_W(MCR);
- SCR_REG_B(CONFIG);
- SCR_REG_B(DEBUG);
- }
- fprintf(stderr, "tc6393xb_scr: unhandled read at %08x\n", (uint32_t) addr);
- return 0;
-}
-#undef SCR_REG_B
-#undef SCR_REG_W
-#undef SCR_REG_L
-#undef SCR_REG_A
-
-#define SCR_REG_B(N) \
- case SCR_ ##N: s->scr.N = value; return;
-#define SCR_REG_W(N) \
- case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); return; \
- case SCR_ ##N + 1: s->scr.N = (s->scr.N & 0xff) | (value << 8); return
-#define SCR_REG_L(N) \
- case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); return; \
- case SCR_ ##N + 1: s->scr.N = (s->scr.N & ~(0xff << 8)) | (value & (0xff << 8)); return; \
- case SCR_ ##N + 2: s->scr.N = (s->scr.N & ~(0xff << 16)) | (value & (0xff << 16)); return; \
- case SCR_ ##N + 3: s->scr.N = (s->scr.N & ~(0xff << 24)) | (value & (0xff << 24)); return;
-#define SCR_REG_A(N) \
- case SCR_ ##N(0): s->scr.N[0] = value; return; \
- case SCR_ ##N(1): s->scr.N[1] = value; return; \
- case SCR_ ##N(2): s->scr.N[2] = value; return
-
-static void tc6393xb_scr_writeb(TC6393xbState *s, hwaddr addr, uint32_t value)
-{
- switch (addr) {
- SCR_REG_B(ISR);
- SCR_REG_B(IMR);
- SCR_REG_B(IRR);
- SCR_REG_W(GPER);
- SCR_REG_A(GPI_SR);
- SCR_REG_A(GPI_IMR);
- SCR_REG_A(GPI_EDER);
- SCR_REG_A(GPI_LIR);
- case SCR_GPO_DSR(0):
- case SCR_GPO_DSR(1):
- case SCR_GPO_DSR(2):
- s->gpio_level = (s->gpio_level & ~(0xff << ((addr - SCR_GPO_DSR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DSR(0))*8));
- tc6393xb_gpio_handler_update(s);
- return;
- case SCR_GPO_DOECR(0):
- case SCR_GPO_DOECR(1):
- case SCR_GPO_DOECR(2):
- s->gpio_dir = (s->gpio_dir & ~(0xff << ((addr - SCR_GPO_DOECR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DOECR(0))*8));
- tc6393xb_gpio_handler_update(s);
- return;
- SCR_REG_A(GP_IARCR);
- SCR_REG_A(GP_IARLCR);
- SCR_REG_A(GPI_BCR);
- SCR_REG_W(GPA_IARCR);
- SCR_REG_W(GPA_IARLCR);
- SCR_REG_W(CCR);
- SCR_REG_W(PLL2CR);
- SCR_REG_L(PLL1CR);
- SCR_REG_B(DIARCR);
- SCR_REG_B(DBOCR);
- SCR_REG_B(FER);
- SCR_REG_W(MCR);
- SCR_REG_B(CONFIG);
- SCR_REG_B(DEBUG);
- }
- fprintf(stderr, "tc6393xb_scr: unhandled write at %08x: %02x\n",
- (uint32_t) addr, value & 0xff);
-}
-#undef SCR_REG_B
-#undef SCR_REG_W
-#undef SCR_REG_L
-#undef SCR_REG_A
-
-static void tc6393xb_nand_irq(TC6393xbState *s) {
- qemu_set_irq(s->sub_irqs[IRQ_TC6393_NAND],
- (s->nand.imr & 0x80) && (s->nand.imr & s->nand.isr));
-}
-
-static uint32_t tc6393xb_nand_cfg_readb(TC6393xbState *s, hwaddr addr) {
- switch (addr) {
- case NAND_CFG_COMMAND:
- return s->nand_enable ? 2 : 0;
- case NAND_CFG_BASE:
- case NAND_CFG_BASE + 1:
- case NAND_CFG_BASE + 2:
- case NAND_CFG_BASE + 3:
- return s->nand_phys >> (addr - NAND_CFG_BASE);
- }
- fprintf(stderr, "tc6393xb_nand_cfg: unhandled read at %08x\n", (uint32_t) addr);
- return 0;
-}
-static void tc6393xb_nand_cfg_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) {
- switch (addr) {
- case NAND_CFG_COMMAND:
- s->nand_enable = (value & 0x2);
- return;
- case NAND_CFG_BASE:
- case NAND_CFG_BASE + 1:
- case NAND_CFG_BASE + 2:
- case NAND_CFG_BASE + 3:
- s->nand_phys &= ~(0xff << ((addr - NAND_CFG_BASE) * 8));
- s->nand_phys |= (value & 0xff) << ((addr - NAND_CFG_BASE) * 8);
- return;
- }
- fprintf(stderr, "tc6393xb_nand_cfg: unhandled write at %08x: %02x\n",
- (uint32_t) addr, value & 0xff);
-}
-
-static uint32_t tc6393xb_nand_readb(TC6393xbState *s, hwaddr addr) {
- switch (addr) {
- case NAND_DATA + 0:
- case NAND_DATA + 1:
- case NAND_DATA + 2:
- case NAND_DATA + 3:
- return nand_getio(s->flash);
- case NAND_MODE:
- return s->nand.mode;
- case NAND_STATUS:
- return 0x14;
- case NAND_ISR:
- return s->nand.isr;
- case NAND_IMR:
- return s->nand.imr;
- }
- fprintf(stderr, "tc6393xb_nand: unhandled read at %08x\n", (uint32_t) addr);
- return 0;
-}
-static void tc6393xb_nand_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) {
-// fprintf(stderr, "tc6393xb_nand: write at %08x: %02x\n",
-// (uint32_t) addr, value & 0xff);
- switch (addr) {
- case NAND_DATA + 0:
- case NAND_DATA + 1:
- case NAND_DATA + 2:
- case NAND_DATA + 3:
- nand_setio(s->flash, value);
- s->nand.isr |= 1;
- tc6393xb_nand_irq(s);
- return;
- case NAND_MODE:
- s->nand.mode = value;
- nand_setpins(s->flash,
- value & NAND_MODE_CLE,
- value & NAND_MODE_ALE,
- !(value & NAND_MODE_CE),
- value & NAND_MODE_WP,
- 0); // FIXME: gnd
- switch (value & NAND_MODE_ECC_MASK) {
- case NAND_MODE_ECC_RST:
- ecc_reset(&s->ecc);
- break;
- case NAND_MODE_ECC_READ:
- // FIXME
- break;
- case NAND_MODE_ECC_EN:
- ecc_reset(&s->ecc);
- }
- return;
- case NAND_ISR:
- s->nand.isr = value;
- tc6393xb_nand_irq(s);
- return;
- case NAND_IMR:
- s->nand.imr = value;
- tc6393xb_nand_irq(s);
- return;
- }
- fprintf(stderr, "tc6393xb_nand: unhandled write at %08x: %02x\n",
- (uint32_t) addr, value & 0xff);
-}
-
-static void tc6393xb_draw_graphic(TC6393xbState *s, int full_update)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int i;
- uint16_t *data_buffer;
- uint8_t *data_display;
-
- data_buffer = s->vram_ptr;
- data_display = surface_data(surface);
- for (i = 0; i < s->scr_height; i++) {
- int j;
- for (j = 0; j < s->scr_width; j++, data_display += 4, data_buffer++) {
- uint16_t color = *data_buffer;
- uint32_t dest_color = rgb_to_pixel32(
- ((color & 0xf800) * 0x108) >> 11,
- ((color & 0x7e0) * 0x41) >> 9,
- ((color & 0x1f) * 0x21) >> 2
- );
- *(uint32_t *)data_display = dest_color;
- }
- }
- dpy_gfx_update_full(s->con);
-}
-
-static void tc6393xb_draw_blank(TC6393xbState *s, int full_update)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int i, w;
- uint8_t *d;
-
- if (!full_update)
- return;
-
- w = s->scr_width * surface_bytes_per_pixel(surface);
- d = surface_data(surface);
- for(i = 0; i < s->scr_height; i++) {
- memset(d, 0, w);
- d += surface_stride(surface);
- }
-
- dpy_gfx_update_full(s->con);
-}
-
-static void tc6393xb_update_display(void *opaque)
-{
- TC6393xbState *s = opaque;
- DisplaySurface *surface = qemu_console_surface(s->con);
- int full_update;
-
- if (s->scr_width == 0 || s->scr_height == 0)
- return;
-
- full_update = 0;
- if (s->blanked != s->blank) {
- s->blanked = s->blank;
- full_update = 1;
- }
- if (s->scr_width != surface_width(surface) ||
- s->scr_height != surface_height(surface)) {
- qemu_console_resize(s->con, s->scr_width, s->scr_height);
- full_update = 1;
- }
- if (s->blanked)
- tc6393xb_draw_blank(s, full_update);
- else
- tc6393xb_draw_graphic(s, full_update);
-}
-
-
-static uint64_t tc6393xb_readb(void *opaque, hwaddr addr,
- unsigned size)
-{
- TC6393xbState *s = opaque;
-
- switch (addr >> 8) {
- case 0:
- return tc6393xb_scr_readb(s, addr & 0xff);
- case 1:
- return tc6393xb_nand_cfg_readb(s, addr & 0xff);
- };
-
- if ((addr &~0xff) == s->nand_phys && s->nand_enable) {
-// return tc6393xb_nand_readb(s, addr & 0xff);
- uint8_t d = tc6393xb_nand_readb(s, addr & 0xff);
-// fprintf(stderr, "tc6393xb_nand: read at %08x: %02hhx\n", (uint32_t) addr, d);
- return d;
- }
-
-// fprintf(stderr, "tc6393xb: unhandled read at %08x\n", (uint32_t) addr);
- return 0;
-}
-
-static void tc6393xb_writeb(void *opaque, hwaddr addr,
- uint64_t value, unsigned size) {
- TC6393xbState *s = opaque;
-
- switch (addr >> 8) {
- case 0:
- tc6393xb_scr_writeb(s, addr & 0xff, value);
- return;
- case 1:
- tc6393xb_nand_cfg_writeb(s, addr & 0xff, value);
- return;
- };
-
- if ((addr &~0xff) == s->nand_phys && s->nand_enable)
- tc6393xb_nand_writeb(s, addr & 0xff, value);
- else
- fprintf(stderr, "tc6393xb: unhandled write at %08x: %02x\n",
- (uint32_t) addr, (int)value & 0xff);
-}
-
-static const GraphicHwOps tc6393xb_gfx_ops = {
- .gfx_update = tc6393xb_update_display,
-};
-
-TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq)
-{
- TC6393xbState *s;
- DriveInfo *nand;
- static const MemoryRegionOps tc6393xb_ops = {
- .read = tc6393xb_readb,
- .write = tc6393xb_writeb,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl = {
- .min_access_size = 1,
- .max_access_size = 1,
- },
- };
-
- s = g_new0(TC6393xbState, 1);
- s->irq = irq;
- s->gpio_in = qemu_allocate_irqs(tc6393xb_gpio_set, s, TC6393XB_GPIOS);
-
- s->l3v = qemu_allocate_irq(tc6393xb_l3v, s, 0);
- s->blanked = 1;
-
- s->sub_irqs = qemu_allocate_irqs(tc6393xb_sub_irq, s, TC6393XB_NR_IRQS);
-
- nand = drive_get(IF_MTD, 0, 0);
- s->flash = nand_init(nand ? blk_by_legacy_dinfo(nand) : NULL,
- NAND_MFR_TOSHIBA, 0x76);
-
- memory_region_init_io(&s->iomem, NULL, &tc6393xb_ops, s, "tc6393xb", 0x10000);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- memory_region_init_ram(&s->vram, NULL, "tc6393xb.vram", 0x100000,
- &error_fatal);
- s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
- memory_region_add_subregion(sysmem, base + 0x100000, &s->vram);
- s->scr_width = 480;
- s->scr_height = 640;
- s->con = graphic_console_init(NULL, 0, &tc6393xb_gfx_ops, s);
-
- return s;
-}
diff --git a/hw/display/tcx.c b/hw/display/tcx.c
index 99507e7..f000288 100644
--- a/hw/display/tcx.c
+++ b/hw/display/tcx.c
@@ -892,7 +892,7 @@ static void tcx_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = tcx_realizefn;
- dc->reset = tcx_reset;
+ device_class_set_legacy_reset(dc, tcx_reset);
dc->vmsd = &vmstate_tcx;
device_class_set_props(dc, tcx_properties);
}
diff --git a/hw/display/trace-events b/hw/display/trace-events
index 781f8a3..d26d663 100644
--- a/hw/display/trace-events
+++ b/hw/display/trace-events
@@ -53,6 +53,9 @@ virtio_gpu_cmd_ctx_submit(uint32_t ctx, uint32_t size) "ctx 0x%x, size %d"
virtio_gpu_update_cursor(uint32_t scanout, uint32_t x, uint32_t y, const char *type, uint32_t res) "scanout %d, x %d, y %d, %s, res 0x%x"
virtio_gpu_fence_ctrl(uint64_t fence, uint32_t type) "fence 0x%" PRIx64 ", type 0x%x"
virtio_gpu_fence_resp(uint64_t fence) "fence 0x%" PRIx64
+virtio_gpu_inc_inflight_fences(uint32_t inflight) "in-flight+ %u"
+virtio_gpu_dec_inflight_fences(uint32_t inflight) "in-flight- %u"
+virtio_gpu_cmd_suspended(uint32_t cmd) "cmd 0x%x"
# qxl.c
disable qxl_io_write_vga(int qid, const char *mode, uint32_t addr, uint32_t val) "%d %s addr=%u val=%u"
diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c
index c096ec9..c025632 100644
--- a/hw/display/vga-isa.c
+++ b/hw/display/vga-isa.c
@@ -98,7 +98,7 @@ static void vga_isa_class_initfn(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = vga_isa_realizefn;
- dc->reset = vga_isa_reset;
+ device_class_set_legacy_reset(dc, vga_isa_reset);
dc->vmsd = &vmstate_vga_common;
device_class_set_props(dc, vga_isa_properties);
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
diff --git a/hw/display/vga-mmio.c b/hw/display/vga-mmio.c
index cd2c467..be33204 100644
--- a/hw/display/vga-mmio.c
+++ b/hw/display/vga-mmio.c
@@ -122,7 +122,7 @@ static void vga_mmio_class_initfn(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = vga_mmio_realizefn;
- dc->reset = vga_mmio_reset;
+ device_class_set_legacy_reset(dc, vga_mmio_reset);
dc->vmsd = &vmstate_vga_common;
device_class_set_props(dc, vga_mmio_properties);
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c
index 2d8adce..6b51019 100644
--- a/hw/display/vga-pci.c
+++ b/hw/display/vga-pci.c
@@ -403,7 +403,7 @@ static void secondary_class_init(ObjectClass *klass, void *data)
k->exit = pci_secondary_vga_exit;
k->class_id = PCI_CLASS_DISPLAY_OTHER;
device_class_set_props(dc, secondary_pci_properties);
- dc->reset = pci_secondary_vga_reset;
+ device_class_set_legacy_reset(dc, pci_secondary_vga_reset);
}
static const TypeInfo vga_info = {
diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c
index 63c64dd..14548f1 100644
--- a/hw/display/vhost-user-gpu.c
+++ b/hw/display/vhost-user-gpu.c
@@ -390,7 +390,7 @@ vhost_user_gpu_chr_read(void *opaque)
}
msg->request = request;
- msg->flags = size;
+ msg->flags = flags;
msg->size = size;
if (request == VHOST_USER_GPU_CURSOR_UPDATE ||
@@ -642,7 +642,7 @@ vhost_user_gpu_device_realize(DeviceState *qdev, Error **errp)
static struct vhost_dev *vhost_user_gpu_get_vhost(VirtIODevice *vdev)
{
VhostUserGPU *g = VHOST_USER_GPU(vdev);
- return &g->vhost->dev;
+ return g->vhost ? &g->vhost->dev : NULL;
}
static Property vhost_user_gpu_properties[] = {
diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c
index e06be60..7c0e448 100644
--- a/hw/display/virtio-gpu-gl.c
+++ b/hw/display/virtio-gpu-gl.c
@@ -29,9 +29,14 @@ static void virtio_gpu_gl_update_cursor_data(VirtIOGPU *g,
struct virtio_gpu_scanout *s,
uint32_t resource_id)
{
+ VirtIOGPUGL *gl = VIRTIO_GPU_GL(g);
uint32_t width, height;
uint32_t pixels, *data;
+ if (gl->renderer_state != RS_INITED) {
+ return;
+ }
+
data = virgl_renderer_get_cursor_data(resource_id, &width, &height);
if (!data) {
return;
@@ -65,13 +70,22 @@ static void virtio_gpu_gl_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
return;
}
- if (!gl->renderer_inited) {
- virtio_gpu_virgl_init(g);
- gl->renderer_inited = true;
- }
- if (gl->renderer_reset) {
- gl->renderer_reset = false;
+ switch (gl->renderer_state) {
+ case RS_RESET:
virtio_gpu_virgl_reset(g);
+ /* fallthrough */
+ case RS_START:
+ if (virtio_gpu_virgl_init(g)) {
+ gl->renderer_state = RS_INIT_FAILED;
+ return;
+ }
+
+ gl->renderer_state = RS_INITED;
+ break;
+ case RS_INIT_FAILED:
+ return;
+ case RS_INITED:
+ break;
}
cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
@@ -98,14 +112,15 @@ static void virtio_gpu_gl_reset(VirtIODevice *vdev)
* GL functions must be called with the associated GL context in main
* thread, and when the renderer is unblocked.
*/
- if (gl->renderer_inited && !gl->renderer_reset) {
+ if (gl->renderer_state == RS_INITED) {
virtio_gpu_virgl_reset_scanout(g);
- gl->renderer_reset = true;
+ gl->renderer_state = RS_RESET;
}
}
static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp)
{
+ ERRP_GUARD();
VirtIOGPU *g = VIRTIO_GPU(qdev);
#if HOST_BIG_ENDIAN
@@ -119,13 +134,22 @@ static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp)
}
if (!display_opengl) {
- error_setg(errp, "opengl is not available");
+ error_setg(errp,
+ "The display backend does not have OpenGL support enabled");
+ error_append_hint(errp,
+ "It can be enabled with '-display BACKEND,gl=on' "
+ "where BACKEND is the name of the display backend "
+ "to use.\n");
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);
+ g->capset_ids = virtio_gpu_virgl_get_capsets(g);
+ VIRTIO_GPU_BASE(g)->virtio_config.num_capsets = g->capset_ids->len;
+
+#if VIRGL_VERSION_MAJOR >= 1
+ g->parent_obj.conf.flags |= 1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED;
+#endif
virtio_gpu_device_realize(qdev, errp);
}
@@ -133,9 +157,32 @@ static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp)
static Property virtio_gpu_gl_properties[] = {
DEFINE_PROP_BIT("stats", VirtIOGPU, parent_obj.conf.flags,
VIRTIO_GPU_FLAG_STATS_ENABLED, false),
+ DEFINE_PROP_BIT("venus", VirtIOGPU, parent_obj.conf.flags,
+ VIRTIO_GPU_FLAG_VENUS_ENABLED, false),
DEFINE_PROP_END_OF_LIST(),
};
+static void virtio_gpu_gl_device_unrealize(DeviceState *qdev)
+{
+ VirtIOGPU *g = VIRTIO_GPU(qdev);
+ VirtIOGPUGL *gl = VIRTIO_GPU_GL(qdev);
+
+ if (gl->renderer_state >= RS_INITED) {
+#if VIRGL_VERSION_MAJOR >= 1
+ qemu_bh_delete(gl->cmdq_resume_bh);
+#endif
+ if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
+ timer_free(gl->print_stats);
+ }
+ timer_free(gl->fence_poll);
+ virgl_renderer_cleanup(NULL);
+ }
+
+ gl->renderer_state = RS_START;
+
+ g_array_unref(g->capset_ids);
+}
+
static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -149,6 +196,7 @@ static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data)
vgc->update_cursor_data = virtio_gpu_gl_update_cursor_data;
vdc->realize = virtio_gpu_gl_device_realize;
+ vdc->unrealize = virtio_gpu_gl_device_unrealize;
vdc->reset = virtio_gpu_gl_reset;
device_class_set_props(dc, virtio_gpu_gl_properties);
}
@@ -170,3 +218,4 @@ static void virtio_register_types(void)
type_init(virtio_register_types)
module_dep("hw-display-virtio-gpu");
+module_dep("ui-opengl");
diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c
index 9f34d0e..eedae73 100644
--- a/hw/display/virtio-gpu-virgl.c
+++ b/hw/display/virtio-gpu-virgl.c
@@ -17,11 +17,31 @@
#include "trace.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 "ui/egl-helpers.h"
#include <virglrenderer.h>
+struct virtio_gpu_virgl_resource {
+ struct virtio_gpu_simple_resource base;
+ MemoryRegion *mr;
+};
+
+static struct virtio_gpu_virgl_resource *
+virtio_gpu_virgl_find_resource(VirtIOGPU *g, uint32_t resource_id)
+{
+ struct virtio_gpu_simple_resource *res;
+
+ res = virtio_gpu_find_resource(g, resource_id);
+ if (!res) {
+ return NULL;
+ }
+
+ return container_of(res, struct virtio_gpu_virgl_resource, base);
+}
+
#if VIRGL_RENDERER_CALLBACKS_VERSION >= 4
static void *
virgl_get_egl_display(G_GNUC_UNUSED void *cookie)
@@ -30,16 +50,179 @@ virgl_get_egl_display(G_GNUC_UNUSED void *cookie)
}
#endif
+#if VIRGL_VERSION_MAJOR >= 1
+struct virtio_gpu_virgl_hostmem_region {
+ MemoryRegion mr;
+ struct VirtIOGPU *g;
+ bool finish_unmapping;
+};
+
+static struct virtio_gpu_virgl_hostmem_region *
+to_hostmem_region(MemoryRegion *mr)
+{
+ return container_of(mr, struct virtio_gpu_virgl_hostmem_region, mr);
+}
+
+static void virtio_gpu_virgl_resume_cmdq_bh(void *opaque)
+{
+ VirtIOGPU *g = opaque;
+
+ virtio_gpu_process_cmdq(g);
+}
+
+static void virtio_gpu_virgl_hostmem_region_free(void *obj)
+{
+ MemoryRegion *mr = MEMORY_REGION(obj);
+ struct virtio_gpu_virgl_hostmem_region *vmr;
+ VirtIOGPUBase *b;
+ VirtIOGPUGL *gl;
+
+ vmr = to_hostmem_region(mr);
+ vmr->finish_unmapping = true;
+
+ b = VIRTIO_GPU_BASE(vmr->g);
+ b->renderer_blocked--;
+
+ /*
+ * memory_region_unref() is executed from RCU thread context, while
+ * virglrenderer works only on the main-loop thread that's holding GL
+ * context.
+ */
+ gl = VIRTIO_GPU_GL(vmr->g);
+ qemu_bh_schedule(gl->cmdq_resume_bh);
+}
+
+static int
+virtio_gpu_virgl_map_resource_blob(VirtIOGPU *g,
+ struct virtio_gpu_virgl_resource *res,
+ uint64_t offset)
+{
+ struct virtio_gpu_virgl_hostmem_region *vmr;
+ VirtIOGPUBase *b = VIRTIO_GPU_BASE(g);
+ MemoryRegion *mr;
+ uint64_t size;
+ void *data;
+ int ret;
+
+ if (!virtio_gpu_hostmem_enabled(b->conf)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: hostmem disabled\n", __func__);
+ return -EOPNOTSUPP;
+ }
+
+ ret = virgl_renderer_resource_map(res->base.resource_id, &data, &size);
+ if (ret) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map virgl resource: %s\n",
+ __func__, strerror(-ret));
+ return ret;
+ }
+
+ vmr = g_new0(struct virtio_gpu_virgl_hostmem_region, 1);
+ vmr->g = g;
+
+ mr = &vmr->mr;
+ memory_region_init_ram_ptr(mr, OBJECT(mr), "blob", size, data);
+ memory_region_add_subregion(&b->hostmem, offset, mr);
+ memory_region_set_enabled(mr, true);
+
+ /*
+ * MR could outlive the resource if MR's reference is held outside of
+ * virtio-gpu. In order to prevent unmapping resource while MR is alive,
+ * and thus, making the data pointer invalid, we will block virtio-gpu
+ * command processing until MR is fully unreferenced and freed.
+ */
+ OBJECT(mr)->free = virtio_gpu_virgl_hostmem_region_free;
+
+ res->mr = mr;
+
+ return 0;
+}
+
+static int
+virtio_gpu_virgl_unmap_resource_blob(VirtIOGPU *g,
+ struct virtio_gpu_virgl_resource *res,
+ bool *cmd_suspended)
+{
+ struct virtio_gpu_virgl_hostmem_region *vmr;
+ VirtIOGPUBase *b = VIRTIO_GPU_BASE(g);
+ MemoryRegion *mr = res->mr;
+ int ret;
+
+ if (!mr) {
+ return 0;
+ }
+
+ vmr = to_hostmem_region(res->mr);
+
+ /*
+ * Perform async unmapping in 3 steps:
+ *
+ * 1. Begin async unmapping with memory_region_del_subregion()
+ * and suspend/block cmd processing.
+ * 2. Wait for res->mr to be freed and cmd processing resumed
+ * asynchronously by virtio_gpu_virgl_hostmem_region_free().
+ * 3. Finish the unmapping with final virgl_renderer_resource_unmap().
+ */
+ if (vmr->finish_unmapping) {
+ res->mr = NULL;
+ g_free(vmr);
+
+ ret = virgl_renderer_resource_unmap(res->base.resource_id);
+ if (ret) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: failed to unmap virgl resource: %s\n",
+ __func__, strerror(-ret));
+ return ret;
+ }
+ } else {
+ *cmd_suspended = true;
+
+ /* render will be unblocked once MR is freed */
+ b->renderer_blocked++;
+
+ /* memory region owns self res->mr object and frees it by itself */
+ memory_region_set_enabled(mr, false);
+ memory_region_del_subregion(&b->hostmem, mr);
+ object_unparent(OBJECT(mr));
+ }
+
+ return 0;
+}
+#endif
+
static void virgl_cmd_create_resource_2d(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd)
{
struct virtio_gpu_resource_create_2d c2d;
struct virgl_renderer_resource_create_args args;
+ struct virtio_gpu_virgl_resource *res;
VIRTIO_GPU_FILL_CMD(c2d);
trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format,
c2d.width, c2d.height);
+ if (c2d.resource_id == 0) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n",
+ __func__);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+ return;
+ }
+
+ res = virtio_gpu_virgl_find_resource(g, c2d.resource_id);
+ if (res) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n",
+ __func__, c2d.resource_id);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+ return;
+ }
+
+ res = g_new0(struct virtio_gpu_virgl_resource, 1);
+ res->base.width = c2d.width;
+ res->base.height = c2d.height;
+ res->base.format = c2d.format;
+ res->base.resource_id = c2d.resource_id;
+ res->base.dmabuf_fd = -1;
+ QTAILQ_INSERT_HEAD(&g->reslist, &res->base, next);
+
args.handle = c2d.resource_id;
args.target = 2;
args.format = c2d.format;
@@ -59,11 +242,35 @@ static void virgl_cmd_create_resource_3d(VirtIOGPU *g,
{
struct virtio_gpu_resource_create_3d c3d;
struct virgl_renderer_resource_create_args args;
+ struct virtio_gpu_virgl_resource *res;
VIRTIO_GPU_FILL_CMD(c3d);
trace_virtio_gpu_cmd_res_create_3d(c3d.resource_id, c3d.format,
c3d.width, c3d.height, c3d.depth);
+ if (c3d.resource_id == 0) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n",
+ __func__);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+ return;
+ }
+
+ res = virtio_gpu_virgl_find_resource(g, c3d.resource_id);
+ if (res) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n",
+ __func__, c3d.resource_id);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+ return;
+ }
+
+ res = g_new0(struct virtio_gpu_virgl_resource, 1);
+ res->base.width = c3d.width;
+ res->base.height = c3d.height;
+ res->base.format = c3d.format;
+ res->base.resource_id = c3d.resource_id;
+ res->base.dmabuf_fd = -1;
+ QTAILQ_INSERT_HEAD(&g->reslist, &res->base, next);
+
args.handle = c3d.resource_id;
args.target = c3d.target;
args.format = c3d.format;
@@ -79,15 +286,35 @@ static void virgl_cmd_create_resource_3d(VirtIOGPU *g,
}
static void virgl_cmd_resource_unref(VirtIOGPU *g,
- struct virtio_gpu_ctrl_command *cmd)
+ struct virtio_gpu_ctrl_command *cmd,
+ bool *cmd_suspended)
{
struct virtio_gpu_resource_unref unref;
+ struct virtio_gpu_virgl_resource *res;
struct iovec *res_iovs = NULL;
int num_iovs = 0;
VIRTIO_GPU_FILL_CMD(unref);
trace_virtio_gpu_cmd_res_unref(unref.resource_id);
+ res = virtio_gpu_virgl_find_resource(g, unref.resource_id);
+ if (!res) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not exist %d\n",
+ __func__, unref.resource_id);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+ return;
+ }
+
+#if VIRGL_VERSION_MAJOR >= 1
+ if (virtio_gpu_virgl_unmap_resource_blob(g, res, cmd_suspended)) {
+ cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+ return;
+ }
+ if (*cmd_suspended) {
+ return;
+ }
+#endif
+
virgl_renderer_resource_detach_iov(unref.resource_id,
&res_iovs,
&num_iovs);
@@ -95,6 +322,10 @@ static void virgl_cmd_resource_unref(VirtIOGPU *g,
virtio_gpu_cleanup_mapping_iov(g, res_iovs, num_iovs);
}
virgl_renderer_resource_unref(unref.resource_id);
+
+ QTAILQ_REMOVE(&g->reslist, &res->base, next);
+
+ g_free(res);
}
static void virgl_cmd_context_create(VirtIOGPU *g,
@@ -106,8 +337,24 @@ static void virgl_cmd_context_create(VirtIOGPU *g,
trace_virtio_gpu_cmd_ctx_create(cc.hdr.ctx_id,
cc.debug_name);
- virgl_renderer_context_create(cc.hdr.ctx_id, cc.nlen,
- cc.debug_name);
+ if (cc.context_init) {
+ if (!virtio_gpu_context_init_enabled(g->parent_obj.conf)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: context_init disabled",
+ __func__);
+ cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+ return;
+ }
+
+#if VIRGL_VERSION_MAJOR >= 1
+ virgl_renderer_context_create_with_flags(cc.hdr.ctx_id,
+ cc.context_init,
+ cc.nlen,
+ cc.debug_name);
+ return;
+#endif
+ }
+
+ virgl_renderer_context_create(cc.hdr.ctx_id, cc.nlen, cc.debug_name);
}
static void virgl_cmd_context_destroy(VirtIOGPU *g,
@@ -171,7 +418,7 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g,
struct virgl_renderer_resource_info info;
void *d3d_tex2d = NULL;
-#ifdef HAVE_VIRGL_D3D_INFO_EXT
+#if VIRGL_VERSION_MAJOR >= 1
struct virgl_renderer_resource_info_ext ext;
memset(&ext, 0, sizeof(ext));
ret = virgl_renderer_resource_get_info_ext(ss.resource_id, &ext);
@@ -375,19 +622,13 @@ static void virgl_cmd_get_capset_info(VirtIOGPU *g,
VIRTIO_GPU_FILL_CMD(info);
memset(&resp, 0, sizeof(resp));
- if (info.capset_index == 0) {
- resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL;
- virgl_renderer_get_cap_set(resp.capset_id,
- &resp.capset_max_version,
- &resp.capset_max_size);
- } else if (info.capset_index == 1) {
- resp.capset_id = VIRTIO_GPU_CAPSET_VIRGL2;
+
+ if (info.capset_index < g->capset_ids->len) {
+ resp.capset_id = g_array_index(g->capset_ids, uint32_t,
+ info.capset_index);
virgl_renderer_get_cap_set(resp.capset_id,
&resp.capset_max_version,
&resp.capset_max_size);
- } else {
- resp.capset_max_version = 0;
- resp.capset_max_size = 0;
}
resp.hdr.type = VIRTIO_GPU_RESP_OK_CAPSET_INFO;
virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp));
@@ -417,9 +658,241 @@ static void virgl_cmd_get_capset(VirtIOGPU *g,
g_free(resp);
}
+#if VIRGL_VERSION_MAJOR >= 1
+static void virgl_cmd_resource_create_blob(VirtIOGPU *g,
+ struct virtio_gpu_ctrl_command *cmd)
+{
+ struct virgl_renderer_resource_create_blob_args virgl_args = { 0 };
+ g_autofree struct virtio_gpu_virgl_resource *res = NULL;
+ struct virtio_gpu_resource_create_blob cblob;
+ struct virgl_renderer_resource_info info;
+ int ret;
+
+ if (!virtio_gpu_blob_enabled(g->parent_obj.conf)) {
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
+ return;
+ }
+
+ VIRTIO_GPU_FILL_CMD(cblob);
+ virtio_gpu_create_blob_bswap(&cblob);
+ trace_virtio_gpu_cmd_res_create_blob(cblob.resource_id, cblob.size);
+
+ if (cblob.resource_id == 0) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n",
+ __func__);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+ return;
+ }
+
+ res = virtio_gpu_virgl_find_resource(g, cblob.resource_id);
+ if (res) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n",
+ __func__, cblob.resource_id);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+ return;
+ }
+
+ res = g_new0(struct virtio_gpu_virgl_resource, 1);
+ res->base.resource_id = cblob.resource_id;
+ res->base.blob_size = cblob.size;
+ res->base.dmabuf_fd = -1;
+
+ if (cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D) {
+ ret = virtio_gpu_create_mapping_iov(g, cblob.nr_entries, sizeof(cblob),
+ cmd, &res->base.addrs,
+ &res->base.iov, &res->base.iov_cnt);
+ if (!ret) {
+ cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+ return;
+ }
+ }
+
+ virgl_args.res_handle = cblob.resource_id;
+ virgl_args.ctx_id = cblob.hdr.ctx_id;
+ virgl_args.blob_mem = cblob.blob_mem;
+ virgl_args.blob_id = cblob.blob_id;
+ virgl_args.blob_flags = cblob.blob_flags;
+ virgl_args.size = cblob.size;
+ virgl_args.iovecs = res->base.iov;
+ virgl_args.num_iovs = res->base.iov_cnt;
+
+ ret = virgl_renderer_resource_create_blob(&virgl_args);
+ if (ret) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: virgl blob create error: %s\n",
+ __func__, strerror(-ret));
+ cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+ virtio_gpu_cleanup_mapping(g, &res->base);
+ return;
+ }
+
+ ret = virgl_renderer_resource_get_info(cblob.resource_id, &info);
+ if (ret) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: resource does not have info %d: %s\n",
+ __func__, cblob.resource_id, strerror(-ret));
+ cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+ virtio_gpu_cleanup_mapping(g, &res->base);
+ virgl_renderer_resource_unref(cblob.resource_id);
+ return;
+ }
+
+ res->base.dmabuf_fd = info.fd;
+
+ QTAILQ_INSERT_HEAD(&g->reslist, &res->base, next);
+ res = NULL;
+}
+
+static void virgl_cmd_resource_map_blob(VirtIOGPU *g,
+ struct virtio_gpu_ctrl_command *cmd)
+{
+ struct virtio_gpu_resource_map_blob mblob;
+ struct virtio_gpu_virgl_resource *res;
+ struct virtio_gpu_resp_map_info resp;
+ int ret;
+
+ VIRTIO_GPU_FILL_CMD(mblob);
+ virtio_gpu_map_blob_bswap(&mblob);
+
+ res = virtio_gpu_virgl_find_resource(g, mblob.resource_id);
+ if (!res) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not exist %d\n",
+ __func__, mblob.resource_id);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+ return;
+ }
+
+ ret = virtio_gpu_virgl_map_resource_blob(g, res, mblob.offset);
+ if (ret) {
+ cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+ return;
+ }
+
+ memset(&resp, 0, sizeof(resp));
+ resp.hdr.type = VIRTIO_GPU_RESP_OK_MAP_INFO;
+ virgl_renderer_resource_get_map_info(mblob.resource_id, &resp.map_info);
+ virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp));
+}
+
+static void virgl_cmd_resource_unmap_blob(VirtIOGPU *g,
+ struct virtio_gpu_ctrl_command *cmd,
+ bool *cmd_suspended)
+{
+ struct virtio_gpu_resource_unmap_blob ublob;
+ struct virtio_gpu_virgl_resource *res;
+ int ret;
+
+ VIRTIO_GPU_FILL_CMD(ublob);
+ virtio_gpu_unmap_blob_bswap(&ublob);
+
+ res = virtio_gpu_virgl_find_resource(g, ublob.resource_id);
+ if (!res) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not exist %d\n",
+ __func__, ublob.resource_id);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+ return;
+ }
+
+ ret = virtio_gpu_virgl_unmap_resource_blob(g, res, cmd_suspended);
+ if (ret) {
+ cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+ return;
+ }
+}
+
+static void virgl_cmd_set_scanout_blob(VirtIOGPU *g,
+ struct virtio_gpu_ctrl_command *cmd)
+{
+ struct virtio_gpu_framebuffer fb = { 0 };
+ struct virtio_gpu_virgl_resource *res;
+ struct virtio_gpu_set_scanout_blob ss;
+ uint64_t fbend;
+
+ VIRTIO_GPU_FILL_CMD(ss);
+ virtio_gpu_scanout_blob_bswap(&ss);
+ trace_virtio_gpu_cmd_set_scanout_blob(ss.scanout_id, ss.resource_id,
+ ss.r.width, ss.r.height, ss.r.x,
+ ss.r.y);
+
+ if (ss.scanout_id >= g->parent_obj.conf.max_outputs) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d",
+ __func__, ss.scanout_id);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
+ return;
+ }
+
+ if (ss.resource_id == 0) {
+ virtio_gpu_disable_scanout(g, ss.scanout_id);
+ return;
+ }
+
+ if (ss.width < 16 ||
+ ss.height < 16 ||
+ ss.r.x + ss.r.width > ss.width ||
+ ss.r.y + ss.r.height > ss.height) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout %d bounds for"
+ " resource %d, rect (%d,%d)+%d,%d, fb %d %d\n",
+ __func__, ss.scanout_id, ss.resource_id,
+ ss.r.x, ss.r.y, ss.r.width, ss.r.height,
+ ss.width, ss.height);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
+ return;
+ }
+
+ res = virtio_gpu_virgl_find_resource(g, ss.resource_id);
+ if (!res) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: resource does not exist %d\n",
+ __func__, ss.resource_id);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+ return;
+ }
+ if (res->base.dmabuf_fd < 0) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: resource not backed by dmabuf %d\n",
+ __func__, ss.resource_id);
+ cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+ return;
+ }
+
+ fb.format = virtio_gpu_get_pixman_format(ss.format);
+ if (!fb.format) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: pixel format not supported %d\n",
+ __func__, ss.format);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
+ return;
+ }
+
+ fb.bytes_pp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(fb.format), 8);
+ fb.width = ss.width;
+ fb.height = ss.height;
+ fb.stride = ss.strides[0];
+ fb.offset = ss.offsets[0] + ss.r.x * fb.bytes_pp + ss.r.y * fb.stride;
+
+ fbend = fb.offset;
+ fbend += fb.stride * (ss.r.height - 1);
+ fbend += fb.bytes_pp * ss.r.width;
+ if (fbend > res->base.blob_size) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: fb end out of range\n",
+ __func__);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
+ return;
+ }
+
+ g->parent_obj.enable = 1;
+ if (virtio_gpu_update_dmabuf(g, ss.scanout_id, &res->base, &fb, &ss.r)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to update dmabuf\n",
+ __func__);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
+ return;
+ }
+
+ virtio_gpu_update_scanout(g, ss.scanout_id, &res->base, &fb, &ss.r);
+}
+#endif
+
void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd)
{
+ bool cmd_suspended = false;
+
VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr);
virgl_renderer_force_ctx_0();
@@ -461,7 +934,7 @@ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
virgl_cmd_resource_flush(g, cmd);
break;
case VIRTIO_GPU_CMD_RESOURCE_UNREF:
- virgl_cmd_resource_unref(g, cmd);
+ virgl_cmd_resource_unref(g, cmd, &cmd_suspended);
break;
case VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE:
/* TODO add security */
@@ -483,12 +956,26 @@ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
case VIRTIO_GPU_CMD_GET_EDID:
virtio_gpu_get_edid(g, cmd);
break;
+#if VIRGL_VERSION_MAJOR >= 1
+ case VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB:
+ virgl_cmd_resource_create_blob(g, cmd);
+ break;
+ case VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB:
+ virgl_cmd_resource_map_blob(g, cmd);
+ break;
+ case VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB:
+ virgl_cmd_resource_unmap_blob(g, cmd, &cmd_suspended);
+ break;
+ case VIRTIO_GPU_CMD_SET_SCANOUT_BLOB:
+ virgl_cmd_set_scanout_blob(g, cmd);
+ break;
+#endif
default:
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
break;
}
- if (cmd->finished) {
+ if (cmd_suspended || cmd->finished) {
return;
}
if (cmd->error) {
@@ -525,7 +1012,7 @@ static void virgl_write_fence(void *opaque, uint32_t fence)
g_free(cmd);
g->inflight--;
if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
- fprintf(stderr, "inflight: %3d (-)\r", g->inflight);
+ trace_virtio_gpu_dec_inflight_fences(g->inflight);
}
}
}
@@ -574,6 +1061,7 @@ static struct virgl_renderer_callbacks virtio_gpu_3d_cbs = {
static void virtio_gpu_print_stats(void *opaque)
{
VirtIOGPU *g = opaque;
+ VirtIOGPUGL *gl = VIRTIO_GPU_GL(g);
if (g->stats.requests) {
fprintf(stderr, "stats: vq req %4d, %3d -- 3D %4d (%5d)\n",
@@ -588,17 +1076,18 @@ static void virtio_gpu_print_stats(void *opaque)
} else {
fprintf(stderr, "stats: idle\r");
}
- timer_mod(g->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000);
+ timer_mod(gl->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000);
}
static void virtio_gpu_fence_poll(void *opaque)
{
VirtIOGPU *g = opaque;
+ VirtIOGPUGL *gl = VIRTIO_GPU_GL(g);
virgl_renderer_poll();
virtio_gpu_process_cmdq(g);
if (!QTAILQ_EMPTY(&g->cmdq) || !QTAILQ_EMPTY(&g->fenceq)) {
- timer_mod(g->fence_poll, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 10);
+ timer_mod(gl->fence_poll, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 10);
}
}
@@ -626,6 +1115,7 @@ int virtio_gpu_virgl_init(VirtIOGPU *g)
{
int ret;
uint32_t flags = 0;
+ VirtIOGPUGL *gl = VIRTIO_GPU_GL(g);
#if VIRGL_RENDERER_CALLBACKS_VERSION >= 4
if (qemu_egl_display) {
@@ -638,6 +1128,11 @@ int virtio_gpu_virgl_init(VirtIOGPU *g)
flags |= VIRGL_RENDERER_D3D11_SHARE_TEXTURE;
}
#endif
+#if VIRGL_VERSION_MAJOR >= 1
+ if (virtio_gpu_venus_enabled(g->parent_obj.conf)) {
+ flags |= VIRGL_RENDERER_VENUS | VIRGL_RENDERER_RENDER_SERVER;
+ }
+#endif
ret = virgl_renderer_init(g, flags, &virtio_gpu_3d_cbs);
if (ret != 0) {
@@ -645,23 +1140,55 @@ int virtio_gpu_virgl_init(VirtIOGPU *g)
return ret;
}
- g->fence_poll = timer_new_ms(QEMU_CLOCK_VIRTUAL,
- virtio_gpu_fence_poll, g);
+ gl->fence_poll = timer_new_ms(QEMU_CLOCK_VIRTUAL,
+ virtio_gpu_fence_poll, g);
if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
- g->print_stats = timer_new_ms(QEMU_CLOCK_VIRTUAL,
- virtio_gpu_print_stats, g);
- timer_mod(g->print_stats, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000);
+ gl->print_stats = timer_new_ms(QEMU_CLOCK_VIRTUAL,
+ virtio_gpu_print_stats, g);
+ timer_mod(gl->print_stats,
+ qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000);
}
+
+#if VIRGL_VERSION_MAJOR >= 1
+ gl->cmdq_resume_bh = aio_bh_new(qemu_get_aio_context(),
+ virtio_gpu_virgl_resume_cmdq_bh,
+ g);
+#endif
+
return 0;
}
-int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g)
+static void virtio_gpu_virgl_add_capset(GArray *capset_ids, uint32_t capset_id)
{
- uint32_t capset2_max_ver, capset2_max_size;
+ g_array_append_val(capset_ids, capset_id);
+}
+
+GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g)
+{
+ uint32_t capset_max_ver, capset_max_size;
+ GArray *capset_ids;
+
+ capset_ids = g_array_new(false, false, sizeof(uint32_t));
+
+ /* VIRGL is always supported. */
+ virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL);
+
virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VIRGL2,
- &capset2_max_ver,
- &capset2_max_size);
+ &capset_max_ver,
+ &capset_max_size);
+ if (capset_max_ver) {
+ virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VIRGL2);
+ }
+
+ if (virtio_gpu_venus_enabled(g->parent_obj.conf)) {
+ virgl_renderer_get_cap_set(VIRTIO_GPU_CAPSET_VENUS,
+ &capset_max_ver,
+ &capset_max_size);
+ if (capset_max_size) {
+ virtio_gpu_virgl_add_capset(capset_ids, VIRTIO_GPU_CAPSET_VENUS);
+ }
+ }
- return capset2_max_ver ? 2 : 1;
+ return capset_ids;
}
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 3281842..c0570ef 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -28,6 +28,7 @@
#include "hw/virtio/virtio-bus.h"
#include "hw/qdev-properties.h"
#include "qemu/log.h"
+#include "qemu/memfd.h"
#include "qemu/module.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
@@ -238,16 +239,6 @@ static uint32_t calc_image_hostmem(pixman_format_code_t pformat,
return height * stride;
}
-#ifdef WIN32
-static void
-win32_pixman_image_destroy(pixman_image_t *image, void *data)
-{
- HANDLE handle = data;
-
- qemu_win32_map_free(pixman_image_get_data(image), handle, &error_warn);
-}
-#endif
-
static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd)
{
@@ -294,28 +285,20 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
res->hostmem = calc_image_hostmem(pformat, c2d.width, c2d.height);
if (res->hostmem + g->hostmem < g->conf_max_hostmem) {
- void *bits = NULL;
-#ifdef WIN32
- bits = qemu_win32_map_alloc(res->hostmem, &res->handle, &error_warn);
- if (!bits) {
+ if (!qemu_pixman_image_new_shareable(
+ &res->image,
+ &res->share_handle,
+ "virtio-gpu res",
+ pformat,
+ c2d.width,
+ c2d.height,
+ c2d.height ? res->hostmem / c2d.height : 0,
+ &error_warn)) {
goto end;
}
-#endif
- res->image = pixman_image_create_bits(
- pformat,
- c2d.width,
- c2d.height,
- bits, c2d.height ? res->hostmem / c2d.height : 0);
-#ifdef WIN32
- if (res->image) {
- pixman_image_set_destroy_function(res->image, win32_pixman_image_destroy, res->handle);
- }
-#endif
}
-#ifdef WIN32
end:
-#endif
if (!res->image) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: resource creation failed %d %d %d\n",
@@ -379,7 +362,7 @@ static void virtio_gpu_resource_create_blob(VirtIOGPU *g,
QTAILQ_INSERT_HEAD(&g->reslist, res, next);
}
-static void virtio_gpu_disable_scanout(VirtIOGPU *g, int scanout_id)
+void virtio_gpu_disable_scanout(VirtIOGPU *g, int scanout_id)
{
struct virtio_gpu_scanout *scanout = &g->parent_obj.scanout[scanout_id];
struct virtio_gpu_simple_resource *res;
@@ -596,11 +579,11 @@ static void virtio_unref_resource(pixman_image_t *image, void *data)
pixman_image_unref(data);
}
-static void virtio_gpu_update_scanout(VirtIOGPU *g,
- uint32_t scanout_id,
- struct virtio_gpu_simple_resource *res,
- struct virtio_gpu_framebuffer *fb,
- struct virtio_gpu_rect *r)
+void virtio_gpu_update_scanout(VirtIOGPU *g,
+ uint32_t scanout_id,
+ struct virtio_gpu_simple_resource *res,
+ struct virtio_gpu_framebuffer *fb,
+ struct virtio_gpu_rect *r)
{
struct virtio_gpu_simple_resource *ores;
struct virtio_gpu_scanout *scanout;
@@ -686,9 +669,7 @@ static bool virtio_gpu_do_set_scanout(VirtIOGPU *g,
/* realloc the surface ptr */
scanout->ds = qemu_create_displaysurface_pixman(rect);
-#ifdef WIN32
- qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, fb->offset);
-#endif
+ qemu_displaysurface_set_share_handle(scanout->ds, res->share_handle, fb->offset);
pixman_image_unref(rect);
dpy_gfx_replace_surface(g->parent_obj.scanout[scanout_id].con,
@@ -1053,6 +1034,12 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g)
/* process command */
vgc->process_cmd(g, cmd);
+ /* command suspended */
+ if (!cmd->finished && !(cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE)) {
+ trace_virtio_gpu_cmd_suspended(cmd->cmd_hdr.type);
+ break;
+ }
+
QTAILQ_REMOVE(&g->cmdq, cmd, next);
if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
g->stats.requests++;
@@ -1065,7 +1052,7 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g)
if (g->stats.max_inflight < g->inflight) {
g->stats.max_inflight = g->inflight;
}
- fprintf(stderr, "inflight: %3d (+)\r", g->inflight);
+ trace_virtio_gpu_inc_inflight_fences(g->inflight);
}
} else {
g_free(cmd);
@@ -1085,7 +1072,7 @@ static void virtio_gpu_process_fenceq(VirtIOGPU *g)
g_free(cmd);
g->inflight--;
if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
- fprintf(stderr, "inflight: %3d (-)\r", g->inflight);
+ trace_virtio_gpu_dec_inflight_fences(g->inflight);
}
}
}
@@ -1284,7 +1271,6 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
VirtIOGPU *g = opaque;
struct virtio_gpu_simple_resource *res;
uint32_t resource_id, pformat;
- void *bits = NULL;
int i;
g->hostmem = 0;
@@ -1311,24 +1297,17 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
}
res->hostmem = calc_image_hostmem(pformat, res->width, res->height);
-#ifdef WIN32
- bits = qemu_win32_map_alloc(res->hostmem, &res->handle, &error_warn);
- if (!bits) {
- g_free(res);
- return -EINVAL;
- }
-#endif
- res->image = pixman_image_create_bits(
- pformat,
- res->width, res->height,
- bits, res->height ? res->hostmem / res->height : 0);
- if (!res->image) {
+ if (!qemu_pixman_image_new_shareable(&res->image,
+ &res->share_handle,
+ "virtio-gpu res",
+ pformat,
+ res->width,
+ res->height,
+ res->height ? res->hostmem / res->height : 0,
+ &error_warn)) {
g_free(res);
return -EINVAL;
}
-#ifdef WIN32
- pixman_image_set_destroy_function(res->image, win32_pixman_image_destroy, res->handle);
-#endif
res->addrs = g_new(uint64_t, res->iov_cnt);
res->iov = g_new(struct iovec, res->iov_cnt);
@@ -1461,9 +1440,7 @@ static int virtio_gpu_post_load(void *opaque, int version_id)
return -EINVAL;
}
scanout->ds = qemu_create_displaysurface_pixman(res->image);
-#ifdef WIN32
- qemu_displaysurface_win32_set_handle(scanout->ds, res->handle, 0);
-#endif
+ qemu_displaysurface_set_share_handle(scanout->ds, res->share_handle, 0);
dpy_gfx_replace_surface(scanout->con, scanout->ds);
}
@@ -1484,15 +1461,35 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
if (virtio_gpu_blob_enabled(g->parent_obj.conf)) {
if (!virtio_gpu_rutabaga_enabled(g->parent_obj.conf) &&
+ !virtio_gpu_virgl_enabled(g->parent_obj.conf) &&
!virtio_gpu_have_udmabuf()) {
error_setg(errp, "need rutabaga or udmabuf for blob resources");
return;
}
+#ifdef VIRGL_VERSION_MAJOR
+ #if VIRGL_VERSION_MAJOR < 1
if (virtio_gpu_virgl_enabled(g->parent_obj.conf)) {
- error_setg(errp, "blobs and virgl are not compatible (yet)");
+ error_setg(errp, "old virglrenderer, blob resources unsupported");
return;
}
+ #endif
+#endif
+ }
+
+ if (virtio_gpu_venus_enabled(g->parent_obj.conf)) {
+#ifdef VIRGL_VERSION_MAJOR
+ #if VIRGL_VERSION_MAJOR >= 1
+ if (!virtio_gpu_blob_enabled(g->parent_obj.conf) ||
+ !virtio_gpu_hostmem_enabled(g->parent_obj.conf)) {
+ error_setg(errp, "venus requires enabled blob and hostmem options");
+ return;
+ }
+ #else
+ error_setg(errp, "old virglrenderer, venus unsupported");
+ return;
+ #endif
+#endif
}
if (!virtio_gpu_base_device_realize(qdev,
diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
index 3db3ff9..f2d72c3 100644
--- a/hw/display/vmware_vga.c
+++ b/hw/display/vmware_vga.c
@@ -1352,7 +1352,7 @@ static void vmsvga_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_DISPLAY_VGA;
k->subsystem_vendor_id = PCI_VENDOR_ID_VMWARE;
k->subsystem_id = SVGA_PCI_DEVICE_ID;
- dc->reset = vmsvga_reset;
+ device_class_set_legacy_reset(dc, vmsvga_reset);
dc->vmsd = &vmstate_vmware_vga;
device_class_set_props(dc, vga_vmware_properties);
dc->hotpluggable = false;
diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c
index c42fc38..6ab2335 100644
--- a/hw/display/xlnx_dp.c
+++ b/hw/display/xlnx_dp.c
@@ -1398,7 +1398,7 @@ static void xlnx_dp_class_init(ObjectClass *oc, void *data)
dc->realize = xlnx_dp_realize;
dc->vmsd = &vmstate_dp;
- dc->reset = xlnx_dp_reset;
+ device_class_set_legacy_reset(dc, xlnx_dp_reset);
device_class_set_props(dc, xlnx_dp_device_properties);
}
diff --git a/hw/dma/bcm2835_dma.c b/hw/dma/bcm2835_dma.c
index 9bda450..9b2fca2 100644
--- a/hw/dma/bcm2835_dma.c
+++ b/hw/dma/bcm2835_dma.c
@@ -390,7 +390,7 @@ static void bcm2835_dma_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = bcm2835_dma_realize;
- dc->reset = bcm2835_dma_reset;
+ device_class_set_legacy_reset(dc, bcm2835_dma_reset);
dc->vmsd = &vmstate_bcm2835_dma;
}
diff --git a/hw/dma/etraxfs_dma.c b/hw/dma/etraxfs_dma.c
deleted file mode 100644
index 9c0003d..0000000
--- a/hw/dma/etraxfs_dma.c
+++ /dev/null
@@ -1,781 +0,0 @@
-/*
- * QEMU ETRAX DMA Controller.
- *
- * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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/hw.h"
-#include "hw/irq.h"
-#include "qemu/main-loop.h"
-#include "sysemu/runstate.h"
-#include "exec/address-spaces.h"
-#include "exec/memory.h"
-
-#include "hw/cris/etraxfs_dma.h"
-
-#define D(x)
-
-#define RW_DATA (0x0 / 4)
-#define RW_SAVED_DATA (0x58 / 4)
-#define RW_SAVED_DATA_BUF (0x5c / 4)
-#define RW_GROUP (0x60 / 4)
-#define RW_GROUP_DOWN (0x7c / 4)
-#define RW_CMD (0x80 / 4)
-#define RW_CFG (0x84 / 4)
-#define RW_STAT (0x88 / 4)
-#define RW_INTR_MASK (0x8c / 4)
-#define RW_ACK_INTR (0x90 / 4)
-#define R_INTR (0x94 / 4)
-#define R_MASKED_INTR (0x98 / 4)
-#define RW_STREAM_CMD (0x9c / 4)
-
-#define DMA_REG_MAX (0x100 / 4)
-
-/* descriptors */
-
-// ------------------------------------------------------------ dma_descr_group
-typedef struct dma_descr_group {
- uint32_t next;
- unsigned eol : 1;
- unsigned tol : 1;
- unsigned bol : 1;
- unsigned : 1;
- unsigned intr : 1;
- unsigned : 2;
- unsigned en : 1;
- unsigned : 7;
- unsigned dis : 1;
- unsigned md : 16;
- struct dma_descr_group *up;
- union {
- struct dma_descr_context *context;
- struct dma_descr_group *group;
- } down;
-} dma_descr_group;
-
-// ---------------------------------------------------------- dma_descr_context
-typedef struct dma_descr_context {
- uint32_t next;
- unsigned eol : 1;
- unsigned : 3;
- unsigned intr : 1;
- unsigned : 1;
- unsigned store_mode : 1;
- unsigned en : 1;
- unsigned : 7;
- unsigned dis : 1;
- unsigned md0 : 16;
- unsigned md1;
- unsigned md2;
- unsigned md3;
- unsigned md4;
- uint32_t saved_data;
- uint32_t saved_data_buf;
-} dma_descr_context;
-
-// ------------------------------------------------------------- dma_descr_data
-typedef struct dma_descr_data {
- uint32_t next;
- uint32_t buf;
- unsigned eol : 1;
- unsigned : 2;
- unsigned out_eop : 1;
- unsigned intr : 1;
- unsigned wait : 1;
- unsigned : 2;
- unsigned : 3;
- unsigned in_eop : 1;
- unsigned : 4;
- unsigned md : 16;
- uint32_t after;
-} dma_descr_data;
-
-/* Constants */
-enum {
- regk_dma_ack_pkt = 0x00000100,
- regk_dma_anytime = 0x00000001,
- regk_dma_array = 0x00000008,
- regk_dma_burst = 0x00000020,
- regk_dma_client = 0x00000002,
- regk_dma_copy_next = 0x00000010,
- regk_dma_copy_up = 0x00000020,
- regk_dma_data_at_eol = 0x00000001,
- regk_dma_dis_c = 0x00000010,
- regk_dma_dis_g = 0x00000020,
- regk_dma_idle = 0x00000001,
- regk_dma_intern = 0x00000004,
- regk_dma_load_c = 0x00000200,
- regk_dma_load_c_n = 0x00000280,
- regk_dma_load_c_next = 0x00000240,
- regk_dma_load_d = 0x00000140,
- regk_dma_load_g = 0x00000300,
- regk_dma_load_g_down = 0x000003c0,
- regk_dma_load_g_next = 0x00000340,
- regk_dma_load_g_up = 0x00000380,
- regk_dma_next_en = 0x00000010,
- regk_dma_next_pkt = 0x00000010,
- regk_dma_no = 0x00000000,
- regk_dma_only_at_wait = 0x00000000,
- regk_dma_restore = 0x00000020,
- regk_dma_rst = 0x00000001,
- regk_dma_running = 0x00000004,
- regk_dma_rw_cfg_default = 0x00000000,
- regk_dma_rw_cmd_default = 0x00000000,
- regk_dma_rw_intr_mask_default = 0x00000000,
- regk_dma_rw_stat_default = 0x00000101,
- regk_dma_rw_stream_cmd_default = 0x00000000,
- regk_dma_save_down = 0x00000020,
- regk_dma_save_up = 0x00000020,
- regk_dma_set_reg = 0x00000050,
- regk_dma_set_w_size1 = 0x00000190,
- regk_dma_set_w_size2 = 0x000001a0,
- regk_dma_set_w_size4 = 0x000001c0,
- regk_dma_stopped = 0x00000002,
- regk_dma_store_c = 0x00000002,
- regk_dma_store_descr = 0x00000000,
- regk_dma_store_g = 0x00000004,
- regk_dma_store_md = 0x00000001,
- regk_dma_sw = 0x00000008,
- regk_dma_update_down = 0x00000020,
- regk_dma_yes = 0x00000001
-};
-
-enum dma_ch_state
-{
- RST = 1,
- STOPPED = 2,
- RUNNING = 4
-};
-
-struct fs_dma_channel
-{
- qemu_irq irq;
- struct etraxfs_dma_client *client;
-
- /* Internal status. */
- int stream_cmd_src;
- enum dma_ch_state state;
-
- unsigned int input : 1;
- unsigned int eol : 1;
-
- struct dma_descr_group current_g;
- struct dma_descr_context current_c;
- struct dma_descr_data current_d;
-
- /* Control registers. */
- uint32_t regs[DMA_REG_MAX];
-};
-
-struct fs_dma_ctrl
-{
- MemoryRegion mmio;
- int nr_channels;
- struct fs_dma_channel *channels;
-
- QEMUBH *bh;
-};
-
-static void DMA_run(void *opaque);
-static int channel_out_run(struct fs_dma_ctrl *ctrl, int c);
-
-static inline uint32_t channel_reg(struct fs_dma_ctrl *ctrl, int c, int reg)
-{
- return ctrl->channels[c].regs[reg];
-}
-
-static inline int channel_stopped(struct fs_dma_ctrl *ctrl, int c)
-{
- return channel_reg(ctrl, c, RW_CFG) & 2;
-}
-
-static inline int channel_en(struct fs_dma_ctrl *ctrl, int c)
-{
- return (channel_reg(ctrl, c, RW_CFG) & 1)
- && ctrl->channels[c].client;
-}
-
-static inline int fs_channel(hwaddr addr)
-{
- /* Every channel has a 0x2000 ctrl register map. */
- return addr >> 13;
-}
-
-#ifdef USE_THIS_DEAD_CODE
-static void channel_load_g(struct fs_dma_ctrl *ctrl, int c)
-{
- hwaddr addr = channel_reg(ctrl, c, RW_GROUP);
-
- /* Load and decode. FIXME: handle endianness. */
- cpu_physical_memory_read(addr, &ctrl->channels[c].current_g,
- sizeof(ctrl->channels[c].current_g));
-}
-
-static void dump_c(int ch, struct dma_descr_context *c)
-{
- printf("%s ch=%d\n", __func__, ch);
- printf("next=%x\n", c->next);
- printf("saved_data=%x\n", c->saved_data);
- printf("saved_data_buf=%x\n", c->saved_data_buf);
- printf("eol=%x\n", (uint32_t) c->eol);
-}
-
-static void dump_d(int ch, struct dma_descr_data *d)
-{
- printf("%s ch=%d\n", __func__, ch);
- printf("next=%x\n", d->next);
- printf("buf=%x\n", d->buf);
- printf("after=%x\n", d->after);
- printf("intr=%x\n", (uint32_t) d->intr);
- printf("out_eop=%x\n", (uint32_t) d->out_eop);
- printf("in_eop=%x\n", (uint32_t) d->in_eop);
- printf("eol=%x\n", (uint32_t) d->eol);
-}
-#endif
-
-static void channel_load_c(struct fs_dma_ctrl *ctrl, int c)
-{
- hwaddr addr = channel_reg(ctrl, c, RW_GROUP_DOWN);
-
- /* Load and decode. FIXME: handle endianness. */
- cpu_physical_memory_read(addr, &ctrl->channels[c].current_c,
- sizeof(ctrl->channels[c].current_c));
-
- D(dump_c(c, &ctrl->channels[c].current_c));
- /* I guess this should update the current pos. */
- ctrl->channels[c].regs[RW_SAVED_DATA] =
- (uint32_t)(unsigned long)ctrl->channels[c].current_c.saved_data;
- ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
- (uint32_t)(unsigned long)ctrl->channels[c].current_c.saved_data_buf;
-}
-
-static void channel_load_d(struct fs_dma_ctrl *ctrl, int c)
-{
- hwaddr addr = channel_reg(ctrl, c, RW_SAVED_DATA);
-
- /* Load and decode. FIXME: handle endianness. */
- D(printf("%s ch=%d addr=" HWADDR_FMT_plx "\n", __func__, c, addr));
- cpu_physical_memory_read(addr, &ctrl->channels[c].current_d,
- sizeof(ctrl->channels[c].current_d));
-
- D(dump_d(c, &ctrl->channels[c].current_d));
- ctrl->channels[c].regs[RW_DATA] = addr;
-}
-
-static void channel_store_c(struct fs_dma_ctrl *ctrl, int c)
-{
- hwaddr addr = channel_reg(ctrl, c, RW_GROUP_DOWN);
-
- /* Encode and store. FIXME: handle endianness. */
- D(printf("%s ch=%d addr=" HWADDR_FMT_plx "\n", __func__, c, addr));
- D(dump_d(c, &ctrl->channels[c].current_d));
- cpu_physical_memory_write(addr, &ctrl->channels[c].current_c,
- sizeof(ctrl->channels[c].current_c));
-}
-
-static void channel_store_d(struct fs_dma_ctrl *ctrl, int c)
-{
- hwaddr addr = channel_reg(ctrl, c, RW_SAVED_DATA);
-
- /* Encode and store. FIXME: handle endianness. */
- D(printf("%s ch=%d addr=" HWADDR_FMT_plx "\n", __func__, c, addr));
- cpu_physical_memory_write(addr, &ctrl->channels[c].current_d,
- sizeof(ctrl->channels[c].current_d));
-}
-
-static inline void channel_stop(struct fs_dma_ctrl *ctrl, int c)
-{
- /* FIXME: */
-}
-
-static inline void channel_start(struct fs_dma_ctrl *ctrl, int c)
-{
- if (ctrl->channels[c].client)
- {
- ctrl->channels[c].eol = 0;
- ctrl->channels[c].state = RUNNING;
- if (!ctrl->channels[c].input)
- channel_out_run(ctrl, c);
- } else
- printf("WARNING: starting DMA ch %d with no client\n", c);
-
- qemu_bh_schedule_idle(ctrl->bh);
-}
-
-static void channel_continue(struct fs_dma_ctrl *ctrl, int c)
-{
- if (!channel_en(ctrl, c)
- || channel_stopped(ctrl, c)
- || ctrl->channels[c].state != RUNNING
- /* Only reload the current data descriptor if it has eol set. */
- || !ctrl->channels[c].current_d.eol) {
- D(printf("continue failed ch=%d state=%d stopped=%d en=%d eol=%d\n",
- c, ctrl->channels[c].state,
- channel_stopped(ctrl, c),
- channel_en(ctrl,c),
- ctrl->channels[c].eol));
- D(dump_d(c, &ctrl->channels[c].current_d));
- return;
- }
-
- /* Reload the current descriptor. */
- channel_load_d(ctrl, c);
-
- /* If the current descriptor cleared the eol flag and we had already
- reached eol state, do the continue. */
- if (!ctrl->channels[c].current_d.eol && ctrl->channels[c].eol) {
- D(printf("continue %d ok %x\n", c,
- ctrl->channels[c].current_d.next));
- ctrl->channels[c].regs[RW_SAVED_DATA] =
- (uint32_t)(unsigned long)ctrl->channels[c].current_d.next;
- channel_load_d(ctrl, c);
- ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
- (uint32_t)(unsigned long)ctrl->channels[c].current_d.buf;
-
- channel_start(ctrl, c);
- }
- ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
- (uint32_t)(unsigned long)ctrl->channels[c].current_d.buf;
-}
-
-static void channel_stream_cmd(struct fs_dma_ctrl *ctrl, int c, uint32_t v)
-{
- unsigned int cmd = v & ((1 << 10) - 1);
-
- D(printf("%s ch=%d cmd=%x\n",
- __func__, c, cmd));
- if (cmd & regk_dma_load_d) {
- channel_load_d(ctrl, c);
- if (cmd & regk_dma_burst)
- channel_start(ctrl, c);
- }
-
- if (cmd & regk_dma_load_c) {
- channel_load_c(ctrl, c);
- }
-}
-
-static void channel_update_irq(struct fs_dma_ctrl *ctrl, int c)
-{
- D(printf("%s %d\n", __func__, c));
- ctrl->channels[c].regs[R_INTR] &=
- ~(ctrl->channels[c].regs[RW_ACK_INTR]);
-
- ctrl->channels[c].regs[R_MASKED_INTR] =
- ctrl->channels[c].regs[R_INTR]
- & ctrl->channels[c].regs[RW_INTR_MASK];
-
- D(printf("%s: chan=%d masked_intr=%x\n", __func__,
- c,
- ctrl->channels[c].regs[R_MASKED_INTR]));
-
- qemu_set_irq(ctrl->channels[c].irq,
- !!ctrl->channels[c].regs[R_MASKED_INTR]);
-}
-
-static int channel_out_run(struct fs_dma_ctrl *ctrl, int c)
-{
- uint32_t len;
- uint32_t saved_data_buf;
- unsigned char buf[2 * 1024];
-
- struct dma_context_metadata meta;
- bool send_context = true;
-
- if (ctrl->channels[c].eol)
- return 0;
-
- do {
- bool out_eop;
- D(printf("ch=%d buf=%x after=%x\n",
- c,
- (uint32_t)ctrl->channels[c].current_d.buf,
- (uint32_t)ctrl->channels[c].current_d.after));
-
- if (send_context) {
- if (ctrl->channels[c].client->client.metadata_push) {
- meta.metadata = ctrl->channels[c].current_d.md;
- ctrl->channels[c].client->client.metadata_push(
- ctrl->channels[c].client->client.opaque,
- &meta);
- }
- send_context = false;
- }
-
- channel_load_d(ctrl, c);
- saved_data_buf = channel_reg(ctrl, c, RW_SAVED_DATA_BUF);
- len = (uint32_t)(unsigned long)
- ctrl->channels[c].current_d.after;
- len -= saved_data_buf;
-
- if (len > sizeof buf)
- len = sizeof buf;
- cpu_physical_memory_read (saved_data_buf, buf, len);
-
- out_eop = ((saved_data_buf + len) ==
- ctrl->channels[c].current_d.after) &&
- ctrl->channels[c].current_d.out_eop;
-
- D(printf("channel %d pushes %x %u bytes eop=%u\n", c,
- saved_data_buf, len, out_eop));
-
- if (ctrl->channels[c].client->client.push) {
- if (len > 0) {
- ctrl->channels[c].client->client.push(
- ctrl->channels[c].client->client.opaque,
- buf, len, out_eop);
- }
- } else {
- printf("WARNING: DMA ch%d dataloss,"
- " no attached client.\n", c);
- }
-
- saved_data_buf += len;
-
- if (saved_data_buf == (uint32_t)(unsigned long)
- ctrl->channels[c].current_d.after) {
- /* Done. Step to next. */
- if (ctrl->channels[c].current_d.out_eop) {
- send_context = true;
- }
- if (ctrl->channels[c].current_d.intr) {
- /* data intr. */
- D(printf("signal intr %d eol=%d\n",
- len, ctrl->channels[c].current_d.eol));
- ctrl->channels[c].regs[R_INTR] |= (1 << 2);
- channel_update_irq(ctrl, c);
- }
- channel_store_d(ctrl, c);
- if (ctrl->channels[c].current_d.eol) {
- D(printf("channel %d EOL\n", c));
- ctrl->channels[c].eol = 1;
-
- /* Mark the context as disabled. */
- ctrl->channels[c].current_c.dis = 1;
- channel_store_c(ctrl, c);
-
- channel_stop(ctrl, c);
- } else {
- ctrl->channels[c].regs[RW_SAVED_DATA] =
- (uint32_t)(unsigned long)ctrl->
- channels[c].current_d.next;
- /* Load new descriptor. */
- channel_load_d(ctrl, c);
- saved_data_buf = (uint32_t)(unsigned long)
- ctrl->channels[c].current_d.buf;
- }
-
- ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
- saved_data_buf;
- D(dump_d(c, &ctrl->channels[c].current_d));
- }
- ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = saved_data_buf;
- } while (!ctrl->channels[c].eol);
- return 1;
-}
-
-static int channel_in_process(struct fs_dma_ctrl *ctrl, int c,
- unsigned char *buf, int buflen, int eop)
-{
- uint32_t len;
- uint32_t saved_data_buf;
-
- if (ctrl->channels[c].eol == 1)
- return 0;
-
- channel_load_d(ctrl, c);
- saved_data_buf = channel_reg(ctrl, c, RW_SAVED_DATA_BUF);
- len = (uint32_t)(unsigned long)ctrl->channels[c].current_d.after;
- len -= saved_data_buf;
-
- if (len > buflen)
- len = buflen;
-
- cpu_physical_memory_write (saved_data_buf, buf, len);
- saved_data_buf += len;
-
- if (saved_data_buf ==
- (uint32_t)(unsigned long)ctrl->channels[c].current_d.after
- || eop) {
- uint32_t r_intr = ctrl->channels[c].regs[R_INTR];
-
- D(printf("in dscr end len=%d\n",
- ctrl->channels[c].current_d.after
- - ctrl->channels[c].current_d.buf));
- ctrl->channels[c].current_d.after = saved_data_buf;
-
- /* Done. Step to next. */
- if (ctrl->channels[c].current_d.intr) {
- /* TODO: signal eop to the client. */
- /* data intr. */
- ctrl->channels[c].regs[R_INTR] |= 3;
- }
- if (eop) {
- ctrl->channels[c].current_d.in_eop = 1;
- ctrl->channels[c].regs[R_INTR] |= 8;
- }
- if (r_intr != ctrl->channels[c].regs[R_INTR])
- channel_update_irq(ctrl, c);
-
- channel_store_d(ctrl, c);
- D(dump_d(c, &ctrl->channels[c].current_d));
-
- if (ctrl->channels[c].current_d.eol) {
- D(printf("channel %d EOL\n", c));
- ctrl->channels[c].eol = 1;
-
- /* Mark the context as disabled. */
- ctrl->channels[c].current_c.dis = 1;
- channel_store_c(ctrl, c);
-
- channel_stop(ctrl, c);
- } else {
- ctrl->channels[c].regs[RW_SAVED_DATA] =
- (uint32_t)(unsigned long)ctrl->
- channels[c].current_d.next;
- /* Load new descriptor. */
- channel_load_d(ctrl, c);
- saved_data_buf = (uint32_t)(unsigned long)
- ctrl->channels[c].current_d.buf;
- }
- }
-
- ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = saved_data_buf;
- return len;
-}
-
-static inline int channel_in_run(struct fs_dma_ctrl *ctrl, int c)
-{
- if (ctrl->channels[c].client->client.pull) {
- ctrl->channels[c].client->client.pull(
- ctrl->channels[c].client->client.opaque);
- return 1;
- } else
- return 0;
-}
-
-static uint32_t dma_rinvalid (void *opaque, hwaddr addr)
-{
- hw_error("Unsupported short raccess. reg=" HWADDR_FMT_plx "\n", addr);
- return 0;
-}
-
-static uint64_t
-dma_read(void *opaque, hwaddr addr, unsigned int size)
-{
- struct fs_dma_ctrl *ctrl = opaque;
- int c;
- uint32_t r = 0;
-
- if (size != 4) {
- dma_rinvalid(opaque, addr);
- }
-
- /* Make addr relative to this channel and bounded to nr regs. */
- c = fs_channel(addr);
- addr &= 0xff;
- addr >>= 2;
- switch (addr)
- {
- case RW_STAT:
- r = ctrl->channels[c].state & 7;
- r |= ctrl->channels[c].eol << 5;
- r |= ctrl->channels[c].stream_cmd_src << 8;
- break;
-
- default:
- r = ctrl->channels[c].regs[addr];
- D(printf("%s c=%d addr=" HWADDR_FMT_plx "\n",
- __func__, c, addr));
- break;
- }
- return r;
-}
-
-static void
-dma_winvalid (void *opaque, hwaddr addr, uint32_t value)
-{
- hw_error("Unsupported short waccess. reg=" HWADDR_FMT_plx "\n", addr);
-}
-
-static void
-dma_update_state(struct fs_dma_ctrl *ctrl, int c)
-{
- if (ctrl->channels[c].regs[RW_CFG] & 2)
- ctrl->channels[c].state = STOPPED;
- if (!(ctrl->channels[c].regs[RW_CFG] & 1))
- ctrl->channels[c].state = RST;
-}
-
-static void
-dma_write(void *opaque, hwaddr addr,
- uint64_t val64, unsigned int size)
-{
- struct fs_dma_ctrl *ctrl = opaque;
- uint32_t value = val64;
- int c;
-
- if (size != 4) {
- dma_winvalid(opaque, addr, value);
- }
-
- /* Make addr relative to this channel and bounded to nr regs. */
- c = fs_channel(addr);
- addr &= 0xff;
- addr >>= 2;
- switch (addr)
- {
- case RW_DATA:
- ctrl->channels[c].regs[addr] = value;
- break;
-
- case RW_CFG:
- ctrl->channels[c].regs[addr] = value;
- dma_update_state(ctrl, c);
- break;
- case RW_CMD:
- /* continue. */
- if (value & ~1)
- printf("Invalid store to ch=%d RW_CMD %x\n",
- c, value);
- ctrl->channels[c].regs[addr] = value;
- channel_continue(ctrl, c);
- break;
-
- case RW_SAVED_DATA:
- case RW_SAVED_DATA_BUF:
- case RW_GROUP:
- case RW_GROUP_DOWN:
- ctrl->channels[c].regs[addr] = value;
- break;
-
- case RW_ACK_INTR:
- case RW_INTR_MASK:
- ctrl->channels[c].regs[addr] = value;
- channel_update_irq(ctrl, c);
- if (addr == RW_ACK_INTR)
- ctrl->channels[c].regs[RW_ACK_INTR] = 0;
- break;
-
- case RW_STREAM_CMD:
- if (value & ~1023)
- printf("Invalid store to ch=%d "
- "RW_STREAMCMD %x\n",
- c, value);
- ctrl->channels[c].regs[addr] = value;
- D(printf("stream_cmd ch=%d\n", c));
- channel_stream_cmd(ctrl, c, value);
- break;
-
- default:
- D(printf("%s c=%d " HWADDR_FMT_plx "\n",
- __func__, c, addr));
- break;
- }
-}
-
-static const MemoryRegionOps dma_ops = {
- .read = dma_read,
- .write = dma_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 4
- }
-};
-
-static int etraxfs_dmac_run(void *opaque)
-{
- struct fs_dma_ctrl *ctrl = opaque;
- int i;
- int p = 0;
-
- for (i = 0;
- i < ctrl->nr_channels;
- i++)
- {
- if (ctrl->channels[i].state == RUNNING)
- {
- if (ctrl->channels[i].input) {
- p += channel_in_run(ctrl, i);
- } else {
- p += channel_out_run(ctrl, i);
- }
- }
- }
- return p;
-}
-
-int etraxfs_dmac_input(struct etraxfs_dma_client *client,
- void *buf, int len, int eop)
-{
- return channel_in_process(client->ctrl, client->channel,
- buf, len, eop);
-}
-
-/* Connect an IRQ line with a channel. */
-void etraxfs_dmac_connect(void *opaque, int c, qemu_irq *line, int input)
-{
- struct fs_dma_ctrl *ctrl = opaque;
- ctrl->channels[c].irq = *line;
- ctrl->channels[c].input = input;
-}
-
-void etraxfs_dmac_connect_client(void *opaque, int c,
- struct etraxfs_dma_client *cl)
-{
- struct fs_dma_ctrl *ctrl = opaque;
- cl->ctrl = ctrl;
- cl->channel = c;
- ctrl->channels[c].client = cl;
-}
-
-
-static void DMA_run(void *opaque)
-{
- struct fs_dma_ctrl *etraxfs_dmac = opaque;
- int p = 1;
-
- if (runstate_is_running())
- p = etraxfs_dmac_run(etraxfs_dmac);
-
- if (p)
- qemu_bh_schedule_idle(etraxfs_dmac->bh);
-}
-
-void *etraxfs_dmac_init(hwaddr base, int nr_channels)
-{
- struct fs_dma_ctrl *ctrl = NULL;
-
- ctrl = g_malloc0(sizeof *ctrl);
-
- ctrl->bh = qemu_bh_new(DMA_run, ctrl);
-
- ctrl->nr_channels = nr_channels;
- ctrl->channels = g_malloc0(sizeof ctrl->channels[0] * nr_channels);
-
- memory_region_init_io(&ctrl->mmio, NULL, &dma_ops, ctrl, "etraxfs-dma",
- nr_channels * 0x2000);
- memory_region_add_subregion(get_system_memory(), base, &ctrl->mmio);
-
- return ctrl;
-}
diff --git a/hw/dma/i8257.c b/hw/dma/i8257.c
index 24a54ca..3e6700e 100644
--- a/hw/dma/i8257.c
+++ b/hw/dma/i8257.c
@@ -599,7 +599,7 @@ static void i8257_class_init(ObjectClass *klass, void *data)
IsaDmaClass *idc = ISADMA_CLASS(klass);
dc->realize = i8257_realize;
- dc->reset = i8257_reset;
+ device_class_set_legacy_reset(dc, i8257_reset);
dc->vmsd = &vmstate_i8257;
device_class_set_props(dc, i8257_properties);
diff --git a/hw/dma/meson.build b/hw/dma/meson.build
index a96c1be..cc7810b 100644
--- a/hw/dma/meson.build
+++ b/hw/dma/meson.build
@@ -5,12 +5,10 @@ system_ss.add(when: 'CONFIG_I82374', if_true: files('i82374.c'))
system_ss.add(when: 'CONFIG_I8257', if_true: files('i8257.c'))
system_ss.add(when: 'CONFIG_XILINX_AXI', if_true: files('xilinx_axidma.c'))
system_ss.add(when: 'CONFIG_ZYNQ_DEVCFG', if_true: files('xlnx-zynq-devcfg.c'))
-system_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_dma.c'))
system_ss.add(when: 'CONFIG_STP2000', if_true: files('sparc32_dma.c'))
system_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx_dpdma.c'))
system_ss.add(when: 'CONFIG_XLNX_ZDMA', if_true: files('xlnx-zdma.c'))
system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_dma.c', 'soc_dma.c'))
-system_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_dma.c'))
system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_dma.c'))
system_ss.add(when: 'CONFIG_SIFIVE_PDMA', if_true: files('sifive_pdma.c'))
system_ss.add(when: 'CONFIG_XLNX_CSU_DMA', if_true: files('xlnx_csu_dma.c'))
diff --git a/hw/dma/omap_dma.c b/hw/dma/omap_dma.c
index 77797a6..9a8c3c3 100644
--- a/hw/dma/omap_dma.c
+++ b/hw/dma/omap_dma.c
@@ -686,10 +686,7 @@ void omap_dma_reset(struct soc_dma_s *dma)
struct omap_dma_s *s = dma->opaque;
soc_dma_reset(s->dma);
- if (s->model < omap_dma_4)
- s->gcr = 0x0004;
- else
- s->gcr = 0x00010010;
+ s->gcr = 0x0004;
s->ocp = 0x00000000;
memset(&s->irqstat, 0, sizeof(s->irqstat));
memset(&s->irqen, 0, sizeof(s->irqen));
@@ -697,8 +694,7 @@ void omap_dma_reset(struct soc_dma_s *dma)
s->lcd_ch.condition = 0;
s->lcd_ch.interrupts = 0;
s->lcd_ch.dual = 0;
- if (s->model < omap_dma_4)
- omap_dma_enable_3_1_mapping(s);
+ omap_dma_enable_3_1_mapping(s);
for (i = 0; i < s->chans; i ++) {
s->ch[i].suspend = 0;
s->ch[i].prefetch = 0;
@@ -721,10 +717,7 @@ void omap_dma_reset(struct soc_dma_s *dma)
s->ch[i].repeat = 0;
s->ch[i].auto_init = 0;
s->ch[i].link_enabled = 0;
- if (s->model < omap_dma_4)
- s->ch[i].interrupts = 0x0003;
- else
- s->ch[i].interrupts = 0x0000;
+ s->ch[i].interrupts = 0x0003;
s->ch[i].status = 0;
s->ch[i].cstatus = 0;
s->ch[i].active = 0;
@@ -1587,7 +1580,6 @@ static void omap_dma_setcaps(struct omap_dma_s *s)
case omap_dma_3_1:
break;
case omap_dma_3_2:
- case omap_dma_4:
/* XXX Only available for sDMA */
s->caps[0] =
(1 << 19) | /* Constant Fill Capability */
@@ -1678,443 +1670,6 @@ struct soc_dma_s *omap_dma_init(hwaddr base, qemu_irq *irqs,
return s->dma;
}
-static void omap_dma_interrupts_4_update(struct omap_dma_s *s)
-{
- struct omap_dma_channel_s *ch = s->ch;
- uint32_t bmp, bit;
-
- for (bmp = 0, bit = 1; bit; ch ++, bit <<= 1)
- if (ch->status) {
- bmp |= bit;
- ch->cstatus |= ch->status;
- ch->status = 0;
- }
- if ((s->irqstat[0] |= s->irqen[0] & bmp))
- qemu_irq_raise(s->irq[0]);
- if ((s->irqstat[1] |= s->irqen[1] & bmp))
- qemu_irq_raise(s->irq[1]);
- if ((s->irqstat[2] |= s->irqen[2] & bmp))
- qemu_irq_raise(s->irq[2]);
- if ((s->irqstat[3] |= s->irqen[3] & bmp))
- qemu_irq_raise(s->irq[3]);
-}
-
-static uint64_t omap_dma4_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_dma_s *s = opaque;
- int irqn = 0, chnum;
- struct omap_dma_channel_s *ch;
-
- if (size == 1) {
- return omap_badwidth_read16(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* DMA4_REVISION */
- return 0x40;
-
- case 0x14: /* DMA4_IRQSTATUS_L3 */
- irqn ++;
- /* fall through */
- case 0x10: /* DMA4_IRQSTATUS_L2 */
- irqn ++;
- /* fall through */
- case 0x0c: /* DMA4_IRQSTATUS_L1 */
- irqn ++;
- /* fall through */
- case 0x08: /* DMA4_IRQSTATUS_L0 */
- return s->irqstat[irqn];
-
- case 0x24: /* DMA4_IRQENABLE_L3 */
- irqn ++;
- /* fall through */
- case 0x20: /* DMA4_IRQENABLE_L2 */
- irqn ++;
- /* fall through */
- case 0x1c: /* DMA4_IRQENABLE_L1 */
- irqn ++;
- /* fall through */
- case 0x18: /* DMA4_IRQENABLE_L0 */
- return s->irqen[irqn];
-
- case 0x28: /* DMA4_SYSSTATUS */
- return 1; /* RESETDONE */
-
- case 0x2c: /* DMA4_OCP_SYSCONFIG */
- return s->ocp;
-
- case 0x64: /* DMA4_CAPS_0 */
- return s->caps[0];
- case 0x6c: /* DMA4_CAPS_2 */
- return s->caps[2];
- case 0x70: /* DMA4_CAPS_3 */
- return s->caps[3];
- case 0x74: /* DMA4_CAPS_4 */
- return s->caps[4];
-
- case 0x78: /* DMA4_GCR */
- return s->gcr;
-
- case 0x80 ... 0xfff:
- addr -= 0x80;
- chnum = addr / 0x60;
- ch = s->ch + chnum;
- addr -= chnum * 0x60;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return 0;
- }
-
- /* Per-channel registers */
- switch (addr) {
- case 0x00: /* DMA4_CCR */
- return (ch->buf_disable << 25) |
- (ch->src_sync << 24) |
- (ch->prefetch << 23) |
- ((ch->sync & 0x60) << 14) |
- (ch->bs << 18) |
- (ch->transparent_copy << 17) |
- (ch->constant_fill << 16) |
- (ch->mode[1] << 14) |
- (ch->mode[0] << 12) |
- (0 << 10) | (0 << 9) |
- (ch->suspend << 8) |
- (ch->enable << 7) |
- (ch->priority << 6) |
- (ch->fs << 5) | (ch->sync & 0x1f);
-
- case 0x04: /* DMA4_CLNK_CTRL */
- return (ch->link_enabled << 15) | ch->link_next_ch;
-
- case 0x08: /* DMA4_CICR */
- return ch->interrupts;
-
- case 0x0c: /* DMA4_CSR */
- return ch->cstatus;
-
- case 0x10: /* DMA4_CSDP */
- return (ch->endian[0] << 21) |
- (ch->endian_lock[0] << 20) |
- (ch->endian[1] << 19) |
- (ch->endian_lock[1] << 18) |
- (ch->write_mode << 16) |
- (ch->burst[1] << 14) |
- (ch->pack[1] << 13) |
- (ch->translate[1] << 9) |
- (ch->burst[0] << 7) |
- (ch->pack[0] << 6) |
- (ch->translate[0] << 2) |
- (ch->data_type >> 1);
-
- case 0x14: /* DMA4_CEN */
- return ch->elements;
-
- case 0x18: /* DMA4_CFN */
- return ch->frames;
-
- case 0x1c: /* DMA4_CSSA */
- return ch->addr[0];
-
- case 0x20: /* DMA4_CDSA */
- return ch->addr[1];
-
- case 0x24: /* DMA4_CSEI */
- return ch->element_index[0];
-
- case 0x28: /* DMA4_CSFI */
- return ch->frame_index[0];
-
- case 0x2c: /* DMA4_CDEI */
- return ch->element_index[1];
-
- case 0x30: /* DMA4_CDFI */
- return ch->frame_index[1];
-
- case 0x34: /* DMA4_CSAC */
- return ch->active_set.src & 0xffff;
-
- case 0x38: /* DMA4_CDAC */
- return ch->active_set.dest & 0xffff;
-
- case 0x3c: /* DMA4_CCEN */
- return ch->active_set.element;
-
- case 0x40: /* DMA4_CCFN */
- return ch->active_set.frame;
-
- case 0x44: /* DMA4_COLOR */
- /* XXX only in sDMA */
- return ch->color;
-
- default:
- OMAP_BAD_REG(addr);
- return 0;
- }
-}
-
-static void omap_dma4_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_dma_s *s = opaque;
- int chnum, irqn = 0;
- struct omap_dma_channel_s *ch;
-
- if (size == 1) {
- omap_badwidth_write16(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x14: /* DMA4_IRQSTATUS_L3 */
- irqn ++;
- /* fall through */
- case 0x10: /* DMA4_IRQSTATUS_L2 */
- irqn ++;
- /* fall through */
- case 0x0c: /* DMA4_IRQSTATUS_L1 */
- irqn ++;
- /* fall through */
- case 0x08: /* DMA4_IRQSTATUS_L0 */
- s->irqstat[irqn] &= ~value;
- if (!s->irqstat[irqn])
- qemu_irq_lower(s->irq[irqn]);
- return;
-
- case 0x24: /* DMA4_IRQENABLE_L3 */
- irqn ++;
- /* fall through */
- case 0x20: /* DMA4_IRQENABLE_L2 */
- irqn ++;
- /* fall through */
- case 0x1c: /* DMA4_IRQENABLE_L1 */
- irqn ++;
- /* fall through */
- case 0x18: /* DMA4_IRQENABLE_L0 */
- s->irqen[irqn] = value;
- return;
-
- case 0x2c: /* DMA4_OCP_SYSCONFIG */
- if (value & 2) /* SOFTRESET */
- omap_dma_reset(s->dma);
- s->ocp = value & 0x3321;
- if (((s->ocp >> 12) & 3) == 3) { /* MIDLEMODE */
- qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid DMA power mode\n",
- __func__);
- }
- return;
-
- case 0x78: /* DMA4_GCR */
- s->gcr = value & 0x00ff00ff;
- if ((value & 0xff) == 0x00) { /* MAX_CHANNEL_FIFO_DEPTH */
- qemu_log_mask(LOG_GUEST_ERROR, "%s: wrong FIFO depth in GCR\n",
- __func__);
- }
- return;
-
- case 0x80 ... 0xfff:
- addr -= 0x80;
- chnum = addr / 0x60;
- ch = s->ch + chnum;
- addr -= chnum * 0x60;
- break;
-
- case 0x00: /* DMA4_REVISION */
- case 0x28: /* DMA4_SYSSTATUS */
- case 0x64: /* DMA4_CAPS_0 */
- case 0x6c: /* DMA4_CAPS_2 */
- case 0x70: /* DMA4_CAPS_3 */
- case 0x74: /* DMA4_CAPS_4 */
- OMAP_RO_REG(addr);
- return;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-
- /* Per-channel registers */
- switch (addr) {
- case 0x00: /* DMA4_CCR */
- ch->buf_disable = (value >> 25) & 1;
- ch->src_sync = (value >> 24) & 1; /* XXX For CamDMA must be 1 */
- if (ch->buf_disable && !ch->src_sync) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Buffering disable is not allowed in "
- "destination synchronised mode\n", __func__);
- }
- ch->prefetch = (value >> 23) & 1;
- ch->bs = (value >> 18) & 1;
- ch->transparent_copy = (value >> 17) & 1;
- ch->constant_fill = (value >> 16) & 1;
- ch->mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14);
- ch->mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12);
- ch->suspend = (value & 0x0100) >> 8;
- ch->priority = (value & 0x0040) >> 6;
- ch->fs = (value & 0x0020) >> 5;
- if (ch->fs && ch->bs && ch->mode[0] && ch->mode[1]) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: For a packet transfer at least one port "
- "must be constant-addressed\n", __func__);
- }
- ch->sync = (value & 0x001f) | ((value >> 14) & 0x0060);
- /* XXX must be 0x01 for CamDMA */
-
- if (value & 0x0080)
- omap_dma_enable_channel(s, ch);
- else
- omap_dma_disable_channel(s, ch);
-
- break;
-
- case 0x04: /* DMA4_CLNK_CTRL */
- ch->link_enabled = (value >> 15) & 0x1;
- ch->link_next_ch = value & 0x1f;
- break;
-
- case 0x08: /* DMA4_CICR */
- ch->interrupts = value & 0x09be;
- break;
-
- case 0x0c: /* DMA4_CSR */
- ch->cstatus &= ~value;
- break;
-
- case 0x10: /* DMA4_CSDP */
- ch->endian[0] =(value >> 21) & 1;
- ch->endian_lock[0] =(value >> 20) & 1;
- ch->endian[1] =(value >> 19) & 1;
- ch->endian_lock[1] =(value >> 18) & 1;
- if (ch->endian[0] != ch->endian[1]) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: DMA endianness conversion enable attempt\n",
- __func__);
- }
- ch->write_mode = (value >> 16) & 3;
- ch->burst[1] = (value & 0xc000) >> 14;
- ch->pack[1] = (value & 0x2000) >> 13;
- ch->translate[1] = (value & 0x1e00) >> 9;
- ch->burst[0] = (value & 0x0180) >> 7;
- ch->pack[0] = (value & 0x0040) >> 6;
- ch->translate[0] = (value & 0x003c) >> 2;
- if (ch->translate[0] | ch->translate[1]) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: bad MReqAddressTranslate sideband signal\n",
- __func__);
- }
- ch->data_type = 1 << (value & 3);
- if ((value & 3) == 3) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: bad data_type for DMA channel\n", __func__);
- ch->data_type >>= 1;
- }
- break;
-
- case 0x14: /* DMA4_CEN */
- ch->set_update = 1;
- ch->elements = value & 0xffffff;
- break;
-
- case 0x18: /* DMA4_CFN */
- ch->frames = value & 0xffff;
- ch->set_update = 1;
- break;
-
- case 0x1c: /* DMA4_CSSA */
- ch->addr[0] = (hwaddr) (uint32_t) value;
- ch->set_update = 1;
- break;
-
- case 0x20: /* DMA4_CDSA */
- ch->addr[1] = (hwaddr) (uint32_t) value;
- ch->set_update = 1;
- break;
-
- case 0x24: /* DMA4_CSEI */
- ch->element_index[0] = (int16_t) value;
- ch->set_update = 1;
- break;
-
- case 0x28: /* DMA4_CSFI */
- ch->frame_index[0] = (int32_t) value;
- ch->set_update = 1;
- break;
-
- case 0x2c: /* DMA4_CDEI */
- ch->element_index[1] = (int16_t) value;
- ch->set_update = 1;
- break;
-
- case 0x30: /* DMA4_CDFI */
- ch->frame_index[1] = (int32_t) value;
- ch->set_update = 1;
- break;
-
- case 0x44: /* DMA4_COLOR */
- /* XXX only in sDMA */
- ch->color = value;
- break;
-
- case 0x34: /* DMA4_CSAC */
- case 0x38: /* DMA4_CDAC */
- case 0x3c: /* DMA4_CCEN */
- case 0x40: /* DMA4_CCFN */
- OMAP_RO_REG(addr);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_dma4_ops = {
- .read = omap_dma4_read,
- .write = omap_dma4_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct soc_dma_s *omap_dma4_init(hwaddr base, qemu_irq *irqs,
- MemoryRegion *sysmem,
- struct omap_mpu_state_s *mpu, int fifo,
- int chans, omap_clk iclk, omap_clk fclk)
-{
- int i;
- struct omap_dma_s *s = g_new0(struct omap_dma_s, 1);
-
- s->model = omap_dma_4;
- s->chans = chans;
- s->mpu = mpu;
- s->clk = fclk;
-
- s->dma = soc_dma_init(s->chans);
- s->dma->freq = omap_clk_getrate(fclk);
- s->dma->transfer_fn = omap_dma_transfer_generic;
- s->dma->setup_fn = omap_dma_transfer_setup;
- s->dma->drq = qemu_allocate_irqs(omap_dma_request, s, 64);
- s->dma->opaque = s;
- for (i = 0; i < s->chans; i ++) {
- s->ch[i].dma = &s->dma->ch[i];
- s->dma->ch[i].opaque = &s->ch[i];
- }
-
- memcpy(&s->irq, irqs, sizeof(s->irq));
- s->intr_update = omap_dma_interrupts_4_update;
-
- omap_dma_setcaps(s);
- omap_clk_adduser(s->clk, qemu_allocate_irq(omap_dma_clk_update, s, 0));
- omap_dma_reset(s->dma);
- omap_dma_clk_update(s, 0, !!s->dma->freq);
-
- memory_region_init_io(&s->iomem, NULL, &omap_dma4_ops, s, "omap.dma4", 0x1000);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- mpu->drq = s->dma->drq;
-
- return s->dma;
-}
-
struct omap_dma_lcd_channel_s *omap_dma_get_lcdch(struct soc_dma_s *dma)
{
struct omap_dma_s *s = dma->opaque;
diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c
index 1e49c22..8e76f88 100644
--- a/hw/dma/pl080.c
+++ b/hw/dma/pl080.c
@@ -421,7 +421,7 @@ static void pl080_class_init(ObjectClass *oc, void *data)
dc->vmsd = &vmstate_pl080;
dc->realize = pl080_realize;
device_class_set_props(dc, pl080_properties);
- dc->reset = pl080_reset;
+ device_class_set_legacy_reset(dc, pl080_reset);
}
static const TypeInfo pl080_info = {
diff --git a/hw/dma/pl330.c b/hw/dma/pl330.c
index 5f89295..0668cae 100644
--- a/hw/dma/pl330.c
+++ b/hw/dma/pl330.c
@@ -1678,7 +1678,7 @@ static void pl330_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = pl330_realize;
- dc->reset = pl330_reset;
+ device_class_set_legacy_reset(dc, pl330_reset);
device_class_set_props(dc, pl330_properties);
dc->vmsd = &vmstate_pl330;
}
diff --git a/hw/dma/pxa2xx_dma.c b/hw/dma/pxa2xx_dma.c
deleted file mode 100644
index 9f62f0b..0000000
--- a/hw/dma/pxa2xx_dma.c
+++ /dev/null
@@ -1,591 +0,0 @@
-/*
- * Intel XScale PXA255/270 DMA controller.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Copyright (c) 2006 Thorsten Zitterell
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPL.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/log.h"
-#include "hw/hw.h"
-#include "hw/irq.h"
-#include "hw/qdev-properties.h"
-#include "hw/arm/pxa.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "qapi/error.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-#define PXA255_DMA_NUM_CHANNELS 16
-#define PXA27X_DMA_NUM_CHANNELS 32
-
-#define PXA2XX_DMA_NUM_REQUESTS 75
-
-typedef struct {
- uint32_t descr;
- uint32_t src;
- uint32_t dest;
- uint32_t cmd;
- uint32_t state;
- int request;
-} PXA2xxDMAChannel;
-
-#define TYPE_PXA2XX_DMA "pxa2xx-dma"
-OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxDMAState, PXA2XX_DMA)
-
-struct PXA2xxDMAState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq irq;
-
- uint32_t stopintr;
- uint32_t eorintr;
- uint32_t rasintr;
- uint32_t startintr;
- uint32_t endintr;
-
- uint32_t align;
- uint32_t pio;
-
- int channels;
- PXA2xxDMAChannel *chan;
-
- uint8_t req[PXA2XX_DMA_NUM_REQUESTS];
-
- /* Flag to avoid recursive DMA invocations. */
- int running;
-};
-
-#define DCSR0 0x0000 /* DMA Control / Status register for Channel 0 */
-#define DCSR31 0x007c /* DMA Control / Status register for Channel 31 */
-#define DALGN 0x00a0 /* DMA Alignment register */
-#define DPCSR 0x00a4 /* DMA Programmed I/O Control Status register */
-#define DRQSR0 0x00e0 /* DMA DREQ<0> Status register */
-#define DRQSR1 0x00e4 /* DMA DREQ<1> Status register */
-#define DRQSR2 0x00e8 /* DMA DREQ<2> Status register */
-#define DINT 0x00f0 /* DMA Interrupt register */
-#define DRCMR0 0x0100 /* Request to Channel Map register 0 */
-#define DRCMR63 0x01fc /* Request to Channel Map register 63 */
-#define D_CH0 0x0200 /* Channel 0 Descriptor start */
-#define DRCMR64 0x1100 /* Request to Channel Map register 64 */
-#define DRCMR74 0x1128 /* Request to Channel Map register 74 */
-
-/* Per-channel register */
-#define DDADR 0x00
-#define DSADR 0x01
-#define DTADR 0x02
-#define DCMD 0x03
-
-/* Bit-field masks */
-#define DRCMR_CHLNUM 0x1f
-#define DRCMR_MAPVLD (1 << 7)
-#define DDADR_STOP (1 << 0)
-#define DDADR_BREN (1 << 1)
-#define DCMD_LEN 0x1fff
-#define DCMD_WIDTH(x) (1 << ((((x) >> 14) & 3) - 1))
-#define DCMD_SIZE(x) (4 << (((x) >> 16) & 3))
-#define DCMD_FLYBYT (1 << 19)
-#define DCMD_FLYBYS (1 << 20)
-#define DCMD_ENDIRQEN (1 << 21)
-#define DCMD_STARTIRQEN (1 << 22)
-#define DCMD_CMPEN (1 << 25)
-#define DCMD_FLOWTRG (1 << 28)
-#define DCMD_FLOWSRC (1 << 29)
-#define DCMD_INCTRGADDR (1 << 30)
-#define DCMD_INCSRCADDR (1 << 31)
-#define DCSR_BUSERRINTR (1 << 0)
-#define DCSR_STARTINTR (1 << 1)
-#define DCSR_ENDINTR (1 << 2)
-#define DCSR_STOPINTR (1 << 3)
-#define DCSR_RASINTR (1 << 4)
-#define DCSR_REQPEND (1 << 8)
-#define DCSR_EORINT (1 << 9)
-#define DCSR_CMPST (1 << 10)
-#define DCSR_MASKRUN (1 << 22)
-#define DCSR_RASIRQEN (1 << 23)
-#define DCSR_CLRCMPST (1 << 24)
-#define DCSR_SETCMPST (1 << 25)
-#define DCSR_EORSTOPEN (1 << 26)
-#define DCSR_EORJMPEN (1 << 27)
-#define DCSR_EORIRQEN (1 << 28)
-#define DCSR_STOPIRQEN (1 << 29)
-#define DCSR_NODESCFETCH (1 << 30)
-#define DCSR_RUN (1 << 31)
-
-static inline void pxa2xx_dma_update(PXA2xxDMAState *s, int ch)
-{
- if (ch >= 0) {
- if ((s->chan[ch].state & DCSR_STOPIRQEN) &&
- (s->chan[ch].state & DCSR_STOPINTR))
- s->stopintr |= 1 << ch;
- else
- s->stopintr &= ~(1 << ch);
-
- if ((s->chan[ch].state & DCSR_EORIRQEN) &&
- (s->chan[ch].state & DCSR_EORINT))
- s->eorintr |= 1 << ch;
- else
- s->eorintr &= ~(1 << ch);
-
- if ((s->chan[ch].state & DCSR_RASIRQEN) &&
- (s->chan[ch].state & DCSR_RASINTR))
- s->rasintr |= 1 << ch;
- else
- s->rasintr &= ~(1 << ch);
-
- if (s->chan[ch].state & DCSR_STARTINTR)
- s->startintr |= 1 << ch;
- else
- s->startintr &= ~(1 << ch);
-
- if (s->chan[ch].state & DCSR_ENDINTR)
- s->endintr |= 1 << ch;
- else
- s->endintr &= ~(1 << ch);
- }
-
- if (s->stopintr | s->eorintr | s->rasintr | s->startintr | s->endintr)
- qemu_irq_raise(s->irq);
- else
- qemu_irq_lower(s->irq);
-}
-
-static inline void pxa2xx_dma_descriptor_fetch(
- PXA2xxDMAState *s, int ch)
-{
- uint32_t desc[4];
- hwaddr daddr = s->chan[ch].descr & ~0xf;
- if ((s->chan[ch].descr & DDADR_BREN) && (s->chan[ch].state & DCSR_CMPST))
- daddr += 32;
-
- cpu_physical_memory_read(daddr, desc, 16);
- s->chan[ch].descr = desc[DDADR];
- s->chan[ch].src = desc[DSADR];
- s->chan[ch].dest = desc[DTADR];
- s->chan[ch].cmd = desc[DCMD];
-
- if (s->chan[ch].cmd & DCMD_FLOWSRC)
- s->chan[ch].src &= ~3;
- if (s->chan[ch].cmd & DCMD_FLOWTRG)
- s->chan[ch].dest &= ~3;
-
- if (s->chan[ch].cmd & (DCMD_CMPEN | DCMD_FLYBYS | DCMD_FLYBYT))
- printf("%s: unsupported mode in channel %i\n", __func__, ch);
-
- if (s->chan[ch].cmd & DCMD_STARTIRQEN)
- s->chan[ch].state |= DCSR_STARTINTR;
-}
-
-static void pxa2xx_dma_run(PXA2xxDMAState *s)
-{
- int c, srcinc, destinc;
- uint32_t n, size;
- uint32_t width;
- uint32_t length;
- uint8_t buffer[32];
- PXA2xxDMAChannel *ch;
-
- if (s->running ++)
- return;
-
- while (s->running) {
- s->running = 1;
- for (c = 0; c < s->channels; c ++) {
- ch = &s->chan[c];
-
- while ((ch->state & DCSR_RUN) && !(ch->state & DCSR_STOPINTR)) {
- /* Test for pending requests */
- if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) && !ch->request)
- break;
-
- length = ch->cmd & DCMD_LEN;
- size = DCMD_SIZE(ch->cmd);
- width = DCMD_WIDTH(ch->cmd);
-
- srcinc = (ch->cmd & DCMD_INCSRCADDR) ? width : 0;
- destinc = (ch->cmd & DCMD_INCTRGADDR) ? width : 0;
-
- while (length) {
- size = MIN(length, size);
-
- for (n = 0; n < size; n += width) {
- cpu_physical_memory_read(ch->src, buffer + n, width);
- ch->src += srcinc;
- }
-
- for (n = 0; n < size; n += width) {
- cpu_physical_memory_write(ch->dest, buffer + n, width);
- ch->dest += destinc;
- }
-
- length -= size;
-
- if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) &&
- !ch->request) {
- ch->state |= DCSR_EORINT;
- if (ch->state & DCSR_EORSTOPEN)
- ch->state |= DCSR_STOPINTR;
- if ((ch->state & DCSR_EORJMPEN) &&
- !(ch->state & DCSR_NODESCFETCH))
- pxa2xx_dma_descriptor_fetch(s, c);
- break;
- }
- }
-
- ch->cmd = (ch->cmd & ~DCMD_LEN) | length;
-
- /* Is the transfer complete now? */
- if (!length) {
- if (ch->cmd & DCMD_ENDIRQEN)
- ch->state |= DCSR_ENDINTR;
-
- if ((ch->state & DCSR_NODESCFETCH) ||
- (ch->descr & DDADR_STOP) ||
- (ch->state & DCSR_EORSTOPEN)) {
- ch->state |= DCSR_STOPINTR;
- ch->state &= ~DCSR_RUN;
-
- break;
- }
-
- ch->state |= DCSR_STOPINTR;
- break;
- }
- }
- }
-
- s->running --;
- }
-}
-
-static uint64_t pxa2xx_dma_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PXA2xxDMAState *s = (PXA2xxDMAState *) opaque;
- unsigned int channel;
-
- if (size != 4) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad access width %u\n",
- __func__, size);
- return 5;
- }
-
- switch (offset) {
- case DRCMR64 ... DRCMR74:
- offset -= DRCMR64 - DRCMR0 - (64 << 2);
- /* Fall through */
- case DRCMR0 ... DRCMR63:
- channel = (offset - DRCMR0) >> 2;
- return s->req[channel];
-
- case DRQSR0:
- case DRQSR1:
- case DRQSR2:
- return 0;
-
- case DCSR0 ... DCSR31:
- channel = offset >> 2;
- if (s->chan[channel].request)
- return s->chan[channel].state | DCSR_REQPEND;
- return s->chan[channel].state;
-
- case DINT:
- return s->stopintr | s->eorintr | s->rasintr |
- s->startintr | s->endintr;
-
- case DALGN:
- return s->align;
-
- case DPCSR:
- return s->pio;
- }
-
- if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) {
- channel = (offset - D_CH0) >> 4;
- switch ((offset & 0x0f) >> 2) {
- case DDADR:
- return s->chan[channel].descr;
- case DSADR:
- return s->chan[channel].src;
- case DTADR:
- return s->chan[channel].dest;
- case DCMD:
- return s->chan[channel].cmd;
- }
- }
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
- __func__, offset);
- return 7;
-}
-
-static void pxa2xx_dma_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxDMAState *s = (PXA2xxDMAState *) opaque;
- unsigned int channel;
-
- if (size != 4) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad access width %u\n",
- __func__, size);
- return;
- }
-
- switch (offset) {
- case DRCMR64 ... DRCMR74:
- offset -= DRCMR64 - DRCMR0 - (64 << 2);
- /* Fall through */
- case DRCMR0 ... DRCMR63:
- channel = (offset - DRCMR0) >> 2;
-
- if (value & DRCMR_MAPVLD)
- if ((value & DRCMR_CHLNUM) > s->channels)
- hw_error("%s: Bad DMA channel %i\n",
- __func__, (unsigned)value & DRCMR_CHLNUM);
-
- s->req[channel] = value;
- break;
-
- case DRQSR0:
- case DRQSR1:
- case DRQSR2:
- /* Nothing to do */
- break;
-
- case DCSR0 ... DCSR31:
- channel = offset >> 2;
- s->chan[channel].state &= 0x0000071f & ~(value &
- (DCSR_EORINT | DCSR_ENDINTR |
- DCSR_STARTINTR | DCSR_BUSERRINTR));
- s->chan[channel].state |= value & 0xfc800000;
-
- if (s->chan[channel].state & DCSR_STOPIRQEN)
- s->chan[channel].state &= ~DCSR_STOPINTR;
-
- if (value & DCSR_NODESCFETCH) {
- /* No-descriptor-fetch mode */
- if (value & DCSR_RUN) {
- s->chan[channel].state &= ~DCSR_STOPINTR;
- pxa2xx_dma_run(s);
- }
- } else {
- /* Descriptor-fetch mode */
- if (value & DCSR_RUN) {
- s->chan[channel].state &= ~DCSR_STOPINTR;
- pxa2xx_dma_descriptor_fetch(s, channel);
- pxa2xx_dma_run(s);
- }
- }
-
- /* Shouldn't matter as our DMA is synchronous. */
- if (!(value & (DCSR_RUN | DCSR_MASKRUN)))
- s->chan[channel].state |= DCSR_STOPINTR;
-
- if (value & DCSR_CLRCMPST)
- s->chan[channel].state &= ~DCSR_CMPST;
- if (value & DCSR_SETCMPST)
- s->chan[channel].state |= DCSR_CMPST;
-
- pxa2xx_dma_update(s, channel);
- break;
-
- case DALGN:
- s->align = value;
- break;
-
- case DPCSR:
- s->pio = value & 0x80000001;
- break;
-
- default:
- if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) {
- channel = (offset - D_CH0) >> 4;
- switch ((offset & 0x0f) >> 2) {
- case DDADR:
- s->chan[channel].descr = value;
- break;
- case DSADR:
- s->chan[channel].src = value;
- break;
- case DTADR:
- s->chan[channel].dest = value;
- break;
- case DCMD:
- s->chan[channel].cmd = value;
- break;
- default:
- goto fail;
- }
-
- break;
- }
- fail:
- qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
- __func__, offset);
- }
-}
-
-static const MemoryRegionOps pxa2xx_dma_ops = {
- .read = pxa2xx_dma_read,
- .write = pxa2xx_dma_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pxa2xx_dma_request(void *opaque, int req_num, int on)
-{
- PXA2xxDMAState *s = opaque;
- int ch;
- if (req_num < 0 || req_num >= PXA2XX_DMA_NUM_REQUESTS)
- hw_error("%s: Bad DMA request %i\n", __func__, req_num);
-
- if (!(s->req[req_num] & DRCMR_MAPVLD))
- return;
- ch = s->req[req_num] & DRCMR_CHLNUM;
-
- if (!s->chan[ch].request && on)
- s->chan[ch].state |= DCSR_RASINTR;
- else
- s->chan[ch].state &= ~DCSR_RASINTR;
- if (s->chan[ch].request && !on)
- s->chan[ch].state |= DCSR_EORINT;
-
- s->chan[ch].request = on;
- if (on) {
- pxa2xx_dma_run(s);
- pxa2xx_dma_update(s, ch);
- }
-}
-
-static void pxa2xx_dma_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- PXA2xxDMAState *s = PXA2XX_DMA(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- memset(s->req, 0, sizeof(uint8_t) * PXA2XX_DMA_NUM_REQUESTS);
-
- qdev_init_gpio_in(dev, pxa2xx_dma_request, PXA2XX_DMA_NUM_REQUESTS);
-
- memory_region_init_io(&s->iomem, obj, &pxa2xx_dma_ops, s,
- "pxa2xx.dma", 0x00010000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
-}
-
-static void pxa2xx_dma_realize(DeviceState *dev, Error **errp)
-{
- PXA2xxDMAState *s = PXA2XX_DMA(dev);
- int i;
-
- if (s->channels <= 0) {
- error_setg(errp, "channels value invalid");
- return;
- }
-
- s->chan = g_new0(PXA2xxDMAChannel, s->channels);
-
- for (i = 0; i < s->channels; i ++)
- s->chan[i].state = DCSR_STOPINTR;
-}
-
-DeviceState *pxa27x_dma_init(hwaddr base, qemu_irq irq)
-{
- DeviceState *dev;
-
- dev = qdev_new("pxa2xx-dma");
- qdev_prop_set_int32(dev, "channels", PXA27X_DMA_NUM_CHANNELS);
- 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;
-}
-
-DeviceState *pxa255_dma_init(hwaddr base, qemu_irq irq)
-{
- DeviceState *dev;
-
- dev = qdev_new("pxa2xx-dma");
- qdev_prop_set_int32(dev, "channels", PXA27X_DMA_NUM_CHANNELS);
- 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 bool is_version_0(void *opaque, int version_id)
-{
- return version_id == 0;
-}
-
-static const VMStateDescription vmstate_pxa2xx_dma_chan = {
- .name = "pxa2xx_dma_chan",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32(descr, PXA2xxDMAChannel),
- VMSTATE_UINT32(src, PXA2xxDMAChannel),
- VMSTATE_UINT32(dest, PXA2xxDMAChannel),
- VMSTATE_UINT32(cmd, PXA2xxDMAChannel),
- VMSTATE_UINT32(state, PXA2xxDMAChannel),
- VMSTATE_INT32(request, PXA2xxDMAChannel),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static const VMStateDescription vmstate_pxa2xx_dma = {
- .name = "pxa2xx_dma",
- .version_id = 1,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UNUSED_TEST(is_version_0, 4),
- VMSTATE_UINT32(stopintr, PXA2xxDMAState),
- VMSTATE_UINT32(eorintr, PXA2xxDMAState),
- VMSTATE_UINT32(rasintr, PXA2xxDMAState),
- VMSTATE_UINT32(startintr, PXA2xxDMAState),
- VMSTATE_UINT32(endintr, PXA2xxDMAState),
- VMSTATE_UINT32(align, PXA2xxDMAState),
- VMSTATE_UINT32(pio, PXA2xxDMAState),
- VMSTATE_BUFFER(req, PXA2xxDMAState),
- VMSTATE_STRUCT_VARRAY_POINTER_INT32(chan, PXA2xxDMAState, channels,
- vmstate_pxa2xx_dma_chan, PXA2xxDMAChannel),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static Property pxa2xx_dma_properties[] = {
- DEFINE_PROP_INT32("channels", PXA2xxDMAState, channels, -1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxa2xx_dma_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->desc = "PXA2xx DMA controller";
- dc->vmsd = &vmstate_pxa2xx_dma;
- device_class_set_props(dc, pxa2xx_dma_properties);
- dc->realize = pxa2xx_dma_realize;
-}
-
-static const TypeInfo pxa2xx_dma_info = {
- .name = TYPE_PXA2XX_DMA,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxDMAState),
- .instance_init = pxa2xx_dma_init,
- .class_init = pxa2xx_dma_class_init,
-};
-
-static void pxa2xx_dma_register_types(void)
-{
- type_register_static(&pxa2xx_dma_info);
-}
-
-type_init(pxa2xx_dma_register_types)
diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c
index 9152841..5bf5434 100644
--- a/hw/dma/rc4030.c
+++ b/hw/dma/rc4030.c
@@ -707,7 +707,7 @@ static void rc4030_class_init(ObjectClass *klass, void *class_data)
dc->realize = rc4030_realize;
dc->unrealize = rc4030_unrealize;
- dc->reset = rc4030_reset;
+ device_class_set_legacy_reset(dc, rc4030_reset);
dc->vmsd = &vmstate_rc4030;
}
diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c
index 8019641..9fdba16 100644
--- a/hw/dma/sparc32_dma.c
+++ b/hw/dma/sparc32_dma.c
@@ -278,7 +278,7 @@ static void sparc32_dma_device_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = sparc32_dma_device_reset;
+ device_class_set_legacy_reset(dc, sparc32_dma_device_reset);
dc->vmsd = &vmstate_sparc32_dma_device;
}
diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c
index c9cfc31..73a480b 100644
--- a/hw/dma/xilinx_axidma.c
+++ b/hw/dma/xilinx_axidma.c
@@ -626,8 +626,8 @@ static void axidma_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->realize = xilinx_axidma_realize,
- dc->reset = xilinx_axidma_reset;
+ dc->realize = xilinx_axidma_realize;
+ device_class_set_legacy_reset(dc, xilinx_axidma_reset);
device_class_set_props(dc, axidma_properties);
}
diff --git a/hw/dma/xlnx-zdma.c b/hw/dma/xlnx-zdma.c
index 670c956..46f5063 100644
--- a/hw/dma/xlnx-zdma.c
+++ b/hw/dma/xlnx-zdma.c
@@ -821,7 +821,7 @@ static void zdma_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = zdma_reset;
+ device_class_set_legacy_reset(dc, zdma_reset);
dc->realize = zdma_realize;
device_class_set_props(dc, zdma_props);
dc->vmsd = &vmstate_zdma;
diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c
index e901f68..b8544d0 100644
--- a/hw/dma/xlnx-zynq-devcfg.c
+++ b/hw/dma/xlnx-zynq-devcfg.c
@@ -384,7 +384,7 @@ static void xlnx_zynq_devcfg_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = xlnx_zynq_devcfg_reset;
+ device_class_set_legacy_reset(dc, xlnx_zynq_devcfg_reset);
dc->vmsd = &vmstate_xlnx_zynq_devcfg;
}
diff --git a/hw/dma/xlnx_csu_dma.c b/hw/dma/xlnx_csu_dma.c
index ae30748..43738c4 100644
--- a/hw/dma/xlnx_csu_dma.c
+++ b/hw/dma/xlnx_csu_dma.c
@@ -719,7 +719,7 @@ static void xlnx_csu_dma_class_init(ObjectClass *klass, void *data)
StreamSinkClass *ssc = STREAM_SINK_CLASS(klass);
XlnxCSUDMAClass *xcdc = XLNX_CSU_DMA_CLASS(klass);
- dc->reset = xlnx_csu_dma_reset;
+ device_class_set_legacy_reset(dc, xlnx_csu_dma_reset);
dc->realize = xlnx_csu_dma_realize;
dc->vmsd = &vmstate_xlnx_csu_dma;
device_class_set_props(dc, xlnx_csu_dma_properties);
diff --git a/hw/dma/xlnx_dpdma.c b/hw/dma/xlnx_dpdma.c
index a685bd2..2657808 100644
--- a/hw/dma/xlnx_dpdma.c
+++ b/hw/dma/xlnx_dpdma.c
@@ -598,7 +598,7 @@ static void xlnx_dpdma_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->vmsd = &vmstate_xlnx_dpdma;
- dc->reset = xlnx_dpdma_reset;
+ device_class_set_legacy_reset(dc, xlnx_dpdma_reset);
}
static const TypeInfo xlnx_dpdma_info = {
diff --git a/hw/fsi/aspeed_apb2opb.c b/hw/fsi/aspeed_apb2opb.c
index ea50718..0e2cc14 100644
--- a/hw/fsi/aspeed_apb2opb.c
+++ b/hw/fsi/aspeed_apb2opb.c
@@ -326,7 +326,7 @@ static void fsi_aspeed_apb2opb_class_init(ObjectClass *klass, void *data)
dc->desc = "ASPEED APB2OPB Bridge";
dc->realize = fsi_aspeed_apb2opb_realize;
- dc->reset = fsi_aspeed_apb2opb_reset;
+ device_class_set_legacy_reset(dc, fsi_aspeed_apb2opb_reset);
}
static const TypeInfo aspeed_apb2opb_info = {
diff --git a/hw/fsi/fsi-master.c b/hw/fsi/fsi-master.c
index a5f0598..50fb1cd 100644
--- a/hw/fsi/fsi-master.c
+++ b/hw/fsi/fsi-master.c
@@ -151,7 +151,7 @@ static void fsi_master_class_init(ObjectClass *klass, void *data)
dc->bus_type = TYPE_OP_BUS;
dc->desc = "FSI Master";
dc->realize = fsi_master_realize;
- dc->reset = fsi_master_reset;
+ device_class_set_legacy_reset(dc, fsi_master_reset);
}
static const TypeInfo fsi_master_info = {
diff --git a/hw/fsi/fsi.c b/hw/fsi/fsi.c
index 9a5f4e6..83ddb17 100644
--- a/hw/fsi/fsi.c
+++ b/hw/fsi/fsi.c
@@ -82,7 +82,7 @@ static void fsi_slave_class_init(ObjectClass *klass, void *data)
dc->bus_type = TYPE_FSI_BUS;
dc->desc = "FSI Slave";
- dc->reset = fsi_slave_reset;
+ device_class_set_legacy_reset(dc, fsi_slave_reset);
}
static const TypeInfo fsi_slave_info = {
diff --git a/hw/fsi/lbus.c b/hw/fsi/lbus.c
index 20495f4..4f87b28 100644
--- a/hw/fsi/lbus.c
+++ b/hw/fsi/lbus.c
@@ -97,7 +97,7 @@ static void fsi_scratchpad_class_init(ObjectClass *klass, void *data)
dc->bus_type = TYPE_FSI_LBUS;
dc->realize = fsi_scratchpad_realize;
- dc->reset = fsi_scratchpad_reset;
+ device_class_set_legacy_reset(dc, fsi_scratchpad_reset);
}
static const TypeInfo fsi_scratchpad_info = {
diff --git a/hw/gpio/Kconfig b/hw/gpio/Kconfig
index 19c97cc..c423e10 100644
--- a/hw/gpio/Kconfig
+++ b/hw/gpio/Kconfig
@@ -1,7 +1,3 @@
-config MAX7310
- bool
- depends on I2C
-
config PL061
bool
@@ -23,3 +19,6 @@ config STM32L4X5_GPIO
config PCF8574
bool
depends on I2C
+
+config ZAURUS_SCOOP
+ bool
diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 6474bb8..a5b3f45 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -227,6 +227,38 @@ REG32(GPIO_INDEX_REG, 0x2AC)
FIELD(GPIO_INDEX_REG, COMMAND_SRC_1, 21, 1)
FIELD(GPIO_INDEX_REG, INPUT_MASK, 20, 1)
+/* AST2700 GPIO Register Address Offsets */
+REG32(GPIO_2700_DEBOUNCE_TIME_1, 0x000)
+REG32(GPIO_2700_DEBOUNCE_TIME_2, 0x004)
+REG32(GPIO_2700_DEBOUNCE_TIME_3, 0x008)
+REG32(GPIO_2700_INT_STATUS_1, 0x100)
+REG32(GPIO_2700_INT_STATUS_2, 0x104)
+REG32(GPIO_2700_INT_STATUS_3, 0x108)
+REG32(GPIO_2700_INT_STATUS_4, 0x10C)
+REG32(GPIO_2700_INT_STATUS_5, 0x110)
+REG32(GPIO_2700_INT_STATUS_6, 0x114)
+REG32(GPIO_2700_INT_STATUS_7, 0x118)
+/* GPIOA0 - GPIOAA7 Control Register */
+REG32(GPIO_A0_CONTROL, 0x180)
+ SHARED_FIELD(GPIO_CONTROL_OUT_DATA, 0, 1)
+ SHARED_FIELD(GPIO_CONTROL_DIRECTION, 1, 1)
+ SHARED_FIELD(GPIO_CONTROL_INT_ENABLE, 2, 1)
+ SHARED_FIELD(GPIO_CONTROL_INT_SENS_0, 3, 1)
+ SHARED_FIELD(GPIO_CONTROL_INT_SENS_1, 4, 1)
+ SHARED_FIELD(GPIO_CONTROL_INT_SENS_2, 5, 1)
+ SHARED_FIELD(GPIO_CONTROL_RESET_TOLERANCE, 6, 1)
+ SHARED_FIELD(GPIO_CONTROL_DEBOUNCE_1, 7, 1)
+ SHARED_FIELD(GPIO_CONTROL_DEBOUNCE_2, 8, 1)
+ SHARED_FIELD(GPIO_CONTROL_INPUT_MASK, 9, 1)
+ SHARED_FIELD(GPIO_CONTROL_BLINK_COUNTER_1, 10, 1)
+ SHARED_FIELD(GPIO_CONTROL_BLINK_COUNTER_2, 11, 1)
+ SHARED_FIELD(GPIO_CONTROL_INT_STATUS, 12, 1)
+ SHARED_FIELD(GPIO_CONTROL_IN_DATA, 13, 1)
+ SHARED_FIELD(GPIO_CONTROL_RESERVED, 14, 18)
+REG32(GPIO_AA7_CONTROL, 0x4DC)
+#define GPIO_2700_MEM_SIZE 0x4E0
+#define GPIO_2700_REG_ARRAY_SIZE (GPIO_2700_MEM_SIZE >> 2)
+
static int aspeed_evaluate_irq(GPIOSets *regs, int gpio_prev_high, int gpio)
{
uint32_t falling_edge = 0, rising_edge = 0;
@@ -281,7 +313,7 @@ static void aspeed_gpio_update(AspeedGPIOState *s, GPIOSets *regs,
diff &= mode_mask;
if (diff) {
for (gpio = 0; gpio < ASPEED_GPIOS_PER_SET; gpio++) {
- uint32_t mask = 1 << gpio;
+ uint32_t mask = 1U << gpio;
/* If the gpio needs to be updated... */
if (!(diff & mask)) {
@@ -340,7 +372,8 @@ static void aspeed_gpio_set_pin_level(AspeedGPIOState *s, uint32_t set_idx,
value &= ~pin_mask;
}
- aspeed_gpio_update(s, &s->sets[set_idx], value, ~s->sets[set_idx].direction);
+ aspeed_gpio_update(s, &s->sets[set_idx], value,
+ ~s->sets[set_idx].direction);
}
/*
@@ -629,7 +662,6 @@ static uint64_t aspeed_gpio_read(void *opaque, hwaddr offset, uint32_t size)
static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset,
uint64_t data, uint32_t size)
{
-
AspeedGPIOState *s = ASPEED_GPIO(opaque);
AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
const GPIOSetProperties *props;
@@ -641,7 +673,7 @@ static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset,
uint32_t pin_idx = reg_idx_number % ASPEED_GPIOS_PER_SET;
uint32_t group_idx = pin_idx / GPIOS_PER_GROUP;
uint32_t reg_value = 0;
- uint32_t cleared;
+ uint32_t pending = 0;
set = &s->sets[set_idx];
props = &agc->props[set_idx];
@@ -703,16 +735,23 @@ static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset,
FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_2));
set->int_sens_2 = update_value_control_source(set, set->int_sens_2,
reg_value);
- /* set interrupt status */
- reg_value = set->int_status;
- reg_value = deposit32(reg_value, pin_idx, 1,
- FIELD_EX32(data, GPIO_INDEX_REG, INT_STATUS));
- cleared = ctpop32(reg_value & set->int_status);
- if (s->pending && cleared) {
- assert(s->pending >= cleared);
- s->pending -= cleared;
+ /* interrupt status */
+ if (FIELD_EX32(data, GPIO_INDEX_REG, INT_STATUS)) {
+ /* pending is either 1 or 0 for a 1-bit field */
+ pending = extract32(set->int_status, pin_idx, 1);
+
+ assert(s->pending >= pending);
+
+ /* No change to s->pending if pending is 0 */
+ s->pending -= pending;
+
+ /*
+ * The write acknowledged the interrupt regardless of whether it
+ * was pending or not. The post-condition is that it mustn't be
+ * pending. Unconditionally clear the status bit.
+ */
+ set->int_status = deposit32(set->int_status, pin_idx, 1, 0);
}
- set->int_status &= ~reg_value;
break;
case gpio_reg_idx_debounce:
reg_value = set->debounce_1;
@@ -963,7 +1002,317 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, const char *name,
aspeed_gpio_set_pin_level(s, set_idx, pin, level);
}
-/****************** Setup functions ******************/
+static uint64_t aspeed_gpio_2700_read_control_reg(AspeedGPIOState *s,
+ uint32_t pin)
+{
+ AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
+ GPIOSets *set;
+ uint64_t value = 0;
+ uint32_t set_idx;
+ uint32_t pin_idx;
+
+ set_idx = pin / ASPEED_GPIOS_PER_SET;
+ pin_idx = pin % ASPEED_GPIOS_PER_SET;
+
+ if (set_idx >= agc->nr_gpio_sets) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: set index: %d, out of bounds\n",
+ __func__, set_idx);
+ return 0;
+ }
+
+ set = &s->sets[set_idx];
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_OUT_DATA,
+ extract32(set->data_read, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DIRECTION,
+ extract32(set->direction, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_ENABLE,
+ extract32(set->int_enable, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_0,
+ extract32(set->int_sens_0, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_1,
+ extract32(set->int_sens_1, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_2,
+ extract32(set->int_sens_2, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_RESET_TOLERANCE,
+ extract32(set->reset_tol, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DEBOUNCE_1,
+ extract32(set->debounce_1, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DEBOUNCE_2,
+ extract32(set->debounce_2, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INPUT_MASK,
+ extract32(set->input_mask, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_STATUS,
+ extract32(set->int_status, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_IN_DATA,
+ extract32(set->data_value, pin_idx, 1));
+ return value;
+}
+
+static void aspeed_gpio_2700_write_control_reg(AspeedGPIOState *s,
+ uint32_t pin, uint64_t data)
+{
+ AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
+ const GPIOSetProperties *props;
+ GPIOSets *set;
+ uint32_t set_idx;
+ uint32_t pin_idx;
+ uint32_t group_value = 0;
+ uint32_t pending = 0;
+
+ set_idx = pin / ASPEED_GPIOS_PER_SET;
+ pin_idx = pin % ASPEED_GPIOS_PER_SET;
+
+ if (set_idx >= agc->nr_gpio_sets) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: set index: %d, out of bounds\n",
+ __func__, set_idx);
+ return;
+ }
+
+ set = &s->sets[set_idx];
+ props = &agc->props[set_idx];
+
+ /* direction */
+ group_value = set->direction;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_DIRECTION));
+ /*
+ * where data is the value attempted to be written to the pin:
+ * pin type | input mask | output mask | expected value
+ * ------------------------------------------------------------
+ * bidirectional | 1 | 1 | data
+ * input only | 1 | 0 | 0
+ * output only | 0 | 1 | 1
+ * no pin | 0 | 0 | 0
+ *
+ * which is captured by:
+ * data = ( data | ~input) & output;
+ */
+ group_value = (group_value | ~props->input) & props->output;
+ set->direction = update_value_control_source(set, set->direction,
+ group_value);
+
+ /* out data */
+ group_value = set->data_read;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_OUT_DATA));
+ group_value &= props->output;
+ group_value = update_value_control_source(set, set->data_read,
+ group_value);
+ set->data_read = group_value;
+
+ /* interrupt enable */
+ group_value = set->int_enable;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_INT_ENABLE));
+ set->int_enable = update_value_control_source(set, set->int_enable,
+ group_value);
+
+ /* interrupt sensitivity type 0 */
+ group_value = set->int_sens_0;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_INT_SENS_0));
+ set->int_sens_0 = update_value_control_source(set, set->int_sens_0,
+ group_value);
+
+ /* interrupt sensitivity type 1 */
+ group_value = set->int_sens_1;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_INT_SENS_1));
+ set->int_sens_1 = update_value_control_source(set, set->int_sens_1,
+ group_value);
+
+ /* interrupt sensitivity type 2 */
+ group_value = set->int_sens_2;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_INT_SENS_2));
+ set->int_sens_2 = update_value_control_source(set, set->int_sens_2,
+ group_value);
+
+ /* reset tolerance enable */
+ group_value = set->reset_tol;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_RESET_TOLERANCE));
+ set->reset_tol = update_value_control_source(set, set->reset_tol,
+ group_value);
+
+ /* debounce 1 */
+ group_value = set->debounce_1;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_DEBOUNCE_1));
+ set->debounce_1 = update_value_control_source(set, set->debounce_1,
+ group_value);
+
+ /* debounce 2 */
+ group_value = set->debounce_2;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_DEBOUNCE_2));
+ set->debounce_2 = update_value_control_source(set, set->debounce_2,
+ group_value);
+
+ /* input mask */
+ group_value = set->input_mask;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_INPUT_MASK));
+ /*
+ * feeds into interrupt generation
+ * 0: read from data value reg will be updated
+ * 1: read from data value reg will not be updated
+ */
+ set->input_mask = group_value & props->input;
+
+ /* blink counter 1 */
+ /* blink counter 2 */
+ /* unimplement */
+
+ /* interrupt status */
+ if (SHARED_FIELD_EX32(data, GPIO_CONTROL_INT_STATUS)) {
+ /* pending is either 1 or 0 for a 1-bit field */
+ pending = extract32(set->int_status, pin_idx, 1);
+
+ assert(s->pending >= pending);
+
+ /* No change to s->pending if pending is 0 */
+ s->pending -= pending;
+
+ /*
+ * The write acknowledged the interrupt regardless of whether it
+ * was pending or not. The post-condition is that it mustn't be
+ * pending. Unconditionally clear the status bit.
+ */
+ set->int_status = deposit32(set->int_status, pin_idx, 1, 0);
+ }
+
+ aspeed_gpio_update(s, set, set->data_value, UINT32_MAX);
+ return;
+}
+
+static uint64_t aspeed_gpio_2700_read(void *opaque, hwaddr offset,
+ uint32_t size)
+{
+ AspeedGPIOState *s = ASPEED_GPIO(opaque);
+ AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
+ GPIOSets *set;
+ uint64_t value;
+ uint64_t reg;
+ uint32_t pin;
+ uint32_t idx;
+
+ reg = offset >> 2;
+
+ if (reg >= agc->reg_table_count) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: offset 0x%" PRIx64 " out of bounds\n",
+ __func__, offset);
+ return 0;
+ }
+
+ switch (reg) {
+ case R_GPIO_2700_DEBOUNCE_TIME_1 ... R_GPIO_2700_DEBOUNCE_TIME_3:
+ idx = reg - R_GPIO_2700_DEBOUNCE_TIME_1;
+
+ if (idx >= ASPEED_GPIO_NR_DEBOUNCE_REGS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: debounce index: %d, out of bounds\n",
+ __func__, idx);
+ return 0;
+ }
+
+ value = (uint64_t) s->debounce_regs[idx];
+ break;
+ case R_GPIO_2700_INT_STATUS_1 ... R_GPIO_2700_INT_STATUS_7:
+ idx = reg - R_GPIO_2700_INT_STATUS_1;
+
+ if (idx >= agc->nr_gpio_sets) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: interrupt status index: %d, out of bounds\n",
+ __func__, idx);
+ return 0;
+ }
+
+ set = &s->sets[idx];
+ value = (uint64_t) set->int_status;
+ break;
+ case R_GPIO_A0_CONTROL ... R_GPIO_AA7_CONTROL:
+ pin = reg - R_GPIO_A0_CONTROL;
+
+ if (pin >= agc->nr_gpio_pins) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid pin number: %d\n",
+ __func__, pin);
+ return 0;
+ }
+
+ value = aspeed_gpio_2700_read_control_reg(s, pin);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: no getter for offset 0x%"
+ PRIx64"\n", __func__, offset);
+ return 0;
+ }
+
+ trace_aspeed_gpio_read(offset, value);
+ return value;
+}
+
+static void aspeed_gpio_2700_write(void *opaque, hwaddr offset,
+ uint64_t data, uint32_t size)
+{
+ AspeedGPIOState *s = ASPEED_GPIO(opaque);
+ AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
+ uint64_t reg;
+ uint32_t pin;
+ uint32_t idx;
+
+ trace_aspeed_gpio_write(offset, data);
+
+ reg = offset >> 2;
+
+ if (reg >= agc->reg_table_count) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: offset 0x%" PRIx64 " out of bounds\n",
+ __func__, offset);
+ return;
+ }
+
+ switch (reg) {
+ case R_GPIO_2700_DEBOUNCE_TIME_1 ... R_GPIO_2700_DEBOUNCE_TIME_3:
+ idx = reg - R_GPIO_2700_DEBOUNCE_TIME_1;
+
+ if (idx >= ASPEED_GPIO_NR_DEBOUNCE_REGS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: debounce index: %d out of bounds\n",
+ __func__, idx);
+ return;
+ }
+
+ s->debounce_regs[idx] = (uint32_t) data;
+ break;
+ case R_GPIO_A0_CONTROL ... R_GPIO_AA7_CONTROL:
+ pin = reg - R_GPIO_A0_CONTROL;
+
+ if (pin >= agc->nr_gpio_pins) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid pin number: %d\n",
+ __func__, pin);
+ return;
+ }
+
+ if (SHARED_FIELD_EX32(data, GPIO_CONTROL_RESERVED)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid reserved data: 0x%"
+ PRIx64"\n", __func__, data);
+ return;
+ }
+
+ aspeed_gpio_2700_write_control_reg(s, pin, data);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: no setter for offset 0x%"
+ PRIx64"\n", __func__, offset);
+ break;
+ }
+
+ return;
+}
+
+/* Setup functions */
static const GPIOSetProperties ast2400_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
[0] = {0xffffffff, 0xffffffff, {"A", "B", "C", "D"} },
[1] = {0xffffffff, 0xffffffff, {"E", "F", "G", "H"} },
@@ -1009,6 +1358,16 @@ static GPIOSetProperties ast1030_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
[5] = {0x000000ff, 0x00000000, {"U"} },
};
+static GPIOSetProperties ast2700_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
+ [0] = {0xffffffff, 0xffffffff, {"A", "B", "C", "D"} },
+ [1] = {0x0fffffff, 0x0fffffff, {"E", "F", "G", "H"} },
+ [2] = {0xffffffff, 0xffffffff, {"I", "J", "K", "L"} },
+ [3] = {0xffffffff, 0xffffffff, {"M", "N", "O", "P"} },
+ [4] = {0xffffffff, 0xffffffff, {"Q", "R", "S", "T"} },
+ [5] = {0xffffffff, 0xffffffff, {"U", "V", "W", "X"} },
+ [6] = {0x00ffffff, 0x00ffffff, {"Y", "Z", "AA"} },
+};
+
static const MemoryRegionOps aspeed_gpio_ops = {
.read = aspeed_gpio_read,
.write = aspeed_gpio_write,
@@ -1017,6 +1376,14 @@ static const MemoryRegionOps aspeed_gpio_ops = {
.valid.max_access_size = 4,
};
+static const MemoryRegionOps aspeed_gpio_2700_ops = {
+ .read = aspeed_gpio_2700_read,
+ .write = aspeed_gpio_2700_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+};
+
static void aspeed_gpio_reset(DeviceState *dev)
{
AspeedGPIOState *s = ASPEED_GPIO(dev);
@@ -1046,8 +1413,8 @@ static void aspeed_gpio_realize(DeviceState *dev, Error **errp)
}
}
- memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s,
- TYPE_ASPEED_GPIO, 0x800);
+ memory_region_init_io(&s->iomem, OBJECT(s), agc->reg_ops, s,
+ TYPE_ASPEED_GPIO, agc->mem_size);
sysbus_init_mmio(sbd, &s->iomem);
}
@@ -1116,7 +1483,7 @@ static void aspeed_gpio_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_gpio_realize;
- dc->reset = aspeed_gpio_reset;
+ device_class_set_legacy_reset(dc, aspeed_gpio_reset);
dc->desc = "Aspeed GPIO Controller";
dc->vmsd = &vmstate_aspeed_gpio;
}
@@ -1130,6 +1497,8 @@ static void aspeed_gpio_ast2400_class_init(ObjectClass *klass, void *data)
agc->nr_gpio_sets = 7;
agc->reg_table = aspeed_3_3v_gpios;
agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+ agc->mem_size = 0x1000;
+ agc->reg_ops = &aspeed_gpio_ops;
}
static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
@@ -1141,6 +1510,8 @@ static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
agc->nr_gpio_sets = 8;
agc->reg_table = aspeed_3_3v_gpios;
agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+ agc->mem_size = 0x1000;
+ agc->reg_ops = &aspeed_gpio_ops;
}
static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
@@ -1152,6 +1523,8 @@ static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
agc->nr_gpio_sets = 7;
agc->reg_table = aspeed_3_3v_gpios;
agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+ agc->mem_size = 0x800;
+ agc->reg_ops = &aspeed_gpio_ops;
}
static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
@@ -1163,6 +1536,8 @@ static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
agc->nr_gpio_sets = 2;
agc->reg_table = aspeed_1_8v_gpios;
agc->reg_table_count = GPIO_1_8V_REG_ARRAY_SIZE;
+ agc->mem_size = 0x800;
+ agc->reg_ops = &aspeed_gpio_ops;
}
static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
@@ -1174,6 +1549,20 @@ static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
agc->nr_gpio_sets = 6;
agc->reg_table = aspeed_3_3v_gpios;
agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+ agc->mem_size = 0x1000;
+ agc->reg_ops = &aspeed_gpio_ops;
+}
+
+static void aspeed_gpio_2700_class_init(ObjectClass *klass, void *data)
+{
+ AspeedGPIOClass *agc = ASPEED_GPIO_CLASS(klass);
+
+ agc->props = ast2700_set_props;
+ agc->nr_gpio_pins = 216;
+ agc->nr_gpio_sets = 7;
+ agc->reg_table_count = GPIO_2700_REG_ARRAY_SIZE;
+ agc->mem_size = 0x1000;
+ agc->reg_ops = &aspeed_gpio_2700_ops;
}
static const TypeInfo aspeed_gpio_info = {
@@ -1220,6 +1609,13 @@ static const TypeInfo aspeed_gpio_ast1030_info = {
.instance_init = aspeed_gpio_init,
};
+static const TypeInfo aspeed_gpio_ast2700_info = {
+ .name = TYPE_ASPEED_GPIO "-ast2700",
+ .parent = TYPE_ASPEED_GPIO,
+ .class_init = aspeed_gpio_2700_class_init,
+ .instance_init = aspeed_gpio_init,
+};
+
static void aspeed_gpio_register_types(void)
{
type_register_static(&aspeed_gpio_info);
@@ -1228,6 +1624,7 @@ static void aspeed_gpio_register_types(void)
type_register_static(&aspeed_gpio_ast2600_3_3v_info);
type_register_static(&aspeed_gpio_ast2600_1_8v_info);
type_register_static(&aspeed_gpio_ast1030_info);
+ type_register_static(&aspeed_gpio_ast2700_info);
}
type_init(aspeed_gpio_register_types);
diff --git a/hw/gpio/bcm2835_gpio.c b/hw/gpio/bcm2835_gpio.c
index 6bd50bb..5a5f1df 100644
--- a/hw/gpio/bcm2835_gpio.c
+++ b/hw/gpio/bcm2835_gpio.c
@@ -325,7 +325,7 @@ static void bcm2835_gpio_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_bcm2835_gpio;
dc->realize = &bcm2835_gpio_realize;
- dc->reset = &bcm2835_gpio_reset;
+ device_class_set_legacy_reset(dc, bcm2835_gpio_reset);
}
static const TypeInfo bcm2835_gpio_info = {
diff --git a/hw/gpio/bcm2838_gpio.c b/hw/gpio/bcm2838_gpio.c
index 2ddf62f..0a1739f 100644
--- a/hw/gpio/bcm2838_gpio.c
+++ b/hw/gpio/bcm2838_gpio.c
@@ -371,7 +371,7 @@ static void bcm2838_gpio_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_bcm2838_gpio;
dc->realize = &bcm2838_gpio_realize;
- dc->reset = &bcm2838_gpio_reset;
+ device_class_set_legacy_reset(dc, bcm2838_gpio_reset);
}
static const TypeInfo bcm2838_gpio_info = {
diff --git a/hw/gpio/gpio_key.c b/hw/gpio/gpio_key.c
index 61bb587..2fcab9e 100644
--- a/hw/gpio/gpio_key.c
+++ b/hw/gpio/gpio_key.c
@@ -91,7 +91,7 @@ static void gpio_key_class_init(ObjectClass *klass, void *data)
dc->realize = gpio_key_realize;
dc->vmsd = &vmstate_gpio_key;
- dc->reset = &gpio_key_reset;
+ device_class_set_legacy_reset(dc, gpio_key_reset);
}
static const TypeInfo gpio_key_info = {
diff --git a/hw/gpio/imx_gpio.c b/hw/gpio/imx_gpio.c
index e53b00d..27535a5 100644
--- a/hw/gpio/imx_gpio.c
+++ b/hw/gpio/imx_gpio.c
@@ -333,7 +333,7 @@ static void imx_gpio_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = imx_gpio_realize;
- dc->reset = imx_gpio_reset;
+ device_class_set_legacy_reset(dc, imx_gpio_reset);
device_class_set_props(dc, imx_gpio_properties);
dc->vmsd = &vmstate_imx_gpio;
dc->desc = "i.MX GPIO controller";
diff --git a/hw/gpio/max7310.c b/hw/gpio/max7310.c
deleted file mode 100644
index 8631571..0000000
--- a/hw/gpio/max7310.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * MAX7310 8-port GPIO expansion chip.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This file is licensed under GNU GPL.
- */
-
-#include "qemu/osdep.h"
-#include "hw/i2c/i2c.h"
-#include "hw/irq.h"
-#include "migration/vmstate.h"
-#include "qemu/log.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-#define TYPE_MAX7310 "max7310"
-OBJECT_DECLARE_SIMPLE_TYPE(MAX7310State, MAX7310)
-
-struct MAX7310State {
- I2CSlave parent_obj;
-
- int i2c_command_byte;
- int len;
-
- uint8_t level;
- uint8_t direction;
- uint8_t polarity;
- uint8_t status;
- uint8_t command;
- qemu_irq handler[8];
- qemu_irq *gpio_in;
-};
-
-static void max7310_reset(DeviceState *dev)
-{
- MAX7310State *s = MAX7310(dev);
-
- s->level &= s->direction;
- s->direction = 0xff;
- s->polarity = 0xf0;
- s->status = 0x01;
- s->command = 0x00;
-}
-
-static uint8_t max7310_rx(I2CSlave *i2c)
-{
- MAX7310State *s = MAX7310(i2c);
-
- switch (s->command) {
- case 0x00: /* Input port */
- return s->level ^ s->polarity;
-
- case 0x01: /* Output port */
- return s->level & ~s->direction;
-
- case 0x02: /* Polarity inversion */
- return s->polarity;
-
- case 0x03: /* Configuration */
- return s->direction;
-
- case 0x04: /* Timeout */
- return s->status;
-
- case 0xff: /* Reserved */
- return 0xff;
-
- default:
- qemu_log_mask(LOG_UNIMP, "%s: Unsupported register 0x02%" PRIx8 "\n",
- __func__, s->command);
- break;
- }
- return 0xff;
-}
-
-static int max7310_tx(I2CSlave *i2c, uint8_t data)
-{
- MAX7310State *s = MAX7310(i2c);
- uint8_t diff;
- int line;
-
- if (s->len ++ > 1) {
-#ifdef VERBOSE
- printf("%s: message too long (%i bytes)\n", __func__, s->len);
-#endif
- return 1;
- }
-
- if (s->i2c_command_byte) {
- s->command = data;
- s->i2c_command_byte = 0;
- return 0;
- }
-
- switch (s->command) {
- case 0x01: /* Output port */
- for (diff = (data ^ s->level) & ~s->direction; diff;
- diff &= ~(1 << line)) {
- line = ctz32(diff);
- if (s->handler[line])
- qemu_set_irq(s->handler[line], (data >> line) & 1);
- }
- s->level = (s->level & s->direction) | (data & ~s->direction);
- break;
-
- case 0x02: /* Polarity inversion */
- s->polarity = data;
- break;
-
- case 0x03: /* Configuration */
- s->level &= ~(s->direction ^ data);
- s->direction = data;
- break;
-
- case 0x04: /* Timeout */
- s->status = data;
- break;
-
- case 0x00: /* Input port - ignore writes */
- break;
- default:
- qemu_log_mask(LOG_UNIMP, "%s: Unsupported register 0x02%" PRIx8 "\n",
- __func__, s->command);
- return 1;
- }
-
- return 0;
-}
-
-static int max7310_event(I2CSlave *i2c, enum i2c_event event)
-{
- MAX7310State *s = MAX7310(i2c);
- s->len = 0;
-
- switch (event) {
- case I2C_START_SEND:
- s->i2c_command_byte = 1;
- break;
- case I2C_FINISH:
-#ifdef VERBOSE
- if (s->len == 1)
- printf("%s: message too short (%i bytes)\n", __func__, s->len);
-#endif
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static const VMStateDescription vmstate_max7310 = {
- .name = "max7310",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_INT32(i2c_command_byte, MAX7310State),
- VMSTATE_INT32(len, MAX7310State),
- VMSTATE_UINT8(level, MAX7310State),
- VMSTATE_UINT8(direction, MAX7310State),
- VMSTATE_UINT8(polarity, MAX7310State),
- VMSTATE_UINT8(status, MAX7310State),
- VMSTATE_UINT8(command, MAX7310State),
- VMSTATE_I2C_SLAVE(parent_obj, MAX7310State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void max7310_gpio_set(void *opaque, int line, int level)
-{
- MAX7310State *s = (MAX7310State *) opaque;
- assert(line >= 0 && line < ARRAY_SIZE(s->handler));
-
- if (level)
- s->level |= s->direction & (1 << line);
- else
- s->level &= ~(s->direction & (1 << line));
-}
-
-/* MAX7310 is SMBus-compatible (can be used with only SMBus protocols),
- * but also accepts sequences that are not SMBus so return an I2C device. */
-static void max7310_realize(DeviceState *dev, Error **errp)
-{
- MAX7310State *s = MAX7310(dev);
-
- qdev_init_gpio_in(dev, max7310_gpio_set, ARRAY_SIZE(s->handler));
- qdev_init_gpio_out(dev, s->handler, ARRAY_SIZE(s->handler));
-}
-
-static void max7310_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
-
- dc->realize = max7310_realize;
- k->event = max7310_event;
- k->recv = max7310_rx;
- k->send = max7310_tx;
- dc->reset = max7310_reset;
- dc->vmsd = &vmstate_max7310;
-}
-
-static const TypeInfo max7310_info = {
- .name = TYPE_MAX7310,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(MAX7310State),
- .class_init = max7310_class_init,
-};
-
-static void max7310_register_types(void)
-{
- type_register_static(&max7310_info);
-}
-
-type_init(max7310_register_types)
diff --git a/hw/gpio/meson.build b/hw/gpio/meson.build
index a7495d1..7484061 100644
--- a/hw/gpio/meson.build
+++ b/hw/gpio/meson.build
@@ -1,11 +1,10 @@
system_ss.add(when: 'CONFIG_GPIO_KEY', if_true: files('gpio_key.c'))
system_ss.add(when: 'CONFIG_GPIO_MPC8XXX', if_true: files('mpc8xxx.c'))
system_ss.add(when: 'CONFIG_GPIO_PWR', if_true: files('gpio_pwr.c'))
-system_ss.add(when: 'CONFIG_MAX7310', if_true: files('max7310.c'))
system_ss.add(when: 'CONFIG_PCA9552', if_true: files('pca9552.c'))
system_ss.add(when: 'CONFIG_PCA9554', if_true: files('pca9554.c'))
system_ss.add(when: 'CONFIG_PL061', if_true: files('pl061.c'))
-system_ss.add(when: 'CONFIG_ZAURUS', if_true: files('zaurus.c'))
+system_ss.add(when: 'CONFIG_ZAURUS_SCOOP', if_true: files('zaurus.c'))
system_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpio.c'))
system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_gpio.c'))
diff --git a/hw/gpio/mpc8xxx.c b/hw/gpio/mpc8xxx.c
index 0b3f9e5..63b7a5c 100644
--- a/hw/gpio/mpc8xxx.c
+++ b/hw/gpio/mpc8xxx.c
@@ -205,7 +205,7 @@ static void mpc8xxx_gpio_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_mpc8xxx_gpio;
- dc->reset = mpc8xxx_gpio_reset;
+ device_class_set_legacy_reset(dc, mpc8xxx_gpio_reset);
}
static const TypeInfo mpc8xxx_gpio_info = {
diff --git a/hw/gpio/nrf51_gpio.c b/hw/gpio/nrf51_gpio.c
index ffc7dff..d08c254 100644
--- a/hw/gpio/nrf51_gpio.c
+++ b/hw/gpio/nrf51_gpio.c
@@ -40,7 +40,6 @@ static bool is_connected(uint32_t config, uint32_t level)
break;
default:
g_assert_not_reached();
- break;
}
return state;
@@ -310,7 +309,7 @@ static void nrf51_gpio_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_nrf51_gpio;
- dc->reset = nrf51_gpio_reset;
+ device_class_set_legacy_reset(dc, nrf51_gpio_reset);
dc->desc = "nRF51 GPIO";
}
diff --git a/hw/gpio/omap_gpio.c b/hw/gpio/omap_gpio.c
index a3341d7..a47a216 100644
--- a/hw/gpio/omap_gpio.c
+++ b/hw/gpio/omap_gpio.c
@@ -190,408 +190,6 @@ static void omap_gpio_reset(struct omap_gpio_s *s)
s->pins = ~0;
}
-struct omap2_gpio_s {
- qemu_irq irq[2];
- qemu_irq wkup;
- qemu_irq *handler;
- MemoryRegion iomem;
-
- uint8_t revision;
- uint8_t config[2];
- uint32_t inputs;
- uint32_t outputs;
- uint32_t dir;
- uint32_t level[2];
- uint32_t edge[2];
- uint32_t mask[2];
- uint32_t wumask;
- uint32_t ints[2];
- uint32_t debounce;
- uint8_t delay;
-};
-
-struct Omap2GpioState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- int mpu_model;
- void *iclk;
- void *fclk[6];
- int modulecount;
- struct omap2_gpio_s *modules;
- qemu_irq *handler;
- int autoidle;
- int gpo;
-};
-
-/* General-Purpose Interface of OMAP2/3 */
-static inline void omap2_gpio_module_int_update(struct omap2_gpio_s *s,
- int line)
-{
- qemu_set_irq(s->irq[line], s->ints[line] & s->mask[line]);
-}
-
-static void omap2_gpio_module_wake(struct omap2_gpio_s *s, int line)
-{
- if (!(s->config[0] & (1 << 2))) /* ENAWAKEUP */
- return;
- if (!(s->config[0] & (3 << 3))) /* Force Idle */
- return;
- if (!(s->wumask & (1 << line)))
- return;
-
- qemu_irq_raise(s->wkup);
-}
-
-static inline void omap2_gpio_module_out_update(struct omap2_gpio_s *s,
- uint32_t diff)
-{
- int ln;
-
- s->outputs ^= diff;
- diff &= ~s->dir;
- while ((ln = ctz32(diff)) != 32) {
- qemu_set_irq(s->handler[ln], (s->outputs >> ln) & 1);
- diff &= ~(1 << ln);
- }
-}
-
-static void omap2_gpio_module_level_update(struct omap2_gpio_s *s, int line)
-{
- s->ints[line] |= s->dir &
- ((s->inputs & s->level[1]) | (~s->inputs & s->level[0]));
- omap2_gpio_module_int_update(s, line);
-}
-
-static inline void omap2_gpio_module_int(struct omap2_gpio_s *s, int line)
-{
- s->ints[0] |= 1 << line;
- omap2_gpio_module_int_update(s, 0);
- s->ints[1] |= 1 << line;
- omap2_gpio_module_int_update(s, 1);
- omap2_gpio_module_wake(s, line);
-}
-
-static void omap2_gpio_set(void *opaque, int line, int level)
-{
- Omap2GpioState *p = opaque;
- struct omap2_gpio_s *s = &p->modules[line >> 5];
-
- line &= 31;
- if (level) {
- if (s->dir & (1 << line) & ((~s->inputs & s->edge[0]) | s->level[1]))
- omap2_gpio_module_int(s, line);
- s->inputs |= 1 << line;
- } else {
- if (s->dir & (1 << line) & ((s->inputs & s->edge[1]) | s->level[0]))
- omap2_gpio_module_int(s, line);
- s->inputs &= ~(1 << line);
- }
-}
-
-static void omap2_gpio_module_reset(struct omap2_gpio_s *s)
-{
- s->config[0] = 0;
- s->config[1] = 2;
- s->ints[0] = 0;
- s->ints[1] = 0;
- s->mask[0] = 0;
- s->mask[1] = 0;
- s->wumask = 0;
- s->dir = ~0;
- s->level[0] = 0;
- s->level[1] = 0;
- s->edge[0] = 0;
- s->edge[1] = 0;
- s->debounce = 0;
- s->delay = 0;
-}
-
-static uint32_t omap2_gpio_module_read(void *opaque, hwaddr addr)
-{
- struct omap2_gpio_s *s = opaque;
-
- switch (addr) {
- case 0x00: /* GPIO_REVISION */
- return s->revision;
-
- case 0x10: /* GPIO_SYSCONFIG */
- return s->config[0];
-
- case 0x14: /* GPIO_SYSSTATUS */
- return 0x01;
-
- case 0x18: /* GPIO_IRQSTATUS1 */
- return s->ints[0];
-
- case 0x1c: /* GPIO_IRQENABLE1 */
- case 0x60: /* GPIO_CLEARIRQENABLE1 */
- case 0x64: /* GPIO_SETIRQENABLE1 */
- return s->mask[0];
-
- case 0x20: /* GPIO_WAKEUPENABLE */
- case 0x80: /* GPIO_CLEARWKUENA */
- case 0x84: /* GPIO_SETWKUENA */
- return s->wumask;
-
- case 0x28: /* GPIO_IRQSTATUS2 */
- return s->ints[1];
-
- case 0x2c: /* GPIO_IRQENABLE2 */
- case 0x70: /* GPIO_CLEARIRQENABLE2 */
- case 0x74: /* GPIO_SETIREQNEABLE2 */
- return s->mask[1];
-
- case 0x30: /* GPIO_CTRL */
- return s->config[1];
-
- case 0x34: /* GPIO_OE */
- return s->dir;
-
- case 0x38: /* GPIO_DATAIN */
- return s->inputs;
-
- case 0x3c: /* GPIO_DATAOUT */
- case 0x90: /* GPIO_CLEARDATAOUT */
- case 0x94: /* GPIO_SETDATAOUT */
- return s->outputs;
-
- case 0x40: /* GPIO_LEVELDETECT0 */
- return s->level[0];
-
- case 0x44: /* GPIO_LEVELDETECT1 */
- return s->level[1];
-
- case 0x48: /* GPIO_RISINGDETECT */
- return s->edge[0];
-
- case 0x4c: /* GPIO_FALLINGDETECT */
- return s->edge[1];
-
- case 0x50: /* GPIO_DEBOUNCENABLE */
- return s->debounce;
-
- case 0x54: /* GPIO_DEBOUNCINGTIME */
- return s->delay;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap2_gpio_module_write(void *opaque, hwaddr addr,
- uint32_t value)
-{
- struct omap2_gpio_s *s = opaque;
- uint32_t diff;
- int ln;
-
- switch (addr) {
- case 0x00: /* GPIO_REVISION */
- case 0x14: /* GPIO_SYSSTATUS */
- case 0x38: /* GPIO_DATAIN */
- OMAP_RO_REG(addr);
- break;
-
- case 0x10: /* GPIO_SYSCONFIG */
- if (((value >> 3) & 3) == 3) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Illegal IDLEMODE value: 3\n", __func__);
- }
- if (value & 2)
- omap2_gpio_module_reset(s);
- s->config[0] = value & 0x1d;
- break;
-
- case 0x18: /* GPIO_IRQSTATUS1 */
- if (s->ints[0] & value) {
- s->ints[0] &= ~value;
- omap2_gpio_module_level_update(s, 0);
- }
- break;
-
- case 0x1c: /* GPIO_IRQENABLE1 */
- s->mask[0] = value;
- omap2_gpio_module_int_update(s, 0);
- break;
-
- case 0x20: /* GPIO_WAKEUPENABLE */
- s->wumask = value;
- break;
-
- case 0x28: /* GPIO_IRQSTATUS2 */
- if (s->ints[1] & value) {
- s->ints[1] &= ~value;
- omap2_gpio_module_level_update(s, 1);
- }
- break;
-
- case 0x2c: /* GPIO_IRQENABLE2 */
- s->mask[1] = value;
- omap2_gpio_module_int_update(s, 1);
- break;
-
- case 0x30: /* GPIO_CTRL */
- s->config[1] = value & 7;
- break;
-
- case 0x34: /* GPIO_OE */
- diff = s->outputs & (s->dir ^ value);
- s->dir = value;
-
- value = s->outputs & ~s->dir;
- while ((ln = ctz32(diff)) != 32) {
- diff &= ~(1 << ln);
- qemu_set_irq(s->handler[ln], (value >> ln) & 1);
- }
-
- omap2_gpio_module_level_update(s, 0);
- omap2_gpio_module_level_update(s, 1);
- break;
-
- case 0x3c: /* GPIO_DATAOUT */
- omap2_gpio_module_out_update(s, s->outputs ^ value);
- break;
-
- case 0x40: /* GPIO_LEVELDETECT0 */
- s->level[0] = value;
- omap2_gpio_module_level_update(s, 0);
- omap2_gpio_module_level_update(s, 1);
- break;
-
- case 0x44: /* GPIO_LEVELDETECT1 */
- s->level[1] = value;
- omap2_gpio_module_level_update(s, 0);
- omap2_gpio_module_level_update(s, 1);
- break;
-
- case 0x48: /* GPIO_RISINGDETECT */
- s->edge[0] = value;
- break;
-
- case 0x4c: /* GPIO_FALLINGDETECT */
- s->edge[1] = value;
- break;
-
- case 0x50: /* GPIO_DEBOUNCENABLE */
- s->debounce = value;
- break;
-
- case 0x54: /* GPIO_DEBOUNCINGTIME */
- s->delay = value;
- break;
-
- case 0x60: /* GPIO_CLEARIRQENABLE1 */
- s->mask[0] &= ~value;
- omap2_gpio_module_int_update(s, 0);
- break;
-
- case 0x64: /* GPIO_SETIRQENABLE1 */
- s->mask[0] |= value;
- omap2_gpio_module_int_update(s, 0);
- break;
-
- case 0x70: /* GPIO_CLEARIRQENABLE2 */
- s->mask[1] &= ~value;
- omap2_gpio_module_int_update(s, 1);
- break;
-
- case 0x74: /* GPIO_SETIREQNEABLE2 */
- s->mask[1] |= value;
- omap2_gpio_module_int_update(s, 1);
- break;
-
- case 0x80: /* GPIO_CLEARWKUENA */
- s->wumask &= ~value;
- break;
-
- case 0x84: /* GPIO_SETWKUENA */
- s->wumask |= value;
- break;
-
- case 0x90: /* GPIO_CLEARDATAOUT */
- omap2_gpio_module_out_update(s, s->outputs & value);
- break;
-
- case 0x94: /* GPIO_SETDATAOUT */
- omap2_gpio_module_out_update(s, ~s->outputs & value);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static uint64_t omap2_gpio_module_readp(void *opaque, hwaddr addr,
- unsigned size)
-{
- return omap2_gpio_module_read(opaque, addr & ~3) >> ((addr & 3) << 3);
-}
-
-static void omap2_gpio_module_writep(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- uint32_t cur = 0;
- uint32_t mask = 0xffff;
-
- if (size == 4) {
- omap2_gpio_module_write(opaque, addr, value);
- return;
- }
-
- switch (addr & ~3) {
- case 0x00: /* GPIO_REVISION */
- case 0x14: /* GPIO_SYSSTATUS */
- case 0x38: /* GPIO_DATAIN */
- OMAP_RO_REG(addr);
- break;
-
- case 0x10: /* GPIO_SYSCONFIG */
- case 0x1c: /* GPIO_IRQENABLE1 */
- case 0x20: /* GPIO_WAKEUPENABLE */
- case 0x2c: /* GPIO_IRQENABLE2 */
- case 0x30: /* GPIO_CTRL */
- case 0x34: /* GPIO_OE */
- case 0x3c: /* GPIO_DATAOUT */
- case 0x40: /* GPIO_LEVELDETECT0 */
- case 0x44: /* GPIO_LEVELDETECT1 */
- case 0x48: /* GPIO_RISINGDETECT */
- case 0x4c: /* GPIO_FALLINGDETECT */
- case 0x50: /* GPIO_DEBOUNCENABLE */
- case 0x54: /* GPIO_DEBOUNCINGTIME */
- cur = omap2_gpio_module_read(opaque, addr & ~3) &
- ~(mask << ((addr & 3) << 3));
-
- /* Fall through. */
- case 0x18: /* GPIO_IRQSTATUS1 */
- case 0x28: /* GPIO_IRQSTATUS2 */
- case 0x60: /* GPIO_CLEARIRQENABLE1 */
- case 0x64: /* GPIO_SETIRQENABLE1 */
- case 0x70: /* GPIO_CLEARIRQENABLE2 */
- case 0x74: /* GPIO_SETIREQNEABLE2 */
- case 0x80: /* GPIO_CLEARWKUENA */
- case 0x84: /* GPIO_SETWKUENA */
- case 0x90: /* GPIO_CLEARDATAOUT */
- case 0x94: /* GPIO_SETDATAOUT */
- value <<= (addr & 3) << 3;
- omap2_gpio_module_write(opaque, addr, cur | value);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap2_gpio_module_ops = {
- .read = omap2_gpio_module_readp,
- .write = omap2_gpio_module_writep,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
static void omap_gpif_reset(DeviceState *dev)
{
Omap1GpioState *s = OMAP1_GPIO(dev);
@@ -599,81 +197,6 @@ static void omap_gpif_reset(DeviceState *dev)
omap_gpio_reset(&s->omap1);
}
-static void omap2_gpif_reset(DeviceState *dev)
-{
- Omap2GpioState *s = OMAP2_GPIO(dev);
- int i;
-
- for (i = 0; i < s->modulecount; i++) {
- omap2_gpio_module_reset(&s->modules[i]);
- }
- s->autoidle = 0;
- s->gpo = 0;
-}
-
-static uint64_t omap2_gpif_top_read(void *opaque, hwaddr addr, unsigned size)
-{
- Omap2GpioState *s = opaque;
-
- switch (addr) {
- case 0x00: /* IPGENERICOCPSPL_REVISION */
- return 0x18;
-
- case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */
- return s->autoidle;
-
- case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */
- return 0x01;
-
- case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */
- return 0x00;
-
- case 0x40: /* IPGENERICOCPSPL_GPO */
- return s->gpo;
-
- case 0x50: /* IPGENERICOCPSPL_GPI */
- return 0x00;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap2_gpif_top_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- Omap2GpioState *s = opaque;
-
- switch (addr) {
- case 0x00: /* IPGENERICOCPSPL_REVISION */
- case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */
- case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */
- case 0x50: /* IPGENERICOCPSPL_GPI */
- OMAP_RO_REG(addr);
- break;
-
- case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */
- if (value & (1 << 1)) /* SOFTRESET */
- omap2_gpif_reset(DEVICE(s));
- s->autoidle = value & 1;
- break;
-
- case 0x40: /* IPGENERICOCPSPL_GPO */
- s->gpo = value & 1;
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap2_gpif_top_ops = {
- .read = omap2_gpif_top_read,
- .write = omap2_gpif_top_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
static void omap_gpio_init(Object *obj)
{
DeviceState *dev = DEVICE(obj);
@@ -697,51 +220,6 @@ static void omap_gpio_realize(DeviceState *dev, Error **errp)
}
}
-static void omap2_gpio_realize(DeviceState *dev, Error **errp)
-{
- Omap2GpioState *s = OMAP2_GPIO(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- int i;
-
- if (!s->iclk) {
- error_setg(errp, "omap2-gpio: iclk not connected");
- return;
- }
-
- s->modulecount = s->mpu_model < omap2430 ? 4
- : s->mpu_model < omap3430 ? 5
- : 6;
-
- if (s->mpu_model < omap3430) {
- memory_region_init_io(&s->iomem, OBJECT(dev), &omap2_gpif_top_ops, s,
- "omap2.gpio", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
- }
-
- s->modules = g_new0(struct omap2_gpio_s, s->modulecount);
- s->handler = g_new0(qemu_irq, s->modulecount * 32);
- qdev_init_gpio_in(dev, omap2_gpio_set, s->modulecount * 32);
- qdev_init_gpio_out(dev, s->handler, s->modulecount * 32);
-
- for (i = 0; i < s->modulecount; i++) {
- struct omap2_gpio_s *m = &s->modules[i];
-
- if (!s->fclk[i]) {
- error_setg(errp, "omap2-gpio: fclk%d not connected", i);
- return;
- }
-
- m->revision = (s->mpu_model < omap3430) ? 0x18 : 0x25;
- m->handler = &s->handler[i * 32];
- sysbus_init_irq(sbd, &m->irq[0]); /* mpu irq */
- sysbus_init_irq(sbd, &m->irq[1]); /* dsp irq */
- sysbus_init_irq(sbd, &m->wkup);
- memory_region_init_io(&m->iomem, OBJECT(dev), &omap2_gpio_module_ops, m,
- "omap.gpio-module", 0x1000);
- sysbus_init_mmio(sbd, &m->iomem);
- }
-}
-
void omap_gpio_set_clk(Omap1GpioState *gpio, omap_clk clk)
{
gpio->clk = clk;
@@ -757,7 +235,7 @@ static void omap_gpio_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = omap_gpio_realize;
- dc->reset = omap_gpif_reset;
+ device_class_set_legacy_reset(dc, omap_gpif_reset);
device_class_set_props(dc, omap_gpio_properties);
/* Reason: pointer property "clk" */
dc->user_creatable = false;
@@ -771,44 +249,9 @@ static const TypeInfo omap_gpio_info = {
.class_init = omap_gpio_class_init,
};
-void omap2_gpio_set_iclk(Omap2GpioState *gpio, omap_clk clk)
-{
- gpio->iclk = clk;
-}
-
-void omap2_gpio_set_fclk(Omap2GpioState *gpio, uint8_t i, omap_clk clk)
-{
- assert(i <= 5);
- gpio->fclk[i] = clk;
-}
-
-static Property omap2_gpio_properties[] = {
- DEFINE_PROP_INT32("mpu_model", Omap2GpioState, mpu_model, 0),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void omap2_gpio_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = omap2_gpio_realize;
- dc->reset = omap2_gpif_reset;
- device_class_set_props(dc, omap2_gpio_properties);
- /* Reason: pointer properties "iclk", "fclk0", ..., "fclk5" */
- dc->user_creatable = false;
-}
-
-static const TypeInfo omap2_gpio_info = {
- .name = TYPE_OMAP2_GPIO,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Omap2GpioState),
- .class_init = omap2_gpio_class_init,
-};
-
static void omap_gpio_register_types(void)
{
type_register_static(&omap_gpio_info);
- type_register_static(&omap2_gpio_info);
}
type_init(omap_gpio_register_types)
diff --git a/hw/gpio/pca9552.c b/hw/gpio/pca9552.c
index 27d4db0..59b2333 100644
--- a/hw/gpio/pca9552.c
+++ b/hw/gpio/pca9552.c
@@ -460,7 +460,7 @@ static void pca9552_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
PCA955xClass *pc = PCA955X_CLASS(oc);
- dc->reset = pca9552_reset;
+ device_class_set_legacy_reset(dc, pca9552_reset);
dc->vmsd = &pca9552_vmstate;
pc->max_reg = PCA9552_LS3;
pc->pin_count = 16;
diff --git a/hw/gpio/pca9554.c b/hw/gpio/pca9554.c
index 7d10a64..68cc9e1 100644
--- a/hw/gpio/pca9554.c
+++ b/hw/gpio/pca9554.c
@@ -305,7 +305,7 @@ static void pca9554_class_init(ObjectClass *klass, void *data)
k->recv = pca9554_recv;
k->send = pca9554_send;
dc->realize = pca9554_realize;
- dc->reset = pca9554_reset;
+ device_class_set_legacy_reset(dc, pca9554_reset);
dc->vmsd = &pca9554_vmstate;
device_class_set_props(dc, pca9554_properties);
}
diff --git a/hw/gpio/pcf8574.c b/hw/gpio/pcf8574.c
index d37909e..208efe6 100644
--- a/hw/gpio/pcf8574.c
+++ b/hw/gpio/pcf8574.c
@@ -146,7 +146,7 @@ static void pcf8574_class_init(ObjectClass *klass, void *data)
k->recv = pcf8574_rx;
k->send = pcf8574_tx;
dc->realize = pcf8574_realize;
- dc->reset = pcf8574_reset;
+ device_class_set_legacy_reset(dc, pcf8574_reset);
dc->vmsd = &vmstate_pcf8574;
}
diff --git a/hw/gpio/sifive_gpio.c b/hw/gpio/sifive_gpio.c
index 995a43c..e85c040 100644
--- a/hw/gpio/sifive_gpio.c
+++ b/hw/gpio/sifive_gpio.c
@@ -378,7 +378,7 @@ static void sifive_gpio_class_init(ObjectClass *klass, void *data)
device_class_set_props(dc, sifive_gpio_properties);
dc->vmsd = &vmstate_sifive_gpio;
dc->realize = sifive_gpio_realize;
- dc->reset = sifive_gpio_reset;
+ device_class_set_legacy_reset(dc, sifive_gpio_reset);
dc->desc = "SiFive GPIO";
}
diff --git a/hw/hppa/Kconfig b/hw/hppa/Kconfig
index d4d457f..9312c42 100644
--- a/hw/hppa/Kconfig
+++ b/hw/hppa/Kconfig
@@ -9,7 +9,7 @@ config HPPA_B160L
select ASTRO
select DINO
select LASI
- select SERIAL
+ select SERIAL_MM
select SERIAL_PCI
select ISA_BUS
select I8259
diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c
index 5d0a873..a31dc32 100644
--- a/hw/hppa/machine.c
+++ b/hw/hppa/machine.c
@@ -17,7 +17,7 @@
#include "sysemu/runstate.h"
#include "hw/rtc/mc146818rtc.h"
#include "hw/timer/i8254.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/char/parallel.h"
#include "hw/intc/i8259.h"
#include "hw/input/lasips2.h"
@@ -642,12 +642,12 @@ static void machine_HP_C3700_init(MachineState *machine)
machine_HP_common_init_tail(machine, pci_bus, translate);
}
-static void hppa_machine_reset(MachineState *ms, ShutdownCause reason)
+static void hppa_machine_reset(MachineState *ms, ResetType type)
{
unsigned int smp_cpus = ms->smp.cpus;
int i;
- qemu_devices_reset(reason);
+ qemu_devices_reset(type);
/* Start all CPUs at the firmware entry point.
* Monarch CPU will initialize firmware, secondary CPUs
diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c
index 483dcca..ba94bf9 100644
--- a/hw/hyperv/hyperv.c
+++ b/hw/hyperv/hyperv.c
@@ -138,7 +138,7 @@ static void synic_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = synic_realize;
- dc->reset = synic_reset;
+ device_class_set_legacy_reset(dc, synic_reset);
dc->user_creatable = false;
}
diff --git a/hw/hyperv/hyperv_testdev.c b/hw/hyperv/hyperv_testdev.c
index 9a56ddf..a630ca7 100644
--- a/hw/hyperv/hyperv_testdev.c
+++ b/hw/hyperv/hyperv_testdev.c
@@ -88,8 +88,7 @@ static TestSintRoute *sint_route_find(HypervTestDev *dev,
return sint_route;
}
}
- assert(false);
- return NULL;
+ g_assert_not_reached();
}
static void sint_route_destroy(HypervTestDev *dev,
@@ -187,7 +186,7 @@ static void msg_conn_destroy(HypervTestDev *dev, uint8_t conn_id)
return;
}
}
- assert(false);
+ g_assert_not_reached();
}
static void evt_conn_handler(EventNotifier *notifier)
@@ -237,7 +236,7 @@ static void evt_conn_destroy(HypervTestDev *dev, uint8_t conn_id)
return;
}
}
- assert(false);
+ g_assert_not_reached();
}
static uint64_t hv_test_dev_read(void *opaque, hwaddr addr, unsigned size)
diff --git a/hw/hyperv/vmbus.c b/hw/hyperv/vmbus.c
index 490d805..b36bd3d 100644
--- a/hw/hyperv/vmbus.c
+++ b/hw/hyperv/vmbus.c
@@ -1874,7 +1874,7 @@ static void send_create_gpadl(VMBus *vmbus)
}
}
- assert(false);
+ g_assert_not_reached();
}
static bool complete_create_gpadl(VMBus *vmbus)
@@ -1889,8 +1889,7 @@ static bool complete_create_gpadl(VMBus *vmbus)
}
}
- assert(false);
- return false;
+ g_assert_not_reached();
}
static void handle_gpadl_teardown(VMBus *vmbus,
@@ -1931,7 +1930,7 @@ static void send_teardown_gpadl(VMBus *vmbus)
}
}
- assert(false);
+ g_assert_not_reached();
}
static bool complete_teardown_gpadl(VMBus *vmbus)
@@ -1946,8 +1945,7 @@ static bool complete_teardown_gpadl(VMBus *vmbus)
}
}
- assert(false);
- return false;
+ g_assert_not_reached();
}
static void handle_open_channel(VMBus *vmbus, vmbus_message_open_channel *msg,
@@ -1996,7 +1994,7 @@ static void send_open_channel(VMBus *vmbus)
}
}
- assert(false);
+ g_assert_not_reached();
}
static bool complete_open_channel(VMBus *vmbus)
@@ -2020,8 +2018,7 @@ static bool complete_open_channel(VMBus *vmbus)
}
}
- assert(false);
- return false;
+ g_assert_not_reached();
}
static void vdev_reset_on_close(VMBusDevice *vdev)
@@ -2362,7 +2359,7 @@ static void vmbus_dev_class_init(ObjectClass *klass, void *data)
kdev->bus_type = TYPE_VMBUS;
kdev->realize = vmbus_dev_realize;
kdev->unrealize = vmbus_dev_unrealize;
- kdev->reset = vmbus_dev_reset;
+ device_class_set_legacy_reset(kdev, vmbus_dev_reset);
}
static void vmbus_dev_instance_init(Object *obj)
diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index b43afd2..3ae22cb 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -114,7 +114,10 @@ static uint64_t aspeed_i2c_bus_old_read(AspeedI2CBus *bus, hwaddr offset,
if (!aic->has_dma) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__);
value = -1;
+ break;
}
+
+ value = extract64(bus->dma_dram_offset, 0, 32);
break;
case A_I2CD_DMA_LEN:
if (!aic->has_dma) {
@@ -137,6 +140,7 @@ static uint64_t aspeed_i2c_bus_old_read(AspeedI2CBus *bus, hwaddr offset,
static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, hwaddr offset,
unsigned size)
{
+ AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
uint64_t value = bus->regs[offset / sizeof(*bus->regs)];
switch (offset) {
@@ -150,9 +154,7 @@ static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, hwaddr offset,
case A_I2CM_DMA_TX_ADDR:
case A_I2CM_DMA_RX_ADDR:
case A_I2CM_DMA_LEN_STS:
- case A_I2CC_DMA_ADDR:
case A_I2CC_DMA_LEN:
-
case A_I2CS_DEV_ADDR:
case A_I2CS_DMA_RX_ADDR:
case A_I2CS_DMA_LEN:
@@ -161,11 +163,24 @@ static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, hwaddr offset,
case A_I2CS_DMA_LEN_STS:
/* Value is already set, don't do anything. */
break;
+ case A_I2CC_DMA_ADDR:
+ value = extract64(bus->dma_dram_offset, 0, 32);
+ break;
case A_I2CS_INTR_STS:
break;
case A_I2CM_CMD:
value = SHARED_FIELD_DP32(value, BUS_BUSY_STS, i2c_bus_busy(bus->bus));
break;
+ case A_I2CM_DMA_TX_ADDR_HI:
+ case A_I2CM_DMA_RX_ADDR_HI:
+ case A_I2CS_DMA_TX_ADDR_HI:
+ case A_I2CS_DMA_RX_ADDR_HI:
+ if (!aic->has_dma64) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+ __func__);
+ value = -1;
+ }
+ break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset);
@@ -210,18 +225,18 @@ static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t *data)
{
MemTxResult result;
AspeedI2CState *s = bus->controller;
- uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus);
uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus);
- result = address_space_read(&s->dram_as, bus->regs[reg_dma_addr],
+ result = address_space_read(&s->dram_as, bus->dma_dram_offset,
MEMTXATTRS_UNSPECIFIED, data, 1);
if (result != MEMTX_OK) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM read failed @%08x\n",
- __func__, bus->regs[reg_dma_addr]);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: DRAM read failed @%" PRIx64 "\n",
+ __func__, bus->dma_dram_offset);
return -1;
}
- bus->regs[reg_dma_addr]++;
+ bus->dma_dram_offset++;
bus->regs[reg_dma_len]--;
return 0;
}
@@ -291,7 +306,6 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)
uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus);
uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus);
uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus);
- uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus);
int pool_rx_count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl,
RX_SIZE) + 1;
@@ -323,14 +337,17 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)
data = i2c_recv(bus->bus);
trace_aspeed_i2c_bus_recv("DMA", bus->regs[reg_dma_len],
bus->regs[reg_dma_len], data);
- result = address_space_write(&s->dram_as, bus->regs[reg_dma_addr],
+
+ result = address_space_write(&s->dram_as, bus->dma_dram_offset,
MEMTXATTRS_UNSPECIFIED, &data, 1);
if (result != MEMTX_OK) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM write failed @%08x\n",
- __func__, bus->regs[reg_dma_addr]);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: DRAM write failed @%" PRIx64 "\n",
+ __func__, bus->dma_dram_offset);
return;
}
- bus->regs[reg_dma_addr]++;
+
+ bus->dma_dram_offset++;
bus->regs[reg_dma_len]--;
/* In new mode, keep track of how many bytes we RXed */
if (aspeed_i2c_is_new_mode(bus->controller)) {
@@ -636,14 +653,18 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
case A_I2CM_DMA_TX_ADDR:
bus->regs[R_I2CM_DMA_TX_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR,
ADDR);
- bus->regs[R_I2CC_DMA_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR, ADDR);
+ bus->dma_dram_offset =
+ deposit64(bus->dma_dram_offset, 0, 32,
+ FIELD_EX32(value, I2CM_DMA_TX_ADDR, ADDR));
bus->regs[R_I2CC_DMA_LEN] = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN,
TX_BUF_LEN) + 1;
break;
case A_I2CM_DMA_RX_ADDR:
bus->regs[R_I2CM_DMA_RX_ADDR] = FIELD_EX32(value, I2CM_DMA_RX_ADDR,
ADDR);
- bus->regs[R_I2CC_DMA_ADDR] = FIELD_EX32(value, I2CM_DMA_RX_ADDR, ADDR);
+ bus->dma_dram_offset =
+ deposit64(bus->dma_dram_offset, 0, 32,
+ FIELD_EX32(value, I2CM_DMA_RX_ADDR, ADDR));
bus->regs[R_I2CC_DMA_LEN] = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN,
RX_BUF_LEN) + 1;
break;
@@ -721,6 +742,56 @@ static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset,
qemu_log_mask(LOG_UNIMP, "%s: Slave mode DMA TX is not implemented\n",
__func__);
break;
+
+ /*
+ * The AST2700 support the maximum DRAM size is 8 GB.
+ * The DRAM offset range is from 0x0_0000_0000 to
+ * 0x1_FFFF_FFFF and it is enough to use bits [33:0]
+ * saving the dram offset.
+ * Therefore, save the high part physical address bit[1:0]
+ * of Tx/Rx buffer address as dma_dram_offset bit[33:32].
+ */
+ case A_I2CM_DMA_TX_ADDR_HI:
+ if (!aic->has_dma64) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+ __func__);
+ break;
+ }
+ bus->regs[R_I2CM_DMA_TX_ADDR_HI] = FIELD_EX32(value,
+ I2CM_DMA_TX_ADDR_HI,
+ ADDR_HI);
+ bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 32, 32,
+ extract32(value, 0, 2));
+ break;
+ case A_I2CM_DMA_RX_ADDR_HI:
+ if (!aic->has_dma64) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+ __func__);
+ break;
+ }
+ bus->regs[R_I2CM_DMA_RX_ADDR_HI] = FIELD_EX32(value,
+ I2CM_DMA_RX_ADDR_HI,
+ ADDR_HI);
+ bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 32, 32,
+ extract32(value, 0, 2));
+ break;
+ case A_I2CS_DMA_TX_ADDR_HI:
+ qemu_log_mask(LOG_UNIMP,
+ "%s: Slave mode DMA TX Addr high is not implemented\n",
+ __func__);
+ break;
+ case A_I2CS_DMA_RX_ADDR_HI:
+ if (!aic->has_dma64) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA 64 bits support\n",
+ __func__);
+ break;
+ }
+ bus->regs[R_I2CS_DMA_RX_ADDR_HI] = FIELD_EX32(value,
+ I2CS_DMA_RX_ADDR_HI,
+ ADDR_HI);
+ bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 32, 32,
+ extract32(value, 0, 2));
+ break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
@@ -811,7 +882,8 @@ static void aspeed_i2c_bus_old_write(AspeedI2CBus *bus, hwaddr offset,
break;
}
- bus->regs[R_I2CD_DMA_ADDR] = value & 0x3ffffffc;
+ bus->dma_dram_offset = deposit64(bus->dma_dram_offset, 0, 32,
+ value & 0x3ffffffc);
break;
case A_I2CD_DMA_LEN:
@@ -906,7 +978,7 @@ static const MemoryRegionOps aspeed_i2c_ctrl_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static uint64_t aspeed_i2c_pool_read(void *opaque, hwaddr offset,
+static uint64_t aspeed_i2c_share_pool_read(void *opaque, hwaddr offset,
unsigned size)
{
AspeedI2CState *s = opaque;
@@ -914,26 +986,61 @@ static uint64_t aspeed_i2c_pool_read(void *opaque, hwaddr offset,
int i;
for (i = 0; i < size; i++) {
- ret |= (uint64_t) s->pool[offset + i] << (8 * i);
+ ret |= (uint64_t) s->share_pool[offset + i] << (8 * i);
}
return ret;
}
-static void aspeed_i2c_pool_write(void *opaque, hwaddr offset,
+static void aspeed_i2c_share_pool_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
AspeedI2CState *s = opaque;
int i;
for (i = 0; i < size; i++) {
+ s->share_pool[offset + i] = (value >> (8 * i)) & 0xFF;
+ }
+}
+
+static const MemoryRegionOps aspeed_i2c_share_pool_ops = {
+ .read = aspeed_i2c_share_pool_read,
+ .write = aspeed_i2c_share_pool_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+};
+
+static uint64_t aspeed_i2c_bus_pool_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ AspeedI2CBus *s = opaque;
+ uint64_t ret = 0;
+ int i;
+
+ for (i = 0; i < size; i++) {
+ ret |= (uint64_t) s->pool[offset + i] << (8 * i);
+ }
+
+ return ret;
+}
+
+static void aspeed_i2c_bus_pool_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ AspeedI2CBus *s = opaque;
+ int i;
+
+ for (i = 0; i < size; i++) {
s->pool[offset + i] = (value >> (8 * i)) & 0xFF;
}
}
-static const MemoryRegionOps aspeed_i2c_pool_ops = {
- .read = aspeed_i2c_pool_read,
- .write = aspeed_i2c_pool_write,
+static const MemoryRegionOps aspeed_i2c_bus_pool_ops = {
+ .read = aspeed_i2c_bus_pool_read,
+ .write = aspeed_i2c_bus_pool_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 1,
@@ -943,24 +1050,27 @@ static const MemoryRegionOps aspeed_i2c_pool_ops = {
static const VMStateDescription aspeed_i2c_bus_vmstate = {
.name = TYPE_ASPEED_I2C,
- .version_id = 5,
- .minimum_version_id = 5,
+ .version_id = 6,
+ .minimum_version_id = 6,
.fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, AspeedI2CBus, ASPEED_I2C_NEW_NUM_REG),
+ VMSTATE_UINT8_ARRAY(pool, AspeedI2CBus, ASPEED_I2C_BUS_POOL_SIZE),
+ VMSTATE_UINT64(dma_dram_offset, AspeedI2CBus),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription aspeed_i2c_vmstate = {
.name = TYPE_ASPEED_I2C,
- .version_id = 2,
- .minimum_version_id = 2,
+ .version_id = 3,
+ .minimum_version_id = 3,
.fields = (const VMStateField[]) {
VMSTATE_UINT32(intr_status, AspeedI2CState),
VMSTATE_STRUCT_ARRAY(busses, AspeedI2CState,
ASPEED_I2C_NR_BUSSES, 1, aspeed_i2c_bus_vmstate,
AspeedI2CBus),
- VMSTATE_UINT8_ARRAY(pool, AspeedI2CState, ASPEED_I2C_MAX_POOL_SIZE),
+ VMSTATE_UINT8_ARRAY(share_pool, AspeedI2CState,
+ ASPEED_I2C_SHARE_POOL_SIZE),
VMSTATE_END_OF_LIST()
}
};
@@ -995,7 +1105,21 @@ static void aspeed_i2c_instance_init(Object *obj)
* 0x140 ... 0x17F: Device 5
* 0x180 ... 0x1BF: Device 6
* 0x1C0 ... 0x1FF: Device 7
- * 0x200 ... 0x2FF: Buffer Pool (unused in linux driver)
+ * 0x200 ... 0x20F: Device 1 buffer (AST2500 unused in linux driver)
+ * 0x210 ... 0x21F: Device 2 buffer
+ * 0x220 ... 0x22F: Device 3 buffer
+ * 0x230 ... 0x23F: Device 4 buffer
+ * 0x240 ... 0x24F: Device 5 buffer
+ * 0x250 ... 0x25F: Device 6 buffer
+ * 0x260 ... 0x26F: Device 7 buffer
+ * 0x270 ... 0x27F: Device 8 buffer
+ * 0x280 ... 0x28F: Device 9 buffer
+ * 0x290 ... 0x29F: Device 10 buffer
+ * 0x2A0 ... 0x2AF: Device 11 buffer
+ * 0x2B0 ... 0x2BF: Device 12 buffer
+ * 0x2C0 ... 0x2CF: Device 13 buffer
+ * 0x2D0 ... 0x2DF: Device 14 buffer
+ * 0x2E0 ... 0x2FF: Reserved
* 0x300 ... 0x33F: Device 8
* 0x340 ... 0x37F: Device 9
* 0x380 ... 0x3BF: Device 10
@@ -1003,7 +1127,77 @@ static void aspeed_i2c_instance_init(Object *obj)
* 0x400 ... 0x43F: Device 12
* 0x440 ... 0x47F: Device 13
* 0x480 ... 0x4BF: Device 14
- * 0x800 ... 0xFFF: Buffer Pool (unused in linux driver)
+ * 0x800 ... 0xFFF: Buffer Pool (AST2400 unused in linux driver)
+ *
+ * Address Definitions (AST2600 and AST1030)
+ * 0x000 ... 0x07F: Global Register
+ * 0x080 ... 0x0FF: Device 1
+ * 0x100 ... 0x17F: Device 2
+ * 0x180 ... 0x1FF: Device 3
+ * 0x200 ... 0x27F: Device 4
+ * 0x280 ... 0x2FF: Device 5
+ * 0x300 ... 0x37F: Device 6
+ * 0x380 ... 0x3FF: Device 7
+ * 0x400 ... 0x47F: Device 8
+ * 0x480 ... 0x4FF: Device 9
+ * 0x500 ... 0x57F: Device 10
+ * 0x580 ... 0x5FF: Device 11
+ * 0x600 ... 0x67F: Device 12
+ * 0x680 ... 0x6FF: Device 13
+ * 0x700 ... 0x77F: Device 14
+ * 0x780 ... 0x7FF: Device 15 (15 and 16 unused in AST1030)
+ * 0x800 ... 0x87F: Device 16
+ * 0xC00 ... 0xC1F: Device 1 buffer
+ * 0xC20 ... 0xC3F: Device 2 buffer
+ * 0xC40 ... 0xC5F: Device 3 buffer
+ * 0xC60 ... 0xC7F: Device 4 buffer
+ * 0xC80 ... 0xC9F: Device 5 buffer
+ * 0xCA0 ... 0xCBF: Device 6 buffer
+ * 0xCC0 ... 0xCDF: Device 7 buffer
+ * 0xCE0 ... 0xCFF: Device 8 buffer
+ * 0xD00 ... 0xD1F: Device 9 buffer
+ * 0xD20 ... 0xD3F: Device 10 buffer
+ * 0xD40 ... 0xD5F: Device 11 buffer
+ * 0xD60 ... 0xD7F: Device 12 buffer
+ * 0xD80 ... 0xD9F: Device 13 buffer
+ * 0xDA0 ... 0xDBF: Device 14 buffer
+ * 0xDC0 ... 0xDDF: Device 15 buffer (15 and 16 unused in AST1030)
+ * 0xDE0 ... 0xDFF: Device 16 buffer
+ *
+ * Address Definitions (AST2700)
+ * 0x000 ... 0x0FF: Global Register
+ * 0x100 ... 0x17F: Device 0
+ * 0x1A0 ... 0x1BF: Device 0 buffer
+ * 0x200 ... 0x27F: Device 1
+ * 0x2A0 ... 0x2BF: Device 1 buffer
+ * 0x300 ... 0x37F: Device 2
+ * 0x3A0 ... 0x3BF: Device 2 buffer
+ * 0x400 ... 0x47F: Device 3
+ * 0x4A0 ... 0x4BF: Device 3 buffer
+ * 0x500 ... 0x57F: Device 4
+ * 0x5A0 ... 0x5BF: Device 4 buffer
+ * 0x600 ... 0x67F: Device 5
+ * 0x6A0 ... 0x6BF: Device 5 buffer
+ * 0x700 ... 0x77F: Device 6
+ * 0x7A0 ... 0x7BF: Device 6 buffer
+ * 0x800 ... 0x87F: Device 7
+ * 0x8A0 ... 0x8BF: Device 7 buffer
+ * 0x900 ... 0x97F: Device 8
+ * 0x9A0 ... 0x9BF: Device 8 buffer
+ * 0xA00 ... 0xA7F: Device 9
+ * 0xAA0 ... 0xABF: Device 9 buffer
+ * 0xB00 ... 0xB7F: Device 10
+ * 0xBA0 ... 0xBBF: Device 10 buffer
+ * 0xC00 ... 0xC7F: Device 11
+ * 0xCA0 ... 0xCBF: Device 11 buffer
+ * 0xD00 ... 0xD7F: Device 12
+ * 0xDA0 ... 0xDBF: Device 12 buffer
+ * 0xE00 ... 0xE7F: Device 13
+ * 0xEA0 ... 0xEBF: Device 13 buffer
+ * 0xF00 ... 0xF7F: Device 14
+ * 0xFA0 ... 0xFBF: Device 14 buffer
+ * 0x1000 ... 0x107F: Device 15
+ * 0x10A0 ... 0x10BF: Device 15 buffer
*/
static void aspeed_i2c_realize(DeviceState *dev, Error **errp)
{
@@ -1011,10 +1205,12 @@ static void aspeed_i2c_realize(DeviceState *dev, Error **errp)
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
AspeedI2CState *s = ASPEED_I2C(dev);
AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
+ uint32_t reg_offset = aic->reg_size + aic->reg_gap_size;
+ uint32_t pool_offset = aic->pool_size + aic->pool_gap_size;
sysbus_init_irq(sbd, &s->irq);
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i2c_ctrl_ops, s,
- "aspeed.i2c", 0x1000);
+ "aspeed.i2c", aic->mem_size);
sysbus_init_mmio(sbd, &s->iomem);
for (i = 0; i < aic->num_busses; i++) {
@@ -1033,13 +1229,23 @@ static void aspeed_i2c_realize(DeviceState *dev, Error **errp)
return;
}
- memory_region_add_subregion(&s->iomem, aic->reg_size * (i + offset),
+ memory_region_add_subregion(&s->iomem, reg_offset * (i + offset),
&s->busses[i].mr);
}
- memory_region_init_io(&s->pool_iomem, OBJECT(s), &aspeed_i2c_pool_ops, s,
- "aspeed.i2c-pool", aic->pool_size);
- memory_region_add_subregion(&s->iomem, aic->pool_base, &s->pool_iomem);
+ if (aic->has_share_pool) {
+ memory_region_init_io(&s->pool_iomem, OBJECT(s),
+ &aspeed_i2c_share_pool_ops, s,
+ "aspeed.i2c-share-pool", aic->pool_size);
+ memory_region_add_subregion(&s->iomem, aic->pool_base,
+ &s->pool_iomem);
+ } else {
+ for (i = 0; i < aic->num_busses; i++) {
+ memory_region_add_subregion(&s->iomem,
+ aic->pool_base + (pool_offset * i),
+ &s->busses[i].mr_pool);
+ }
+ }
if (aic->has_dma) {
if (!s->dram_mr) {
@@ -1063,7 +1269,7 @@ static void aspeed_i2c_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &aspeed_i2c_vmstate;
- dc->reset = aspeed_i2c_reset;
+ device_class_set_legacy_reset(dc, aspeed_i2c_reset);
device_class_set_props(dc, aspeed_i2c_properties);
dc->realize = aspeed_i2c_realize;
dc->desc = "Aspeed I2C Controller";
@@ -1090,8 +1296,9 @@ static int aspeed_i2c_bus_new_slave_event(AspeedI2CBus *bus,
return -1;
}
ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN, 0);
- bus->regs[R_I2CC_DMA_ADDR] =
- ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_RX_ADDR, ADDR);
+ bus->dma_dram_offset =
+ deposit64(bus->dma_dram_offset, 0, 32,
+ ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_RX_ADDR, ADDR));
bus->regs[R_I2CC_DMA_LEN] =
ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN) + 1;
i2c_ack(bus->bus);
@@ -1157,10 +1364,10 @@ static int aspeed_i2c_bus_slave_event(I2CSlave *slave, enum i2c_event event)
static void aspeed_i2c_bus_new_slave_send_async(AspeedI2CBus *bus, uint8_t data)
{
assert(address_space_write(&bus->controller->dram_as,
- bus->regs[R_I2CC_DMA_ADDR],
+ bus->dma_dram_offset,
MEMTXATTRS_UNSPECIFIED, &data, 1) == MEMTX_OK);
- bus->regs[R_I2CC_DMA_ADDR]++;
+ bus->dma_dram_offset++;
bus->regs[R_I2CC_DMA_LEN]--;
ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN,
ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN) + 1);
@@ -1215,6 +1422,7 @@ static void aspeed_i2c_bus_realize(DeviceState *dev, Error **errp)
AspeedI2CBus *s = ASPEED_I2C_BUS(dev);
AspeedI2CClass *aic;
g_autofree char *name = g_strdup_printf(TYPE_ASPEED_I2C_BUS ".%d", s->id);
+ g_autofree char *pool_name = g_strdup_printf("%s.pool", name);
if (!s->controller) {
error_setg(errp, TYPE_ASPEED_I2C_BUS ": 'controller' link not set");
@@ -1232,6 +1440,10 @@ static void aspeed_i2c_bus_realize(DeviceState *dev, Error **errp)
memory_region_init_io(&s->mr, OBJECT(s), &aspeed_i2c_bus_ops,
s, name, aic->reg_size);
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr);
+
+ memory_region_init_io(&s->mr_pool, OBJECT(s), &aspeed_i2c_bus_pool_ops,
+ s, pool_name, aic->pool_size);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr_pool);
}
static Property aspeed_i2c_bus_properties[] = {
@@ -1247,7 +1459,7 @@ static void aspeed_i2c_bus_class_init(ObjectClass *klass, void *data)
dc->desc = "Aspeed I2C Bus";
dc->realize = aspeed_i2c_bus_realize;
- dc->reset = aspeed_i2c_bus_reset;
+ device_class_set_legacy_reset(dc, aspeed_i2c_bus_reset);
device_class_set_props(dc, aspeed_i2c_bus_properties);
}
@@ -1266,8 +1478,9 @@ static qemu_irq aspeed_2400_i2c_bus_get_irq(AspeedI2CBus *bus)
static uint8_t *aspeed_2400_i2c_bus_pool_base(AspeedI2CBus *bus)
{
uint8_t *pool_page =
- &bus->controller->pool[ARRAY_FIELD_EX32(bus->regs, I2CD_FUN_CTRL,
- POOL_PAGE_SEL) * 0x100];
+ &bus->controller->share_pool[ARRAY_FIELD_EX32(bus->regs,
+ I2CD_FUN_CTRL,
+ POOL_PAGE_SEL) * 0x100];
return &pool_page[ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, OFFSET)];
}
@@ -1283,9 +1496,11 @@ static void aspeed_2400_i2c_class_init(ObjectClass *klass, void *data)
aic->reg_size = 0x40;
aic->gap = 7;
aic->bus_get_irq = aspeed_2400_i2c_bus_get_irq;
+ aic->has_share_pool = true;
aic->pool_size = 0x800;
aic->pool_base = 0x800;
aic->bus_pool_base = aspeed_2400_i2c_bus_pool_base;
+ aic->mem_size = 0x1000;
}
static const TypeInfo aspeed_2400_i2c_info = {
@@ -1301,7 +1516,7 @@ static qemu_irq aspeed_2500_i2c_bus_get_irq(AspeedI2CBus *bus)
static uint8_t *aspeed_2500_i2c_bus_pool_base(AspeedI2CBus *bus)
{
- return &bus->controller->pool[bus->id * 0x10];
+ return bus->pool;
}
static void aspeed_2500_i2c_class_init(ObjectClass *klass, void *data)
@@ -1315,11 +1530,12 @@ static void aspeed_2500_i2c_class_init(ObjectClass *klass, void *data)
aic->reg_size = 0x40;
aic->gap = 7;
aic->bus_get_irq = aspeed_2500_i2c_bus_get_irq;
- aic->pool_size = 0x100;
+ aic->pool_size = 0x10;
aic->pool_base = 0x200;
aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base;
aic->check_sram = true;
aic->has_dma = true;
+ aic->mem_size = 0x1000;
}
static const TypeInfo aspeed_2500_i2c_info = {
@@ -1333,11 +1549,6 @@ static qemu_irq aspeed_2600_i2c_bus_get_irq(AspeedI2CBus *bus)
return bus->irq;
}
-static uint8_t *aspeed_2600_i2c_bus_pool_base(AspeedI2CBus *bus)
-{
- return &bus->controller->pool[bus->id * 0x20];
-}
-
static void aspeed_2600_i2c_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1349,10 +1560,11 @@ static void aspeed_2600_i2c_class_init(ObjectClass *klass, void *data)
aic->reg_size = 0x80;
aic->gap = -1; /* no gap */
aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq;
- aic->pool_size = 0x200;
+ aic->pool_size = 0x20;
aic->pool_base = 0xC00;
- aic->bus_pool_base = aspeed_2600_i2c_bus_pool_base;
+ aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base;
aic->has_dma = true;
+ aic->mem_size = 0x1000;
}
static const TypeInfo aspeed_2600_i2c_info = {
@@ -1372,10 +1584,11 @@ static void aspeed_1030_i2c_class_init(ObjectClass *klass, void *data)
aic->reg_size = 0x80;
aic->gap = -1; /* no gap */
aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq;
- aic->pool_size = 0x200;
+ aic->pool_size = 0x20;
aic->pool_base = 0xC00;
- aic->bus_pool_base = aspeed_2600_i2c_bus_pool_base;
+ aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base;
aic->has_dma = true;
+ aic->mem_size = 0x10000;
}
static const TypeInfo aspeed_1030_i2c_info = {
@@ -1384,6 +1597,33 @@ static const TypeInfo aspeed_1030_i2c_info = {
.class_init = aspeed_1030_i2c_class_init,
};
+static void aspeed_2700_i2c_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass);
+
+ dc->desc = "ASPEED 2700 I2C Controller";
+
+ aic->num_busses = 16;
+ aic->reg_size = 0x80;
+ aic->reg_gap_size = 0x80;
+ aic->gap = -1; /* no gap */
+ aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq;
+ aic->pool_size = 0x20;
+ aic->pool_gap_size = 0xe0;
+ aic->pool_base = 0x1a0;
+ aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base;
+ aic->has_dma = true;
+ aic->mem_size = 0x2000;
+ aic->has_dma64 = true;
+}
+
+static const TypeInfo aspeed_2700_i2c_info = {
+ .name = TYPE_ASPEED_2700_I2C,
+ .parent = TYPE_ASPEED_I2C,
+ .class_init = aspeed_2700_i2c_class_init,
+};
+
static void aspeed_i2c_register_types(void)
{
type_register_static(&aspeed_i2c_bus_info);
@@ -1393,6 +1633,7 @@ static void aspeed_i2c_register_types(void)
type_register_static(&aspeed_2500_i2c_info);
type_register_static(&aspeed_2600_i2c_info);
type_register_static(&aspeed_1030_i2c_info);
+ type_register_static(&aspeed_2700_i2c_info);
}
type_init(aspeed_i2c_register_types)
diff --git a/hw/i2c/bcm2835_i2c.c b/hw/i2c/bcm2835_i2c.c
index 20ec46e..67bfdef 100644
--- a/hw/i2c/bcm2835_i2c.c
+++ b/hw/i2c/bcm2835_i2c.c
@@ -262,7 +262,7 @@ static void bcm2835_i2c_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = bcm2835_i2c_reset;
+ device_class_set_legacy_reset(dc, bcm2835_i2c_reset);
dc->realize = bcm2835_i2c_realize;
dc->vmsd = &vmstate_bcm2835_i2c;
}
diff --git a/hw/i2c/exynos4210_i2c.c b/hw/i2c/exynos4210_i2c.c
index 9445424..b1d0009 100644
--- a/hw/i2c/exynos4210_i2c.c
+++ b/hw/i2c/exynos4210_i2c.c
@@ -314,7 +314,7 @@ static void exynos4210_i2c_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &exynos4210_i2c_vmstate;
- dc->reset = exynos4210_i2c_reset;
+ device_class_set_legacy_reset(dc, exynos4210_i2c_reset);
}
static const TypeInfo exynos4210_i2c_type_info = {
diff --git a/hw/i2c/imx_i2c.c b/hw/i2c/imx_i2c.c
index a25676f..c565fd5 100644
--- a/hw/i2c/imx_i2c.c
+++ b/hw/i2c/imx_i2c.c
@@ -313,7 +313,7 @@ static void imx_i2c_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &imx_i2c_vmstate;
- dc->reset = imx_i2c_reset;
+ device_class_set_legacy_reset(dc, imx_i2c_reset);
dc->realize = imx_i2c_realize;
dc->desc = "i.MX I2C Controller";
}
diff --git a/hw/i2c/microbit_i2c.c b/hw/i2c/microbit_i2c.c
index 24d36d1..06fbd18 100644
--- a/hw/i2c/microbit_i2c.c
+++ b/hw/i2c/microbit_i2c.c
@@ -110,7 +110,7 @@ static void microbit_i2c_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &microbit_i2c_vmstate;
- dc->reset = microbit_i2c_reset;
+ device_class_set_legacy_reset(dc, microbit_i2c_reset);
dc->realize = microbit_i2c_realize;
dc->desc = "Microbit I2C controller";
}
diff --git a/hw/i2c/mpc_i2c.c b/hw/i2c/mpc_i2c.c
index cb051a5..2467d1a 100644
--- a/hw/i2c/mpc_i2c.c
+++ b/hw/i2c/mpc_i2c.c
@@ -82,7 +82,7 @@ struct MPCI2CState {
uint8_t cr;
uint8_t sr;
uint8_t dr;
- uint8_t dfssr;
+ uint8_t dfsrr;
};
static bool mpc_i2c_is_enabled(MPCI2CState *s)
@@ -293,7 +293,7 @@ static void mpc_i2c_write(void *opaque, hwaddr addr,
}
break;
case MPC_I2C_DFSRR:
- s->dfssr = value;
+ s->dfsrr = value;
break;
default:
DPRINTF("ERROR: Bad write addr 0x%x\n", (unsigned int)addr);
@@ -319,7 +319,7 @@ static const VMStateDescription mpc_i2c_vmstate = {
VMSTATE_UINT8(cr, MPCI2CState),
VMSTATE_UINT8(sr, MPCI2CState),
VMSTATE_UINT8(dr, MPCI2CState),
- VMSTATE_UINT8(dfssr, MPCI2CState),
+ VMSTATE_UINT8(dfsrr, MPCI2CState),
VMSTATE_END_OF_LIST()
}
};
@@ -329,7 +329,7 @@ static void mpc_i2c_realize(DeviceState *dev, Error **errp)
MPCI2CState *i2c = MPC_I2C(dev);
sysbus_init_irq(SYS_BUS_DEVICE(dev), &i2c->irq);
memory_region_init_io(&i2c->iomem, OBJECT(i2c), &i2c_ops, i2c,
- "mpc-i2c", 0x14);
+ "mpc-i2c", 0x15);
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &i2c->iomem);
i2c->bus = i2c_init_bus(dev, "i2c");
}
@@ -339,7 +339,7 @@ static void mpc_i2c_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &mpc_i2c_vmstate ;
- dc->reset = mpc_i2c_reset;
+ device_class_set_legacy_reset(dc, mpc_i2c_reset);
dc->realize = mpc_i2c_realize;
dc->desc = "MPC I2C Controller";
}
diff --git a/hw/i2c/omap_i2c.c b/hw/i2c/omap_i2c.c
index e5d205d..e78505e 100644
--- a/hw/i2c/omap_i2c.c
+++ b/hw/i2c/omap_i2c.c
@@ -521,7 +521,7 @@ static void omap_i2c_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_props(dc, omap_i2c_properties);
- dc->reset = omap_i2c_reset;
+ device_class_set_legacy_reset(dc, omap_i2c_reset);
/* Reason: pointer properties "iclk", "fclk" */
dc->user_creatable = false;
dc->realize = omap_i2c_realize;
diff --git a/hw/i2c/ppc4xx_i2c.c b/hw/i2c/ppc4xx_i2c.c
index 75d50f1..7b124a7 100644
--- a/hw/i2c/ppc4xx_i2c.c
+++ b/hw/i2c/ppc4xx_i2c.c
@@ -358,7 +358,7 @@ static void ppc4xx_i2c_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = ppc4xx_i2c_reset;
+ device_class_set_legacy_reset(dc, ppc4xx_i2c_reset);
}
static const TypeInfo ppc4xx_i2c_type_info = {
diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c
index c42236b..9e62c27 100644
--- a/hw/i2c/smbus_eeprom.c
+++ b/hw/i2c/smbus_eeprom.c
@@ -143,7 +143,7 @@ static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data)
SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass);
dc->realize = smbus_eeprom_realize;
- dc->reset = smbus_eeprom_reset;
+ device_class_set_legacy_reset(dc, smbus_eeprom_reset);
sc->receive_byte = eeprom_receive_byte;
sc->write_data = eeprom_write_data;
dc->vmsd = &vmstate_smbus_eeprom;
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index f4e366f..4967aa7 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -724,120 +724,44 @@ static Aml *aml_pci_pdsm(void)
return method;
}
-/**
- * build_prt_entry:
- * @link_name: link name for PCI route entry
- *
- * build AML package containing a PCI route entry for @link_name
- */
-static Aml *build_prt_entry(const char *link_name)
-{
- Aml *a_zero = aml_int(0);
- Aml *pkg = aml_package(4);
- aml_append(pkg, a_zero);
- aml_append(pkg, a_zero);
- aml_append(pkg, aml_name("%s", link_name));
- aml_append(pkg, a_zero);
- return pkg;
-}
-
/*
- * initialize_route - Initialize the interrupt routing rule
- * through a specific LINK:
- * if (lnk_idx == idx)
- * route using link 'link_name'
- */
-static Aml *initialize_route(Aml *route, const char *link_name,
- Aml *lnk_idx, int idx)
-{
- Aml *if_ctx = aml_if(aml_equal(lnk_idx, aml_int(idx)));
- Aml *pkg = build_prt_entry(link_name);
-
- aml_append(if_ctx, aml_store(pkg, route));
-
- return if_ctx;
-}
-
-/*
- * build_prt - Define interrupt rounting rules
+ * build_prt - Define interrupt routing rules
*
* Returns an array of 128 routes, one for each device,
* based on device location.
* The main goal is to equally distribute the interrupts
* over the 4 existing ACPI links (works only for i440fx).
- * The hash function is (slot + pin) & 3 -> "LNK[D|A|B|C]".
+ * The hash function is: (slot + pin) & 3 -> "LNK[D|A|B|C]".
*
*/
static Aml *build_prt(bool is_pci0_prt)
{
- Aml *method, *while_ctx, *pin, *res;
+ const int nroutes = 128;
+ Aml *rt_pkg, *method;
+ int pin;
method = aml_method("_PRT", 0, AML_NOTSERIALIZED);
- res = aml_local(0);
- pin = aml_local(1);
- aml_append(method, aml_store(aml_package(128), res));
- aml_append(method, aml_store(aml_int(0), pin));
+ rt_pkg = aml_varpackage(nroutes);
- /* while (pin < 128) */
- while_ctx = aml_while(aml_lless(pin, aml_int(128)));
- {
- Aml *slot = aml_local(2);
- Aml *lnk_idx = aml_local(3);
- Aml *route = aml_local(4);
-
- /* slot = pin >> 2 */
- aml_append(while_ctx,
- aml_store(aml_shiftright(pin, aml_int(2), NULL), slot));
- /* lnk_idx = (slot + pin) & 3 */
- aml_append(while_ctx,
- aml_store(aml_and(aml_add(pin, slot, NULL), aml_int(3), NULL),
- lnk_idx));
-
- /* route[2] = "LNK[D|A|B|C]", selection based on pin % 3 */
- aml_append(while_ctx, initialize_route(route, "LNKD", lnk_idx, 0));
- if (is_pci0_prt) {
- Aml *if_device_1, *if_pin_4, *else_pin_4;
-
- /* device 1 is the power-management device, needs SCI */
- if_device_1 = aml_if(aml_equal(lnk_idx, aml_int(1)));
- {
- if_pin_4 = aml_if(aml_equal(pin, aml_int(4)));
- {
- aml_append(if_pin_4,
- aml_store(build_prt_entry("LNKS"), route));
- }
- aml_append(if_device_1, if_pin_4);
- else_pin_4 = aml_else();
- {
- aml_append(else_pin_4,
- aml_store(build_prt_entry("LNKA"), route));
- }
- aml_append(if_device_1, else_pin_4);
- }
- aml_append(while_ctx, if_device_1);
+ for (pin = 0; pin < nroutes; pin++) {
+ Aml *pkg = aml_package(4);
+ int slot = pin >> 2;
+
+ aml_append(pkg, aml_int((slot << 16) | 0xFFFF));
+ aml_append(pkg, aml_int(pin & 3));
+ /* device 1 is the power-management device, needs SCI */
+ if (is_pci0_prt && pin == 4) {
+ aml_append(pkg, aml_name("%s", "LNKS"));
} else {
- aml_append(while_ctx, initialize_route(route, "LNKA", lnk_idx, 1));
+ static const char link_name[][5] = {"LNKD", "LNKA", "LNKB", "LNKC"};
+ int hash = (slot + pin) & 3;
+ aml_append(pkg, aml_name("%s", link_name[hash]));
}
- aml_append(while_ctx, initialize_route(route, "LNKB", lnk_idx, 2));
- aml_append(while_ctx, initialize_route(route, "LNKC", lnk_idx, 3));
-
- /* route[0] = 0x[slot]FFFF */
- aml_append(while_ctx,
- aml_store(aml_or(aml_shiftleft(slot, aml_int(16)), aml_int(0xFFFF),
- NULL),
- aml_index(route, aml_int(0))));
- /* route[1] = pin & 3 */
- aml_append(while_ctx,
- aml_store(aml_and(pin, aml_int(3), NULL),
- aml_index(route, aml_int(1))));
- /* res[pin] = route */
- aml_append(while_ctx, aml_store(route, aml_index(res, pin)));
- /* pin++ */
- aml_append(while_ctx, aml_increment(pin));
+ aml_append(pkg, aml_int(0));
+ aml_append(rt_pkg, pkg);
}
- aml_append(method, while_ctx);
- /* return res*/
- aml_append(method, aml_return(res));
+
+ aml_append(method, aml_return(rt_pkg));
return method;
}
@@ -1536,7 +1460,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
.fw_unplugs_cpu = pm->smi_on_cpu_unplug,
};
build_cpus_aml(dsdt, machine, opts, pc_madt_cpu_entry,
- pm->cpu_hp_io_base, "\\_SB.PCI0", "\\_GPE._E02");
+ pm->cpu_hp_io_base, "\\_SB.PCI0", "\\_GPE._E02",
+ AML_SYSTEM_IO);
}
if (pcms->memhp_io_base && nr_mem) {
diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
index 6d4fde7..464f0b6 100644
--- a/hw/i386/amd_iommu.c
+++ b/hw/i386/amd_iommu.c
@@ -357,12 +357,12 @@ static void amdvi_update_iotlb(AMDVIState *s, uint16_t devid,
uint64_t gpa, IOMMUTLBEntry to_cache,
uint16_t domid)
{
- AMDVIIOTLBEntry *entry = g_new(AMDVIIOTLBEntry, 1);
- uint64_t *key = g_new(uint64_t, 1);
- uint64_t gfn = gpa >> AMDVI_PAGE_SHIFT_4K;
-
/* don't cache erroneous translations */
if (to_cache.perm != IOMMU_NONE) {
+ AMDVIIOTLBEntry *entry = g_new(AMDVIIOTLBEntry, 1);
+ uint64_t *key = g_new(uint64_t, 1);
+ uint64_t gfn = gpa >> AMDVI_PAGE_SHIFT_4K;
+
trace_amdvi_cache_update(domid, PCI_BUS_NUM(devid), PCI_SLOT(devid),
PCI_FUNC(devid), gpa, to_cache.translated_addr);
@@ -1628,7 +1628,7 @@ static void amdvi_sysbus_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
X86IOMMUClass *dc_class = X86_IOMMU_DEVICE_CLASS(klass);
- dc->reset = amdvi_sysbus_reset;
+ device_class_set_legacy_reset(dc, amdvi_sysbus_reset);
dc->vmsd = &vmstate_amdvi_sysbus;
dc->hotpluggable = false;
dc_class->realize = amdvi_sysbus_realize;
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index 37c21a0a..08fe218 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -358,7 +358,7 @@ static VTDIOTLBEntry *vtd_lookup_iotlb(IntelIOMMUState *s, uint16_t source_id,
{
struct vtd_iotlb_key key;
VTDIOTLBEntry *entry;
- int level;
+ unsigned level;
for (level = VTD_SL_PT_LEVEL; level < VTD_SL_PML4_LEVEL; level++) {
key.gfn = vtd_get_iotlb_gfn(addr, level);
@@ -2666,13 +2666,43 @@ static bool vtd_process_inv_iec_desc(IntelIOMMUState *s,
return true;
}
+static void do_invalidate_device_tlb(VTDAddressSpace *vtd_dev_as,
+ bool size, hwaddr addr)
+{
+ /*
+ * According to ATS spec table 2.4:
+ * S = 0, bits 15:12 = xxxx range size: 4K
+ * S = 1, bits 15:12 = xxx0 range size: 8K
+ * S = 1, bits 15:12 = xx01 range size: 16K
+ * S = 1, bits 15:12 = x011 range size: 32K
+ * S = 1, bits 15:12 = 0111 range size: 64K
+ * ...
+ */
+
+ IOMMUTLBEvent event;
+ uint64_t sz;
+
+ if (size) {
+ sz = (VTD_PAGE_SIZE * 2) << cto64(addr >> VTD_PAGE_SHIFT);
+ addr &= ~(sz - 1);
+ } else {
+ sz = VTD_PAGE_SIZE;
+ }
+
+ event.type = IOMMU_NOTIFIER_DEVIOTLB_UNMAP;
+ event.entry.target_as = &vtd_dev_as->as;
+ event.entry.addr_mask = sz - 1;
+ event.entry.iova = addr;
+ event.entry.perm = IOMMU_NONE;
+ event.entry.translated_addr = 0;
+ memory_region_notify_iommu(&vtd_dev_as->iommu, 0, event);
+}
+
static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s,
VTDInvDesc *inv_desc)
{
VTDAddressSpace *vtd_dev_as;
- IOMMUTLBEvent event;
hwaddr addr;
- uint64_t sz;
uint16_t sid;
bool size;
@@ -2697,28 +2727,7 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s,
goto done;
}
- /* According to ATS spec table 2.4:
- * S = 0, bits 15:12 = xxxx range size: 4K
- * S = 1, bits 15:12 = xxx0 range size: 8K
- * S = 1, bits 15:12 = xx01 range size: 16K
- * S = 1, bits 15:12 = x011 range size: 32K
- * S = 1, bits 15:12 = 0111 range size: 64K
- * ...
- */
- if (size) {
- sz = (VTD_PAGE_SIZE * 2) << cto64(addr >> VTD_PAGE_SHIFT);
- addr &= ~(sz - 1);
- } else {
- sz = VTD_PAGE_SIZE;
- }
-
- event.type = IOMMU_NOTIFIER_DEVIOTLB_UNMAP;
- event.entry.target_as = &vtd_dev_as->as;
- event.entry.addr_mask = sz - 1;
- event.entry.iova = addr;
- event.entry.perm = IOMMU_NONE;
- event.entry.translated_addr = 0;
- memory_region_notify_iommu(&vtd_dev_as->iommu, 0, event);
+ do_invalidate_device_tlb(vtd_dev_as, size, addr);
done:
return true;
@@ -2735,7 +2744,7 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s)
return false;
}
- desc_type = inv_desc.lo & VTD_INV_DESC_TYPE;
+ desc_type = VTD_INV_DESC_TYPE(inv_desc.lo);
/* FIXME: should update at first or at last? */
s->iq_last_desc_type = desc_type;
@@ -2754,17 +2763,6 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s)
}
break;
- /*
- * TODO: the entity of below two cases will be implemented in future series.
- * To make guest (which integrates scalable mode support patch set in
- * iommu driver) work, just return true is enough so far.
- */
- case VTD_INV_DESC_PC:
- break;
-
- case VTD_INV_DESC_PIOTLB:
- break;
-
case VTD_INV_DESC_WAIT:
trace_vtd_inv_desc("wait", inv_desc.hi, inv_desc.lo);
if (!vtd_process_wait_desc(s, &inv_desc)) {
@@ -2786,6 +2784,17 @@ static bool vtd_process_inv_desc(IntelIOMMUState *s)
}
break;
+ /*
+ * TODO: the entity of below two cases will be implemented in future series.
+ * To make guest (which integrates scalable mode support patch set in
+ * iommu driver) work, just return true is enough so far.
+ */
+ case VTD_INV_DESC_PC:
+ case VTD_INV_DESC_PIOTLB:
+ if (s->scalable_mode) {
+ break;
+ }
+ /* fallthrough */
default:
error_report_once("%s: invalid inv desc: hi=%"PRIx64", lo=%"PRIx64
" (unknown type)", __func__, inv_desc.hi,
@@ -2938,7 +2947,9 @@ static uint64_t vtd_mem_read(void *opaque, hwaddr addr, unsigned size)
/* Invalidation Queue Address Register, 64-bit */
case DMAR_IQA_REG:
- val = s->iq | (vtd_get_quad(s, DMAR_IQA_REG) & VTD_IQA_QS);
+ val = s->iq |
+ (vtd_get_quad(s, DMAR_IQA_REG) &
+ (VTD_IQA_QS | VTD_IQA_DW_MASK));
if (size == 4) {
val = val & ((1ULL << 32) - 1);
}
@@ -4357,7 +4368,7 @@ static void vtd_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
X86IOMMUClass *x86_class = X86_IOMMU_DEVICE_CLASS(klass);
- dc->reset = vtd_reset;
+ device_class_set_legacy_reset(dc, vtd_reset);
dc->vmsd = &vtd_vmstate;
device_class_set_props(dc, vtd_properties);
dc->hotpluggable = false;
diff --git a/hw/i386/intel_iommu_internal.h b/hw/i386/intel_iommu_internal.h
index f8cf99b..13d5d12 100644
--- a/hw/i386/intel_iommu_internal.h
+++ b/hw/i386/intel_iommu_internal.h
@@ -264,10 +264,10 @@
#define VTD_FRCD_FR(val) (((val) & 0xffULL) << 32)
#define VTD_FRCD_SID_MASK 0xffffULL
#define VTD_FRCD_SID(val) ((val) & VTD_FRCD_SID_MASK)
+#define VTD_FRCD_PV(val) (((val) & 0xffffULL) << 40)
+#define VTD_FRCD_PP(val) (((val) & 0x1ULL) << 31)
/* For the low 64-bit of 128-bit */
#define VTD_FRCD_FI(val) ((val) & ~0xfffULL)
-#define VTD_FRCD_PV(val) (((val) & 0xffffULL) << 40)
-#define VTD_FRCD_PP(val) (((val) & 0x1) << 31)
#define VTD_FRCD_IR_IDX(val) (((val) & 0xffffULL) << 48)
/* DMA Remapping Fault Conditions */
@@ -356,7 +356,8 @@ union VTDInvDesc {
typedef union VTDInvDesc VTDInvDesc;
/* Masks for struct VTDInvDesc */
-#define VTD_INV_DESC_TYPE 0xf
+#define VTD_INV_DESC_TYPE(val) ((((val) >> 5) & 0x70ULL) | \
+ ((val) & 0xfULL))
#define VTD_INV_DESC_CC 0x1 /* Context-cache Invalidate Desc */
#define VTD_INV_DESC_IOTLB 0x2
#define VTD_INV_DESC_DEVICE 0x3
@@ -372,7 +373,7 @@ typedef union VTDInvDesc VTDInvDesc;
#define VTD_INV_DESC_WAIT_IF (1ULL << 4)
#define VTD_INV_DESC_WAIT_FN (1ULL << 6)
#define VTD_INV_DESC_WAIT_DATA_SHIFT 32
-#define VTD_INV_DESC_WAIT_RSVD_LO 0Xffffff80ULL
+#define VTD_INV_DESC_WAIT_RSVD_LO 0Xfffff180ULL
#define VTD_INV_DESC_WAIT_RSVD_HI 3ULL
/* Masks for Context-cache Invalidation Descriptor */
@@ -383,7 +384,7 @@ typedef union VTDInvDesc VTDInvDesc;
#define VTD_INV_DESC_CC_DID(val) (((val) >> 16) & VTD_DOMAIN_ID_MASK)
#define VTD_INV_DESC_CC_SID(val) (((val) >> 32) & 0xffffUL)
#define VTD_INV_DESC_CC_FM(val) (((val) >> 48) & 3UL)
-#define VTD_INV_DESC_CC_RSVD 0xfffc00000000ffc0ULL
+#define VTD_INV_DESC_CC_RSVD 0xfffc00000000f1c0ULL
/* Masks for IOTLB Invalidate Descriptor */
#define VTD_INV_DESC_IOTLB_G (3ULL << 4)
@@ -393,7 +394,7 @@ typedef union VTDInvDesc VTDInvDesc;
#define VTD_INV_DESC_IOTLB_DID(val) (((val) >> 16) & VTD_DOMAIN_ID_MASK)
#define VTD_INV_DESC_IOTLB_ADDR(val) ((val) & ~0xfffULL)
#define VTD_INV_DESC_IOTLB_AM(val) ((val) & 0x3fULL)
-#define VTD_INV_DESC_IOTLB_RSVD_LO 0xffffffff0000ff00ULL
+#define VTD_INV_DESC_IOTLB_RSVD_LO 0xffffffff0000f100ULL
#define VTD_INV_DESC_IOTLB_RSVD_HI 0xf80ULL
#define VTD_INV_DESC_IOTLB_PASID_PASID (2ULL << 4)
#define VTD_INV_DESC_IOTLB_PASID_PAGE (3ULL << 4)
@@ -406,7 +407,7 @@ typedef union VTDInvDesc VTDInvDesc;
#define VTD_INV_DESC_DEVICE_IOTLB_SIZE(val) ((val) & 0x1)
#define VTD_INV_DESC_DEVICE_IOTLB_SID(val) (((val) >> 32) & 0xFFFFULL)
#define VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI 0xffeULL
-#define VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO 0xffff0000ffe0fff8
+#define VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO 0xffff0000ffe0f1f0
/* Rsvd field masks for spte */
#define VTD_SPTE_SNP 0x800ULL
@@ -436,7 +437,7 @@ struct VTDIOTLBPageInvInfo {
uint16_t domain_id;
uint32_t pasid;
uint64_t addr;
- uint8_t mask;
+ uint64_t mask;
};
typedef struct VTDIOTLBPageInvInfo VTDIOTLBPageInvInfo;
diff --git a/hw/i386/kvm/i8254.c b/hw/i386/kvm/i8254.c
index e49b9c4..baa4b39 100644
--- a/hw/i386/kvm/i8254.c
+++ b/hw/i386/kvm/i8254.c
@@ -303,7 +303,7 @@ static void kvm_pit_class_init(ObjectClass *klass, void *data)
&kpc->parent_realize);
k->set_channel_gate = kvm_pit_set_gate;
k->get_channel_info = kvm_pit_get_channel_info;
- dc->reset = kvm_pit_reset;
+ device_class_set_legacy_reset(dc, kvm_pit_reset);
device_class_set_props(dc, kvm_pit_properties);
}
diff --git a/hw/i386/kvm/i8259.c b/hw/i386/kvm/i8259.c
index 3ca0e1f..9c2fb64 100644
--- a/hw/i386/kvm/i8259.c
+++ b/hw/i386/kvm/i8259.c
@@ -145,7 +145,7 @@ static void kvm_i8259_class_init(ObjectClass *klass, void *data)
PICCommonClass *k = PIC_COMMON_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = kvm_pic_reset;
+ device_class_set_legacy_reset(dc, kvm_pic_reset);
device_class_set_parent_realize(dc, kvm_pic_realize, &kpc->parent_realize);
k->pre_save = kvm_pic_get;
k->post_load = kvm_pic_put;
diff --git a/hw/i386/kvm/ioapic.c b/hw/i386/kvm/ioapic.c
index b96fe84..2907b08 100644
--- a/hw/i386/kvm/ioapic.c
+++ b/hw/i386/kvm/ioapic.c
@@ -146,7 +146,7 @@ static void kvm_ioapic_class_init(ObjectClass *klass, void *data)
k->realize = kvm_ioapic_realize;
k->pre_save = kvm_ioapic_get;
k->post_load = kvm_ioapic_put;
- dc->reset = kvm_ioapic_reset;
+ device_class_set_legacy_reset(dc, kvm_ioapic_reset);
device_class_set_props(dc, kvm_ioapic_properties);
}
diff --git a/hw/i386/kvm/xen_overlay.c b/hw/i386/kvm/xen_overlay.c
index c68e78a..3483a33 100644
--- a/hw/i386/kvm/xen_overlay.c
+++ b/hw/i386/kvm/xen_overlay.c
@@ -155,7 +155,7 @@ static void xen_overlay_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = xen_overlay_reset;
+ device_class_set_legacy_reset(dc, xen_overlay_reset);
dc->realize = xen_overlay_realize;
dc->vmsd = &xen_overlay_vmstate;
}
diff --git a/hw/i386/microvm-dt.c b/hw/i386/microvm-dt.c
index b3049e4..fc5db6e 100644
--- a/hw/i386/microvm-dt.c
+++ b/hw/i386/microvm-dt.c
@@ -34,7 +34,7 @@
#include "qemu/cutils.h"
#include "qapi/error.h"
#include "sysemu/device_tree.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-isa.h"
#include "hw/i386/fw_cfg.h"
#include "hw/rtc/mc146818rtc.h"
#include "hw/sysbus.h"
diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c
index 40edcee..693099f 100644
--- a/hw/i386/microvm.c
+++ b/hw/i386/microvm.c
@@ -39,7 +39,7 @@
#include "hw/intc/i8259.h"
#include "hw/timer/i8254.h"
#include "hw/rtc/mc146818rtc.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-isa.h"
#include "hw/display/ramfb.h"
#include "hw/i386/topology.h"
#include "hw/i386/e820_memory_layout.h"
@@ -462,7 +462,7 @@ static void microvm_machine_state_init(MachineState *machine)
microvm_devices_init(mms);
}
-static void microvm_machine_reset(MachineState *machine, ShutdownCause reason)
+static void microvm_machine_reset(MachineState *machine, ResetType type)
{
MicrovmMachineState *mms = MICROVM_MACHINE(machine);
CPUState *cs;
@@ -475,7 +475,7 @@ static void microvm_machine_reset(MachineState *machine, ShutdownCause reason)
mms->kernel_cmdline_fixed = true;
}
- qemu_devices_reset(reason);
+ qemu_devices_reset(type);
CPU_FOREACH(cs) {
cpu = X86_CPU(cs);
diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c
index 3332712..b2648bf 100644
--- a/hw/i386/multiboot.c
+++ b/hw/i386/multiboot.c
@@ -133,9 +133,9 @@ static void mb_add_mod(MultibootState *s,
p = (char *)s->mb_buf + s->offset_mbinfo + MB_MOD_SIZE * s->mb_mods_count;
- stl_p(p + MB_MOD_START, start);
- stl_p(p + MB_MOD_END, end);
- stl_p(p + MB_MOD_CMDLINE, cmdline_phys);
+ stl_le_p(p + MB_MOD_START, start);
+ stl_le_p(p + MB_MOD_END, end);
+ stl_le_p(p + MB_MOD_CMDLINE, cmdline_phys);
mb_debug("mod%02d: "HWADDR_FMT_plx" - "HWADDR_FMT_plx,
s->mb_mods_count, start, end);
@@ -168,9 +168,9 @@ int load_multiboot(X86MachineState *x86ms,
/* Ok, let's see if it is a multiboot image.
The header is 12x32bit long, so the latest entry may be 8192 - 48. */
for (i = 0; i < (8192 - 48); i += 4) {
- if (ldl_p(header+i) == 0x1BADB002) {
- uint32_t checksum = ldl_p(header+i+8);
- flags = ldl_p(header+i+4);
+ if (ldl_le_p(header + i) == 0x1BADB002) {
+ uint32_t checksum = ldl_le_p(header + i + 8);
+ flags = ldl_le_p(header + i + 4);
checksum += flags;
checksum += (uint32_t)0x1BADB002;
if (!checksum) {
@@ -223,11 +223,11 @@ int load_multiboot(X86MachineState *x86ms,
mb_kernel_size, (size_t)mh_entry_addr);
} else {
/* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
- uint32_t mh_header_addr = ldl_p(header+i+12);
- uint32_t mh_load_end_addr = ldl_p(header+i+20);
- uint32_t mh_bss_end_addr = ldl_p(header+i+24);
+ uint32_t mh_header_addr = ldl_le_p(header + i + 12);
+ uint32_t mh_load_end_addr = ldl_le_p(header + i + 20);
+ uint32_t mh_bss_end_addr = ldl_le_p(header + i + 24);
- mh_load_addr = ldl_p(header+i+16);
+ mh_load_addr = ldl_le_p(header + i + 16);
if (mh_header_addr < mh_load_addr) {
error_report("invalid load_addr address");
exit(1);
@@ -239,7 +239,7 @@ int load_multiboot(X86MachineState *x86ms,
uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
uint32_t mb_load_size = 0;
- mh_entry_addr = ldl_p(header+i+28);
+ mh_entry_addr = ldl_le_p(header + i + 28);
if (mh_load_end_addr) {
if (mh_load_end_addr < mh_load_addr) {
@@ -364,22 +364,21 @@ int load_multiboot(X86MachineState *x86ms,
/* Commandline support */
kcmdline = g_strdup_printf("%s %s", kernel_filename, kernel_cmdline);
- stl_p(bootinfo + MBI_CMDLINE, mb_add_cmdline(&mbs, kcmdline));
-
- stl_p(bootinfo + MBI_BOOTLOADER, mb_add_bootloader(&mbs, bootloader_name));
-
- stl_p(bootinfo + MBI_MODS_ADDR, mbs.mb_buf_phys + mbs.offset_mbinfo);
- stl_p(bootinfo + MBI_MODS_COUNT, mbs.mb_mods_count); /* mods_count */
+ stl_le_p(bootinfo + MBI_CMDLINE, mb_add_cmdline(&mbs, kcmdline));
+ stl_le_p(bootinfo + MBI_BOOTLOADER, mb_add_bootloader(&mbs,
+ bootloader_name));
+ stl_le_p(bootinfo + MBI_MODS_ADDR, mbs.mb_buf_phys + mbs.offset_mbinfo);
+ stl_le_p(bootinfo + MBI_MODS_COUNT, mbs.mb_mods_count); /* mods_count */
/* the kernel is where we want it to be now */
- stl_p(bootinfo + MBI_FLAGS, MULTIBOOT_FLAGS_MEMORY
+ stl_le_p(bootinfo + MBI_FLAGS, MULTIBOOT_FLAGS_MEMORY
| MULTIBOOT_FLAGS_BOOT_DEVICE
| MULTIBOOT_FLAGS_CMDLINE
| MULTIBOOT_FLAGS_MODULES
| MULTIBOOT_FLAGS_MMAP
| MULTIBOOT_FLAGS_BOOTLOADER);
- stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8000ffff); /* XXX: use the -boot switch? */
- stl_p(bootinfo + MBI_MMAP_ADDR, ADDR_E820_MAP);
+ stl_le_p(bootinfo + MBI_BOOT_DEVICE, 0x8000ffff); /* XXX: use the -boot switch? */
+ stl_le_p(bootinfo + MBI_MMAP_ADDR, ADDR_E820_MAP);
mb_debug("multiboot: entry_addr = %#x", mh_entry_addr);
mb_debug(" mb_buf_phys = "HWADDR_FMT_plx, mbs.mb_buf_phys);
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index c74931d..2047633 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -25,7 +25,7 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "hw/i386/pc.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-isa.h"
#include "hw/char/parallel.h"
#include "hw/hyperv/hv-balloon.h"
#include "hw/i386/fw_cfg.h"
@@ -79,6 +79,12 @@
{ "qemu64-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },\
{ "athlon-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },
+GlobalProperty pc_compat_9_1[] = {
+ { "ICH9-LPC", "x-smi-swsmi-timer", "off" },
+ { "ICH9-LPC", "x-smi-periodic-timer", "off" },
+};
+const size_t pc_compat_9_1_len = G_N_ELEMENTS(pc_compat_9_1);
+
GlobalProperty pc_compat_9_0[] = {
{ TYPE_X86_CPU, "x-amd-topoext-features-only", "false" },
{ TYPE_X86_CPU, "x-l1-cache-per-thread", "false" },
@@ -1075,7 +1081,7 @@ static const MemoryRegionOps ioportF0_io_ops = {
};
static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl,
- bool create_i8042, bool no_vmport)
+ bool create_i8042, bool no_vmport, Error **errp)
{
int i;
DriveInfo *fd[MAX_FD];
@@ -1100,6 +1106,10 @@ static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl,
}
if (!create_i8042) {
+ if (!no_vmport) {
+ error_setg(errp,
+ "vmport requires the i8042 controller to be enabled");
+ }
return;
}
@@ -1217,9 +1227,15 @@ void pc_basic_device_init(struct PCMachineState *pcms,
isa_realize_and_unref(pcms->pcspk, isa_bus, &error_fatal);
}
+ assert(pcms->vmport >= 0 && pcms->vmport < ON_OFF_AUTO__MAX);
+ if (pcms->vmport == ON_OFF_AUTO_AUTO) {
+ pcms->vmport = (xen_enabled() || !pcms->i8042_enabled)
+ ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON;
+ }
+
/* Super I/O */
pc_superio_init(isa_bus, create_fdctrl, pcms->i8042_enabled,
- pcms->vmport != ON_OFF_AUTO_ON);
+ pcms->vmport != ON_OFF_AUTO_ON, &error_fatal);
}
void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus)
@@ -1696,12 +1712,12 @@ static void pc_machine_initfn(Object *obj)
qemu_add_machine_init_done_notifier(&pcms->machine_done);
}
-static void pc_machine_reset(MachineState *machine, ShutdownCause reason)
+static void pc_machine_reset(MachineState *machine, ResetType type)
{
CPUState *cs;
X86CPU *cpu;
- qemu_devices_reset(reason);
+ qemu_devices_reset(type);
/* Reset APIC after devices have been reset to cancel
* any changes that qemu_devices_reset() might have done.
@@ -1716,7 +1732,7 @@ static void pc_machine_reset(MachineState *machine, ShutdownCause reason)
static void pc_machine_wakeup(MachineState *machine)
{
cpu_synchronize_all_states();
- pc_machine_reset(machine, SHUTDOWN_CAUSE_NONE);
+ pc_machine_reset(machine, RESET_TYPE_WAKEUP);
cpu_synchronize_all_post_reset();
}
@@ -1807,6 +1823,8 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
object_class_property_add_bool(oc, PC_MACHINE_I8042,
pc_machine_get_i8042, pc_machine_set_i8042);
+ object_class_property_set_description(oc, PC_MACHINE_I8042,
+ "Enable/disable Intel 8042 PS/2 controller emulation");
object_class_property_add_bool(oc, "default-bus-bypass-iommu",
pc_machine_get_default_bus_bypass_iommu,
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 9445b07..2bf6865 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -310,11 +310,6 @@ static void pc_init1(MachineState *machine, const char *pci_type)
pc_vga_init(isa_bus, pcmc->pci_enabled ? pcms->pcibus : NULL);
- assert(pcms->vmport != ON_OFF_AUTO__MAX);
- if (pcms->vmport == ON_OFF_AUTO_AUTO) {
- pcms->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON;
- }
-
/* init basic PC hardware */
pc_basic_device_init(pcms, isa_bus, x86ms->gsi, x86ms->rtc,
!MACHINE_CLASS(pcmc)->no_floppy, 0x4);
@@ -479,13 +474,24 @@ static void pc_i440fx_machine_options(MachineClass *m)
"Use a different south bridge than PIIX3");
}
-static void pc_i440fx_machine_9_1_options(MachineClass *m)
+static void pc_i440fx_machine_9_2_options(MachineClass *m)
{
pc_i440fx_machine_options(m);
m->alias = "pc";
m->is_default = true;
}
+DEFINE_I440FX_MACHINE(9, 2);
+
+static void pc_i440fx_machine_9_1_options(MachineClass *m)
+{
+ pc_i440fx_machine_9_2_options(m);
+ m->alias = NULL;
+ m->is_default = false;
+ compat_props_add(m->compat_props, hw_compat_9_1, hw_compat_9_1_len);
+ compat_props_add(m->compat_props, pc_compat_9_1, pc_compat_9_1_len);
+}
+
DEFINE_I440FX_MACHINE(9, 1);
static void pc_i440fx_machine_9_0_options(MachineClass *m)
@@ -493,8 +499,7 @@ static void pc_i440fx_machine_9_0_options(MachineClass *m)
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_i440fx_machine_9_1_options(m);
- m->alias = NULL;
- m->is_default = false;
+ m->smbios_memory_device_size = 16 * GiB;
compat_props_add(m->compat_props, hw_compat_9_0, hw_compat_9_0_len);
compat_props_add(m->compat_props, pc_compat_9_0, pc_compat_9_0_len);
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 71d3c6d..8319b6d 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -276,11 +276,6 @@ static void pc_q35_init(MachineState *machine)
x86_register_ferr_irq(x86ms->gsi[13]);
}
- assert(pcms->vmport != ON_OFF_AUTO__MAX);
- if (pcms->vmport == ON_OFF_AUTO_AUTO) {
- pcms->vmport = ON_OFF_AUTO_ON;
- }
-
/* init basic PC hardware */
pc_basic_device_init(pcms, isa_bus, x86ms->gsi, x86ms->rtc, !mc->no_floppy,
0xff0104);
@@ -361,19 +356,29 @@ static void pc_q35_machine_options(MachineClass *m)
pc_q35_compat_defaults, pc_q35_compat_defaults_len);
}
-static void pc_q35_machine_9_1_options(MachineClass *m)
+static void pc_q35_machine_9_2_options(MachineClass *m)
{
pc_q35_machine_options(m);
m->alias = "q35";
}
+DEFINE_Q35_MACHINE(9, 2);
+
+static void pc_q35_machine_9_1_options(MachineClass *m)
+{
+ pc_q35_machine_9_2_options(m);
+ m->alias = NULL;
+ compat_props_add(m->compat_props, hw_compat_9_1, hw_compat_9_1_len);
+ compat_props_add(m->compat_props, pc_compat_9_1, pc_compat_9_1_len);
+}
+
DEFINE_Q35_MACHINE(9, 1);
static void pc_q35_machine_9_0_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_q35_machine_9_1_options(m);
- m->alias = NULL;
+ m->smbios_memory_device_size = 16 * GiB;
compat_props_add(m->compat_props, hw_compat_9_0, hw_compat_9_0_len);
compat_props_add(m->compat_props, pc_compat_9_0, pc_compat_9_0_len);
pcmc->isa_bios_alias = false;
diff --git a/hw/i386/port92.c b/hw/i386/port92.c
index b25157f..1b03b34 100644
--- a/hw/i386/port92.c
+++ b/hw/i386/port92.c
@@ -102,7 +102,7 @@ static void port92_class_initfn(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = port92_realizefn;
- dc->reset = port92_reset;
+ device_class_set_legacy_reset(dc, port92_reset);
dc->vmsd = &vmstate_port92_isa;
/*
* Reason: unlike ordinary ISA devices, this one needs additional
diff --git a/hw/i386/sgx-stub.c b/hw/i386/sgx-stub.c
index 16b1dfd..38ff75e 100644
--- a/hw/i386/sgx-stub.c
+++ b/hw/i386/sgx-stub.c
@@ -32,6 +32,11 @@ void pc_machine_init_sgx_epc(PCMachineState *pcms)
memset(&pcms->sgx_epc, 0, sizeof(SGXEPCState));
}
+bool check_sgx_support(void)
+{
+ return false;
+}
+
bool sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size)
{
return true;
diff --git a/hw/i386/sgx.c b/hw/i386/sgx.c
index a14a84b..4900dd4 100644
--- a/hw/i386/sgx.c
+++ b/hw/i386/sgx.c
@@ -266,12 +266,22 @@ void hmp_info_sgx(Monitor *mon, const QDict *qdict)
size);
}
+bool check_sgx_support(void)
+{
+ if (!object_dynamic_cast(qdev_get_machine(), TYPE_PC_MACHINE)) {
+ return false;
+ }
+ return true;
+}
+
bool sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size)
{
- PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
+ PCMachineState *pcms =
+ (PCMachineState *)object_dynamic_cast(qdev_get_machine(),
+ TYPE_PC_MACHINE);
SGXEPCDevice *epc;
- if (pcms->sgx_epc.size == 0 || pcms->sgx_epc.nr_sections <= section_nr) {
+ if (!pcms || pcms->sgx_epc.size == 0 || pcms->sgx_epc.nr_sections <= section_nr) {
return true;
}
diff --git a/hw/i386/vapic.c b/hw/i386/vapic.c
index f5b1db7..ef7f8b9 100644
--- a/hw/i386/vapic.c
+++ b/hw/i386/vapic.c
@@ -850,7 +850,7 @@ static void vapic_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = vapic_reset;
+ device_class_set_legacy_reset(dc, vapic_reset);
dc->vmsd = &vmstate_vapic;
dc->realize = vapic_realize;
}
diff --git a/hw/i386/vmmouse.c b/hw/i386/vmmouse.c
index a8d014d..76130cd 100644
--- a/hw/i386/vmmouse.c
+++ b/hw/i386/vmmouse.c
@@ -327,7 +327,7 @@ static void vmmouse_class_initfn(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = vmmouse_realizefn;
- dc->reset = vmmouse_reset;
+ device_class_set_legacy_reset(dc, vmmouse_reset);
dc->vmsd = &vmstate_vmmouse;
device_class_set_props(dc, vmmouse_properties);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c
index c0c66a0..b86c382 100644
--- a/hw/i386/x86-common.c
+++ b/hw/i386/x86-common.c
@@ -586,7 +586,7 @@ static bool load_elfboot(const char *kernel_filename,
uint64_t elf_low, elf_high;
int kernel_size;
- if (ldl_p(header) != 0x464c457f) {
+ if (ldl_le_p(header) != 0x464c457f) {
return false; /* no elfboot */
}
@@ -665,9 +665,12 @@ void x86_load_linux(X86MachineState *x86ms,
exit(1);
}
- /* kernel protocol version */
- if (ldl_p(header + 0x202) == 0x53726448) {
- protocol = lduw_p(header + 0x206);
+ /*
+ * kernel protocol version.
+ * Please see https://www.kernel.org/doc/Documentation/x86/boot.txt
+ */
+ if (ldl_le_p(header + 0x202) == 0x53726448) /* Magic signature "HdrS" */ {
+ protocol = lduw_le_p(header + 0x206);
} else {
/*
* This could be a multiboot kernel. If it is, let's stop treating it
@@ -759,7 +762,7 @@ void x86_load_linux(X86MachineState *x86ms,
/* highest address for loading the initrd */
if (protocol >= 0x20c &&
- lduw_p(header + 0x236) & XLF_CAN_BE_LOADED_ABOVE_4G) {
+ lduw_le_p(header + 0x236) & XLF_CAN_BE_LOADED_ABOVE_4G) {
/*
* Linux has supported initrd up to 4 GB for a very long time (2007,
* long before XLF_CAN_BE_LOADED_ABOVE_4G which was added in 2013),
@@ -778,7 +781,7 @@ void x86_load_linux(X86MachineState *x86ms,
*/
initrd_max = UINT32_MAX;
} else if (protocol >= 0x203) {
- initrd_max = ldl_p(header + 0x22c);
+ initrd_max = ldl_le_p(header + 0x22c);
} else {
initrd_max = 0x37ffffff;
}
@@ -794,10 +797,10 @@ void x86_load_linux(X86MachineState *x86ms,
sev_load_ctx.cmdline_size = strlen(kernel_cmdline) + 1;
if (protocol >= 0x202) {
- stl_p(header + 0x228, cmdline_addr);
+ stl_le_p(header + 0x228, cmdline_addr);
} else {
- stw_p(header + 0x20, 0xA33F);
- stw_p(header + 0x22, cmdline_addr - real_addr);
+ stw_le_p(header + 0x20, 0xA33F);
+ stw_le_p(header + 0x22, cmdline_addr - real_addr);
}
/* handle vga= parameter */
@@ -821,7 +824,7 @@ void x86_load_linux(X86MachineState *x86ms,
exit(1);
}
}
- stw_p(header + 0x1fa, video_mode);
+ stw_le_p(header + 0x1fa, video_mode);
}
/* loader type */
@@ -836,7 +839,7 @@ void x86_load_linux(X86MachineState *x86ms,
/* heap */
if (protocol >= 0x201) {
header[0x211] |= 0x80; /* CAN_USE_HEAP */
- stw_p(header + 0x224, cmdline_addr - real_addr - 0x200);
+ stw_le_p(header + 0x224, cmdline_addr - real_addr - 0x200);
}
/* load initrd */
@@ -876,8 +879,8 @@ void x86_load_linux(X86MachineState *x86ms,
sev_load_ctx.initrd_data = initrd_data;
sev_load_ctx.initrd_size = initrd_size;
- stl_p(header + 0x218, initrd_addr);
- stl_p(header + 0x21c, initrd_size);
+ stl_le_p(header + 0x218, initrd_addr);
+ stl_le_p(header + 0x21c, initrd_size);
}
/* load kernel and setup */
@@ -923,7 +926,7 @@ void x86_load_linux(X86MachineState *x86ms,
kernel_size = setup_data_offset + sizeof(struct setup_data) + dtb_size;
kernel = g_realloc(kernel, kernel_size);
- stq_p(header + 0x250, prot_addr + setup_data_offset);
+ stq_le_p(header + 0x250, prot_addr + setup_data_offset);
setup_data = (struct setup_data *)(kernel + setup_data_offset);
setup_data->next = 0;
diff --git a/hw/i386/xen/meson.build b/hw/i386/xen/meson.build
index 3f0df8b..c73c62b 100644
--- a/hw/i386/xen/meson.build
+++ b/hw/i386/xen/meson.build
@@ -4,6 +4,7 @@ i386_ss.add(when: 'CONFIG_XEN', if_true: files(
))
i386_ss.add(when: ['CONFIG_XEN', xen], if_true: files(
'xen-hvm.c',
+ 'xen-pvh.c',
))
i386_ss.add(when: 'CONFIG_XEN_BUS', if_true: files(
diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c
index 4f64466..d3df488 100644
--- a/hw/i386/xen/xen-hvm.c
+++ b/hw/i386/xen/xen-hvm.c
@@ -614,7 +614,9 @@ void xen_hvm_init_pc(PCMachineState *pcms, MemoryRegion **ram_memory)
state = g_new0(XenIOState, 1);
- xen_register_ioreq(state, max_cpus, &xen_memory_listener);
+ xen_register_ioreq(state, max_cpus,
+ HVM_IOREQSRV_BUFIOREQ_ATOMIC,
+ &xen_memory_listener);
xen_is_stubdomain = xen_check_stubdomain(state->xenstore);
diff --git a/hw/i386/xen/xen-pvh.c b/hw/i386/xen/xen-pvh.c
new file mode 100644
index 0000000..f1f02d3
--- /dev/null
+++ b/hw/i386/xen/xen-pvh.c
@@ -0,0 +1,124 @@
+/*
+ * QEMU Xen PVH x86 Machine
+ *
+ * Copyright (c) 2024 Advanced Micro Devices, Inc.
+ * Written by Edgar E. Iglesias <edgar.iglesias@amd.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "hw/boards.h"
+#include "sysemu/sysemu.h"
+#include "hw/xen/arch_hvm.h"
+#include <xen/hvm/hvm_info_table.h>
+#include "hw/xen/xen-pvh-common.h"
+
+#define TYPE_XEN_PVH_X86 MACHINE_TYPE_NAME("xenpvh")
+OBJECT_DECLARE_SIMPLE_TYPE(XenPVHx86State, XEN_PVH_X86)
+
+struct XenPVHx86State {
+ /*< private >*/
+ XenPVHMachineState parent;
+
+ DeviceState **cpu;
+};
+
+static DeviceState *xen_pvh_cpu_new(MachineState *ms,
+ int64_t apic_id)
+{
+ Object *cpu = object_new(ms->cpu_type);
+
+ object_property_add_child(OBJECT(ms), "cpu[*]", cpu);
+ object_property_set_uint(cpu, "apic-id", apic_id, &error_fatal);
+ qdev_realize(DEVICE(cpu), NULL, &error_fatal);
+ object_unref(cpu);
+
+ return DEVICE(cpu);
+}
+
+static void xen_pvh_init(MachineState *ms)
+{
+ XenPVHx86State *xp = XEN_PVH_X86(ms);
+ int i;
+
+ /* Create dummy cores. This will indirectly create the APIC MSI window. */
+ xp->cpu = g_malloc(sizeof xp->cpu[0] * ms->smp.max_cpus);
+ for (i = 0; i < ms->smp.max_cpus; i++) {
+ xp->cpu[i] = xen_pvh_cpu_new(ms, i);
+ }
+}
+
+static void xen_pvh_instance_init(Object *obj)
+{
+ XenPVHMachineState *s = XEN_PVH_MACHINE(obj);
+
+ /* Default values. */
+ s->cfg.ram_low = (MemMapEntry) { 0x0, 0x80000000U };
+ s->cfg.ram_high = (MemMapEntry) { 0xC000000000ULL, 0x4000000000ULL };
+ s->cfg.pci_intx_irq_base = 16;
+}
+
+/*
+ * Deliver INTX interrupts to Xen guest.
+ */
+static void xen_pvh_set_pci_intx_irq(void *opaque, int irq, int level)
+{
+ /*
+ * Since QEMU emulates all of the swizziling
+ * We don't want Xen to do any additional swizzling in
+ * xen_set_pci_intx_level() so we always set device to 0.
+ */
+ if (xen_set_pci_intx_level(xen_domid, 0, 0, 0, irq, level)) {
+ error_report("xendevicemodel_set_pci_intx_level failed");
+ }
+}
+
+static void xen_pvh_machine_class_init(ObjectClass *oc, void *data)
+{
+ XenPVHMachineClass *xpc = XEN_PVH_MACHINE_CLASS(oc);
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->desc = "Xen PVH x86 machine";
+ mc->default_cpu_type = TARGET_DEFAULT_CPU_TYPE;
+
+ /* mc->max_cpus holds the MAX value allowed in the -smp cmd-line opts. */
+ mc->max_cpus = HVM_MAX_VCPUS;
+
+ /* We have an implementation specific init to create CPU objects. */
+ xpc->init = xen_pvh_init;
+
+ /* Enable buffered IOREQs. */
+ xpc->handle_bufioreq = HVM_IOREQSRV_BUFIOREQ_ATOMIC;
+
+ /*
+ * PCI INTX routing.
+ *
+ * We describe the mapping between the 4 INTX interrupt and GSIs
+ * using xen_set_pci_link_route(). xen_pvh_set_pci_intx_irq is
+ * used to deliver the interrupt.
+ */
+ xpc->set_pci_intx_irq = xen_pvh_set_pci_intx_irq;
+ xpc->set_pci_link_route = xen_set_pci_link_route;
+
+ /* List of supported features known to work on PVH x86. */
+ xpc->has_pci = true;
+
+ xen_pvh_class_setup_common_props(xpc);
+}
+
+static const TypeInfo xen_pvh_x86_machine_type = {
+ .name = TYPE_XEN_PVH_X86,
+ .parent = TYPE_XEN_PVH_MACHINE,
+ .class_init = xen_pvh_machine_class_init,
+ .instance_init = xen_pvh_instance_init,
+ .instance_size = sizeof(XenPVHx86State),
+};
+
+static void xen_pvh_machine_register_types(void)
+{
+ type_register_static(&xen_pvh_x86_machine_type);
+}
+
+type_init(xen_pvh_machine_register_types)
diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c
index 708488a..ec0e536 100644
--- a/hw/i386/xen/xen_platform.c
+++ b/hw/i386/xen/xen_platform.c
@@ -595,7 +595,7 @@ static void xen_platform_class_init(ObjectClass *klass, void *data)
k->revision = 1;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->desc = "XEN platform pci device";
- dc->reset = platform_reset;
+ device_class_set_legacy_reset(dc, platform_reset);
dc->vmsd = &vmstate_xen_platform;
}
diff --git a/hw/ide/Kconfig b/hw/ide/Kconfig
index 6dfc5a2..2e22b67 100644
--- a/hw/ide/Kconfig
+++ b/hw/ide/Kconfig
@@ -43,12 +43,6 @@ config IDE_VIA
bool
select IDE_PCI
-config MICRODRIVE
- bool
- select IDE_BUS
- select IDE_DEV
- depends on PCMCIA
-
config AHCI
bool
select IDE_BUS
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index bfefad2..0eb2430 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -948,7 +948,6 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist,
uint64_t sum = 0;
int off_idx = -1;
int64_t off_pos = -1;
- int tbl_entry_size;
IDEBus *bus = &ad->port;
BusState *qbus = BUS(bus);
@@ -976,6 +975,8 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist,
/* Get entries in the PRDT, init a qemu sglist accordingly */
if (prdtl > 0) {
AHCI_SG *tbl = (AHCI_SG *)prdt;
+ int tbl_entry_size = 0;
+
sum = 0;
for (i = 0; i < prdtl; i++) {
tbl_entry_size = prdt_tbl_entry_size(&tbl[i]);
@@ -1878,7 +1879,7 @@ static void sysbus_ahci_class_init(ObjectClass *klass, void *data)
dc->realize = sysbus_ahci_realize;
dc->vmsd = &vmstate_sysbus_ahci;
device_class_set_props(dc, sysbus_ahci_properties);
- dc->reset = sysbus_ahci_reset;
+ device_class_set_legacy_reset(dc, sysbus_ahci_reset);
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
}
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index fcb6cca..e82959d 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -265,7 +265,7 @@ void ide_atapi_cmd_reply_end(IDEState *s)
byte_count_limit--;
size = byte_count_limit;
}
- s->lcyl = size;
+ s->lcyl = size & 0xff;
s->hcyl = size >> 8;
s->elementary_transfer_size = size;
/* we cannot transmit more than one sector at a time */
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index 8cebd1b..6b02fc8 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -323,7 +323,7 @@ static void cmd646_ide_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- dc->reset = cmd646_reset;
+ device_class_set_legacy_reset(dc, cmd646_reset);
dc->vmsd = &vmstate_ide_pci;
k->realize = pci_cmd646_ide_realize;
k->exit = pci_cmd646_ide_exitfn;
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 9b909c8..b311450 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -176,7 +176,7 @@ static void ich_ahci_class_init(ObjectClass *klass, void *data)
k->revision = 0x02;
k->class_id = PCI_CLASS_STORAGE_SATA;
dc->vmsd = &vmstate_ich9_ahci;
- dc->reset = pci_ich9_reset;
+ device_class_set_legacy_reset(dc, pci_ich9_reset);
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
}
diff --git a/hw/ide/isa.c b/hw/ide/isa.c
index 934c458..211ebc9 100644
--- a/hw/ide/isa.c
+++ b/hw/ide/isa.c
@@ -114,7 +114,7 @@ static void isa_ide_class_initfn(ObjectClass *klass, void *data)
dc->realize = isa_ide_realizefn;
dc->fw_name = "ide";
- dc->reset = isa_ide_reset;
+ device_class_set_legacy_reset(dc, isa_ide_reset);
device_class_set_props(dc, isa_ide_properties);
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
}
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index e84bf2c..99477a3 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -119,9 +119,6 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
return;
done:
- dma_memory_unmap(&address_space_memory, io->dma_mem, io->dma_len,
- io->dir, io->dma_len);
-
if (ret < 0) {
block_acct_failed(blk_get_stats(s->blk), &s->acct);
} else {
@@ -202,9 +199,6 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
return;
done:
- dma_memory_unmap(&address_space_memory, io->dma_mem, io->dma_len,
- io->dir, io->dma_len);
-
if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) {
if (ret < 0) {
block_acct_failed(blk_get_stats(s->blk), &s->acct);
@@ -476,7 +470,7 @@ static void macio_ide_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = macio_ide_realizefn;
- dc->reset = macio_ide_reset;
+ device_class_set_legacy_reset(dc, macio_ide_reset);
device_class_set_props(dc, macio_ide_properties);
dc->vmsd = &vmstate_pmac;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
diff --git a/hw/ide/meson.build b/hw/ide/meson.build
index d09705c..90ea861 100644
--- a/hw/ide/meson.build
+++ b/hw/ide/meson.build
@@ -13,4 +13,3 @@ system_ss.add(when: 'CONFIG_IDE_PCI', if_true: files('pci.c'))
system_ss.add(when: 'CONFIG_IDE_PIIX', if_true: files('piix.c', 'ioport.c'))
system_ss.add(when: 'CONFIG_IDE_SII3112', if_true: files('sii3112.c'))
system_ss.add(when: 'CONFIG_IDE_VIA', if_true: files('via.c'))
-system_ss.add(when: 'CONFIG_MICRODRIVE', if_true: files('microdrive.c'))
diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c
deleted file mode 100644
index 3bb152b..0000000
--- a/hw/ide/microdrive.c
+++ /dev/null
@@ -1,644 +0,0 @@
-/*
- * QEMU IDE Emulation: microdrive (CF / PCMCIA)
- *
- * Copyright (c) 2003 Fabrice Bellard
- * Copyright (c) 2006 Openedhand Ltd.
- *
- * 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/pcmcia.h"
-#include "migration/vmstate.h"
-#include "qapi/error.h"
-#include "qemu/module.h"
-#include "sysemu/dma.h"
-#include "hw/irq.h"
-
-#include "qom/object.h"
-#include "ide-internal.h"
-
-#define TYPE_MICRODRIVE "microdrive"
-OBJECT_DECLARE_SIMPLE_TYPE(MicroDriveState, MICRODRIVE)
-
-/***********************************************************/
-/* CF-ATA Microdrive */
-
-#define METADATA_SIZE 0x20
-
-/* DSCM-1XXXX Microdrive hard disk with CF+ II / PCMCIA interface. */
-
-struct MicroDriveState {
- /*< private >*/
- PCMCIACardState parent_obj;
- /*< public >*/
-
- IDEBus bus;
- uint32_t attr_base;
- uint32_t io_base;
-
- /* Card state */
- uint8_t opt;
- uint8_t stat;
- uint8_t pins;
-
- uint8_t ctrl;
- uint16_t io;
- uint8_t cycle;
-};
-
-/* Register bitfields */
-enum md_opt {
- OPT_MODE_MMAP = 0,
- OPT_MODE_IOMAP16 = 1,
- OPT_MODE_IOMAP1 = 2,
- OPT_MODE_IOMAP2 = 3,
- OPT_MODE = 0x3f,
- OPT_LEVIREQ = 0x40,
- OPT_SRESET = 0x80,
-};
-enum md_cstat {
- STAT_INT = 0x02,
- STAT_PWRDWN = 0x04,
- STAT_XE = 0x10,
- STAT_IOIS8 = 0x20,
- STAT_SIGCHG = 0x40,
- STAT_CHANGED = 0x80,
-};
-enum md_pins {
- PINS_MRDY = 0x02,
- PINS_CRDY = 0x20,
-};
-enum md_ctrl {
- CTRL_IEN = 0x02,
- CTRL_SRST = 0x04,
-};
-
-static inline void md_interrupt_update(MicroDriveState *s)
-{
- PCMCIACardState *card = PCMCIA_CARD(s);
-
- if (card->slot == NULL) {
- return;
- }
-
- qemu_set_irq(card->slot->irq,
- !(s->stat & STAT_INT) && /* Inverted */
- !(s->ctrl & (CTRL_IEN | CTRL_SRST)) &&
- !(s->opt & OPT_SRESET));
-}
-
-static void md_set_irq(void *opaque, int irq, int level)
-{
- MicroDriveState *s = opaque;
-
- if (level) {
- s->stat |= STAT_INT;
- } else {
- s->stat &= ~STAT_INT;
- }
-
- md_interrupt_update(s);
-}
-
-static void md_reset(DeviceState *dev)
-{
- MicroDriveState *s = MICRODRIVE(dev);
-
- s->opt = OPT_MODE_MMAP;
- s->stat = 0;
- s->pins = 0;
- s->cycle = 0;
- s->ctrl = 0;
- ide_bus_reset(&s->bus);
-}
-
-static uint8_t md_attr_read(PCMCIACardState *card, uint32_t at)
-{
- MicroDriveState *s = MICRODRIVE(card);
- PCMCIACardClass *pcc = PCMCIA_CARD_GET_CLASS(card);
-
- if (at < s->attr_base) {
- if (at < pcc->cis_len) {
- return pcc->cis[at];
- } else {
- return 0x00;
- }
- }
-
- at -= s->attr_base;
-
- switch (at) {
- case 0x00: /* Configuration Option Register */
- return s->opt;
- case 0x02: /* Card Configuration Status Register */
- if (s->ctrl & CTRL_IEN) {
- return s->stat & ~STAT_INT;
- } else {
- return s->stat;
- }
- case 0x04: /* Pin Replacement Register */
- return (s->pins & PINS_CRDY) | 0x0c;
- case 0x06: /* Socket and Copy Register */
- return 0x00;
-#ifdef VERBOSE
- default:
- printf("%s: Bad attribute space register %02x\n", __func__, at);
-#endif
- }
-
- return 0;
-}
-
-static void md_attr_write(PCMCIACardState *card, uint32_t at, uint8_t value)
-{
- MicroDriveState *s = MICRODRIVE(card);
-
- at -= s->attr_base;
-
- switch (at) {
- case 0x00: /* Configuration Option Register */
- s->opt = value & 0xcf;
- if (value & OPT_SRESET) {
- device_cold_reset(DEVICE(s));
- }
- md_interrupt_update(s);
- break;
- case 0x02: /* Card Configuration Status Register */
- if ((s->stat ^ value) & STAT_PWRDWN) {
- s->pins |= PINS_CRDY;
- }
- s->stat &= 0x82;
- s->stat |= value & 0x74;
- md_interrupt_update(s);
- /* Word 170 in Identify Device must be equal to STAT_XE */
- break;
- case 0x04: /* Pin Replacement Register */
- s->pins &= PINS_CRDY;
- s->pins |= value & PINS_MRDY;
- break;
- case 0x06: /* Socket and Copy Register */
- break;
- default:
- printf("%s: Bad attribute space register %02x\n", __func__, at);
- }
-}
-
-static uint16_t md_common_read(PCMCIACardState *card, uint32_t at)
-{
- MicroDriveState *s = MICRODRIVE(card);
- IDEState *ifs;
- uint16_t ret;
- at -= s->io_base;
-
- switch (s->opt & OPT_MODE) {
- case OPT_MODE_MMAP:
- if ((at & ~0x3ff) == 0x400) {
- at = 0;
- }
- break;
- case OPT_MODE_IOMAP16:
- at &= 0xf;
- break;
- case OPT_MODE_IOMAP1:
- if ((at & ~0xf) == 0x3f0) {
- at -= 0x3e8;
- } else if ((at & ~0xf) == 0x1f0) {
- at -= 0x1f0;
- }
- break;
- case OPT_MODE_IOMAP2:
- if ((at & ~0xf) == 0x370) {
- at -= 0x368;
- } else if ((at & ~0xf) == 0x170) {
- at -= 0x170;
- }
- }
-
- switch (at) {
- case 0x0: /* Even RD Data */
- case 0x8:
- return ide_data_readw(&s->bus, 0);
-
- /* TODO: 8-bit accesses */
- if (s->cycle) {
- ret = s->io >> 8;
- } else {
- s->io = ide_data_readw(&s->bus, 0);
- ret = s->io & 0xff;
- }
- s->cycle = !s->cycle;
- return ret;
- case 0x9: /* Odd RD Data */
- return s->io >> 8;
- case 0xd: /* Error */
- return ide_ioport_read(&s->bus, 0x1);
- case 0xe: /* Alternate Status */
- ifs = ide_bus_active_if(&s->bus);
- if (ifs->blk) {
- return ifs->status;
- } else {
- return 0;
- }
- case 0xf: /* Device Address */
- ifs = ide_bus_active_if(&s->bus);
- return 0xc2 | ((~ifs->select << 2) & 0x3c);
- default:
- return ide_ioport_read(&s->bus, at);
- }
-
- return 0;
-}
-
-static void md_common_write(PCMCIACardState *card, uint32_t at, uint16_t value)
-{
- MicroDriveState *s = MICRODRIVE(card);
- at -= s->io_base;
-
- switch (s->opt & OPT_MODE) {
- case OPT_MODE_MMAP:
- if ((at & ~0x3ff) == 0x400) {
- at = 0;
- }
- break;
- case OPT_MODE_IOMAP16:
- at &= 0xf;
- break;
- case OPT_MODE_IOMAP1:
- if ((at & ~0xf) == 0x3f0) {
- at -= 0x3e8;
- } else if ((at & ~0xf) == 0x1f0) {
- at -= 0x1f0;
- }
- break;
- case OPT_MODE_IOMAP2:
- if ((at & ~0xf) == 0x370) {
- at -= 0x368;
- } else if ((at & ~0xf) == 0x170) {
- at -= 0x170;
- }
- }
-
- switch (at) {
- case 0x0: /* Even WR Data */
- case 0x8:
- ide_data_writew(&s->bus, 0, value);
- break;
-
- /* TODO: 8-bit accesses */
- if (s->cycle) {
- ide_data_writew(&s->bus, 0, s->io | (value << 8));
- } else {
- s->io = value & 0xff;
- }
- s->cycle = !s->cycle;
- break;
- case 0x9:
- s->io = value & 0xff;
- s->cycle = !s->cycle;
- break;
- case 0xd: /* Features */
- ide_ioport_write(&s->bus, 0x1, value);
- break;
- case 0xe: /* Device Control */
- s->ctrl = value;
- if (value & CTRL_SRST) {
- device_cold_reset(DEVICE(s));
- }
- md_interrupt_update(s);
- break;
- default:
- if (s->stat & STAT_PWRDWN) {
- s->pins |= PINS_CRDY;
- s->stat &= ~STAT_PWRDWN;
- }
- ide_ioport_write(&s->bus, at, value);
- }
-}
-
-static const VMStateDescription vmstate_microdrive = {
- .name = "microdrive",
- .version_id = 3,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT8(opt, MicroDriveState),
- VMSTATE_UINT8(stat, MicroDriveState),
- VMSTATE_UINT8(pins, MicroDriveState),
- VMSTATE_UINT8(ctrl, MicroDriveState),
- VMSTATE_UINT16(io, MicroDriveState),
- VMSTATE_UINT8(cycle, MicroDriveState),
- VMSTATE_IDE_BUS(bus, MicroDriveState),
- VMSTATE_IDE_DRIVES(bus.ifs, MicroDriveState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const uint8_t dscm1xxxx_cis[0x14a] = {
- [0x000] = CISTPL_DEVICE, /* 5V Device Information */
- [0x002] = 0x03, /* Tuple length = 4 bytes */
- [0x004] = 0xdb, /* ID: DTYPE_FUNCSPEC, non WP, DSPEED_150NS */
- [0x006] = 0x01, /* Size = 2K bytes */
- [0x008] = CISTPL_ENDMARK,
-
- [0x00a] = CISTPL_DEVICE_OC, /* Additional Device Information */
- [0x00c] = 0x04, /* Tuple length = 4 byest */
- [0x00e] = 0x03, /* Conditions: Ext = 0, Vcc 3.3V, MWAIT = 1 */
- [0x010] = 0xdb, /* ID: DTYPE_FUNCSPEC, non WP, DSPEED_150NS */
- [0x012] = 0x01, /* Size = 2K bytes */
- [0x014] = CISTPL_ENDMARK,
-
- [0x016] = CISTPL_JEDEC_C, /* JEDEC ID */
- [0x018] = 0x02, /* Tuple length = 2 bytes */
- [0x01a] = 0xdf, /* PC Card ATA with no Vpp required */
- [0x01c] = 0x01,
-
- [0x01e] = CISTPL_MANFID, /* Manufacture ID */
- [0x020] = 0x04, /* Tuple length = 4 bytes */
- [0x022] = 0xa4, /* TPLMID_MANF = 00a4 (IBM) */
- [0x024] = 0x00,
- [0x026] = 0x00, /* PLMID_CARD = 0000 */
- [0x028] = 0x00,
-
- [0x02a] = CISTPL_VERS_1, /* Level 1 Version */
- [0x02c] = 0x12, /* Tuple length = 23 bytes */
- [0x02e] = 0x04, /* Major Version = JEIDA 4.2 / PCMCIA 2.1 */
- [0x030] = 0x01, /* Minor Version = 1 */
- [0x032] = 'I',
- [0x034] = 'B',
- [0x036] = 'M',
- [0x038] = 0x00,
- [0x03a] = 'm',
- [0x03c] = 'i',
- [0x03e] = 'c',
- [0x040] = 'r',
- [0x042] = 'o',
- [0x044] = 'd',
- [0x046] = 'r',
- [0x048] = 'i',
- [0x04a] = 'v',
- [0x04c] = 'e',
- [0x04e] = 0x00,
- [0x050] = CISTPL_ENDMARK,
-
- [0x052] = CISTPL_FUNCID, /* Function ID */
- [0x054] = 0x02, /* Tuple length = 2 bytes */
- [0x056] = 0x04, /* TPLFID_FUNCTION = Fixed Disk */
- [0x058] = 0x01, /* TPLFID_SYSINIT: POST = 1, ROM = 0 */
-
- [0x05a] = CISTPL_FUNCE, /* Function Extension */
- [0x05c] = 0x02, /* Tuple length = 2 bytes */
- [0x05e] = 0x01, /* TPLFE_TYPE = Disk Device Interface */
- [0x060] = 0x01, /* TPLFE_DATA = PC Card ATA Interface */
-
- [0x062] = CISTPL_FUNCE, /* Function Extension */
- [0x064] = 0x03, /* Tuple length = 3 bytes */
- [0x066] = 0x02, /* TPLFE_TYPE = Basic PC Card ATA Interface */
- [0x068] = 0x08, /* TPLFE_DATA: Rotating, Unique, Single */
- [0x06a] = 0x0f, /* TPLFE_DATA: Sleep, Standby, Idle, Auto */
-
- [0x06c] = CISTPL_CONFIG, /* Configuration */
- [0x06e] = 0x05, /* Tuple length = 5 bytes */
- [0x070] = 0x01, /* TPCC_RASZ = 2 bytes, TPCC_RMSZ = 1 byte */
- [0x072] = 0x07, /* TPCC_LAST = 7 */
- [0x074] = 0x00, /* TPCC_RADR = 0200 */
- [0x076] = 0x02,
- [0x078] = 0x0f, /* TPCC_RMSK = 200, 202, 204, 206 */
-
- [0x07a] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x07c] = 0x0b, /* Tuple length = 11 bytes */
- [0x07e] = 0xc0, /* TPCE_INDX = Memory Mode, Default, Iface */
- [0x080] = 0xc0, /* TPCE_IF = Memory, no BVDs, no WP, READY */
- [0x082] = 0xa1, /* TPCE_FS = Vcc only, no I/O, Memory, Misc */
- [0x084] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
- [0x086] = 0x55, /* NomV: 5.0 V */
- [0x088] = 0x4d, /* MinV: 4.5 V */
- [0x08a] = 0x5d, /* MaxV: 5.5 V */
- [0x08c] = 0x4e, /* Peakl: 450 mA */
- [0x08e] = 0x08, /* TPCE_MS = 1 window, 1 byte, Host address */
- [0x090] = 0x00, /* Window descriptor: Window length = 0 */
- [0x092] = 0x20, /* TPCE_MI: support power down mode, RW */
-
- [0x094] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x096] = 0x06, /* Tuple length = 6 bytes */
- [0x098] = 0x00, /* TPCE_INDX = Memory Mode, no Default */
- [0x09a] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */
- [0x09c] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
- [0x09e] = 0xb5, /* NomV: 3.3 V */
- [0x0a0] = 0x1e,
- [0x0a2] = 0x3e, /* Peakl: 350 mA */
-
- [0x0a4] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x0a6] = 0x0d, /* Tuple length = 13 bytes */
- [0x0a8] = 0xc1, /* TPCE_INDX = I/O and Memory Mode, Default */
- [0x0aa] = 0x41, /* TPCE_IF = I/O and Memory, no BVD, no WP */
- [0x0ac] = 0x99, /* TPCE_FS = Vcc only, I/O, Interrupt, Misc */
- [0x0ae] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
- [0x0b0] = 0x55, /* NomV: 5.0 V */
- [0x0b2] = 0x4d, /* MinV: 4.5 V */
- [0x0b4] = 0x5d, /* MaxV: 5.5 V */
- [0x0b6] = 0x4e, /* Peakl: 450 mA */
- [0x0b8] = 0x64, /* TPCE_IO = 16-byte boundary, 16/8 accesses */
- [0x0ba] = 0xf0, /* TPCE_IR = MASK, Level, Pulse, Share */
- [0x0bc] = 0xff, /* IRQ0..IRQ7 supported */
- [0x0be] = 0xff, /* IRQ8..IRQ15 supported */
- [0x0c0] = 0x20, /* TPCE_MI = support power down mode */
-
- [0x0c2] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x0c4] = 0x06, /* Tuple length = 6 bytes */
- [0x0c6] = 0x01, /* TPCE_INDX = I/O and Memory Mode */
- [0x0c8] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */
- [0x0ca] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
- [0x0cc] = 0xb5, /* NomV: 3.3 V */
- [0x0ce] = 0x1e,
- [0x0d0] = 0x3e, /* Peakl: 350 mA */
-
- [0x0d2] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x0d4] = 0x12, /* Tuple length = 18 bytes */
- [0x0d6] = 0xc2, /* TPCE_INDX = I/O Primary Mode */
- [0x0d8] = 0x41, /* TPCE_IF = I/O and Memory, no BVD, no WP */
- [0x0da] = 0x99, /* TPCE_FS = Vcc only, I/O, Interrupt, Misc */
- [0x0dc] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
- [0x0de] = 0x55, /* NomV: 5.0 V */
- [0x0e0] = 0x4d, /* MinV: 4.5 V */
- [0x0e2] = 0x5d, /* MaxV: 5.5 V */
- [0x0e4] = 0x4e, /* Peakl: 450 mA */
- [0x0e6] = 0xea, /* TPCE_IO = 1K boundary, 16/8 access, Range */
- [0x0e8] = 0x61, /* Range: 2 fields, 2 bytes addr, 1 byte len */
- [0x0ea] = 0xf0, /* Field 1 address = 0x01f0 */
- [0x0ec] = 0x01,
- [0x0ee] = 0x07, /* Address block length = 8 */
- [0x0f0] = 0xf6, /* Field 2 address = 0x03f6 */
- [0x0f2] = 0x03,
- [0x0f4] = 0x01, /* Address block length = 2 */
- [0x0f6] = 0xee, /* TPCE_IR = IRQ E, Level, Pulse, Share */
- [0x0f8] = 0x20, /* TPCE_MI = support power down mode */
-
- [0x0fa] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x0fc] = 0x06, /* Tuple length = 6 bytes */
- [0x0fe] = 0x02, /* TPCE_INDX = I/O Primary Mode, no Default */
- [0x100] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */
- [0x102] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
- [0x104] = 0xb5, /* NomV: 3.3 V */
- [0x106] = 0x1e,
- [0x108] = 0x3e, /* Peakl: 350 mA */
-
- [0x10a] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x10c] = 0x12, /* Tuple length = 18 bytes */
- [0x10e] = 0xc3, /* TPCE_INDX = I/O Secondary Mode, Default */
- [0x110] = 0x41, /* TPCE_IF = I/O and Memory, no BVD, no WP */
- [0x112] = 0x99, /* TPCE_FS = Vcc only, I/O, Interrupt, Misc */
- [0x114] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
- [0x116] = 0x55, /* NomV: 5.0 V */
- [0x118] = 0x4d, /* MinV: 4.5 V */
- [0x11a] = 0x5d, /* MaxV: 5.5 V */
- [0x11c] = 0x4e, /* Peakl: 450 mA */
- [0x11e] = 0xea, /* TPCE_IO = 1K boundary, 16/8 access, Range */
- [0x120] = 0x61, /* Range: 2 fields, 2 byte addr, 1 byte len */
- [0x122] = 0x70, /* Field 1 address = 0x0170 */
- [0x124] = 0x01,
- [0x126] = 0x07, /* Address block length = 8 */
- [0x128] = 0x76, /* Field 2 address = 0x0376 */
- [0x12a] = 0x03,
- [0x12c] = 0x01, /* Address block length = 2 */
- [0x12e] = 0xee, /* TPCE_IR = IRQ E, Level, Pulse, Share */
- [0x130] = 0x20, /* TPCE_MI = support power down mode */
-
- [0x132] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x134] = 0x06, /* Tuple length = 6 bytes */
- [0x136] = 0x03, /* TPCE_INDX = I/O Secondary Mode */
- [0x138] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */
- [0x13a] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
- [0x13c] = 0xb5, /* NomV: 3.3 V */
- [0x13e] = 0x1e,
- [0x140] = 0x3e, /* Peakl: 350 mA */
-
- [0x142] = CISTPL_NO_LINK, /* No Link */
- [0x144] = 0x00, /* Tuple length = 0 bytes */
-
- [0x146] = CISTPL_END, /* Tuple End */
-};
-
-#define TYPE_DSCM1XXXX "dscm1xxxx"
-
-static int dscm1xxxx_attach(PCMCIACardState *card)
-{
- MicroDriveState *md = MICRODRIVE(card);
- PCMCIACardClass *pcc = PCMCIA_CARD_GET_CLASS(card);
-
- md->attr_base = pcc->cis[0x74] | (pcc->cis[0x76] << 8);
- md->io_base = 0x0;
-
- device_cold_reset(DEVICE(md));
- md_interrupt_update(md);
-
- return 0;
-}
-
-static int dscm1xxxx_detach(PCMCIACardState *card)
-{
- MicroDriveState *md = MICRODRIVE(card);
-
- device_cold_reset(DEVICE(md));
- return 0;
-}
-
-PCMCIACardState *dscm1xxxx_init(DriveInfo *dinfo)
-{
- MicroDriveState *md;
-
- md = MICRODRIVE(object_new(TYPE_DSCM1XXXX));
- qdev_realize(DEVICE(md), NULL, &error_fatal);
-
- if (dinfo != NULL) {
- ide_bus_create_drive(&md->bus, 0, dinfo);
- }
- md->bus.ifs[0].drive_kind = IDE_CFATA;
- md->bus.ifs[0].mdata_size = METADATA_SIZE;
- md->bus.ifs[0].mdata_storage = g_malloc0(METADATA_SIZE);
-
- return PCMCIA_CARD(md);
-}
-
-static void dscm1xxxx_class_init(ObjectClass *oc, void *data)
-{
- PCMCIACardClass *pcc = PCMCIA_CARD_CLASS(oc);
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- pcc->cis = dscm1xxxx_cis;
- pcc->cis_len = sizeof(dscm1xxxx_cis);
-
- pcc->attach = dscm1xxxx_attach;
- pcc->detach = dscm1xxxx_detach;
- /* Reason: Needs to be wired-up in code, see dscm1xxxx_init() */
- dc->user_creatable = false;
-}
-
-static const TypeInfo dscm1xxxx_type_info = {
- .name = TYPE_DSCM1XXXX,
- .parent = TYPE_MICRODRIVE,
- .class_init = dscm1xxxx_class_init,
-};
-
-static void microdrive_realize(DeviceState *dev, Error **errp)
-{
- MicroDriveState *md = MICRODRIVE(dev);
-
- ide_bus_init_output_irq(&md->bus, qemu_allocate_irq(md_set_irq, md, 0));
-}
-
-static void microdrive_init(Object *obj)
-{
- MicroDriveState *md = MICRODRIVE(obj);
-
- ide_bus_init(&md->bus, sizeof(md->bus), DEVICE(obj), 0, 1);
-}
-
-static void microdrive_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- PCMCIACardClass *pcc = PCMCIA_CARD_CLASS(oc);
-
- pcc->attr_read = md_attr_read;
- pcc->attr_write = md_attr_write;
- pcc->common_read = md_common_read;
- pcc->common_write = md_common_write;
- pcc->io_read = md_common_read;
- pcc->io_write = md_common_write;
-
- dc->realize = microdrive_realize;
- dc->reset = md_reset;
- dc->vmsd = &vmstate_microdrive;
-}
-
-static const TypeInfo microdrive_type_info = {
- .name = TYPE_MICRODRIVE,
- .parent = TYPE_PCMCIA_CARD,
- .instance_size = sizeof(MicroDriveState),
- .instance_init = microdrive_init,
- .abstract = true,
- .class_init = microdrive_class_init,
-};
-
-static void microdrive_register_types(void)
-{
- type_register_static(&microdrive_type_info);
- type_register_static(&dscm1xxxx_type_info);
-}
-
-type_init(microdrive_register_types)
diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c
index 8736281..53d22fb 100644
--- a/hw/ide/mmio.c
+++ b/hw/ide/mmio.c
@@ -151,7 +151,7 @@ static void mmio_ide_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = mmio_ide_realizefn;
- dc->reset = mmio_ide_reset;
+ device_class_set_legacy_reset(dc, mmio_ide_reset);
device_class_set_props(dc, mmio_ide_properties);
dc->vmsd = &vmstate_ide_mmio;
}
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index 4675d07..a008fe7 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -237,7 +237,7 @@ static int32_t bmdma_prepare_buf(const IDEDMA *dma, int32_t limit)
/* end of table (with a fail safe of one page) */
if (bm->cur_prd_last ||
(bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) {
- return s->sg.size;
+ break;
}
pci_dma_read(pci_dev, bm->cur_addr, &prd, 8);
bm->cur_addr += 8;
@@ -266,10 +266,7 @@ static int32_t bmdma_prepare_buf(const IDEDMA *dma, int32_t limit)
s->io_buffer_size += l;
}
}
-
- qemu_sglist_destroy(&s->sg);
- s->io_buffer_size = 0;
- return -1;
+ return s->sg.size;
}
/* return 0 if buffer completed */
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index 80efc63..818ff60 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -183,7 +183,7 @@ static void piix3_ide_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- dc->reset = piix_ide_reset;
+ device_class_set_legacy_reset(dc, piix_ide_reset);
dc->vmsd = &vmstate_ide_pci;
k->realize = pci_piix_ide_realize;
k->exit = pci_piix_ide_exitfn;
@@ -206,7 +206,7 @@ static void piix4_ide_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- dc->reset = piix_ide_reset;
+ device_class_set_legacy_reset(dc, piix_ide_reset);
dc->vmsd = &vmstate_ide_pci;
k->realize = pci_piix_ide_realize;
k->exit = pci_piix_ide_exitfn;
diff --git a/hw/ide/sii3112.c b/hw/ide/sii3112.c
index af17384..ce8a1e4 100644
--- a/hw/ide/sii3112.c
+++ b/hw/ide/sii3112.c
@@ -300,7 +300,7 @@ static void sii3112_pci_class_init(ObjectClass *klass, void *data)
pd->class_id = PCI_CLASS_STORAGE_RAID;
pd->revision = 1;
pd->realize = sii3112_pci_realize;
- dc->reset = sii3112_reset;
+ device_class_set_legacy_reset(dc, sii3112_reset);
dc->desc = "SiI3112A SATA controller";
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
}
diff --git a/hw/ide/via.c b/hw/ide/via.c
index a32f56b..c88eb6c 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -250,7 +250,7 @@ static void via_ide_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- dc->reset = via_ide_reset;
+ device_class_set_legacy_reset(dc, via_ide_reset);
dc->vmsd = &vmstate_ide_pci;
/* Reason: only works as function of VIA southbridge */
dc->user_creatable = false;
diff --git a/hw/input/Kconfig b/hw/input/Kconfig
index f86e98c..a116cb8 100644
--- a/hw/input/Kconfig
+++ b/hw/input/Kconfig
@@ -1,13 +1,6 @@
config ADB
bool
-config ADS7846
- bool
-
-config LM832X
- bool
- depends on I2C
-
config PCKBD
bool
select PS2
@@ -23,9 +16,6 @@ config PS2
config STELLARIS_GAMEPAD
bool
-config TSC2005
- bool
-
config VIRTIO_INPUT
bool
default y
@@ -41,8 +31,5 @@ config VHOST_USER_INPUT
default y
depends on VIRTIO_INPUT && VHOST_USER
-config TSC210X
- bool
-
config LASIPS2
select PS2
diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c
index 758fa6d..3649d03 100644
--- a/hw/input/adb-kbd.c
+++ b/hw/input/adb-kbd.c
@@ -387,7 +387,7 @@ static void adb_kbd_class_init(ObjectClass *oc, void *data)
adc->devreq = adb_kbd_request;
adc->devhasdata = adb_kbd_has_data;
- dc->reset = adb_kbd_reset;
+ device_class_set_legacy_reset(dc, adb_kbd_reset);
dc->vmsd = &vmstate_adb_kbd;
}
diff --git a/hw/input/adb-mouse.c b/hw/input/adb-mouse.c
index 144a0cc..77b280d 100644
--- a/hw/input/adb-mouse.c
+++ b/hw/input/adb-mouse.c
@@ -38,6 +38,7 @@ struct MouseState {
ADBDevice parent_obj;
/*< private >*/
+ QemuInputHandlerState *hs;
int buttons_state, last_buttons_state;
int dx, dy, dz;
};
@@ -51,17 +52,57 @@ struct ADBMouseClass {
DeviceRealize parent_realize;
};
-static void adb_mouse_event(void *opaque,
- int dx1, int dy1, int dz1, int buttons_state)
+#define ADB_MOUSE_BUTTON_LEFT 0x01
+#define ADB_MOUSE_BUTTON_RIGHT 0x02
+
+static void adb_mouse_handle_event(DeviceState *dev, QemuConsole *src,
+ InputEvent *evt)
{
- MouseState *s = opaque;
+ MouseState *s = (MouseState *)dev;
+ InputMoveEvent *move;
+ InputBtnEvent *btn;
+ static const int bmap[INPUT_BUTTON__MAX] = {
+ [INPUT_BUTTON_LEFT] = ADB_MOUSE_BUTTON_LEFT,
+ [INPUT_BUTTON_RIGHT] = ADB_MOUSE_BUTTON_RIGHT,
+ };
+
+ switch (evt->type) {
+ case INPUT_EVENT_KIND_REL:
+ move = evt->u.rel.data;
+ if (move->axis == INPUT_AXIS_X) {
+ s->dx += move->value;
+ } else if (move->axis == INPUT_AXIS_Y) {
+ s->dy += move->value;
+ }
+ break;
+
+ case INPUT_EVENT_KIND_BTN:
+ btn = evt->u.btn.data;
+ if (bmap[btn->button]) {
+ if (btn->down) {
+ s->buttons_state |= bmap[btn->button];
+ } else {
+ s->buttons_state &= ~bmap[btn->button];
+ }
+ }
+ break;
- s->dx += dx1;
- s->dy += dy1;
- s->dz += dz1;
- s->buttons_state = buttons_state;
+ default:
+ /* keep gcc happy */
+ break;
+ }
}
+static const QemuInputHandler adb_mouse_handler = {
+ .name = "QEMU ADB Mouse",
+ .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
+ .event = adb_mouse_handle_event,
+ /*
+ * We do not need the .sync handler because unlike e.g. PS/2 where async
+ * mouse events are sent over the serial port, an ADB mouse is constantly
+ * polled by the host via the adb_mouse_poll() callback.
+ */
+};
static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
{
@@ -94,10 +135,10 @@ static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
dx &= 0x7f;
dy &= 0x7f;
- if (!(s->buttons_state & MOUSE_EVENT_LBUTTON)) {
+ if (!(s->buttons_state & ADB_MOUSE_BUTTON_LEFT)) {
dy |= 0x80;
}
- if (!(s->buttons_state & MOUSE_EVENT_RBUTTON)) {
+ if (!(s->buttons_state & ADB_MOUSE_BUTTON_RIGHT)) {
dx |= 0x80;
}
@@ -236,7 +277,7 @@ static void adb_mouse_realizefn(DeviceState *dev, Error **errp)
amc->parent_realize(dev, errp);
- qemu_add_mouse_event_handler(adb_mouse_event, s, 0, "QEMU ADB Mouse");
+ s->hs = qemu_input_handler_register(dev, &adb_mouse_handler);
}
static void adb_mouse_initfn(Object *obj)
@@ -258,7 +299,7 @@ static void adb_mouse_class_init(ObjectClass *oc, void *data)
adc->devreq = adb_mouse_request;
adc->devhasdata = adb_mouse_has_data;
- dc->reset = adb_mouse_reset;
+ device_class_set_legacy_reset(dc, adb_mouse_reset);
dc->vmsd = &vmstate_adb_mouse;
}
diff --git a/hw/input/ads7846.c b/hw/input/ads7846.c
deleted file mode 100644
index cde3892..0000000
--- a/hw/input/ads7846.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * TI ADS7846 / TSC2046 chip emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/irq.h"
-#include "hw/ssi/ssi.h"
-#include "migration/vmstate.h"
-#include "qemu/module.h"
-#include "ui/console.h"
-#include "qom/object.h"
-
-struct ADS7846State {
- SSIPeripheral ssidev;
- qemu_irq interrupt;
-
- int input[8];
- int pressure;
- int noise;
-
- int cycle;
- int output;
-};
-
-#define TYPE_ADS7846 "ads7846"
-OBJECT_DECLARE_SIMPLE_TYPE(ADS7846State, ADS7846)
-
-/* Control-byte bitfields */
-#define CB_PD0 (1 << 0)
-#define CB_PD1 (1 << 1)
-#define CB_SER (1 << 2)
-#define CB_MODE (1 << 3)
-#define CB_A0 (1 << 4)
-#define CB_A1 (1 << 5)
-#define CB_A2 (1 << 6)
-#define CB_START (1 << 7)
-
-#define X_AXIS_DMAX 3470
-#define X_AXIS_MIN 290
-#define Y_AXIS_DMAX 3450
-#define Y_AXIS_MIN 200
-
-#define ADS_VBAT 2000
-#define ADS_VAUX 2000
-#define ADS_TEMP0 2000
-#define ADS_TEMP1 3000
-#define ADS_XPOS(x, y) (X_AXIS_MIN + ((X_AXIS_DMAX * (x)) >> 15))
-#define ADS_YPOS(x, y) (Y_AXIS_MIN + ((Y_AXIS_DMAX * (y)) >> 15))
-#define ADS_Z1POS(x, y) 600
-#define ADS_Z2POS(x, y) (600 + 6000 / ADS_XPOS(x, y))
-
-static void ads7846_int_update(ADS7846State *s)
-{
- if (s->interrupt)
- qemu_set_irq(s->interrupt, s->pressure == 0);
-}
-
-static uint32_t ads7846_transfer(SSIPeripheral *dev, uint32_t value)
-{
- ADS7846State *s = ADS7846(dev);
-
- switch (s->cycle ++) {
- case 0:
- if (!(value & CB_START)) {
- s->cycle = 0;
- break;
- }
-
- s->output = s->input[(value >> 4) & 7];
-
- /* Imitate the ADC noise, some drivers expect this. */
- s->noise = (s->noise + 3) & 7;
- switch ((value >> 4) & 7) {
- case 1: s->output += s->noise ^ 2; break;
- case 3: s->output += s->noise ^ 0; break;
- case 4: s->output += s->noise ^ 7; break;
- case 5: s->output += s->noise ^ 5; break;
- }
-
- if (value & CB_MODE)
- s->output >>= 4; /* 8 bits instead of 12 */
-
- break;
- case 1:
- s->cycle = 0;
- break;
- }
- return s->output;
-}
-
-static void ads7846_ts_event(void *opaque,
- int x, int y, int z, int buttons_state)
-{
- ADS7846State *s = opaque;
-
- if (buttons_state) {
- x = 0x7fff - x;
- s->input[1] = ADS_XPOS(x, y);
- s->input[3] = ADS_Z1POS(x, y);
- s->input[4] = ADS_Z2POS(x, y);
- s->input[5] = ADS_YPOS(x, y);
- }
-
- if (s->pressure == !buttons_state) {
- s->pressure = !!buttons_state;
-
- ads7846_int_update(s);
- }
-}
-
-static int ads7856_post_load(void *opaque, int version_id)
-{
- ADS7846State *s = opaque;
-
- s->pressure = 0;
- ads7846_int_update(s);
- return 0;
-}
-
-static const VMStateDescription vmstate_ads7846 = {
- .name = "ads7846",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = ads7856_post_load,
- .fields = (const VMStateField[]) {
- VMSTATE_SSI_PERIPHERAL(ssidev, ADS7846State),
- VMSTATE_INT32_ARRAY(input, ADS7846State, 8),
- VMSTATE_INT32(noise, ADS7846State),
- VMSTATE_INT32(cycle, ADS7846State),
- VMSTATE_INT32(output, ADS7846State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void ads7846_realize(SSIPeripheral *d, Error **errp)
-{
- DeviceState *dev = DEVICE(d);
- ADS7846State *s = ADS7846(d);
-
- qdev_init_gpio_out(dev, &s->interrupt, 1);
-
- s->input[0] = ADS_TEMP0; /* TEMP0 */
- s->input[2] = ADS_VBAT; /* VBAT */
- s->input[6] = ADS_VAUX; /* VAUX */
- s->input[7] = ADS_TEMP1; /* TEMP1 */
-
- /* We want absolute coordinates */
- qemu_add_mouse_event_handler(ads7846_ts_event, s, 1,
- "QEMU ADS7846-driven Touchscreen");
-
- ads7846_int_update(s);
-
- vmstate_register_any(NULL, &vmstate_ads7846, s);
-}
-
-static void ads7846_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
-
- k->realize = ads7846_realize;
- k->transfer = ads7846_transfer;
- set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
-}
-
-static const TypeInfo ads7846_info = {
- .name = TYPE_ADS7846,
- .parent = TYPE_SSI_PERIPHERAL,
- .instance_size = sizeof(ADS7846State),
- .class_init = ads7846_class_init,
-};
-
-static void ads7846_register_types(void)
-{
- type_register_static(&ads7846_info);
-}
-
-type_init(ads7846_register_types)
diff --git a/hw/input/lm832x.c b/hw/input/lm832x.c
deleted file mode 100644
index 59e5567..0000000
--- a/hw/input/lm832x.c
+++ /dev/null
@@ -1,528 +0,0 @@
-/*
- * National Semiconductor LM8322/8323 GPIO keyboard & PWM chips.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/input/lm832x.h"
-#include "hw/i2c/i2c.h"
-#include "hw/irq.h"
-#include "migration/vmstate.h"
-#include "qemu/module.h"
-#include "qemu/timer.h"
-#include "ui/console.h"
-#include "qom/object.h"
-
-OBJECT_DECLARE_SIMPLE_TYPE(LM823KbdState, LM8323)
-
-struct LM823KbdState {
- I2CSlave parent_obj;
-
- uint8_t i2c_dir;
- uint8_t i2c_cycle;
- uint8_t reg;
-
- qemu_irq nirq;
- uint16_t model;
-
- struct {
- qemu_irq out[2];
- int in[2][2];
- } mux;
-
- uint8_t config;
- uint8_t status;
- uint8_t acttime;
- uint8_t error;
- uint8_t clock;
-
- struct {
- uint16_t pull;
- uint16_t mask;
- uint16_t dir;
- uint16_t level;
- qemu_irq out[16];
- } gpio;
-
- struct {
- uint8_t dbnctime;
- uint8_t size;
- uint8_t start;
- uint8_t len;
- uint8_t fifo[16];
- } kbd;
-
- struct {
- uint16_t file[256];
- uint8_t faddr;
- uint8_t addr[3];
- QEMUTimer *tm[3];
- } pwm;
-};
-
-#define INT_KEYPAD (1 << 0)
-#define INT_ERROR (1 << 3)
-#define INT_NOINIT (1 << 4)
-#define INT_PWMEND(n) (1 << (5 + n))
-
-#define ERR_BADPAR (1 << 0)
-#define ERR_CMDUNK (1 << 1)
-#define ERR_KEYOVR (1 << 2)
-#define ERR_FIFOOVR (1 << 6)
-
-static void lm_kbd_irq_update(LM823KbdState *s)
-{
- qemu_set_irq(s->nirq, !s->status);
-}
-
-static void lm_kbd_gpio_update(LM823KbdState *s)
-{
-}
-
-static void lm_kbd_reset(DeviceState *dev)
-{
- LM823KbdState *s = LM8323(dev);
-
- s->config = 0x80;
- s->status = INT_NOINIT;
- s->acttime = 125;
- s->kbd.dbnctime = 3;
- s->kbd.size = 0x33;
- s->clock = 0x08;
-
- lm_kbd_irq_update(s);
- lm_kbd_gpio_update(s);
-}
-
-static void lm_kbd_error(LM823KbdState *s, int err)
-{
- s->error |= err;
- s->status |= INT_ERROR;
- lm_kbd_irq_update(s);
-}
-
-static void lm_kbd_pwm_tick(LM823KbdState *s, int line)
-{
-}
-
-static void lm_kbd_pwm_start(LM823KbdState *s, int line)
-{
- lm_kbd_pwm_tick(s, line);
-}
-
-static void lm_kbd_pwm0_tick(void *opaque)
-{
- lm_kbd_pwm_tick(opaque, 0);
-}
-static void lm_kbd_pwm1_tick(void *opaque)
-{
- lm_kbd_pwm_tick(opaque, 1);
-}
-static void lm_kbd_pwm2_tick(void *opaque)
-{
- lm_kbd_pwm_tick(opaque, 2);
-}
-
-enum {
- LM832x_CMD_READ_ID = 0x80, /* Read chip ID. */
- LM832x_CMD_WRITE_CFG = 0x81, /* Set configuration item. */
- LM832x_CMD_READ_INT = 0x82, /* Get interrupt status. */
- LM832x_CMD_RESET = 0x83, /* Reset, same as external one */
- LM823x_CMD_WRITE_PULL_DOWN = 0x84, /* Select GPIO pull-up/down. */
- LM832x_CMD_WRITE_PORT_SEL = 0x85, /* Select GPIO in/out. */
- LM832x_CMD_WRITE_PORT_STATE = 0x86, /* Set GPIO pull-up/down. */
- LM832x_CMD_READ_PORT_SEL = 0x87, /* Get GPIO in/out. */
- LM832x_CMD_READ_PORT_STATE = 0x88, /* Get GPIO pull-up/down. */
- LM832x_CMD_READ_FIFO = 0x89, /* Read byte from FIFO. */
- LM832x_CMD_RPT_READ_FIFO = 0x8a, /* Read FIFO (no increment). */
- LM832x_CMD_SET_ACTIVE = 0x8b, /* Set active time. */
- LM832x_CMD_READ_ERROR = 0x8c, /* Get error status. */
- LM832x_CMD_READ_ROTATOR = 0x8e, /* Read rotator status. */
- LM832x_CMD_SET_DEBOUNCE = 0x8f, /* Set debouncing time. */
- LM832x_CMD_SET_KEY_SIZE = 0x90, /* Set keypad size. */
- LM832x_CMD_READ_KEY_SIZE = 0x91, /* Get keypad size. */
- LM832x_CMD_READ_CFG = 0x92, /* Get configuration item. */
- LM832x_CMD_WRITE_CLOCK = 0x93, /* Set clock config. */
- LM832x_CMD_READ_CLOCK = 0x94, /* Get clock config. */
- LM832x_CMD_PWM_WRITE = 0x95, /* Write PWM script. */
- LM832x_CMD_PWM_START = 0x96, /* Start PWM engine. */
- LM832x_CMD_PWM_STOP = 0x97, /* Stop PWM engine. */
- LM832x_GENERAL_ERROR = 0xff, /* There was one error.
- Previously was represented by -1
- This is not a command */
-};
-
-#define LM832x_MAX_KPX 8
-#define LM832x_MAX_KPY 12
-
-static uint8_t lm_kbd_read(LM823KbdState *s, int reg, int byte)
-{
- int ret;
-
- switch (reg) {
- case LM832x_CMD_READ_ID:
- ret = 0x0400;
- break;
-
- case LM832x_CMD_READ_INT:
- ret = s->status;
- if (!(s->status & INT_NOINIT)) {
- s->status = 0;
- lm_kbd_irq_update(s);
- }
- break;
-
- case LM832x_CMD_READ_PORT_SEL:
- ret = s->gpio.dir;
- break;
- case LM832x_CMD_READ_PORT_STATE:
- ret = s->gpio.mask;
- break;
-
- case LM832x_CMD_READ_FIFO:
- if (s->kbd.len <= 1)
- return 0x00;
-
- /* Example response from the two commands after a INT_KEYPAD
- * interrupt caused by the key 0x3c being pressed:
- * RPT_READ_FIFO: 55 bc 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
- * READ_FIFO: bc 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
- * RPT_READ_FIFO: bc 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
- *
- * 55 is the code of the key release event serviced in the previous
- * interrupt handling.
- *
- * TODO: find out whether the FIFO is advanced a single character
- * before reading every byte or the whole size of the FIFO at the
- * last LM832x_CMD_READ_FIFO. This affects LM832x_CMD_RPT_READ_FIFO
- * output in cases where there are more than one event in the FIFO.
- * Assume 0xbc and 0x3c events are in the FIFO:
- * RPT_READ_FIFO: 55 bc 3c 00 4e ff 0a 50 08 00 29 d9 08 01 c9
- * READ_FIFO: bc 3c 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9
- * Does RPT_READ_FIFO now return 0xbc and 0x3c or only 0x3c?
- */
- s->kbd.start ++;
- s->kbd.start &= sizeof(s->kbd.fifo) - 1;
- s->kbd.len --;
-
- return s->kbd.fifo[s->kbd.start];
- case LM832x_CMD_RPT_READ_FIFO:
- if (byte >= s->kbd.len)
- return 0x00;
-
- return s->kbd.fifo[(s->kbd.start + byte) & (sizeof(s->kbd.fifo) - 1)];
-
- case LM832x_CMD_READ_ERROR:
- return s->error;
-
- case LM832x_CMD_READ_ROTATOR:
- return 0;
-
- case LM832x_CMD_READ_KEY_SIZE:
- return s->kbd.size;
-
- case LM832x_CMD_READ_CFG:
- return s->config & 0xf;
-
- case LM832x_CMD_READ_CLOCK:
- return (s->clock & 0xfc) | 2;
-
- default:
- lm_kbd_error(s, ERR_CMDUNK);
- fprintf(stderr, "%s: unknown command %02x\n", __func__, reg);
- return 0x00;
- }
-
- return ret >> (byte << 3);
-}
-
-static void lm_kbd_write(LM823KbdState *s, int reg, int byte, uint8_t value)
-{
- switch (reg) {
- case LM832x_CMD_WRITE_CFG:
- s->config = value;
- /* This must be done whenever s->mux.in is updated (never). */
- if ((s->config >> 1) & 1) /* MUX1EN */
- qemu_set_irq(s->mux.out[0], s->mux.in[0][(s->config >> 0) & 1]);
- if ((s->config >> 3) & 1) /* MUX2EN */
- qemu_set_irq(s->mux.out[0], s->mux.in[0][(s->config >> 2) & 1]);
- /* TODO: check that this is issued only following the chip reset
- * and not in the middle of operation and that it is followed by
- * the GPIO ports re-resablishing through WRITE_PORT_SEL and
- * WRITE_PORT_STATE (using a timer perhaps) and otherwise output
- * warnings. */
- s->status = 0;
- lm_kbd_irq_update(s);
- s->kbd.len = 0;
- s->kbd.start = 0;
- s->reg = LM832x_GENERAL_ERROR;
- break;
-
- case LM832x_CMD_RESET:
- if (value == 0xaa)
- lm_kbd_reset(DEVICE(s));
- else
- lm_kbd_error(s, ERR_BADPAR);
- s->reg = LM832x_GENERAL_ERROR;
- break;
-
- case LM823x_CMD_WRITE_PULL_DOWN:
- if (!byte)
- s->gpio.pull = value;
- else {
- s->gpio.pull |= value << 8;
- lm_kbd_gpio_update(s);
- s->reg = LM832x_GENERAL_ERROR;
- }
- break;
- case LM832x_CMD_WRITE_PORT_SEL:
- if (!byte)
- s->gpio.dir = value;
- else {
- s->gpio.dir |= value << 8;
- lm_kbd_gpio_update(s);
- s->reg = LM832x_GENERAL_ERROR;
- }
- break;
- case LM832x_CMD_WRITE_PORT_STATE:
- if (!byte)
- s->gpio.mask = value;
- else {
- s->gpio.mask |= value << 8;
- lm_kbd_gpio_update(s);
- s->reg = LM832x_GENERAL_ERROR;
- }
- break;
-
- case LM832x_CMD_SET_ACTIVE:
- s->acttime = value;
- s->reg = LM832x_GENERAL_ERROR;
- break;
-
- case LM832x_CMD_SET_DEBOUNCE:
- s->kbd.dbnctime = value;
- s->reg = LM832x_GENERAL_ERROR;
- if (!value)
- lm_kbd_error(s, ERR_BADPAR);
- break;
-
- case LM832x_CMD_SET_KEY_SIZE:
- s->kbd.size = value;
- s->reg = LM832x_GENERAL_ERROR;
- if (
- (value & 0xf) < 3 || (value & 0xf) > LM832x_MAX_KPY ||
- (value >> 4) < 3 || (value >> 4) > LM832x_MAX_KPX)
- lm_kbd_error(s, ERR_BADPAR);
- break;
-
- case LM832x_CMD_WRITE_CLOCK:
- s->clock = value;
- s->reg = LM832x_GENERAL_ERROR;
- if ((value & 3) && (value & 3) != 3) {
- lm_kbd_error(s, ERR_BADPAR);
- fprintf(stderr, "%s: invalid clock setting in RCPWM\n",
- __func__);
- }
- /* TODO: Validate that the command is only issued once */
- break;
-
- case LM832x_CMD_PWM_WRITE:
- if (byte == 0) {
- if (!(value & 3) || (value >> 2) > 59) {
- lm_kbd_error(s, ERR_BADPAR);
- s->reg = LM832x_GENERAL_ERROR;
- break;
- }
-
- s->pwm.faddr = value;
- s->pwm.file[s->pwm.faddr] = 0;
- } else if (byte == 1) {
- s->pwm.file[s->pwm.faddr] |= value << 8;
- } else if (byte == 2) {
- s->pwm.file[s->pwm.faddr] |= value << 0;
- s->reg = LM832x_GENERAL_ERROR;
- }
- break;
- case LM832x_CMD_PWM_START:
- s->reg = LM832x_GENERAL_ERROR;
- if (!(value & 3) || (value >> 2) > 59) {
- lm_kbd_error(s, ERR_BADPAR);
- break;
- }
-
- s->pwm.addr[(value & 3) - 1] = value >> 2;
- lm_kbd_pwm_start(s, (value & 3) - 1);
- break;
- case LM832x_CMD_PWM_STOP:
- s->reg = LM832x_GENERAL_ERROR;
- if (!(value & 3)) {
- lm_kbd_error(s, ERR_BADPAR);
- break;
- }
-
- timer_del(s->pwm.tm[(value & 3) - 1]);
- break;
-
- case LM832x_GENERAL_ERROR:
- lm_kbd_error(s, ERR_BADPAR);
- break;
- default:
- lm_kbd_error(s, ERR_CMDUNK);
- fprintf(stderr, "%s: unknown command %02x\n", __func__, reg);
- break;
- }
-}
-
-static int lm_i2c_event(I2CSlave *i2c, enum i2c_event event)
-{
- LM823KbdState *s = LM8323(i2c);
-
- switch (event) {
- case I2C_START_RECV:
- case I2C_START_SEND:
- s->i2c_cycle = 0;
- s->i2c_dir = (event == I2C_START_SEND);
- break;
-
- default:
- break;
- }
-
- return 0;
-}
-
-static uint8_t lm_i2c_rx(I2CSlave *i2c)
-{
- LM823KbdState *s = LM8323(i2c);
-
- return lm_kbd_read(s, s->reg, s->i2c_cycle ++);
-}
-
-static int lm_i2c_tx(I2CSlave *i2c, uint8_t data)
-{
- LM823KbdState *s = LM8323(i2c);
-
- if (!s->i2c_cycle)
- s->reg = data;
- else
- lm_kbd_write(s, s->reg, s->i2c_cycle - 1, data);
- s->i2c_cycle ++;
-
- return 0;
-}
-
-static int lm_kbd_post_load(void *opaque, int version_id)
-{
- LM823KbdState *s = opaque;
-
- lm_kbd_irq_update(s);
- lm_kbd_gpio_update(s);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_lm_kbd = {
- .name = "LM8323",
- .version_id = 0,
- .minimum_version_id = 0,
- .post_load = lm_kbd_post_load,
- .fields = (const VMStateField[]) {
- VMSTATE_I2C_SLAVE(parent_obj, LM823KbdState),
- VMSTATE_UINT8(i2c_dir, LM823KbdState),
- VMSTATE_UINT8(i2c_cycle, LM823KbdState),
- VMSTATE_UINT8(reg, LM823KbdState),
- VMSTATE_UINT8(config, LM823KbdState),
- VMSTATE_UINT8(status, LM823KbdState),
- VMSTATE_UINT8(acttime, LM823KbdState),
- VMSTATE_UINT8(error, LM823KbdState),
- VMSTATE_UINT8(clock, LM823KbdState),
- VMSTATE_UINT16(gpio.pull, LM823KbdState),
- VMSTATE_UINT16(gpio.mask, LM823KbdState),
- VMSTATE_UINT16(gpio.dir, LM823KbdState),
- VMSTATE_UINT16(gpio.level, LM823KbdState),
- VMSTATE_UINT8(kbd.dbnctime, LM823KbdState),
- VMSTATE_UINT8(kbd.size, LM823KbdState),
- VMSTATE_UINT8(kbd.start, LM823KbdState),
- VMSTATE_UINT8(kbd.len, LM823KbdState),
- VMSTATE_BUFFER(kbd.fifo, LM823KbdState),
- VMSTATE_UINT16_ARRAY(pwm.file, LM823KbdState, 256),
- VMSTATE_UINT8(pwm.faddr, LM823KbdState),
- VMSTATE_BUFFER(pwm.addr, LM823KbdState),
- VMSTATE_TIMER_PTR_ARRAY(pwm.tm, LM823KbdState, 3),
- VMSTATE_END_OF_LIST()
- }
-};
-
-
-static void lm8323_realize(DeviceState *dev, Error **errp)
-{
- LM823KbdState *s = LM8323(dev);
-
- s->model = 0x8323;
- s->pwm.tm[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, lm_kbd_pwm0_tick, s);
- s->pwm.tm[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, lm_kbd_pwm1_tick, s);
- s->pwm.tm[2] = timer_new_ns(QEMU_CLOCK_VIRTUAL, lm_kbd_pwm2_tick, s);
- qdev_init_gpio_out(dev, &s->nirq, 1);
-}
-
-void lm832x_key_event(DeviceState *dev, int key, int state)
-{
- LM823KbdState *s = LM8323(dev);
-
- if ((s->status & INT_ERROR) && (s->error & ERR_FIFOOVR))
- return;
-
- if (s->kbd.len >= sizeof(s->kbd.fifo)) {
- lm_kbd_error(s, ERR_FIFOOVR);
- return;
- }
-
- s->kbd.fifo[(s->kbd.start + s->kbd.len ++) & (sizeof(s->kbd.fifo) - 1)] =
- key | (state << 7);
-
- /* We never set ERR_KEYOVR because we support multiple keys fine. */
- s->status |= INT_KEYPAD;
- lm_kbd_irq_update(s);
-}
-
-static void lm8323_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
-
- dc->reset = lm_kbd_reset;
- dc->realize = lm8323_realize;
- k->event = lm_i2c_event;
- k->recv = lm_i2c_rx;
- k->send = lm_i2c_tx;
- dc->vmsd = &vmstate_lm_kbd;
-}
-
-static const TypeInfo lm8323_info = {
- .name = TYPE_LM8323,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(LM823KbdState),
- .class_init = lm8323_class_init,
-};
-
-static void lm832x_register_types(void)
-{
- type_register_static(&lm8323_info);
-}
-
-type_init(lm832x_register_types)
diff --git a/hw/input/meson.build b/hw/input/meson.build
index 3cc8ab8..90a2149 100644
--- a/hw/input/meson.build
+++ b/hw/input/meson.build
@@ -1,17 +1,12 @@
system_ss.add(files('hid.c'))
system_ss.add(when: 'CONFIG_ADB', if_true: files('adb.c', 'adb-mouse.c', 'adb-kbd.c'))
-system_ss.add(when: 'CONFIG_ADS7846', if_true: files('ads7846.c'))
-system_ss.add(when: 'CONFIG_LM832X', if_true: files('lm832x.c'))
system_ss.add(when: 'CONFIG_PCKBD', if_true: files('pckbd.c'))
system_ss.add(when: 'CONFIG_PL050', if_true: files('pl050.c'))
system_ss.add(when: 'CONFIG_PS2', if_true: files('ps2.c'))
system_ss.add(when: 'CONFIG_STELLARIS_GAMEPAD', if_true: files('stellaris_gamepad.c'))
-system_ss.add(when: 'CONFIG_TSC2005', if_true: files('tsc2005.c'))
system_ss.add(when: 'CONFIG_VIRTIO_INPUT', if_true: files('virtio-input.c'))
system_ss.add(when: 'CONFIG_VIRTIO_INPUT', if_true: files('virtio-input-hid.c'))
system_ss.add(when: 'CONFIG_VIRTIO_INPUT_HOST', if_true: files('virtio-input-host.c'))
-system_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_keypad.c'))
-system_ss.add(when: 'CONFIG_TSC210X', if_true: files('tsc210x.c'))
system_ss.add(when: 'CONFIG_LASIPS2', if_true: files('lasips2.c'))
diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c
index 74f10b6..04c1b3c 100644
--- a/hw/input/pckbd.c
+++ b/hw/input/pckbd.c
@@ -756,7 +756,7 @@ static void i8042_mmio_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = i8042_mmio_realize;
- dc->reset = i8042_mmio_reset;
+ device_class_set_legacy_reset(dc, i8042_mmio_reset);
dc->vmsd = &vmstate_kbd_mmio;
device_class_set_props(dc, i8042_mmio_properties);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
@@ -947,7 +947,7 @@ static void i8042_class_initfn(ObjectClass *klass, void *data)
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
device_class_set_props(dc, i8042_properties);
- dc->reset = i8042_reset;
+ device_class_set_legacy_reset(dc, i8042_reset);
dc->realize = i8042_realizefn;
dc->vmsd = &vmstate_kbd_isa;
adevc->build_dev_aml = i8042_build_aml;
diff --git a/hw/input/pxa2xx_keypad.c b/hw/input/pxa2xx_keypad.c
deleted file mode 100644
index 3858648..0000000
--- a/hw/input/pxa2xx_keypad.c
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * Intel PXA27X Keypad Controller emulation.
- *
- * Copyright (c) 2007 MontaVista Software, Inc
- * Written by Armin Kuster <akuster@kama-aina.net>
- * or <Akuster@mvista.com>
- *
- * This code is licensed under the GPLv2.
- *
- * 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/log.h"
-#include "hw/irq.h"
-#include "migration/vmstate.h"
-#include "hw/arm/pxa.h"
-#include "ui/console.h"
-
-/*
- * Keypad
- */
-#define KPC 0x00 /* Keypad Interface Control register */
-#define KPDK 0x08 /* Keypad Interface Direct Key register */
-#define KPREC 0x10 /* Keypad Interface Rotary Encoder register */
-#define KPMK 0x18 /* Keypad Interface Matrix Key register */
-#define KPAS 0x20 /* Keypad Interface Automatic Scan register */
-#define KPASMKP0 0x28 /* Keypad Interface Automatic Scan Multiple
- Key Presser register 0 */
-#define KPASMKP1 0x30 /* Keypad Interface Automatic Scan Multiple
- Key Presser register 1 */
-#define KPASMKP2 0x38 /* Keypad Interface Automatic Scan Multiple
- Key Presser register 2 */
-#define KPASMKP3 0x40 /* Keypad Interface Automatic Scan Multiple
- Key Presser register 3 */
-#define KPKDI 0x48 /* Keypad Interface Key Debounce Interval
- register */
-
-/* Keypad defines */
-#define KPC_AS (0x1 << 30) /* Automatic Scan bit */
-#define KPC_ASACT (0x1 << 29) /* Automatic Scan on Activity */
-#define KPC_MI (0x1 << 22) /* Matrix interrupt bit */
-#define KPC_IMKP (0x1 << 21) /* Ignore Multiple Key Press */
-#define KPC_MS7 (0x1 << 20) /* Matrix scan line 7 */
-#define KPC_MS6 (0x1 << 19) /* Matrix scan line 6 */
-#define KPC_MS5 (0x1 << 18) /* Matrix scan line 5 */
-#define KPC_MS4 (0x1 << 17) /* Matrix scan line 4 */
-#define KPC_MS3 (0x1 << 16) /* Matrix scan line 3 */
-#define KPC_MS2 (0x1 << 15) /* Matrix scan line 2 */
-#define KPC_MS1 (0x1 << 14) /* Matrix scan line 1 */
-#define KPC_MS0 (0x1 << 13) /* Matrix scan line 0 */
-#define KPC_ME (0x1 << 12) /* Matrix Keypad Enable */
-#define KPC_MIE (0x1 << 11) /* Matrix Interrupt Enable */
-#define KPC_DK_DEB_SEL (0x1 << 9) /* Direct Keypad Debounce Select */
-#define KPC_DI (0x1 << 5) /* Direct key interrupt bit */
-#define KPC_RE_ZERO_DEB (0x1 << 4) /* Rotary Encoder Zero Debounce */
-#define KPC_REE1 (0x1 << 3) /* Rotary Encoder1 Enable */
-#define KPC_REE0 (0x1 << 2) /* Rotary Encoder0 Enable */
-#define KPC_DE (0x1 << 1) /* Direct Keypad Enable */
-#define KPC_DIE (0x1 << 0) /* Direct Keypad interrupt Enable */
-
-#define KPDK_DKP (0x1 << 31)
-#define KPDK_DK7 (0x1 << 7)
-#define KPDK_DK6 (0x1 << 6)
-#define KPDK_DK5 (0x1 << 5)
-#define KPDK_DK4 (0x1 << 4)
-#define KPDK_DK3 (0x1 << 3)
-#define KPDK_DK2 (0x1 << 2)
-#define KPDK_DK1 (0x1 << 1)
-#define KPDK_DK0 (0x1 << 0)
-
-#define KPREC_OF1 (0x1 << 31)
-#define KPREC_UF1 (0x1 << 30)
-#define KPREC_OF0 (0x1 << 15)
-#define KPREC_UF0 (0x1 << 14)
-
-#define KPMK_MKP (0x1 << 31)
-#define KPAS_SO (0x1 << 31)
-#define KPASMKPx_SO (0x1 << 31)
-
-
-#define KPASMKPx_MKC(row, col) (1 << (row + 16 * (col % 2)))
-
-#define PXAKBD_MAXROW 8
-#define PXAKBD_MAXCOL 8
-
-struct PXA2xxKeyPadState {
- MemoryRegion iomem;
- qemu_irq irq;
- const struct keymap *map;
- int pressed_cnt;
- int alt_code;
-
- uint32_t kpc;
- uint32_t kpdk;
- uint32_t kprec;
- uint32_t kpmk;
- uint32_t kpas;
- uint32_t kpasmkp[4];
- uint32_t kpkdi;
-};
-
-static void pxa27x_keypad_find_pressed_key(PXA2xxKeyPadState *kp, int *row, int *col)
-{
- int i;
- for (i = 0; i < 4; i++)
- {
- *col = i * 2;
- for (*row = 0; *row < 8; (*row)++) {
- if (kp->kpasmkp[i] & (1 << *row))
- return;
- }
- *col = i * 2 + 1;
- for (*row = 0; *row < 8; (*row)++) {
- if (kp->kpasmkp[i] & (1 << (*row + 16)))
- return;
- }
- }
-}
-
-static void pxa27x_keyboard_event (PXA2xxKeyPadState *kp, int keycode)
-{
- int row, col, rel, assert_irq = 0;
- uint32_t val;
-
- if (keycode == 0xe0) {
- kp->alt_code = 1;
- return;
- }
-
- if(!(kp->kpc & KPC_ME)) /* skip if not enabled */
- return;
-
- rel = (keycode & 0x80) ? 1 : 0; /* key release from qemu */
- keycode &= ~0x80; /* strip qemu key release bit */
- if (kp->alt_code) {
- keycode |= 0x80;
- kp->alt_code = 0;
- }
-
- row = kp->map[keycode].row;
- col = kp->map[keycode].column;
- if (row == -1 || col == -1) {
- return;
- }
-
- val = KPASMKPx_MKC(row, col);
- if (rel) {
- if (kp->kpasmkp[col / 2] & val) {
- kp->kpasmkp[col / 2] &= ~val;
- kp->pressed_cnt--;
- assert_irq = 1;
- }
- } else {
- if (!(kp->kpasmkp[col / 2] & val)) {
- kp->kpasmkp[col / 2] |= val;
- kp->pressed_cnt++;
- assert_irq = 1;
- }
- }
- kp->kpas = ((kp->pressed_cnt & 0x1f) << 26) | (0xf << 4) | 0xf;
- if (kp->pressed_cnt == 1) {
- kp->kpas &= ~((0xf << 4) | 0xf);
- if (rel) {
- pxa27x_keypad_find_pressed_key(kp, &row, &col);
- }
- kp->kpas |= ((row & 0xf) << 4) | (col & 0xf);
- }
-
- if (!(kp->kpc & (KPC_AS | KPC_ASACT)))
- assert_irq = 0;
-
- if (assert_irq && (kp->kpc & KPC_MIE)) {
- kp->kpc |= KPC_MI;
- qemu_irq_raise(kp->irq);
- }
-}
-
-static uint64_t pxa2xx_keypad_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque;
- uint32_t tmp;
-
- switch (offset) {
- case KPC:
- tmp = s->kpc;
- if(tmp & KPC_MI)
- s->kpc &= ~(KPC_MI);
- if(tmp & KPC_DI)
- s->kpc &= ~(KPC_DI);
- qemu_irq_lower(s->irq);
- return tmp;
- case KPDK:
- return s->kpdk;
- case KPREC:
- tmp = s->kprec;
- if(tmp & KPREC_OF1)
- s->kprec &= ~(KPREC_OF1);
- if(tmp & KPREC_UF1)
- s->kprec &= ~(KPREC_UF1);
- if(tmp & KPREC_OF0)
- s->kprec &= ~(KPREC_OF0);
- if(tmp & KPREC_UF0)
- s->kprec &= ~(KPREC_UF0);
- return tmp;
- case KPMK:
- tmp = s->kpmk;
- if(tmp & KPMK_MKP)
- s->kpmk &= ~(KPMK_MKP);
- return tmp;
- case KPAS:
- return s->kpas;
- case KPASMKP0:
- return s->kpasmkp[0];
- case KPASMKP1:
- return s->kpasmkp[1];
- case KPASMKP2:
- return s->kpasmkp[2];
- case KPASMKP3:
- return s->kpasmkp[3];
- case KPKDI:
- return s->kpkdi;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad read offset 0x%"HWADDR_PRIx"\n",
- __func__, offset);
- }
-
- return 0;
-}
-
-static void pxa2xx_keypad_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque;
-
- switch (offset) {
- case KPC:
- s->kpc = value;
- if (s->kpc & KPC_AS) {
- s->kpc &= ~(KPC_AS);
- }
- break;
- case KPDK:
- s->kpdk = value;
- break;
- case KPREC:
- s->kprec = value;
- break;
- case KPMK:
- s->kpmk = value;
- break;
- case KPAS:
- s->kpas = value;
- break;
- case KPASMKP0:
- s->kpasmkp[0] = value;
- break;
- case KPASMKP1:
- s->kpasmkp[1] = value;
- break;
- case KPASMKP2:
- s->kpasmkp[2] = value;
- break;
- case KPASMKP3:
- s->kpasmkp[3] = value;
- break;
- case KPKDI:
- s->kpkdi = value;
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: Bad write offset 0x%"HWADDR_PRIx"\n",
- __func__, offset);
- }
-}
-
-static const MemoryRegionOps pxa2xx_keypad_ops = {
- .read = pxa2xx_keypad_read,
- .write = pxa2xx_keypad_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pxa2xx_keypad = {
- .name = "pxa2xx_keypad",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32(kpc, PXA2xxKeyPadState),
- VMSTATE_UINT32(kpdk, PXA2xxKeyPadState),
- VMSTATE_UINT32(kprec, PXA2xxKeyPadState),
- VMSTATE_UINT32(kpmk, PXA2xxKeyPadState),
- VMSTATE_UINT32(kpas, PXA2xxKeyPadState),
- VMSTATE_UINT32_ARRAY(kpasmkp, PXA2xxKeyPadState, 4),
- VMSTATE_UINT32(kpkdi, PXA2xxKeyPadState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-PXA2xxKeyPadState *pxa27x_keypad_init(MemoryRegion *sysmem,
- hwaddr base,
- qemu_irq irq)
-{
- PXA2xxKeyPadState *s;
-
- s = g_new0(PXA2xxKeyPadState, 1);
- s->irq = irq;
-
- memory_region_init_io(&s->iomem, NULL, &pxa2xx_keypad_ops, s,
- "pxa2xx-keypad", 0x00100000);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- vmstate_register(NULL, 0, &vmstate_pxa2xx_keypad, s);
-
- return s;
-}
-
-void pxa27x_register_keypad(PXA2xxKeyPadState *kp,
- const struct keymap *map, int size)
-{
- if(!map || size < 0x80) {
- fprintf(stderr, "%s - No PXA keypad map defined\n", __func__);
- exit(-1);
- }
-
- kp->map = map;
- qemu_add_kbd_event_handler((QEMUPutKBDEvent *) pxa27x_keyboard_event, kp);
-}
diff --git a/hw/input/trace-events b/hw/input/trace-events
index 29001a8..1484625 100644
--- a/hw/input/trace-events
+++ b/hw/input/trace-events
@@ -46,9 +46,6 @@ ps2_mouse_reset(void *opaque) "%p"
hid_kbd_queue_full(void) "queue full"
hid_kbd_queue_empty(void) "queue empty"
-# tsc2005.c
-tsc2005_sense(const char *state) "touchscreen sense %s"
-
# virtio-input.c
virtio_input_queue_full(void) "queue full"
diff --git a/hw/input/tsc2005.c b/hw/input/tsc2005.c
deleted file mode 100644
index 54a15d2..0000000
--- a/hw/input/tsc2005.c
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- * TI TSC2005 emulator.
- *
- * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
- * Copyright (C) 2008 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/log.h"
-#include "qemu/timer.h"
-#include "sysemu/reset.h"
-#include "ui/console.h"
-#include "hw/input/tsc2xxx.h"
-#include "hw/irq.h"
-#include "migration/vmstate.h"
-#include "trace.h"
-
-#define TSC_CUT_RESOLUTION(value, p) ((value) >> (16 - (p ? 12 : 10)))
-
-typedef struct {
- qemu_irq pint; /* Combination of the nPENIRQ and DAV signals */
- QEMUTimer *timer;
- uint16_t model;
-
- int32_t x, y;
- bool pressure;
-
- uint8_t reg, state;
- bool irq, command;
- uint16_t data, dav;
-
- bool busy;
- bool enabled;
- bool host_mode;
- int8_t function;
- int8_t nextfunction;
- bool precision;
- bool nextprecision;
- uint16_t filter;
- uint8_t pin_func;
- uint16_t timing[2];
- uint8_t noise;
- bool reset;
- bool pdst;
- bool pnd0;
- uint16_t temp_thr[2];
- uint16_t aux_thr[2];
-
- int32_t tr[8];
-} TSC2005State;
-
-enum {
- TSC_MODE_XYZ_SCAN = 0x0,
- TSC_MODE_XY_SCAN,
- TSC_MODE_X,
- TSC_MODE_Y,
- TSC_MODE_Z,
- TSC_MODE_AUX,
- TSC_MODE_TEMP1,
- TSC_MODE_TEMP2,
- TSC_MODE_AUX_SCAN,
- TSC_MODE_X_TEST,
- TSC_MODE_Y_TEST,
- TSC_MODE_TS_TEST,
- TSC_MODE_RESERVED,
- TSC_MODE_XX_DRV,
- TSC_MODE_YY_DRV,
- TSC_MODE_YX_DRV,
-};
-
-static const uint16_t mode_regs[16] = {
- 0xf000, /* X, Y, Z scan */
- 0xc000, /* X, Y scan */
- 0x8000, /* X */
- 0x4000, /* Y */
- 0x3000, /* Z */
- 0x0800, /* AUX */
- 0x0400, /* TEMP1 */
- 0x0200, /* TEMP2 */
- 0x0800, /* AUX scan */
- 0x0040, /* X test */
- 0x0020, /* Y test */
- 0x0080, /* Short-circuit test */
- 0x0000, /* Reserved */
- 0x0000, /* X+, X- drivers */
- 0x0000, /* Y+, Y- drivers */
- 0x0000, /* Y+, X- drivers */
-};
-
-#define X_TRANSFORM(s) \
- ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3])
-#define Y_TRANSFORM(s) \
- ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7])
-#define Z1_TRANSFORM(s) \
- ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4)
-#define Z2_TRANSFORM(s) \
- ((4000 + ((s)->y >> 7) - ((s)->pressure << 10)) << 4)
-
-#define AUX_VAL (700 << 4) /* +/- 3 at 12-bit */
-#define TEMP1_VAL (1264 << 4) /* +/- 5 at 12-bit */
-#define TEMP2_VAL (1531 << 4) /* +/- 5 at 12-bit */
-
-static uint16_t tsc2005_read(TSC2005State *s, int reg)
-{
- uint16_t ret;
-
- switch (reg) {
- case 0x0: /* X */
- s->dav &= ~mode_regs[TSC_MODE_X];
- return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) +
- (s->noise & 3);
- case 0x1: /* Y */
- s->dav &= ~mode_regs[TSC_MODE_Y];
- s->noise++;
- return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^
- (s->noise & 3);
- case 0x2: /* Z1 */
- s->dav &= 0xdfff;
- return TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) -
- (s->noise & 3);
- case 0x3: /* Z2 */
- s->dav &= 0xefff;
- return TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) |
- (s->noise & 3);
-
- case 0x4: /* AUX */
- s->dav &= ~mode_regs[TSC_MODE_AUX];
- return TSC_CUT_RESOLUTION(AUX_VAL, s->precision);
-
- case 0x5: /* TEMP1 */
- s->dav &= ~mode_regs[TSC_MODE_TEMP1];
- return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) -
- (s->noise & 5);
- case 0x6: /* TEMP2 */
- s->dav &= 0xdfff;
- s->dav &= ~mode_regs[TSC_MODE_TEMP2];
- return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^
- (s->noise & 3);
-
- case 0x7: /* Status */
- ret = s->dav | (s->reset << 7) | (s->pdst << 2) | 0x0;
- s->dav &= ~(mode_regs[TSC_MODE_X_TEST] | mode_regs[TSC_MODE_Y_TEST] |
- mode_regs[TSC_MODE_TS_TEST]);
- s->reset = true;
- return ret;
-
- case 0x8: /* AUX high threshold */
- return s->aux_thr[1];
- case 0x9: /* AUX low threshold */
- return s->aux_thr[0];
-
- case 0xa: /* TEMP high threshold */
- return s->temp_thr[1];
- case 0xb: /* TEMP low threshold */
- return s->temp_thr[0];
-
- case 0xc: /* CFR0 */
- return (s->pressure << 15) | ((!s->busy) << 14) |
- (s->nextprecision << 13) | s->timing[0];
- case 0xd: /* CFR1 */
- return s->timing[1];
- case 0xe: /* CFR2 */
- return (s->pin_func << 14) | s->filter;
-
- case 0xf: /* Function select status */
- return s->function >= 0 ? 1 << s->function : 0;
- }
-
- /* Never gets here */
- return 0xffff;
-}
-
-static void tsc2005_write(TSC2005State *s, int reg, uint16_t data)
-{
- switch (reg) {
- case 0x8: /* AUX high threshold */
- s->aux_thr[1] = data;
- break;
- case 0x9: /* AUX low threshold */
- s->aux_thr[0] = data;
- break;
-
- case 0xa: /* TEMP high threshold */
- s->temp_thr[1] = data;
- break;
- case 0xb: /* TEMP low threshold */
- s->temp_thr[0] = data;
- break;
-
- case 0xc: /* CFR0 */
- s->host_mode = (data >> 15) != 0;
- if (s->enabled != !(data & 0x4000)) {
- s->enabled = !(data & 0x4000);
- trace_tsc2005_sense(s->enabled ? "enabled" : "disabled");
- if (s->busy && !s->enabled) {
- timer_del(s->timer);
- }
- s->busy = s->busy && s->enabled;
- }
- s->nextprecision = (data >> 13) & 1;
- s->timing[0] = data & 0x1fff;
- if ((s->timing[0] >> 11) == 3) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "tsc2005_write: illegal conversion clock setting\n");
- }
- break;
- case 0xd: /* CFR1 */
- s->timing[1] = data & 0xf07;
- break;
- case 0xe: /* CFR2 */
- s->pin_func = (data >> 14) & 3;
- s->filter = data & 0x3fff;
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: write into read-only register 0x%x\n",
- __func__, reg);
- }
-}
-
-/* This handles most of the chip's logic. */
-static void tsc2005_pin_update(TSC2005State *s)
-{
- int64_t expires;
- bool pin_state;
-
- switch (s->pin_func) {
- case 0:
- pin_state = !s->pressure && !!s->dav;
- break;
- case 1:
- case 3:
- default:
- pin_state = !s->dav;
- break;
- case 2:
- pin_state = !s->pressure;
- }
-
- if (pin_state != s->irq) {
- s->irq = pin_state;
- qemu_set_irq(s->pint, s->irq);
- }
-
- switch (s->nextfunction) {
- case TSC_MODE_XYZ_SCAN:
- case TSC_MODE_XY_SCAN:
- if (!s->host_mode && s->dav) {
- s->enabled = false;
- }
- if (!s->pressure) {
- return;
- }
- /* Fall through */
- case TSC_MODE_AUX_SCAN:
- break;
-
- case TSC_MODE_X:
- case TSC_MODE_Y:
- case TSC_MODE_Z:
- if (!s->pressure) {
- return;
- }
- /* Fall through */
- case TSC_MODE_AUX:
- case TSC_MODE_TEMP1:
- case TSC_MODE_TEMP2:
- case TSC_MODE_X_TEST:
- case TSC_MODE_Y_TEST:
- case TSC_MODE_TS_TEST:
- if (s->dav) {
- s->enabled = false;
- }
- break;
-
- case TSC_MODE_RESERVED:
- case TSC_MODE_XX_DRV:
- case TSC_MODE_YY_DRV:
- case TSC_MODE_YX_DRV:
- default:
- return;
- }
-
- if (!s->enabled || s->busy) {
- return;
- }
-
- s->busy = true;
- s->precision = s->nextprecision;
- s->function = s->nextfunction;
- s->pdst = !s->pnd0; /* Synchronised on internal clock */
- expires = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND >> 7);
- timer_mod(s->timer, expires);
-}
-
-static void tsc2005_reset(TSC2005State *s)
-{
- s->state = 0;
- s->pin_func = 0;
- s->enabled = false;
- s->busy = false;
- s->nextprecision = false;
- s->nextfunction = 0;
- s->timing[0] = 0;
- s->timing[1] = 0;
- s->irq = false;
- s->dav = 0;
- s->reset = false;
- s->pdst = true;
- s->pnd0 = false;
- s->function = -1;
- s->temp_thr[0] = 0x000;
- s->temp_thr[1] = 0xfff;
- s->aux_thr[0] = 0x000;
- s->aux_thr[1] = 0xfff;
-
- tsc2005_pin_update(s);
-}
-
-static uint8_t tsc2005_txrx_word(void *opaque, uint8_t value)
-{
- TSC2005State *s = opaque;
- uint32_t ret = 0;
-
- switch (s->state++) {
- case 0:
- if (value & 0x80) {
- /* Command */
- if (value & (1 << 1))
- tsc2005_reset(s);
- else {
- s->nextfunction = (value >> 3) & 0xf;
- s->nextprecision = (value >> 2) & 1;
- if (s->enabled != !(value & 1)) {
- s->enabled = !(value & 1);
- trace_tsc2005_sense(s->enabled ? "enabled" : "disabled");
- if (s->busy && !s->enabled) {
- timer_del(s->timer);
- }
- s->busy = s->busy && s->enabled;
- }
- tsc2005_pin_update(s);
- }
-
- s->state = 0;
- } else if (value) {
- /* Data transfer */
- s->reg = (value >> 3) & 0xf;
- s->pnd0 = (value >> 1) & 1;
- s->command = value & 1;
-
- if (s->command) {
- /* Read */
- s->data = tsc2005_read(s, s->reg);
- tsc2005_pin_update(s);
- } else
- s->data = 0;
- } else
- s->state = 0;
- break;
-
- case 1:
- if (s->command) {
- ret = (s->data >> 8) & 0xff;
- } else {
- s->data |= value << 8;
- }
- break;
-
- case 2:
- if (s->command)
- ret = s->data & 0xff;
- else {
- s->data |= value;
- tsc2005_write(s, s->reg, s->data);
- tsc2005_pin_update(s);
- }
-
- s->state = 0;
- break;
- }
-
- return ret;
-}
-
-uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len)
-{
- uint32_t ret = 0;
-
- len &= ~7;
- while (len > 0) {
- len -= 8;
- ret |= tsc2005_txrx_word(opaque, (value >> len) & 0xff) << len;
- }
-
- return ret;
-}
-
-static void tsc2005_timer_tick(void *opaque)
-{
- TSC2005State *s = opaque;
- unsigned int function = s->function;
-
- assert(function < ARRAY_SIZE(mode_regs));
-
- /* Timer ticked -- a set of conversions has been finished. */
-
- if (!s->busy) {
- return;
- }
-
- s->busy = false;
- s->dav |= mode_regs[function];
- s->function = -1;
- tsc2005_pin_update(s);
-}
-
-static void tsc2005_touchscreen_event(void *opaque,
- int x, int y, int z, int buttons_state)
-{
- TSC2005State *s = opaque;
- int p = s->pressure;
-
- if (buttons_state) {
- s->x = x;
- s->y = y;
- }
- s->pressure = !!buttons_state;
-
- /*
- * Note: We would get better responsiveness in the guest by
- * signaling TS events immediately, but for now we simulate
- * the first conversion delay for sake of correctness.
- */
- if (p != s->pressure) {
- tsc2005_pin_update(s);
- }
-}
-
-static int tsc2005_post_load(void *opaque, int version_id)
-{
- TSC2005State *s = (TSC2005State *) opaque;
-
- s->busy = timer_pending(s->timer);
- tsc2005_pin_update(s);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_tsc2005 = {
- .name = "tsc2005",
- .version_id = 2,
- .minimum_version_id = 2,
- .post_load = tsc2005_post_load,
- .fields = (const VMStateField []) {
- VMSTATE_BOOL(pressure, TSC2005State),
- VMSTATE_BOOL(irq, TSC2005State),
- VMSTATE_BOOL(command, TSC2005State),
- VMSTATE_BOOL(enabled, TSC2005State),
- VMSTATE_BOOL(host_mode, TSC2005State),
- VMSTATE_BOOL(reset, TSC2005State),
- VMSTATE_BOOL(pdst, TSC2005State),
- VMSTATE_BOOL(pnd0, TSC2005State),
- VMSTATE_BOOL(precision, TSC2005State),
- VMSTATE_BOOL(nextprecision, TSC2005State),
- VMSTATE_UINT8(reg, TSC2005State),
- VMSTATE_UINT8(state, TSC2005State),
- VMSTATE_UINT16(data, TSC2005State),
- VMSTATE_UINT16(dav, TSC2005State),
- VMSTATE_UINT16(filter, TSC2005State),
- VMSTATE_INT8(nextfunction, TSC2005State),
- VMSTATE_INT8(function, TSC2005State),
- VMSTATE_INT32(x, TSC2005State),
- VMSTATE_INT32(y, TSC2005State),
- VMSTATE_TIMER_PTR(timer, TSC2005State),
- VMSTATE_UINT8(pin_func, TSC2005State),
- VMSTATE_UINT16_ARRAY(timing, TSC2005State, 2),
- VMSTATE_UINT8(noise, TSC2005State),
- VMSTATE_UINT16_ARRAY(temp_thr, TSC2005State, 2),
- VMSTATE_UINT16_ARRAY(aux_thr, TSC2005State, 2),
- VMSTATE_INT32_ARRAY(tr, TSC2005State, 8),
- VMSTATE_END_OF_LIST()
- }
-};
-
-void *tsc2005_init(qemu_irq pintdav)
-{
- TSC2005State *s;
-
- s = g_new0(TSC2005State, 1);
- s->x = 400;
- s->y = 240;
- s->pressure = false;
- s->precision = s->nextprecision = false;
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tsc2005_timer_tick, s);
- s->pint = pintdav;
- s->model = 0x2005;
-
- s->tr[0] = 0;
- s->tr[1] = 1;
- s->tr[2] = 1;
- s->tr[3] = 0;
- s->tr[4] = 1;
- s->tr[5] = 0;
- s->tr[6] = 1;
- s->tr[7] = 0;
-
- tsc2005_reset(s);
-
- qemu_add_mouse_event_handler(tsc2005_touchscreen_event, s, 1,
- "QEMU TSC2005-driven Touchscreen");
-
- qemu_register_reset((void *) tsc2005_reset, s);
- vmstate_register(NULL, 0, &vmstate_tsc2005, s);
-
- return s;
-}
-
-/*
- * Use tslib generated calibration data to generate ADC input values
- * from the touchscreen. Assuming 12-bit precision was used during
- * tslib calibration.
- */
-void tsc2005_set_transform(void *opaque, const MouseTransformInfo *info)
-{
- TSC2005State *s = (TSC2005State *) opaque;
-
- /* This version assumes touchscreen X & Y axis are parallel or
- * perpendicular to LCD's X & Y axis in some way. */
- if (abs(info->a[0]) > abs(info->a[1])) {
- s->tr[0] = 0;
- s->tr[1] = -info->a[6] * info->x;
- s->tr[2] = info->a[0];
- s->tr[3] = -info->a[2] / info->a[0];
- s->tr[4] = info->a[6] * info->y;
- s->tr[5] = 0;
- s->tr[6] = info->a[4];
- s->tr[7] = -info->a[5] / info->a[4];
- } else {
- s->tr[0] = info->a[6] * info->y;
- s->tr[1] = 0;
- s->tr[2] = info->a[1];
- s->tr[3] = -info->a[2] / info->a[1];
- s->tr[4] = 0;
- s->tr[5] = -info->a[6] * info->x;
- s->tr[6] = info->a[3];
- s->tr[7] = -info->a[5] / info->a[3];
- }
-
- s->tr[0] >>= 11;
- s->tr[1] >>= 11;
- s->tr[3] <<= 4;
- s->tr[4] >>= 11;
- s->tr[5] >>= 11;
- s->tr[7] <<= 4;
-}
diff --git a/hw/input/tsc210x.c b/hw/input/tsc210x.c
deleted file mode 100644
index c4e32c7..0000000
--- a/hw/input/tsc210x.c
+++ /dev/null
@@ -1,1241 +0,0 @@
-/*
- * TI TSC2102 (touchscreen/sensors/audio controller) emulator.
- * TI TSC2301 (touchscreen/sensors/keypad).
- *
- * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
- * Copyright (C) 2008 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "audio/audio.h"
-#include "qemu/timer.h"
-#include "qemu/log.h"
-#include "sysemu/reset.h"
-#include "ui/console.h"
-#include "hw/arm/omap.h" /* For I2SCodec */
-#include "hw/boards.h" /* for current_machine */
-#include "hw/input/tsc2xxx.h"
-#include "hw/irq.h"
-#include "migration/vmstate.h"
-#include "qapi/error.h"
-
-#define TSC_DATA_REGISTERS_PAGE 0x0
-#define TSC_CONTROL_REGISTERS_PAGE 0x1
-#define TSC_AUDIO_REGISTERS_PAGE 0x2
-
-#define TSC_VERBOSE
-
-#define TSC_CUT_RESOLUTION(value, p) ((value) >> (16 - resolution[p]))
-
-typedef struct {
- qemu_irq pint;
- qemu_irq kbint;
- qemu_irq davint;
- QEMUTimer *timer;
- QEMUSoundCard card;
- uWireSlave chip;
- I2SCodec codec;
- uint8_t in_fifo[16384];
- uint8_t out_fifo[16384];
- uint16_t model;
-
- int32_t x, y;
- bool pressure;
-
- uint8_t page, offset;
- uint16_t dav;
-
- bool state;
- bool irq;
- bool command;
- bool busy;
- bool enabled;
- bool host_mode;
- uint8_t function, nextfunction;
- uint8_t precision, nextprecision;
- uint8_t filter;
- uint8_t pin_func;
- uint8_t ref;
- uint8_t timing;
- uint8_t noise;
-
- uint16_t audio_ctrl1;
- uint16_t audio_ctrl2;
- uint16_t audio_ctrl3;
- uint16_t pll[3];
- uint16_t volume;
- int64_t volume_change;
- bool softstep;
- uint16_t dac_power;
- int64_t powerdown;
- uint16_t filter_data[0x14];
-
- const char *name;
- SWVoiceIn *adc_voice[1];
- SWVoiceOut *dac_voice[1];
- int i2s_rx_rate;
- int i2s_tx_rate;
-
- int tr[8];
-
- struct {
- uint16_t down;
- uint16_t mask;
- int scan;
- int debounce;
- int mode;
- int intr;
- } kb;
- int64_t now; /* Time at migration */
-} TSC210xState;
-
-static const int resolution[4] = { 12, 8, 10, 12 };
-
-#define TSC_MODE_NO_SCAN 0x0
-#define TSC_MODE_XY_SCAN 0x1
-#define TSC_MODE_XYZ_SCAN 0x2
-#define TSC_MODE_X 0x3
-#define TSC_MODE_Y 0x4
-#define TSC_MODE_Z 0x5
-#define TSC_MODE_BAT1 0x6
-#define TSC_MODE_BAT2 0x7
-#define TSC_MODE_AUX 0x8
-#define TSC_MODE_AUX_SCAN 0x9
-#define TSC_MODE_TEMP1 0xa
-#define TSC_MODE_PORT_SCAN 0xb
-#define TSC_MODE_TEMP2 0xc
-#define TSC_MODE_XX_DRV 0xd
-#define TSC_MODE_YY_DRV 0xe
-#define TSC_MODE_YX_DRV 0xf
-
-static const uint16_t mode_regs[16] = {
- 0x0000, /* No scan */
- 0x0600, /* X, Y scan */
- 0x0780, /* X, Y, Z scan */
- 0x0400, /* X */
- 0x0200, /* Y */
- 0x0180, /* Z */
- 0x0040, /* BAT1 */
- 0x0030, /* BAT2 */
- 0x0010, /* AUX */
- 0x0010, /* AUX scan */
- 0x0004, /* TEMP1 */
- 0x0070, /* Port scan */
- 0x0002, /* TEMP2 */
- 0x0000, /* X+, X- drivers */
- 0x0000, /* Y+, Y- drivers */
- 0x0000, /* Y+, X- drivers */
-};
-
-#define X_TRANSFORM(s) \
- ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3])
-#define Y_TRANSFORM(s) \
- ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7])
-#define Z1_TRANSFORM(s) \
- ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4)
-#define Z2_TRANSFORM(s) \
- ((4000 + ((s)->y >> 7) - ((s)->pressure << 10)) << 4)
-
-#define BAT1_VAL 0x8660
-#define BAT2_VAL 0x0000
-#define AUX1_VAL 0x35c0
-#define AUX2_VAL 0xffff
-#define TEMP1_VAL 0x8c70
-#define TEMP2_VAL 0xa5b0
-
-#define TSC_POWEROFF_DELAY 50
-#define TSC_SOFTSTEP_DELAY 50
-
-static void tsc210x_reset(TSC210xState *s)
-{
- s->state = false;
- s->pin_func = 2;
- s->enabled = false;
- s->busy = false;
- s->nextfunction = 0;
- s->ref = 0;
- s->timing = 0;
- s->irq = false;
- s->dav = 0;
-
- s->audio_ctrl1 = 0x0000;
- s->audio_ctrl2 = 0x4410;
- s->audio_ctrl3 = 0x0000;
- s->pll[0] = 0x1004;
- s->pll[1] = 0x0000;
- s->pll[2] = 0x1fff;
- s->volume = 0xffff;
- s->dac_power = 0x8540;
- s->softstep = true;
- s->volume_change = 0;
- s->powerdown = 0;
- s->filter_data[0x00] = 0x6be3;
- s->filter_data[0x01] = 0x9666;
- s->filter_data[0x02] = 0x675d;
- s->filter_data[0x03] = 0x6be3;
- s->filter_data[0x04] = 0x9666;
- s->filter_data[0x05] = 0x675d;
- s->filter_data[0x06] = 0x7d83;
- s->filter_data[0x07] = 0x84ee;
- s->filter_data[0x08] = 0x7d83;
- s->filter_data[0x09] = 0x84ee;
- s->filter_data[0x0a] = 0x6be3;
- s->filter_data[0x0b] = 0x9666;
- s->filter_data[0x0c] = 0x675d;
- s->filter_data[0x0d] = 0x6be3;
- s->filter_data[0x0e] = 0x9666;
- s->filter_data[0x0f] = 0x675d;
- s->filter_data[0x10] = 0x7d83;
- s->filter_data[0x11] = 0x84ee;
- s->filter_data[0x12] = 0x7d83;
- s->filter_data[0x13] = 0x84ee;
-
- s->i2s_tx_rate = 0;
- s->i2s_rx_rate = 0;
-
- s->kb.scan = 1;
- s->kb.debounce = 0;
- s->kb.mask = 0x0000;
- s->kb.mode = 3;
- s->kb.intr = 0;
-
- qemu_set_irq(s->pint, !s->irq);
- qemu_set_irq(s->davint, !s->dav);
- qemu_irq_raise(s->kbint);
-}
-
-typedef struct {
- int rate;
- int dsor;
- int fsref;
-} TSC210xRateInfo;
-
-/* { rate, dsor, fsref } */
-static const TSC210xRateInfo tsc2102_rates[] = {
- /* Fsref / 6.0 */
- { 7350, 63, 1 },
- { 8000, 63, 0 },
- /* Fsref / 6.0 */
- { 7350, 54, 1 },
- { 8000, 54, 0 },
- /* Fsref / 5.0 */
- { 8820, 45, 1 },
- { 9600, 45, 0 },
- /* Fsref / 4.0 */
- { 11025, 36, 1 },
- { 12000, 36, 0 },
- /* Fsref / 3.0 */
- { 14700, 27, 1 },
- { 16000, 27, 0 },
- /* Fsref / 2.0 */
- { 22050, 18, 1 },
- { 24000, 18, 0 },
- /* Fsref / 1.5 */
- { 29400, 9, 1 },
- { 32000, 9, 0 },
- /* Fsref */
- { 44100, 0, 1 },
- { 48000, 0, 0 },
-
- { 0, 0, 0 },
-};
-
-static inline void tsc210x_out_flush(TSC210xState *s, int len)
-{
- uint8_t *data = s->codec.out.fifo + s->codec.out.start;
- uint8_t *end = data + len;
-
- while (data < end)
- data += AUD_write(s->dac_voice[0], data, end - data) ?: (end - data);
-
- s->codec.out.len -= len;
- if (s->codec.out.len)
- memmove(s->codec.out.fifo, end, s->codec.out.len);
- s->codec.out.start = 0;
-}
-
-static void tsc210x_audio_out_cb(TSC210xState *s, int free_b)
-{
- if (s->codec.out.len >= free_b) {
- tsc210x_out_flush(s, free_b);
- return;
- }
-
- s->codec.out.size = MIN(free_b, 16384);
- qemu_irq_raise(s->codec.tx_start);
-}
-
-static void tsc2102_audio_rate_update(TSC210xState *s)
-{
- const TSC210xRateInfo *rate;
-
- s->codec.tx_rate = 0;
- s->codec.rx_rate = 0;
- if (s->dac_power & (1 << 15)) /* PWDNC */
- return;
-
- for (rate = tsc2102_rates; rate->rate; rate ++)
- if (rate->dsor == (s->audio_ctrl1 & 0x3f) && /* DACFS */
- rate->fsref == ((s->audio_ctrl3 >> 13) & 1))/* REFFS */
- break;
- if (!rate->rate) {
- printf("%s: unknown sampling rate configured\n", __func__);
- return;
- }
-
- s->codec.tx_rate = rate->rate;
-}
-
-static void tsc2102_audio_output_update(TSC210xState *s)
-{
- int enable;
- struct audsettings fmt;
-
- if (s->dac_voice[0]) {
- tsc210x_out_flush(s, s->codec.out.len);
- s->codec.out.size = 0;
- AUD_set_active_out(s->dac_voice[0], 0);
- AUD_close_out(&s->card, s->dac_voice[0]);
- s->dac_voice[0] = NULL;
- }
- s->codec.cts = 0;
-
- enable =
- (~s->dac_power & (1 << 15)) && /* PWDNC */
- (~s->dac_power & (1 << 10)); /* DAPWDN */
- if (!enable || !s->codec.tx_rate)
- return;
-
- /* Force our own sampling rate even in slave DAC mode */
- fmt.endianness = 0;
- fmt.nchannels = 2;
- fmt.freq = s->codec.tx_rate;
- fmt.fmt = AUDIO_FORMAT_S16;
-
- s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
- "tsc2102.sink", s, (void *) tsc210x_audio_out_cb, &fmt);
- if (s->dac_voice[0]) {
- s->codec.cts = 1;
- AUD_set_active_out(s->dac_voice[0], 1);
- }
-}
-
-static uint16_t tsc2102_data_register_read(TSC210xState *s, int reg)
-{
- switch (reg) {
- case 0x00: /* X */
- s->dav &= 0xfbff;
- return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) +
- (s->noise & 3);
-
- case 0x01: /* Y */
- s->noise ++;
- s->dav &= 0xfdff;
- return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^
- (s->noise & 3);
-
- case 0x02: /* Z1 */
- s->dav &= 0xfeff;
- return TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) -
- (s->noise & 3);
-
- case 0x03: /* Z2 */
- s->dav &= 0xff7f;
- return TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) |
- (s->noise & 3);
-
- case 0x04: /* KPData */
- if ((s->model & 0xff00) == 0x2300) {
- if (s->kb.intr && (s->kb.mode & 2)) {
- s->kb.intr = 0;
- qemu_irq_raise(s->kbint);
- }
- return s->kb.down;
- }
-
- return 0xffff;
-
- case 0x05: /* BAT1 */
- s->dav &= 0xffbf;
- return TSC_CUT_RESOLUTION(BAT1_VAL, s->precision) +
- (s->noise & 6);
-
- case 0x06: /* BAT2 */
- s->dav &= 0xffdf;
- return TSC_CUT_RESOLUTION(BAT2_VAL, s->precision);
-
- case 0x07: /* AUX1 */
- s->dav &= 0xffef;
- return TSC_CUT_RESOLUTION(AUX1_VAL, s->precision);
-
- case 0x08: /* AUX2 */
- s->dav &= 0xfff7;
- return 0xffff;
-
- case 0x09: /* TEMP1 */
- s->dav &= 0xfffb;
- return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) -
- (s->noise & 5);
-
- case 0x0a: /* TEMP2 */
- s->dav &= 0xfffd;
- return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^
- (s->noise & 3);
-
- case 0x0b: /* DAC */
- s->dav &= 0xfffe;
- return 0xffff;
-
- default:
-#ifdef TSC_VERBOSE
- fprintf(stderr, "tsc2102_data_register_read: "
- "no such register: 0x%02x\n", reg);
-#endif
- return 0xffff;
- }
-}
-
-static uint16_t tsc2102_control_register_read(
- TSC210xState *s, int reg)
-{
- switch (reg) {
- case 0x00: /* TSC ADC */
- return (s->pressure << 15) | ((!s->busy) << 14) |
- (s->nextfunction << 10) | (s->nextprecision << 8) | s->filter;
-
- case 0x01: /* Status / Keypad Control */
- if ((s->model & 0xff00) == 0x2100)
- return (s->pin_func << 14) | ((!s->enabled) << 13) |
- (s->host_mode << 12) | ((!!s->dav) << 11) | s->dav;
- else
- return (s->kb.intr << 15) | ((s->kb.scan || !s->kb.down) << 14) |
- (s->kb.debounce << 11);
-
- case 0x02: /* DAC Control */
- if ((s->model & 0xff00) == 0x2300)
- return s->dac_power & 0x8000;
- else
- goto bad_reg;
-
- case 0x03: /* Reference */
- return s->ref;
-
- case 0x04: /* Reset */
- return 0xffff;
-
- case 0x05: /* Configuration */
- return s->timing;
-
- case 0x06: /* Secondary configuration */
- if ((s->model & 0xff00) == 0x2100)
- goto bad_reg;
- return ((!s->dav) << 15) | ((s->kb.mode & 1) << 14) | s->pll[2];
-
- case 0x10: /* Keypad Mask */
- if ((s->model & 0xff00) == 0x2100)
- goto bad_reg;
- return s->kb.mask;
-
- default:
- bad_reg:
-#ifdef TSC_VERBOSE
- fprintf(stderr, "tsc2102_control_register_read: "
- "no such register: 0x%02x\n", reg);
-#endif
- return 0xffff;
- }
-}
-
-static uint16_t tsc2102_audio_register_read(TSC210xState *s, int reg)
-{
- int l_ch, r_ch;
- uint16_t val;
-
- switch (reg) {
- case 0x00: /* Audio Control 1 */
- return s->audio_ctrl1;
-
- case 0x01:
- return 0xff00;
-
- case 0x02: /* DAC Volume Control */
- return s->volume;
-
- case 0x03:
- return 0x8b00;
-
- case 0x04: /* Audio Control 2 */
- l_ch = 1;
- r_ch = 1;
- if (s->softstep && !(s->dac_power & (1 << 10))) {
- l_ch = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) >
- s->volume_change + TSC_SOFTSTEP_DELAY);
- r_ch = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) >
- s->volume_change + TSC_SOFTSTEP_DELAY);
- }
-
- return s->audio_ctrl2 | (l_ch << 3) | (r_ch << 2);
-
- case 0x05: /* Stereo DAC Power Control */
- return 0x2aa0 | s->dac_power |
- (((s->dac_power & (1 << 10)) &&
- (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) >
- s->powerdown + TSC_POWEROFF_DELAY)) << 6);
-
- case 0x06: /* Audio Control 3 */
- val = s->audio_ctrl3 | 0x0001;
- s->audio_ctrl3 &= 0xff3f;
- return val;
-
- case 0x07: /* LCH_BASS_BOOST_N0 */
- case 0x08: /* LCH_BASS_BOOST_N1 */
- case 0x09: /* LCH_BASS_BOOST_N2 */
- case 0x0a: /* LCH_BASS_BOOST_N3 */
- case 0x0b: /* LCH_BASS_BOOST_N4 */
- case 0x0c: /* LCH_BASS_BOOST_N5 */
- case 0x0d: /* LCH_BASS_BOOST_D1 */
- case 0x0e: /* LCH_BASS_BOOST_D2 */
- case 0x0f: /* LCH_BASS_BOOST_D4 */
- case 0x10: /* LCH_BASS_BOOST_D5 */
- case 0x11: /* RCH_BASS_BOOST_N0 */
- case 0x12: /* RCH_BASS_BOOST_N1 */
- case 0x13: /* RCH_BASS_BOOST_N2 */
- case 0x14: /* RCH_BASS_BOOST_N3 */
- case 0x15: /* RCH_BASS_BOOST_N4 */
- case 0x16: /* RCH_BASS_BOOST_N5 */
- case 0x17: /* RCH_BASS_BOOST_D1 */
- case 0x18: /* RCH_BASS_BOOST_D2 */
- case 0x19: /* RCH_BASS_BOOST_D4 */
- case 0x1a: /* RCH_BASS_BOOST_D5 */
- return s->filter_data[reg - 0x07];
-
- case 0x1b: /* PLL Programmability 1 */
- return s->pll[0];
-
- case 0x1c: /* PLL Programmability 2 */
- return s->pll[1];
-
- case 0x1d: /* Audio Control 4 */
- return (!s->softstep) << 14;
-
- default:
-#ifdef TSC_VERBOSE
- fprintf(stderr, "tsc2102_audio_register_read: "
- "no such register: 0x%02x\n", reg);
-#endif
- return 0xffff;
- }
-}
-
-static void tsc2102_data_register_write(
- TSC210xState *s, int reg, uint16_t value)
-{
- switch (reg) {
- case 0x00: /* X */
- case 0x01: /* Y */
- case 0x02: /* Z1 */
- case 0x03: /* Z2 */
- case 0x05: /* BAT1 */
- case 0x06: /* BAT2 */
- case 0x07: /* AUX1 */
- case 0x08: /* AUX2 */
- case 0x09: /* TEMP1 */
- case 0x0a: /* TEMP2 */
- return;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "tsc2102_data_register_write: "
- "no such register: 0x%02x\n", reg);
- }
-}
-
-static void tsc2102_control_register_write(
- TSC210xState *s, int reg, uint16_t value)
-{
- switch (reg) {
- case 0x00: /* TSC ADC */
- s->host_mode = value >> 15;
- s->enabled = !(value & 0x4000);
- if (s->busy && !s->enabled)
- timer_del(s->timer);
- s->busy = s->busy && s->enabled;
- s->nextfunction = (value >> 10) & 0xf;
- s->nextprecision = (value >> 8) & 3;
- s->filter = value & 0xff;
- return;
-
- case 0x01: /* Status / Keypad Control */
- if ((s->model & 0xff00) == 0x2100)
- s->pin_func = value >> 14;
- else {
- s->kb.scan = (value >> 14) & 1;
- s->kb.debounce = (value >> 11) & 7;
- if (s->kb.intr && s->kb.scan) {
- s->kb.intr = 0;
- qemu_irq_raise(s->kbint);
- }
- }
- return;
-
- case 0x02: /* DAC Control */
- if ((s->model & 0xff00) == 0x2300) {
- s->dac_power &= 0x7fff;
- s->dac_power |= 0x8000 & value;
- } else
- goto bad_reg;
- break;
-
- case 0x03: /* Reference */
- s->ref = value & 0x1f;
- return;
-
- case 0x04: /* Reset */
- if (value == 0xbb00) {
- if (s->busy)
- timer_del(s->timer);
- tsc210x_reset(s);
-#ifdef TSC_VERBOSE
- } else {
- fprintf(stderr, "tsc2102_control_register_write: "
- "wrong value written into RESET\n");
-#endif
- }
- return;
-
- case 0x05: /* Configuration */
- s->timing = value & 0x3f;
-#ifdef TSC_VERBOSE
- if (value & ~0x3f)
- fprintf(stderr, "tsc2102_control_register_write: "
- "wrong value written into CONFIG\n");
-#endif
- return;
-
- case 0x06: /* Secondary configuration */
- if ((s->model & 0xff00) == 0x2100)
- goto bad_reg;
- s->kb.mode = value >> 14;
- s->pll[2] = value & 0x3ffff;
- return;
-
- case 0x10: /* Keypad Mask */
- if ((s->model & 0xff00) == 0x2100)
- goto bad_reg;
- s->kb.mask = value;
- return;
-
- default:
- bad_reg:
- qemu_log_mask(LOG_GUEST_ERROR, "tsc2102_control_register_write: "
- "no such register: 0x%02x\n", reg);
- }
-}
-
-static void tsc2102_audio_register_write(
- TSC210xState *s, int reg, uint16_t value)
-{
- switch (reg) {
- case 0x00: /* Audio Control 1 */
- s->audio_ctrl1 = value & 0x0f3f;
-#ifdef TSC_VERBOSE
- if ((value & ~0x0f3f) || ((value & 7) != ((value >> 3) & 7)))
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into Audio 1\n");
-#endif
- tsc2102_audio_rate_update(s);
- tsc2102_audio_output_update(s);
- return;
-
- case 0x01:
-#ifdef TSC_VERBOSE
- if (value != 0xff00)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into reg 0x01\n");
-#endif
- return;
-
- case 0x02: /* DAC Volume Control */
- s->volume = value;
- s->volume_change = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- return;
-
- case 0x03:
-#ifdef TSC_VERBOSE
- if (value != 0x8b00)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into reg 0x03\n");
-#endif
- return;
-
- case 0x04: /* Audio Control 2 */
- s->audio_ctrl2 = value & 0xf7f2;
-#ifdef TSC_VERBOSE
- if (value & ~0xf7fd)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into Audio 2\n");
-#endif
- return;
-
- case 0x05: /* Stereo DAC Power Control */
- if ((value & ~s->dac_power) & (1 << 10))
- s->powerdown = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- s->dac_power = value & 0x9543;
-#ifdef TSC_VERBOSE
- if ((value & ~0x9543) != 0x2aa0)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into Power\n");
-#endif
- tsc2102_audio_rate_update(s);
- tsc2102_audio_output_update(s);
- return;
-
- case 0x06: /* Audio Control 3 */
- s->audio_ctrl3 &= 0x00c0;
- s->audio_ctrl3 |= value & 0xf800;
-#ifdef TSC_VERBOSE
- if (value & ~0xf8c7)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into Audio 3\n");
-#endif
- tsc2102_audio_output_update(s);
- return;
-
- case 0x07: /* LCH_BASS_BOOST_N0 */
- case 0x08: /* LCH_BASS_BOOST_N1 */
- case 0x09: /* LCH_BASS_BOOST_N2 */
- case 0x0a: /* LCH_BASS_BOOST_N3 */
- case 0x0b: /* LCH_BASS_BOOST_N4 */
- case 0x0c: /* LCH_BASS_BOOST_N5 */
- case 0x0d: /* LCH_BASS_BOOST_D1 */
- case 0x0e: /* LCH_BASS_BOOST_D2 */
- case 0x0f: /* LCH_BASS_BOOST_D4 */
- case 0x10: /* LCH_BASS_BOOST_D5 */
- case 0x11: /* RCH_BASS_BOOST_N0 */
- case 0x12: /* RCH_BASS_BOOST_N1 */
- case 0x13: /* RCH_BASS_BOOST_N2 */
- case 0x14: /* RCH_BASS_BOOST_N3 */
- case 0x15: /* RCH_BASS_BOOST_N4 */
- case 0x16: /* RCH_BASS_BOOST_N5 */
- case 0x17: /* RCH_BASS_BOOST_D1 */
- case 0x18: /* RCH_BASS_BOOST_D2 */
- case 0x19: /* RCH_BASS_BOOST_D4 */
- case 0x1a: /* RCH_BASS_BOOST_D5 */
- s->filter_data[reg - 0x07] = value;
- return;
-
- case 0x1b: /* PLL Programmability 1 */
- s->pll[0] = value & 0xfffc;
-#ifdef TSC_VERBOSE
- if (value & ~0xfffc)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into PLL 1\n");
-#endif
- return;
-
- case 0x1c: /* PLL Programmability 2 */
- s->pll[1] = value & 0xfffc;
-#ifdef TSC_VERBOSE
- if (value & ~0xfffc)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into PLL 2\n");
-#endif
- return;
-
- case 0x1d: /* Audio Control 4 */
- s->softstep = !(value & 0x4000);
-#ifdef TSC_VERBOSE
- if (value & ~0x4000)
- fprintf(stderr, "tsc2102_audio_register_write: "
- "wrong value written into Audio 4\n");
-#endif
- return;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "tsc2102_audio_register_write: "
- "no such register: 0x%02x\n", reg);
- }
-}
-
-/* This handles most of the chip logic. */
-static void tsc210x_pin_update(TSC210xState *s)
-{
- int64_t expires;
- bool pin_state;
-
- switch (s->pin_func) {
- case 0:
- pin_state = s->pressure;
- break;
- case 1:
- pin_state = !!s->dav;
- break;
- case 2:
- default:
- pin_state = s->pressure && !s->dav;
- }
-
- if (!s->enabled)
- pin_state = false;
-
- if (pin_state != s->irq) {
- s->irq = pin_state;
- qemu_set_irq(s->pint, !s->irq);
- }
-
- switch (s->nextfunction) {
- case TSC_MODE_XY_SCAN:
- case TSC_MODE_XYZ_SCAN:
- if (!s->pressure)
- return;
- break;
-
- case TSC_MODE_X:
- case TSC_MODE_Y:
- case TSC_MODE_Z:
- if (!s->pressure)
- return;
- /* Fall through */
- case TSC_MODE_BAT1:
- case TSC_MODE_BAT2:
- case TSC_MODE_AUX:
- case TSC_MODE_TEMP1:
- case TSC_MODE_TEMP2:
- if (s->dav)
- s->enabled = false;
- break;
-
- case TSC_MODE_AUX_SCAN:
- case TSC_MODE_PORT_SCAN:
- break;
-
- case TSC_MODE_NO_SCAN:
- case TSC_MODE_XX_DRV:
- case TSC_MODE_YY_DRV:
- case TSC_MODE_YX_DRV:
- default:
- return;
- }
-
- if (!s->enabled || s->busy || s->dav)
- return;
-
- s->busy = true;
- s->precision = s->nextprecision;
- s->function = s->nextfunction;
- expires = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- (NANOSECONDS_PER_SECOND >> 10);
- timer_mod(s->timer, expires);
-}
-
-static uint16_t tsc210x_read(TSC210xState *s)
-{
- uint16_t ret = 0x0000;
-
- if (!s->command)
- fprintf(stderr, "tsc210x_read: SPI underrun!\n");
-
- switch (s->page) {
- case TSC_DATA_REGISTERS_PAGE:
- ret = tsc2102_data_register_read(s, s->offset);
- if (!s->dav)
- qemu_irq_raise(s->davint);
- break;
- case TSC_CONTROL_REGISTERS_PAGE:
- ret = tsc2102_control_register_read(s, s->offset);
- break;
- case TSC_AUDIO_REGISTERS_PAGE:
- ret = tsc2102_audio_register_read(s, s->offset);
- break;
- default:
- hw_error("tsc210x_read: wrong memory page\n");
- }
-
- tsc210x_pin_update(s);
-
- /* Allow sequential reads. */
- s->offset ++;
- s->state = false;
- return ret;
-}
-
-static void tsc210x_write(TSC210xState *s, uint16_t value)
-{
- /*
- * This is a two-state state machine for reading
- * command and data every second time.
- */
- if (!s->state) {
- s->command = (value >> 15) != 0;
- s->page = (value >> 11) & 0x0f;
- s->offset = (value >> 5) & 0x3f;
- s->state = true;
- } else {
- if (s->command)
- fprintf(stderr, "tsc210x_write: SPI overrun!\n");
- else
- switch (s->page) {
- case TSC_DATA_REGISTERS_PAGE:
- tsc2102_data_register_write(s, s->offset, value);
- break;
- case TSC_CONTROL_REGISTERS_PAGE:
- tsc2102_control_register_write(s, s->offset, value);
- break;
- case TSC_AUDIO_REGISTERS_PAGE:
- tsc2102_audio_register_write(s, s->offset, value);
- break;
- default:
- hw_error("tsc210x_write: wrong memory page\n");
- }
-
- tsc210x_pin_update(s);
- s->state = false;
- }
-}
-
-uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len)
-{
- TSC210xState *s = opaque;
- uint32_t ret = 0;
-
- if (len != 16) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: bad SPI word width %i\n", __func__, len);
- return 0;
- }
-
- /* TODO: sequential reads etc - how do we make sure the host doesn't
- * unintentionally read out a conversion result from a register while
- * transmitting the command word of the next command? */
- if (!value || (s->state && s->command))
- ret = tsc210x_read(s);
- if (value || (s->state && !s->command))
- tsc210x_write(s, value);
-
- return ret;
-}
-
-static void tsc210x_timer_tick(void *opaque)
-{
- TSC210xState *s = opaque;
-
- /* Timer ticked -- a set of conversions has been finished. */
-
- if (!s->busy)
- return;
-
- s->busy = false;
- s->dav |= mode_regs[s->function];
- tsc210x_pin_update(s);
- qemu_irq_lower(s->davint);
-}
-
-static void tsc210x_touchscreen_event(void *opaque,
- int x, int y, int z, int buttons_state)
-{
- TSC210xState *s = opaque;
- int p = s->pressure;
-
- if (buttons_state) {
- s->x = x;
- s->y = y;
- }
- s->pressure = !!buttons_state;
-
- /*
- * Note: We would get better responsiveness in the guest by
- * signaling TS events immediately, but for now we simulate
- * the first conversion delay for sake of correctness.
- */
- if (p != s->pressure)
- tsc210x_pin_update(s);
-}
-
-static void tsc210x_i2s_swallow(TSC210xState *s)
-{
- if (s->dac_voice[0])
- tsc210x_out_flush(s, s->codec.out.len);
- else
- s->codec.out.len = 0;
-}
-
-static void tsc210x_i2s_set_rate(TSC210xState *s, int in, int out)
-{
- s->i2s_tx_rate = out;
- s->i2s_rx_rate = in;
-}
-
-static int tsc210x_pre_save(void *opaque)
-{
- TSC210xState *s = (TSC210xState *) opaque;
- s->now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- return 0;
-}
-
-static int tsc210x_post_load(void *opaque, int version_id)
-{
- TSC210xState *s = (TSC210xState *) opaque;
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- if (s->function >= ARRAY_SIZE(mode_regs)) {
- return -EINVAL;
- }
- if (s->nextfunction >= ARRAY_SIZE(mode_regs)) {
- return -EINVAL;
- }
- if (s->precision >= ARRAY_SIZE(resolution)) {
- return -EINVAL;
- }
- if (s->nextprecision >= ARRAY_SIZE(resolution)) {
- return -EINVAL;
- }
-
- s->volume_change -= s->now;
- s->volume_change += now;
- s->powerdown -= s->now;
- s->powerdown += now;
-
- s->busy = timer_pending(s->timer);
- qemu_set_irq(s->pint, !s->irq);
- qemu_set_irq(s->davint, !s->dav);
-
- return 0;
-}
-
-static const VMStateField vmstatefields_tsc210x[] = {
- VMSTATE_BOOL(enabled, TSC210xState),
- VMSTATE_BOOL(host_mode, TSC210xState),
- VMSTATE_BOOL(irq, TSC210xState),
- VMSTATE_BOOL(command, TSC210xState),
- VMSTATE_BOOL(pressure, TSC210xState),
- VMSTATE_BOOL(softstep, TSC210xState),
- VMSTATE_BOOL(state, TSC210xState),
- VMSTATE_UINT16(dav, TSC210xState),
- VMSTATE_INT32(x, TSC210xState),
- VMSTATE_INT32(y, TSC210xState),
- VMSTATE_UINT8(offset, TSC210xState),
- VMSTATE_UINT8(page, TSC210xState),
- VMSTATE_UINT8(filter, TSC210xState),
- VMSTATE_UINT8(pin_func, TSC210xState),
- VMSTATE_UINT8(ref, TSC210xState),
- VMSTATE_UINT8(timing, TSC210xState),
- VMSTATE_UINT8(noise, TSC210xState),
- VMSTATE_UINT8(function, TSC210xState),
- VMSTATE_UINT8(nextfunction, TSC210xState),
- VMSTATE_UINT8(precision, TSC210xState),
- VMSTATE_UINT8(nextprecision, TSC210xState),
- VMSTATE_UINT16(audio_ctrl1, TSC210xState),
- VMSTATE_UINT16(audio_ctrl2, TSC210xState),
- VMSTATE_UINT16(audio_ctrl3, TSC210xState),
- VMSTATE_UINT16_ARRAY(pll, TSC210xState, 3),
- VMSTATE_UINT16(volume, TSC210xState),
- VMSTATE_UINT16(dac_power, TSC210xState),
- VMSTATE_INT64(volume_change, TSC210xState),
- VMSTATE_INT64(powerdown, TSC210xState),
- VMSTATE_INT64(now, TSC210xState),
- VMSTATE_UINT16_ARRAY(filter_data, TSC210xState, 0x14),
- VMSTATE_TIMER_PTR(timer, TSC210xState),
- VMSTATE_END_OF_LIST()
-};
-
-static const VMStateDescription vmstate_tsc2102 = {
- .name = "tsc2102",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_save = tsc210x_pre_save,
- .post_load = tsc210x_post_load,
- .fields = vmstatefields_tsc210x,
-};
-
-static const VMStateDescription vmstate_tsc2301 = {
- .name = "tsc2301",
- .version_id = 1,
- .minimum_version_id = 1,
- .pre_save = tsc210x_pre_save,
- .post_load = tsc210x_post_load,
- .fields = vmstatefields_tsc210x,
-};
-
-static void tsc210x_init(TSC210xState *s,
- const char *name,
- const VMStateDescription *vmsd)
-{
- s->tr[0] = 0;
- s->tr[1] = 1;
- s->tr[2] = 1;
- s->tr[3] = 0;
- s->tr[4] = 1;
- s->tr[5] = 0;
- s->tr[6] = 1;
- s->tr[7] = 0;
-
- s->chip.opaque = s;
- s->chip.send = (void *) tsc210x_write;
- s->chip.receive = (void *) tsc210x_read;
-
- s->codec.opaque = s;
- s->codec.tx_swallow = (void *) tsc210x_i2s_swallow;
- s->codec.set_rate = (void *) tsc210x_i2s_set_rate;
- s->codec.in.fifo = s->in_fifo;
- s->codec.out.fifo = s->out_fifo;
-
- tsc210x_reset(s);
-
- qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1, name);
-
- if (current_machine->audiodev) {
- s->card.name = g_strdup(current_machine->audiodev);
- s->card.state = audio_state_by_name(s->card.name, &error_fatal);
- }
- AUD_register_card(s->name, &s->card, &error_fatal);
-
- qemu_register_reset((void *) tsc210x_reset, s);
- vmstate_register(NULL, 0, vmsd, s);
-}
-
-uWireSlave *tsc2102_init(qemu_irq pint)
-{
- TSC210xState *s;
-
- s = g_new0(TSC210xState, 1);
- s->x = 160;
- s->y = 160;
- s->pressure = 0;
- s->precision = s->nextprecision = 0;
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tsc210x_timer_tick, s);
- s->pint = pint;
- s->model = 0x2102;
- s->name = "tsc2102";
-
- tsc210x_init(s, "QEMU TSC2102-driven Touchscreen", &vmstate_tsc2102);
-
- return &s->chip;
-}
-
-uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav)
-{
- TSC210xState *s;
-
- s = g_new0(TSC210xState, 1);
- s->x = 400;
- s->y = 240;
- s->pressure = 0;
- s->precision = s->nextprecision = 0;
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tsc210x_timer_tick, s);
- s->pint = penirq;
- s->kbint = kbirq;
- s->davint = dav;
- s->model = 0x2301;
- s->name = "tsc2301";
-
- tsc210x_init(s, "QEMU TSC2301-driven Touchscreen", &vmstate_tsc2301);
-
- return &s->chip;
-}
-
-I2SCodec *tsc210x_codec(uWireSlave *chip)
-{
- TSC210xState *s = (TSC210xState *) chip->opaque;
-
- return &s->codec;
-}
-
-/*
- * Use tslib generated calibration data to generate ADC input values
- * from the touchscreen. Assuming 12-bit precision was used during
- * tslib calibration.
- */
-void tsc210x_set_transform(uWireSlave *chip, const MouseTransformInfo *info)
-{
- TSC210xState *s = (TSC210xState *) chip->opaque;
-#if 0
- int64_t ltr[8];
-
- ltr[0] = (int64_t) info->a[1] * info->y;
- ltr[1] = (int64_t) info->a[4] * info->x;
- ltr[2] = (int64_t) info->a[1] * info->a[3] -
- (int64_t) info->a[4] * info->a[0];
- ltr[3] = (int64_t) info->a[2] * info->a[4] -
- (int64_t) info->a[5] * info->a[1];
- ltr[4] = (int64_t) info->a[0] * info->y;
- ltr[5] = (int64_t) info->a[3] * info->x;
- ltr[6] = (int64_t) info->a[4] * info->a[0] -
- (int64_t) info->a[1] * info->a[3];
- ltr[7] = (int64_t) info->a[2] * info->a[3] -
- (int64_t) info->a[5] * info->a[0];
-
- /* Avoid integer overflow */
- s->tr[0] = ltr[0] >> 11;
- s->tr[1] = ltr[1] >> 11;
- s->tr[2] = muldiv64(ltr[2], 1, info->a[6]);
- s->tr[3] = muldiv64(ltr[3], 1 << 4, ltr[2]);
- s->tr[4] = ltr[4] >> 11;
- s->tr[5] = ltr[5] >> 11;
- s->tr[6] = muldiv64(ltr[6], 1, info->a[6]);
- s->tr[7] = muldiv64(ltr[7], 1 << 4, ltr[6]);
-#else
-
- /* This version assumes touchscreen X & Y axis are parallel or
- * perpendicular to LCD's X & Y axis in some way. */
- if (abs(info->a[0]) > abs(info->a[1])) {
- s->tr[0] = 0;
- s->tr[1] = -info->a[6] * info->x;
- s->tr[2] = info->a[0];
- s->tr[3] = -info->a[2] / info->a[0];
- s->tr[4] = info->a[6] * info->y;
- s->tr[5] = 0;
- s->tr[6] = info->a[4];
- s->tr[7] = -info->a[5] / info->a[4];
- } else {
- s->tr[0] = info->a[6] * info->y;
- s->tr[1] = 0;
- s->tr[2] = info->a[1];
- s->tr[3] = -info->a[2] / info->a[1];
- s->tr[4] = 0;
- s->tr[5] = -info->a[6] * info->x;
- s->tr[6] = info->a[3];
- s->tr[7] = -info->a[5] / info->a[3];
- }
-
- s->tr[0] >>= 11;
- s->tr[1] >>= 11;
- s->tr[3] <<= 4;
- s->tr[4] >>= 11;
- s->tr[5] >>= 11;
- s->tr[7] <<= 4;
-#endif
-}
-
-void tsc210x_key_event(uWireSlave *chip, int key, int down)
-{
- TSC210xState *s = (TSC210xState *) chip->opaque;
-
- if (down)
- s->kb.down |= 1 << key;
- else
- s->kb.down &= ~(1 << key);
-
- if (down && (s->kb.down & ~s->kb.mask) && !s->kb.intr) {
- s->kb.intr = 1;
- qemu_irq_lower(s->kbint);
- } else if (s->kb.intr && !(s->kb.down & ~s->kb.mask) &&
- !(s->kb.mode & 1)) {
- s->kb.intr = 0;
- qemu_irq_raise(s->kbint);
- }
-}
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index 58b6d3a..dd405bd 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -87,8 +87,16 @@ config GOLDFISH_PIC
config M68K_IRQC
bool
+config LOONGSON_IPI_COMMON
+ bool
+
config LOONGSON_IPI
bool
+ select LOONGSON_IPI_COMMON
+
+config LOONGARCH_IPI
+ bool
+ select LOONGSON_IPI_COMMON
config LOONGARCH_PCH_PIC
bool
diff --git a/hw/intc/allwinner-a10-pic.c b/hw/intc/allwinner-a10-pic.c
index cea559c..c0f3009 100644
--- a/hw/intc/allwinner-a10-pic.c
+++ b/hw/intc/allwinner-a10-pic.c
@@ -191,7 +191,7 @@ static void aw_a10_pic_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = aw_a10_pic_reset;
+ device_class_set_legacy_reset(dc, aw_a10_pic_reset);
dc->desc = "allwinner a10 pic";
dc->vmsd = &vmstate_aw_a10_pic;
}
diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c
index c13cdd7..62f3bbf 100644
--- a/hw/intc/apic_common.c
+++ b/hw/intc/apic_common.c
@@ -471,7 +471,7 @@ static void apic_common_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = apic_reset_common;
+ device_class_set_legacy_reset(dc, apic_reset_common);
device_class_set_props(dc, apic_properties_common);
dc->realize = apic_common_realize;
dc->unrealize = apic_common_unrealize;
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
index 8068324..2a48f0d 100644
--- a/hw/intc/arm_gic.c
+++ b/hw/intc/arm_gic.c
@@ -1263,9 +1263,14 @@ static void gic_dist_writeb(void *opaque, hwaddr offset,
trace_gic_enable_irq(irq + i);
}
GIC_DIST_SET_ENABLED(irq + i, cm);
- /* If a raised level triggered IRQ enabled then mark
- is as pending. */
- if (GIC_DIST_TEST_LEVEL(irq + i, mask)
+ /*
+ * If a raised level triggered IRQ enabled then mark
+ * it as pending on 11MPCore. For other GIC revisions we
+ * handle the "level triggered and line asserted" check
+ * at the other end in gic_test_pending().
+ */
+ if (s->revision == REV_11MPCORE
+ && GIC_DIST_TEST_LEVEL(irq + i, mask)
&& !GIC_DIST_TEST_EDGE_TRIGGER(irq + i)) {
DPRINTF("Set %d pending mask %x\n", irq + i, mask);
GIC_DIST_SET_PENDING(irq + i, mask);
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
index bdb13b0..ea1d1b3 100644
--- a/hw/intc/arm_gicv3_cpuif.c
+++ b/hw/intc/arm_gicv3_cpuif.c
@@ -781,7 +781,7 @@ static void icv_activate_irq(GICv3CPUState *cs, int idx, int grp)
if (nmi) {
cs->ich_apr[grp][regno] |= ICV_AP1R_EL1_NMI;
} else {
- cs->ich_apr[grp][regno] |= (1 << regbit);
+ cs->ich_apr[grp][regno] |= (1U << regbit);
}
}
@@ -793,7 +793,7 @@ static void icv_activate_vlpi(GICv3CPUState *cs)
int regno = aprbit / 32;
int regbit = aprbit % 32;
- cs->ich_apr[cs->hppvlpi.grp][regno] |= (1 << regbit);
+ cs->ich_apr[cs->hppvlpi.grp][regno] |= (1U << regbit);
gicv3_redist_vlpi_pending(cs, cs->hppvlpi.irq, 0);
}
@@ -1170,7 +1170,7 @@ static void icc_activate_irq(GICv3CPUState *cs, int irq)
if (nmi) {
cs->icc_apr[cs->hppi.grp][regno] |= ICC_AP1R_EL1_NMI;
} else {
- cs->icc_apr[cs->hppi.grp][regno] |= (1 << regbit);
+ cs->icc_apr[cs->hppi.grp][regno] |= (1U << regbit);
}
if (irq < GIC_INTERNAL) {
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index 404a445..98f3cf5 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -2737,7 +2737,7 @@ static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_nvic;
device_class_set_props(dc, props_nvic);
- dc->reset = armv7m_nvic_reset;
+ device_class_set_legacy_reset(dc, armv7m_nvic_reset);
dc->realize = armv7m_nvic_realize;
}
diff --git a/hw/intc/aspeed_intc.c b/hw/intc/aspeed_intc.c
index 7515558..126b711 100644
--- a/hw/intc/aspeed_intc.c
+++ b/hw/intc/aspeed_intc.c
@@ -322,7 +322,7 @@ static void aspeed_intc_class_init(ObjectClass *klass, void *data)
dc->desc = "ASPEED INTC Controller";
dc->realize = aspeed_intc_realize;
- dc->reset = aspeed_intc_reset;
+ device_class_set_legacy_reset(dc, aspeed_intc_reset);
dc->vmsd = NULL;
}
diff --git a/hw/intc/aspeed_vic.c b/hw/intc/aspeed_vic.c
index ba1d953..55fe51a 100644
--- a/hw/intc/aspeed_vic.c
+++ b/hw/intc/aspeed_vic.c
@@ -343,7 +343,7 @@ static void aspeed_vic_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_vic_realize;
- dc->reset = aspeed_vic_reset;
+ device_class_set_legacy_reset(dc, aspeed_vic_reset);
dc->desc = "ASPEED Interrupt Controller (New)";
dc->vmsd = &vmstate_aspeed_vic;
}
diff --git a/hw/intc/bcm2835_ic.c b/hw/intc/bcm2835_ic.c
index 2c2e2b1..4a42fcf 100644
--- a/hw/intc/bcm2835_ic.c
+++ b/hw/intc/bcm2835_ic.c
@@ -223,7 +223,7 @@ static void bcm2835_ic_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = bcm2835_ic_reset;
+ device_class_set_legacy_reset(dc, bcm2835_ic_reset);
dc->vmsd = &vmstate_bcm2835_ic;
}
diff --git a/hw/intc/bcm2836_control.c b/hw/intc/bcm2836_control.c
index 81faf03..197a0e2 100644
--- a/hw/intc/bcm2836_control.c
+++ b/hw/intc/bcm2836_control.c
@@ -388,7 +388,7 @@ static void bcm2836_control_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = bcm2836_control_reset;
+ device_class_set_legacy_reset(dc, bcm2836_control_reset);
dc->vmsd = &vmstate_bcm2836_control;
}
diff --git a/hw/intc/etraxfs_pic.c b/hw/intc/etraxfs_pic.c
deleted file mode 100644
index bd37d1c..0000000
--- a/hw/intc/etraxfs_pic.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * QEMU ETRAX Interrupt Controller.
- *
- * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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/sysbus.h"
-#include "qemu/module.h"
-#include "hw/irq.h"
-#include "hw/qdev-properties.h"
-#include "qom/object.h"
-
-#define D(x)
-
-#define R_RW_MASK 0
-#define R_R_VECT 1
-#define R_R_MASKED_VECT 2
-#define R_R_NMI 3
-#define R_R_GURU 4
-#define R_MAX 5
-
-#define TYPE_ETRAX_FS_PIC "etraxfs-pic"
-DECLARE_INSTANCE_CHECKER(struct etrax_pic, ETRAX_FS_PIC,
- TYPE_ETRAX_FS_PIC)
-
-struct etrax_pic
-{
- SysBusDevice parent_obj;
-
- MemoryRegion mmio;
- qemu_irq parent_irq;
- qemu_irq parent_nmi;
- uint32_t regs[R_MAX];
-};
-
-static void pic_update(struct etrax_pic *fs)
-{
- uint32_t vector = 0;
- int i;
-
- fs->regs[R_R_MASKED_VECT] = fs->regs[R_R_VECT] & fs->regs[R_RW_MASK];
-
- /* The ETRAX interrupt controller signals interrupts to the core
- through an interrupt request wire and an irq vector bus. If
- multiple interrupts are simultaneously active it chooses vector
- 0x30 and lets the sw choose the priorities. */
- if (fs->regs[R_R_MASKED_VECT]) {
- uint32_t mv = fs->regs[R_R_MASKED_VECT];
- for (i = 0; i < 31; i++) {
- if (mv & 1) {
- vector = 0x31 + i;
- /* Check for multiple interrupts. */
- if (mv > 1)
- vector = 0x30;
- break;
- }
- mv >>= 1;
- }
- }
-
- qemu_set_irq(fs->parent_irq, vector);
-}
-
-static uint64_t
-pic_read(void *opaque, hwaddr addr, unsigned int size)
-{
- struct etrax_pic *fs = opaque;
- uint32_t rval;
-
- rval = fs->regs[addr >> 2];
- D(printf("%s %x=%x\n", __func__, addr, rval));
- return rval;
-}
-
-static void pic_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned int size)
-{
- struct etrax_pic *fs = opaque;
- D(printf("%s addr=%x val=%x\n", __func__, addr, value));
-
- if (addr == R_RW_MASK) {
- fs->regs[R_RW_MASK] = value;
- pic_update(fs);
- }
-}
-
-static const MemoryRegionOps pic_ops = {
- .read = pic_read,
- .write = pic_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4
- }
-};
-
-static void nmi_handler(void *opaque, int irq, int level)
-{
- struct etrax_pic *fs = (void *)opaque;
- uint32_t mask;
-
- mask = 1 << irq;
- if (level)
- fs->regs[R_R_NMI] |= mask;
- else
- fs->regs[R_R_NMI] &= ~mask;
-
- qemu_set_irq(fs->parent_nmi, !!fs->regs[R_R_NMI]);
-}
-
-static void irq_handler(void *opaque, int irq, int level)
-{
- struct etrax_pic *fs = (void *)opaque;
-
- if (irq >= 30) {
- nmi_handler(opaque, irq, level);
- return;
- }
-
- irq -= 1;
- fs->regs[R_R_VECT] &= ~(1 << irq);
- fs->regs[R_R_VECT] |= (!!level << irq);
- pic_update(fs);
-}
-
-static void etraxfs_pic_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- struct etrax_pic *s = ETRAX_FS_PIC(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- qdev_init_gpio_in(dev, irq_handler, 32);
- sysbus_init_irq(sbd, &s->parent_irq);
- sysbus_init_irq(sbd, &s->parent_nmi);
-
- memory_region_init_io(&s->mmio, obj, &pic_ops, s,
- "etraxfs-pic", R_MAX * 4);
- sysbus_init_mmio(sbd, &s->mmio);
-}
-
-static const TypeInfo etraxfs_pic_info = {
- .name = TYPE_ETRAX_FS_PIC,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(struct etrax_pic),
- .instance_init = etraxfs_pic_init,
-};
-
-static void etraxfs_pic_register_types(void)
-{
- type_register_static(&etraxfs_pic_info);
-}
-
-type_init(etraxfs_pic_register_types)
diff --git a/hw/intc/exynos4210_combiner.c b/hw/intc/exynos4210_combiner.c
index f0d310a..afecef1 100644
--- a/hw/intc/exynos4210_combiner.c
+++ b/hw/intc/exynos4210_combiner.c
@@ -334,7 +334,7 @@ static void exynos4210_combiner_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = exynos4210_combiner_reset;
+ device_class_set_legacy_reset(dc, exynos4210_combiner_reset);
device_class_set_props(dc, exynos4210_combiner_properties);
dc->vmsd = &vmstate_exynos4210_combiner;
}
diff --git a/hw/intc/goldfish_pic.c b/hw/intc/goldfish_pic.c
index 6cc1c69..166a3cb 100644
--- a/hw/intc/goldfish_pic.c
+++ b/hw/intc/goldfish_pic.c
@@ -191,7 +191,7 @@ static void goldfish_pic_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(oc);
- dc->reset = goldfish_pic_reset;
+ device_class_set_legacy_reset(dc, goldfish_pic_reset);
dc->realize = goldfish_pic_realize;
dc->vmsd = &vmstate_goldfish_pic;
ic->get_statistics = goldfish_pic_get_statistics;
diff --git a/hw/intc/grlib_irqmp.c b/hw/intc/grlib_irqmp.c
index c6c51a3..37ac63f 100644
--- a/hw/intc/grlib_irqmp.c
+++ b/hw/intc/grlib_irqmp.c
@@ -386,7 +386,7 @@ static void grlib_irqmp_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = grlib_irqmp_realize;
- dc->reset = grlib_irqmp_reset;
+ device_class_set_legacy_reset(dc, grlib_irqmp_reset);
device_class_set_props(dc, grlib_irqmp_properties);
}
diff --git a/hw/intc/heathrow_pic.c b/hw/intc/heathrow_pic.c
index c2946ba..729498f 100644
--- a/hw/intc/heathrow_pic.c
+++ b/hw/intc/heathrow_pic.c
@@ -188,7 +188,7 @@ static void heathrow_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
- dc->reset = heathrow_reset;
+ device_class_set_legacy_reset(dc, heathrow_reset);
dc->vmsd = &vmstate_heathrow;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c
index bbae2d8..d88b20f 100644
--- a/hw/intc/i8259.c
+++ b/hw/intc/i8259.c
@@ -442,7 +442,7 @@ static void i8259_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_parent_realize(dc, pic_realize, &k->parent_realize);
- dc->reset = pic_reset;
+ device_class_set_legacy_reset(dc, pic_reset);
}
static const TypeInfo i8259_info = {
diff --git a/hw/intc/imx_avic.c b/hw/intc/imx_avic.c
index aedc708..e1c9ce7 100644
--- a/hw/intc/imx_avic.c
+++ b/hw/intc/imx_avic.c
@@ -346,7 +346,7 @@ static void imx_avic_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_imx_avic;
- dc->reset = imx_avic_reset;
+ device_class_set_legacy_reset(dc, imx_avic_reset);
dc->desc = "i.MX Advanced Vector Interrupt Controller";
}
diff --git a/hw/intc/imx_gpcv2.c b/hw/intc/imx_gpcv2.c
index af45e51..9e5cf28 100644
--- a/hw/intc/imx_gpcv2.c
+++ b/hw/intc/imx_gpcv2.c
@@ -106,7 +106,7 @@ static void imx_gpcv2_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = imx_gpcv2_reset;
+ device_class_set_legacy_reset(dc, imx_gpcv2_reset);
dc->vmsd = &vmstate_imx_gpcv2;
dc->desc = "i.MX GPCv2 Module";
}
diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
index 716ffc8..e73c8d4 100644
--- a/hw/intc/ioapic.c
+++ b/hw/intc/ioapic.c
@@ -493,7 +493,7 @@ static void ioapic_class_init(ObjectClass *klass, void *data)
* migration, otherwise first 24 gsi routes will be invalid.
*/
k->post_load = ioapic_update_kvm_routes;
- dc->reset = ioapic_reset_common;
+ device_class_set_legacy_reset(dc, ioapic_reset_common);
device_class_set_props(dc, ioapic_properties);
}
diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c
index 1e8e011..02dc4e6 100644
--- a/hw/intc/loongarch_extioi.c
+++ b/hw/intc/loongarch_extioi.c
@@ -440,7 +440,7 @@ static void loongarch_extioi_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = loongarch_extioi_realize;
- dc->reset = loongarch_extioi_reset;
+ device_class_set_legacy_reset(dc, loongarch_extioi_reset);
device_class_set_props(dc, extioi_properties);
dc->vmsd = &vmstate_loongarch_extioi;
}
diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c
new file mode 100644
index 0000000..2ae1a42
--- /dev/null
+++ b/hw/intc/loongarch_ipi.c
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch IPI interrupt support
+ *
+ * Copyright (C) 2024 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "hw/boards.h"
+#include "hw/intc/loongarch_ipi.h"
+#include "target/loongarch/cpu.h"
+
+static AddressSpace *get_iocsr_as(CPUState *cpu)
+{
+ return LOONGARCH_CPU(cpu)->env.address_space_iocsr;
+}
+
+static int archid_cmp(const void *a, const void *b)
+{
+ CPUArchId *archid_a = (CPUArchId *)a;
+ CPUArchId *archid_b = (CPUArchId *)b;
+
+ return archid_a->arch_id - archid_b->arch_id;
+}
+
+static CPUArchId *find_cpu_by_archid(MachineState *ms, uint32_t id)
+{
+ CPUArchId apic_id, *found_cpu;
+
+ apic_id.arch_id = id;
+ found_cpu = bsearch(&apic_id, ms->possible_cpus->cpus,
+ ms->possible_cpus->len,
+ sizeof(*ms->possible_cpus->cpus),
+ archid_cmp);
+
+ return found_cpu;
+}
+
+static CPUState *loongarch_cpu_by_arch_id(int64_t arch_id)
+{
+ MachineState *machine = MACHINE(qdev_get_machine());
+ CPUArchId *archid;
+
+ archid = find_cpu_by_archid(machine, arch_id);
+ if (archid) {
+ return CPU(archid->cpu);
+ }
+
+ return NULL;
+}
+
+static void loongarch_ipi_class_init(ObjectClass *klass, void *data)
+{
+ LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_CLASS(klass);
+
+ licc->get_iocsr_as = get_iocsr_as;
+ licc->cpu_by_arch_id = loongarch_cpu_by_arch_id;
+}
+
+static const TypeInfo loongarch_ipi_types[] = {
+ {
+ .name = TYPE_LOONGARCH_IPI,
+ .parent = TYPE_LOONGSON_IPI_COMMON,
+ .class_init = loongarch_ipi_class_init,
+ }
+};
+
+DEFINE_TYPES(loongarch_ipi_types)
diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c
index 2d5e65a..b958180 100644
--- a/hw/intc/loongarch_pch_pic.c
+++ b/hw/intc/loongarch_pch_pic.c
@@ -442,7 +442,7 @@ static void loongarch_pch_pic_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = loongarch_pch_pic_realize;
- dc->reset = loongarch_pch_pic_reset;
+ device_class_set_legacy_reset(dc, loongarch_pch_pic_reset);
dc->vmsd = &vmstate_loongarch_pch_pic;
device_class_set_props(dc, loongarch_pch_pic_properties);
}
diff --git a/hw/intc/loongson_ipi.c b/hw/intc/loongson_ipi.c
index e6a7142..4e08f03 100644
--- a/hw/intc/loongson_ipi.c
+++ b/hw/intc/loongson_ipi.c
@@ -6,222 +6,17 @@
*/
#include "qemu/osdep.h"
-#include "hw/boards.h"
-#include "hw/sysbus.h"
#include "hw/intc/loongson_ipi.h"
-#include "hw/irq.h"
-#include "hw/qdev-properties.h"
#include "qapi/error.h"
-#include "qemu/log.h"
-#include "exec/address-spaces.h"
-#include "migration/vmstate.h"
-#ifdef TARGET_LOONGARCH64
-#include "target/loongarch/cpu.h"
-#endif
-#ifdef TARGET_MIPS
#include "target/mips/cpu.h"
-#endif
-#include "trace.h"
-static MemTxResult loongson_ipi_core_readl(void *opaque, hwaddr addr,
- uint64_t *data,
- unsigned size, MemTxAttrs attrs)
+static AddressSpace *get_iocsr_as(CPUState *cpu)
{
- IPICore *s = opaque;
- uint64_t ret = 0;
- int index = 0;
-
- addr &= 0xff;
- switch (addr) {
- case CORE_STATUS_OFF:
- ret = s->status;
- break;
- case CORE_EN_OFF:
- ret = s->en;
- break;
- case CORE_SET_OFF:
- ret = 0;
- break;
- case CORE_CLEAR_OFF:
- ret = 0;
- break;
- case CORE_BUF_20 ... CORE_BUF_38 + 4:
- index = (addr - CORE_BUF_20) >> 2;
- ret = s->buf[index];
- break;
- default:
- qemu_log_mask(LOG_UNIMP, "invalid read: %x", (uint32_t)addr);
- break;
- }
-
- trace_loongson_ipi_read(size, (uint64_t)addr, ret);
- *data = ret;
- return MEMTX_OK;
-}
-
-static MemTxResult loongson_ipi_iocsr_readl(void *opaque, hwaddr addr,
- uint64_t *data,
- unsigned size, MemTxAttrs attrs)
-{
- LoongsonIPI *ipi = opaque;
- IPICore *s;
-
- if (attrs.requester_id >= ipi->num_cpu) {
- return MEMTX_DECODE_ERROR;
- }
-
- s = &ipi->cpu[attrs.requester_id];
- return loongson_ipi_core_readl(s, addr, data, size, attrs);
-}
-
-static AddressSpace *get_cpu_iocsr_as(CPUState *cpu)
-{
-#ifdef TARGET_LOONGARCH64
- return LOONGARCH_CPU(cpu)->env.address_space_iocsr;
-#endif
-#ifdef TARGET_MIPS
if (ase_lcsr_available(&MIPS_CPU(cpu)->env)) {
return &MIPS_CPU(cpu)->env.iocsr.as;
}
-#endif
- return NULL;
-}
-
-static MemTxResult send_ipi_data(CPUState *cpu, uint64_t val, hwaddr addr,
- MemTxAttrs attrs)
-{
- int i, mask = 0, data = 0;
- AddressSpace *iocsr_as = get_cpu_iocsr_as(cpu);
-
- if (!iocsr_as) {
- return MEMTX_DECODE_ERROR;
- }
-
- /*
- * bit 27-30 is mask for byte writing,
- * if the mask is 0, we need not to do anything.
- */
- if ((val >> 27) & 0xf) {
- data = address_space_ldl(iocsr_as, addr, attrs, NULL);
- for (i = 0; i < 4; i++) {
- /* get mask for byte writing */
- if (val & (0x1 << (27 + i))) {
- mask |= 0xff << (i * 8);
- }
- }
- }
-
- data &= mask;
- data |= (val >> 32) & ~mask;
- address_space_stl(iocsr_as, addr, data, attrs, NULL);
-
- return MEMTX_OK;
-}
-
-static MemTxResult mail_send(uint64_t val, MemTxAttrs attrs)
-{
- uint32_t cpuid;
- hwaddr addr;
- CPUState *cs;
-
- cpuid = extract32(val, 16, 10);
- cs = cpu_by_arch_id(cpuid);
- if (cs == NULL) {
- return MEMTX_DECODE_ERROR;
- }
-
- /* override requester_id */
- addr = SMP_IPI_MAILBOX + CORE_BUF_20 + (val & 0x1c);
- attrs.requester_id = cs->cpu_index;
- return send_ipi_data(cs, val, addr, attrs);
-}
-
-static MemTxResult any_send(uint64_t val, MemTxAttrs attrs)
-{
- uint32_t cpuid;
- hwaddr addr;
- CPUState *cs;
-
- cpuid = extract32(val, 16, 10);
- cs = cpu_by_arch_id(cpuid);
- if (cs == NULL) {
- return MEMTX_DECODE_ERROR;
- }
-
- /* override requester_id */
- addr = val & 0xffff;
- attrs.requester_id = cs->cpu_index;
- return send_ipi_data(cs, val, addr, attrs);
-}
-
-static MemTxResult loongson_ipi_core_writel(void *opaque, hwaddr addr,
- uint64_t val, unsigned size,
- MemTxAttrs attrs)
-{
- IPICore *s = opaque;
- LoongsonIPI *ipi = s->ipi;
- int index = 0;
- uint32_t cpuid;
- uint8_t vector;
- CPUState *cs;
-
- addr &= 0xff;
- trace_loongson_ipi_write(size, (uint64_t)addr, val);
- switch (addr) {
- case CORE_STATUS_OFF:
- qemu_log_mask(LOG_GUEST_ERROR, "can not be written");
- break;
- case CORE_EN_OFF:
- s->en = val;
- break;
- case CORE_SET_OFF:
- s->status |= val;
- if (s->status != 0 && (s->status & s->en) != 0) {
- qemu_irq_raise(s->irq);
- }
- break;
- case CORE_CLEAR_OFF:
- s->status &= ~val;
- if (s->status == 0 && s->en != 0) {
- qemu_irq_lower(s->irq);
- }
- break;
- case CORE_BUF_20 ... CORE_BUF_38 + 4:
- index = (addr - CORE_BUF_20) >> 2;
- s->buf[index] = val;
- break;
- case IOCSR_IPI_SEND:
- cpuid = extract32(val, 16, 10);
- /* IPI status vector */
- vector = extract8(val, 0, 5);
- cs = cpu_by_arch_id(cpuid);
- if (cs == NULL || cs->cpu_index >= ipi->num_cpu) {
- return MEMTX_DECODE_ERROR;
- }
- loongson_ipi_core_writel(&ipi->cpu[cs->cpu_index], CORE_SET_OFF,
- BIT(vector), 4, attrs);
- break;
- default:
- qemu_log_mask(LOG_UNIMP, "invalid write: %x", (uint32_t)addr);
- break;
- }
-
- return MEMTX_OK;
-}
-
-static MemTxResult loongson_ipi_iocsr_writel(void *opaque, hwaddr addr,
- uint64_t val, unsigned size,
- MemTxAttrs attrs)
-{
- LoongsonIPI *ipi = opaque;
- IPICore *s;
-
- if (attrs.requester_id >= ipi->num_cpu) {
- return MEMTX_DECODE_ERROR;
- }
- s = &ipi->cpu[attrs.requester_id];
- return loongson_ipi_core_writel(s, addr, val, size, attrs);
+ return NULL;
}
static const MemoryRegionOps loongson_ipi_core_ops = {
@@ -234,146 +29,62 @@ static const MemoryRegionOps loongson_ipi_core_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static const MemoryRegionOps loongson_ipi_iocsr_ops = {
- .read_with_attrs = loongson_ipi_iocsr_readl,
- .write_with_attrs = loongson_ipi_iocsr_writel,
- .impl.min_access_size = 4,
- .impl.max_access_size = 4,
- .valid.min_access_size = 4,
- .valid.max_access_size = 8,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-/* mail send and any send only support writeq */
-static MemTxResult loongson_ipi_writeq(void *opaque, hwaddr addr, uint64_t val,
- unsigned size, MemTxAttrs attrs)
-{
- MemTxResult ret = MEMTX_OK;
-
- addr &= 0xfff;
- switch (addr) {
- case MAIL_SEND_OFFSET:
- ret = mail_send(val, attrs);
- break;
- case ANY_SEND_OFFSET:
- ret = any_send(val, attrs);
- break;
- default:
- break;
- }
-
- return ret;
-}
-
-static const MemoryRegionOps loongson_ipi64_ops = {
- .write_with_attrs = loongson_ipi_writeq,
- .impl.min_access_size = 8,
- .impl.max_access_size = 8,
- .valid.min_access_size = 8,
- .valid.max_access_size = 8,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
static void loongson_ipi_realize(DeviceState *dev, Error **errp)
{
- LoongsonIPI *s = LOONGSON_IPI(dev);
+ LoongsonIPICommonState *sc = LOONGSON_IPI_COMMON(dev);
+ LoongsonIPIState *s = LOONGSON_IPI(dev);
+ LoongsonIPIClass *lic = LOONGSON_IPI_GET_CLASS(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- int i;
+ Error *local_err = NULL;
- if (s->num_cpu == 0) {
- error_setg(errp, "num-cpu must be at least 1");
+ lic->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
return;
}
- memory_region_init_io(&s->ipi_iocsr_mem, OBJECT(dev),
- &loongson_ipi_iocsr_ops,
- s, "loongson_ipi_iocsr", 0x48);
-
- /* loongson_ipi_iocsr performs re-entrant IO through ipi_send */
- s->ipi_iocsr_mem.disable_reentrancy_guard = true;
-
- sysbus_init_mmio(sbd, &s->ipi_iocsr_mem);
-
- memory_region_init_io(&s->ipi64_iocsr_mem, OBJECT(dev),
- &loongson_ipi64_ops,
- s, "loongson_ipi64_iocsr", 0x118);
- sysbus_init_mmio(sbd, &s->ipi64_iocsr_mem);
-
- s->cpu = g_new0(IPICore, s->num_cpu);
- if (s->cpu == NULL) {
- error_setg(errp, "Memory allocation for IPICore faile");
- return;
- }
-
- for (i = 0; i < s->num_cpu; i++) {
- s->cpu[i].ipi = s;
- s->cpu[i].ipi_mmio_mem = g_new0(MemoryRegion, 1);
+ s->ipi_mmio_mem = g_new0(MemoryRegion, sc->num_cpu);
+ for (unsigned i = 0; i < sc->num_cpu; i++) {
g_autofree char *name = g_strdup_printf("loongson_ipi_cpu%d_mmio", i);
- memory_region_init_io(s->cpu[i].ipi_mmio_mem, OBJECT(dev),
- &loongson_ipi_core_ops, &s->cpu[i], name, 0x48);
- sysbus_init_mmio(sbd, s->cpu[i].ipi_mmio_mem);
- qdev_init_gpio_out(dev, &s->cpu[i].irq, 1);
+ memory_region_init_io(&s->ipi_mmio_mem[i], OBJECT(dev),
+ &loongson_ipi_core_ops, &sc->cpu[i], name, 0x48);
+ sysbus_init_mmio(sbd, &s->ipi_mmio_mem[i]);
}
}
-static const VMStateDescription vmstate_ipi_core = {
- .name = "ipi-single",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32(status, IPICore),
- VMSTATE_UINT32(en, IPICore),
- VMSTATE_UINT32(set, IPICore),
- VMSTATE_UINT32(clear, IPICore),
- VMSTATE_UINT32_ARRAY(buf, IPICore, IPI_MBX_NUM * 2),
- VMSTATE_END_OF_LIST()
- }
-};
+static void loongson_ipi_unrealize(DeviceState *dev)
+{
+ LoongsonIPIState *s = LOONGSON_IPI(dev);
+ LoongsonIPIClass *k = LOONGSON_IPI_GET_CLASS(dev);
-static const VMStateDescription vmstate_loongson_ipi = {
- .name = TYPE_LOONGSON_IPI,
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (const VMStateField[]) {
- VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, LoongsonIPI, num_cpu,
- vmstate_ipi_core, IPICore),
- VMSTATE_END_OF_LIST()
- }
-};
+ g_free(s->ipi_mmio_mem);
-static Property ipi_properties[] = {
- DEFINE_PROP_UINT32("num-cpu", LoongsonIPI, num_cpu, 1),
- DEFINE_PROP_END_OF_LIST(),
-};
+ k->parent_unrealize(dev);
+}
static void loongson_ipi_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = loongson_ipi_realize;
- device_class_set_props(dc, ipi_properties);
- dc->vmsd = &vmstate_loongson_ipi;
-}
-
-static void loongson_ipi_finalize(Object *obj)
-{
- LoongsonIPI *s = LOONGSON_IPI(obj);
-
- g_free(s->cpu);
+ LoongsonIPIClass *lic = LOONGSON_IPI_CLASS(klass);
+ LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_CLASS(klass);
+
+ device_class_set_parent_realize(dc, loongson_ipi_realize,
+ &lic->parent_realize);
+ device_class_set_parent_unrealize(dc, loongson_ipi_unrealize,
+ &lic->parent_unrealize);
+ licc->get_iocsr_as = get_iocsr_as;
+ licc->cpu_by_arch_id = cpu_by_arch_id;
}
-static const TypeInfo loongson_ipi_info = {
- .name = TYPE_LOONGSON_IPI,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(LoongsonIPI),
- .class_init = loongson_ipi_class_init,
- .instance_finalize = loongson_ipi_finalize,
+static const TypeInfo loongson_ipi_types[] = {
+ {
+ .name = TYPE_LOONGSON_IPI,
+ .parent = TYPE_LOONGSON_IPI_COMMON,
+ .instance_size = sizeof(LoongsonIPIState),
+ .class_size = sizeof(LoongsonIPIClass),
+ .class_init = loongson_ipi_class_init,
+ }
};
-static void loongson_ipi_register_types(void)
-{
- type_register_static(&loongson_ipi_info);
-}
-
-type_init(loongson_ipi_register_types)
+DEFINE_TYPES(loongson_ipi_types)
diff --git a/hw/intc/loongson_ipi_common.c b/hw/intc/loongson_ipi_common.c
new file mode 100644
index 0000000..a6ce018
--- /dev/null
+++ b/hw/intc/loongson_ipi_common.c
@@ -0,0 +1,347 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Loongson IPI interrupt common support
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "hw/sysbus.h"
+#include "hw/intc/loongson_ipi_common.h"
+#include "hw/irq.h"
+#include "hw/qdev-properties.h"
+#include "qapi/error.h"
+#include "qemu/log.h"
+#include "migration/vmstate.h"
+#include "trace.h"
+
+MemTxResult loongson_ipi_core_readl(void *opaque, hwaddr addr, uint64_t *data,
+ unsigned size, MemTxAttrs attrs)
+{
+ IPICore *s = opaque;
+ uint64_t ret = 0;
+ int index = 0;
+
+ addr &= 0xff;
+ switch (addr) {
+ case CORE_STATUS_OFF:
+ ret = s->status;
+ break;
+ case CORE_EN_OFF:
+ ret = s->en;
+ break;
+ case CORE_SET_OFF:
+ ret = 0;
+ break;
+ case CORE_CLEAR_OFF:
+ ret = 0;
+ break;
+ case CORE_BUF_20 ... CORE_BUF_38 + 4:
+ index = (addr - CORE_BUF_20) >> 2;
+ ret = s->buf[index];
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "invalid read: %x", (uint32_t)addr);
+ break;
+ }
+
+ trace_loongson_ipi_read(size, (uint64_t)addr, ret);
+ *data = ret;
+
+ return MEMTX_OK;
+}
+
+static MemTxResult loongson_ipi_iocsr_readl(void *opaque, hwaddr addr,
+ uint64_t *data, unsigned size,
+ MemTxAttrs attrs)
+{
+ LoongsonIPICommonState *ipi = opaque;
+ IPICore *s;
+
+ if (attrs.requester_id >= ipi->num_cpu) {
+ return MEMTX_DECODE_ERROR;
+ }
+
+ s = &ipi->cpu[attrs.requester_id];
+ return loongson_ipi_core_readl(s, addr, data, size, attrs);
+}
+
+static MemTxResult send_ipi_data(LoongsonIPICommonState *ipi, CPUState *cpu,
+ uint64_t val, hwaddr addr, MemTxAttrs attrs)
+{
+ LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(ipi);
+ int i, mask = 0, data = 0;
+ AddressSpace *iocsr_as = licc->get_iocsr_as(cpu);
+
+ if (!iocsr_as) {
+ return MEMTX_DECODE_ERROR;
+ }
+
+ /*
+ * bit 27-30 is mask for byte writing,
+ * if the mask is 0, we need not to do anything.
+ */
+ if ((val >> 27) & 0xf) {
+ data = address_space_ldl_le(iocsr_as, addr, attrs, NULL);
+ for (i = 0; i < 4; i++) {
+ /* get mask for byte writing */
+ if (val & (0x1 << (27 + i))) {
+ mask |= 0xff << (i * 8);
+ }
+ }
+ }
+
+ data &= mask;
+ data |= (val >> 32) & ~mask;
+ address_space_stl_le(iocsr_as, addr, data, attrs, NULL);
+
+ return MEMTX_OK;
+}
+
+static MemTxResult mail_send(LoongsonIPICommonState *ipi,
+ uint64_t val, MemTxAttrs attrs)
+{
+ LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(ipi);
+ uint32_t cpuid;
+ hwaddr addr;
+ CPUState *cs;
+
+ cpuid = extract32(val, 16, 10);
+ cs = licc->cpu_by_arch_id(cpuid);
+ if (cs == NULL) {
+ return MEMTX_DECODE_ERROR;
+ }
+
+ /* override requester_id */
+ addr = SMP_IPI_MAILBOX + CORE_BUF_20 + (val & 0x1c);
+ attrs.requester_id = cs->cpu_index;
+ return send_ipi_data(ipi, cs, val, addr, attrs);
+}
+
+static MemTxResult any_send(LoongsonIPICommonState *ipi,
+ uint64_t val, MemTxAttrs attrs)
+{
+ LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(ipi);
+ uint32_t cpuid;
+ hwaddr addr;
+ CPUState *cs;
+
+ cpuid = extract32(val, 16, 10);
+ cs = licc->cpu_by_arch_id(cpuid);
+ if (cs == NULL) {
+ return MEMTX_DECODE_ERROR;
+ }
+
+ /* override requester_id */
+ addr = val & 0xffff;
+ attrs.requester_id = cs->cpu_index;
+ return send_ipi_data(ipi, cs, val, addr, attrs);
+}
+
+MemTxResult loongson_ipi_core_writel(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size, MemTxAttrs attrs)
+{
+ IPICore *s = opaque;
+ LoongsonIPICommonState *ipi = s->ipi;
+ LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(ipi);
+ int index = 0;
+ uint32_t cpuid;
+ uint8_t vector;
+ CPUState *cs;
+
+ addr &= 0xff;
+ trace_loongson_ipi_write(size, (uint64_t)addr, val);
+ switch (addr) {
+ case CORE_STATUS_OFF:
+ qemu_log_mask(LOG_GUEST_ERROR, "can not be written");
+ break;
+ case CORE_EN_OFF:
+ s->en = val;
+ break;
+ case CORE_SET_OFF:
+ s->status |= val;
+ if (s->status != 0 && (s->status & s->en) != 0) {
+ qemu_irq_raise(s->irq);
+ }
+ break;
+ case CORE_CLEAR_OFF:
+ s->status &= ~val;
+ if (s->status == 0 && s->en != 0) {
+ qemu_irq_lower(s->irq);
+ }
+ break;
+ case CORE_BUF_20 ... CORE_BUF_38 + 4:
+ index = (addr - CORE_BUF_20) >> 2;
+ s->buf[index] = val;
+ break;
+ case IOCSR_IPI_SEND:
+ cpuid = extract32(val, 16, 10);
+ /* IPI status vector */
+ vector = extract8(val, 0, 5);
+ cs = licc->cpu_by_arch_id(cpuid);
+ if (cs == NULL || cs->cpu_index >= ipi->num_cpu) {
+ return MEMTX_DECODE_ERROR;
+ }
+ loongson_ipi_core_writel(&ipi->cpu[cs->cpu_index], CORE_SET_OFF,
+ BIT(vector), 4, attrs);
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "invalid write: %x", (uint32_t)addr);
+ break;
+ }
+
+ return MEMTX_OK;
+}
+
+static MemTxResult loongson_ipi_iocsr_writel(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size,
+ MemTxAttrs attrs)
+{
+ LoongsonIPICommonState *ipi = opaque;
+ IPICore *s;
+
+ if (attrs.requester_id >= ipi->num_cpu) {
+ return MEMTX_DECODE_ERROR;
+ }
+
+ s = &ipi->cpu[attrs.requester_id];
+ return loongson_ipi_core_writel(s, addr, val, size, attrs);
+}
+
+static const MemoryRegionOps loongson_ipi_iocsr_ops = {
+ .read_with_attrs = loongson_ipi_iocsr_readl,
+ .write_with_attrs = loongson_ipi_iocsr_writel,
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 8,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+/* mail send and any send only support writeq */
+static MemTxResult loongson_ipi_writeq(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size, MemTxAttrs attrs)
+{
+ LoongsonIPICommonState *ipi = opaque;
+ MemTxResult ret = MEMTX_OK;
+
+ addr &= 0xfff;
+ switch (addr) {
+ case MAIL_SEND_OFFSET:
+ ret = mail_send(ipi, val, attrs);
+ break;
+ case ANY_SEND_OFFSET:
+ ret = any_send(ipi, val, attrs);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static const MemoryRegionOps loongson_ipi64_ops = {
+ .write_with_attrs = loongson_ipi_writeq,
+ .impl.min_access_size = 8,
+ .impl.max_access_size = 8,
+ .valid.min_access_size = 8,
+ .valid.max_access_size = 8,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void loongson_ipi_common_realize(DeviceState *dev, Error **errp)
+{
+ LoongsonIPICommonState *s = LOONGSON_IPI_COMMON(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ int i;
+
+ if (s->num_cpu == 0) {
+ error_setg(errp, "num-cpu must be at least 1");
+ return;
+ }
+
+ memory_region_init_io(&s->ipi_iocsr_mem, OBJECT(dev),
+ &loongson_ipi_iocsr_ops,
+ s, "loongson_ipi_iocsr", 0x48);
+
+ /* loongson_ipi_iocsr performs re-entrant IO through ipi_send */
+ s->ipi_iocsr_mem.disable_reentrancy_guard = true;
+
+ sysbus_init_mmio(sbd, &s->ipi_iocsr_mem);
+
+ memory_region_init_io(&s->ipi64_iocsr_mem, OBJECT(dev),
+ &loongson_ipi64_ops,
+ s, "loongson_ipi64_iocsr", 0x118);
+ sysbus_init_mmio(sbd, &s->ipi64_iocsr_mem);
+
+ s->cpu = g_new0(IPICore, s->num_cpu);
+ for (i = 0; i < s->num_cpu; i++) {
+ s->cpu[i].ipi = s;
+
+ qdev_init_gpio_out(dev, &s->cpu[i].irq, 1);
+ }
+}
+
+static void loongson_ipi_common_unrealize(DeviceState *dev)
+{
+ LoongsonIPICommonState *s = LOONGSON_IPI_COMMON(dev);
+
+ g_free(s->cpu);
+}
+
+static const VMStateDescription vmstate_ipi_core = {
+ .name = "ipi-single",
+ .version_id = 2,
+ .minimum_version_id = 2,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32(status, IPICore),
+ VMSTATE_UINT32(en, IPICore),
+ VMSTATE_UINT32(set, IPICore),
+ VMSTATE_UINT32(clear, IPICore),
+ VMSTATE_UINT32_ARRAY(buf, IPICore, IPI_MBX_NUM * 2),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_loongson_ipi_common = {
+ .name = "loongson_ipi",
+ .version_id = 2,
+ .minimum_version_id = 2,
+ .fields = (const VMStateField[]) {
+ VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, LoongsonIPICommonState,
+ num_cpu, vmstate_ipi_core,
+ IPICore),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static Property ipi_common_properties[] = {
+ DEFINE_PROP_UINT32("num-cpu", LoongsonIPICommonState, num_cpu, 1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void loongson_ipi_common_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_CLASS(klass);
+
+ device_class_set_parent_realize(dc, loongson_ipi_common_realize,
+ &licc->parent_realize);
+ device_class_set_parent_unrealize(dc, loongson_ipi_common_unrealize,
+ &licc->parent_unrealize);
+ device_class_set_props(dc, ipi_common_properties);
+ dc->vmsd = &vmstate_loongson_ipi_common;
+}
+
+static const TypeInfo loongarch_ipi_common_types[] = {
+ {
+ .name = TYPE_LOONGSON_IPI_COMMON,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(LoongsonIPICommonState),
+ .class_size = sizeof(LoongsonIPICommonClass),
+ .class_init = loongson_ipi_common_class_init,
+ .abstract = true,
+ }
+};
+
+DEFINE_TYPES(loongarch_ipi_common_types)
diff --git a/hw/intc/m68k_irqc.c b/hw/intc/m68k_irqc.c
index cf3beef..b4471e1 100644
--- a/hw/intc/m68k_irqc.c
+++ b/hw/intc/m68k_irqc.c
@@ -99,7 +99,7 @@ static void m68k_irqc_class_init(ObjectClass *oc, void *data)
device_class_set_props(dc, m68k_irqc_properties);
nc->nmi_monitor_handler = m68k_nmi;
- dc->reset = m68k_irqc_reset;
+ device_class_set_legacy_reset(dc, m68k_irqc_reset);
dc->vmsd = &vmstate_m68k_irqc;
ic->get_statistics = m68k_irqc_get_statistics;
ic->print_info = m68k_irqc_print_info;
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index afd1aa5..6bfdc4e 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -15,7 +15,6 @@ system_ss.add(when: 'CONFIG_ARM_GICV3_TCG', if_true: files(
system_ss.add(when: 'CONFIG_ALLWINNER_A10_PIC', if_true: files('allwinner-a10-pic.c'))
system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_vic.c'))
system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_intc.c'))
-system_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_pic.c'))
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_gic.c', 'exynos4210_combiner.c'))
system_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
system_ss.add(when: 'CONFIG_HEATHROW_PIC', if_true: files('heathrow_pic.c'))
@@ -69,7 +68,9 @@ specific_ss.add(when: 'CONFIG_XIVE', if_true: files('xive.c'))
specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'],
if_true: files('spapr_xive_kvm.c'))
specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
+specific_ss.add(when: 'CONFIG_LOONGSON_IPI_COMMON', if_true: files('loongson_ipi_common.c'))
specific_ss.add(when: 'CONFIG_LOONGSON_IPI', if_true: files('loongson_ipi.c'))
+specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c'))
diff --git a/hw/intc/omap_intc.c b/hw/intc/omap_intc.c
index 435c476..a98358d 100644
--- a/hw/intc/omap_intc.c
+++ b/hw/intc/omap_intc.c
@@ -50,8 +50,6 @@ struct OMAPIntcState {
int level_only;
uint32_t size;
- uint8_t revision;
-
/* state */
uint32_t new_agr[2];
int sir_intr[2];
@@ -133,26 +131,6 @@ static void omap_set_intr(void *opaque, int irq, int req)
}
}
-/* Simplified version with no edge detection */
-static void omap_set_intr_noedge(void *opaque, int irq, int req)
-{
- OMAPIntcState *ih = opaque;
- uint32_t rise;
-
- struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
- int n = irq & 31;
-
- if (req) {
- rise = ~bank->inputs & (1 << n);
- if (rise) {
- bank->irqs |= bank->inputs |= rise;
- omap_inth_update(ih, 0);
- omap_inth_update(ih, 1);
- }
- } else
- bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi;
-}
-
static uint64_t omap_inth_read(void *opaque, hwaddr addr,
unsigned size)
{
@@ -406,7 +384,7 @@ static void omap_intc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = omap_inth_reset;
+ device_class_set_legacy_reset(dc, omap_inth_reset);
device_class_set_props(dc, omap_intc_properties);
/* Reason: pointer property "clk" */
dc->user_creatable = false;
@@ -414,277 +392,16 @@ static void omap_intc_class_init(ObjectClass *klass, void *data)
}
static const TypeInfo omap_intc_info = {
- .name = "omap-intc",
- .parent = TYPE_OMAP_INTC,
- .instance_init = omap_intc_init,
- .class_init = omap_intc_class_init,
-};
-
-static uint64_t omap2_inth_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- OMAPIntcState *s = opaque;
- int offset = addr;
- int bank_no, line_no;
- struct omap_intr_handler_bank_s *bank = NULL;
-
- if ((offset & 0xf80) == 0x80) {
- bank_no = (offset & 0x60) >> 5;
- if (bank_no < s->nbanks) {
- offset &= ~0x60;
- bank = &s->bank[bank_no];
- } else {
- OMAP_BAD_REG(addr);
- return 0;
- }
- }
-
- switch (offset) {
- case 0x00: /* INTC_REVISION */
- return s->revision;
-
- case 0x10: /* INTC_SYSCONFIG */
- return (s->autoidle >> 2) & 1;
-
- case 0x14: /* INTC_SYSSTATUS */
- return 1; /* RESETDONE */
-
- case 0x40: /* INTC_SIR_IRQ */
- return s->sir_intr[0];
-
- case 0x44: /* INTC_SIR_FIQ */
- return s->sir_intr[1];
-
- case 0x48: /* INTC_CONTROL */
- return (!s->mask) << 2; /* GLOBALMASK */
-
- case 0x4c: /* INTC_PROTECTION */
- return 0;
-
- case 0x50: /* INTC_IDLE */
- return s->autoidle & 3;
-
- /* Per-bank registers */
- case 0x80: /* INTC_ITR */
- return bank->inputs;
-
- case 0x84: /* INTC_MIR */
- return bank->mask;
-
- case 0x88: /* INTC_MIR_CLEAR */
- case 0x8c: /* INTC_MIR_SET */
- return 0;
-
- case 0x90: /* INTC_ISR_SET */
- return bank->swi;
-
- case 0x94: /* INTC_ISR_CLEAR */
- return 0;
-
- case 0x98: /* INTC_PENDING_IRQ */
- return bank->irqs & ~bank->mask & ~bank->fiq;
-
- case 0x9c: /* INTC_PENDING_FIQ */
- return bank->irqs & ~bank->mask & bank->fiq;
-
- /* Per-line registers */
- case 0x100 ... 0x300: /* INTC_ILR */
- bank_no = (offset - 0x100) >> 7;
- if (bank_no > s->nbanks)
- break;
- bank = &s->bank[bank_no];
- line_no = (offset & 0x7f) >> 2;
- return (bank->priority[line_no] << 2) |
- ((bank->fiq >> line_no) & 1);
- }
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap2_inth_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- OMAPIntcState *s = opaque;
- int offset = addr;
- int bank_no, line_no;
- struct omap_intr_handler_bank_s *bank = NULL;
-
- if ((offset & 0xf80) == 0x80) {
- bank_no = (offset & 0x60) >> 5;
- if (bank_no < s->nbanks) {
- offset &= ~0x60;
- bank = &s->bank[bank_no];
- } else {
- OMAP_BAD_REG(addr);
- return;
- }
- }
-
- switch (offset) {
- case 0x10: /* INTC_SYSCONFIG */
- s->autoidle &= 4;
- s->autoidle |= (value & 1) << 2;
- if (value & 2) { /* SOFTRESET */
- omap_inth_reset(DEVICE(s));
- }
- return;
-
- case 0x48: /* INTC_CONTROL */
- s->mask = (value & 4) ? 0 : ~0; /* GLOBALMASK */
- if (value & 2) { /* NEWFIQAGR */
- qemu_set_irq(s->parent_intr[1], 0);
- s->new_agr[1] = ~0;
- omap_inth_update(s, 1);
- }
- if (value & 1) { /* NEWIRQAGR */
- qemu_set_irq(s->parent_intr[0], 0);
- s->new_agr[0] = ~0;
- omap_inth_update(s, 0);
- }
- return;
-
- case 0x4c: /* INTC_PROTECTION */
- /* TODO: Make a bitmap (or sizeof(char)map) of access privileges
- * for every register, see Chapter 3 and 4 for privileged mode. */
- if (value & 1)
- fprintf(stderr, "%s: protection mode enable attempt\n",
- __func__);
- return;
-
- case 0x50: /* INTC_IDLE */
- s->autoidle &= ~3;
- s->autoidle |= value & 3;
- return;
-
- /* Per-bank registers */
- case 0x84: /* INTC_MIR */
- bank->mask = value;
- omap_inth_update(s, 0);
- omap_inth_update(s, 1);
- return;
-
- case 0x88: /* INTC_MIR_CLEAR */
- bank->mask &= ~value;
- omap_inth_update(s, 0);
- omap_inth_update(s, 1);
- return;
-
- case 0x8c: /* INTC_MIR_SET */
- bank->mask |= value;
- return;
-
- case 0x90: /* INTC_ISR_SET */
- bank->irqs |= bank->swi |= value;
- omap_inth_update(s, 0);
- omap_inth_update(s, 1);
- return;
-
- case 0x94: /* INTC_ISR_CLEAR */
- bank->swi &= ~value;
- bank->irqs = bank->swi & bank->inputs;
- return;
-
- /* Per-line registers */
- case 0x100 ... 0x300: /* INTC_ILR */
- bank_no = (offset - 0x100) >> 7;
- if (bank_no > s->nbanks)
- break;
- bank = &s->bank[bank_no];
- line_no = (offset & 0x7f) >> 2;
- bank->priority[line_no] = (value >> 2) & 0x3f;
- bank->fiq &= ~(1 << line_no);
- bank->fiq |= (value & 1) << line_no;
- return;
-
- case 0x00: /* INTC_REVISION */
- case 0x14: /* INTC_SYSSTATUS */
- case 0x40: /* INTC_SIR_IRQ */
- case 0x44: /* INTC_SIR_FIQ */
- case 0x80: /* INTC_ITR */
- case 0x98: /* INTC_PENDING_IRQ */
- case 0x9c: /* INTC_PENDING_FIQ */
- OMAP_RO_REG(addr);
- return;
- }
- OMAP_BAD_REG(addr);
-}
-
-static const MemoryRegionOps omap2_inth_mem_ops = {
- .read = omap2_inth_read,
- .write = omap2_inth_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static void omap2_intc_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- OMAPIntcState *s = OMAP_INTC(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- s->level_only = 1;
- s->nbanks = 3;
- sysbus_init_irq(sbd, &s->parent_intr[0]);
- sysbus_init_irq(sbd, &s->parent_intr[1]);
- qdev_init_gpio_in(dev, omap_set_intr_noedge, s->nbanks * 32);
- memory_region_init_io(&s->mmio, obj, &omap2_inth_mem_ops, s,
- "omap2-intc", 0x1000);
- sysbus_init_mmio(sbd, &s->mmio);
-}
-
-static void omap2_intc_realize(DeviceState *dev, Error **errp)
-{
- OMAPIntcState *s = OMAP_INTC(dev);
-
- if (!s->iclk) {
- error_setg(errp, "omap2-intc: iclk not connected");
- return;
- }
- if (!s->fclk) {
- error_setg(errp, "omap2-intc: fclk not connected");
- return;
- }
-}
-
-static Property omap2_intc_properties[] = {
- DEFINE_PROP_UINT8("revision", OMAPIntcState,
- revision, 0x21),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void omap2_intc_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->reset = omap_inth_reset;
- device_class_set_props(dc, omap2_intc_properties);
- /* Reason: pointer property "iclk", "fclk" */
- dc->user_creatable = false;
- dc->realize = omap2_intc_realize;
-}
-
-static const TypeInfo omap2_intc_info = {
- .name = "omap2-intc",
- .parent = TYPE_OMAP_INTC,
- .instance_init = omap2_intc_init,
- .class_init = omap2_intc_class_init,
-};
-
-static const TypeInfo omap_intc_type_info = {
.name = TYPE_OMAP_INTC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(OMAPIntcState),
- .abstract = true,
+ .instance_init = omap_intc_init,
+ .class_init = omap_intc_class_init,
};
static void omap_intc_register_types(void)
{
- type_register_static(&omap_intc_type_info);
type_register_static(&omap_intc_info);
- type_register_static(&omap2_intc_info);
}
type_init(omap_intc_register_types)
diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c
index 9792a11..cd3d877 100644
--- a/hw/intc/openpic.c
+++ b/hw/intc/openpic.c
@@ -41,7 +41,6 @@
#include "hw/pci/msi.h"
#include "qapi/error.h"
#include "qemu/bitops.h"
-#include "qapi/qmp/qerror.h"
#include "qemu/module.h"
#include "qemu/timer.h"
#include "qemu/error-report.h"
@@ -1535,9 +1534,7 @@ static void openpic_realize(DeviceState *dev, Error **errp)
};
if (opp->nb_cpus > MAX_CPU) {
- error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
- TYPE_OPENPIC, "nb_cpus", (uint64_t)opp->nb_cpus,
- (uint64_t)0, (uint64_t)MAX_CPU);
+ error_setg(errp, "property 'nb_cpus' can be at most %d", MAX_CPU);
return;
}
@@ -1620,7 +1617,7 @@ static void openpic_class_init(ObjectClass *oc, void *data)
dc->realize = openpic_realize;
device_class_set_props(dc, openpic_properties);
- dc->reset = openpic_reset;
+ device_class_set_legacy_reset(dc, openpic_reset);
dc->vmsd = &vmstate_openpic;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
diff --git a/hw/intc/openpic_kvm.c b/hw/intc/openpic_kvm.c
index 557dd0c..838c6b9 100644
--- a/hw/intc/openpic_kvm.c
+++ b/hw/intc/openpic_kvm.c
@@ -274,7 +274,7 @@ static void kvm_openpic_class_init(ObjectClass *oc, void *data)
dc->realize = kvm_openpic_realize;
device_class_set_props(dc, kvm_openpic_properties);
- dc->reset = kvm_openpic_reset;
+ device_class_set_legacy_reset(dc, kvm_openpic_reset);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
diff --git a/hw/intc/pl190.c b/hw/intc/pl190.c
index d79e5d8..a5e2d76 100644
--- a/hw/intc/pl190.c
+++ b/hw/intc/pl190.c
@@ -277,7 +277,7 @@ static void pl190_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = pl190_reset;
+ device_class_set_legacy_reset(dc, pl190_reset);
dc->vmsd = &vmstate_pl190;
}
diff --git a/hw/intc/pnv_xive2.c b/hw/intc/pnv_xive2.c
index 2fb4fa2..7860910 100644
--- a/hw/intc/pnv_xive2.c
+++ b/hw/intc/pnv_xive2.c
@@ -25,6 +25,7 @@
#include "hw/ppc/ppc.h"
#include "hw/qdev-properties.h"
#include "sysemu/reset.h"
+#include "sysemu/qtest.h"
#include <libfdt.h>
@@ -32,6 +33,16 @@
#undef XIVE2_DEBUG
+/* XIVE Sync or Flush Notification Block */
+typedef struct XiveSfnBlock {
+ uint8_t bytes[32];
+} XiveSfnBlock;
+
+/* XIVE Thread Sync or Flush Notification Area */
+typedef struct XiveThreadNA {
+ XiveSfnBlock topo[16];
+} XiveThreadNA;
+
/*
* Virtual structures table (VST)
*/
@@ -45,16 +56,16 @@ typedef struct XiveVstInfo {
static const XiveVstInfo vst_infos[] = {
- [VST_EAS] = { "EAT", sizeof(Xive2Eas), 16 },
- [VST_ESB] = { "ESB", 1, 16 },
- [VST_END] = { "ENDT", sizeof(Xive2End), 16 },
+ [VST_EAS] = { "EAT", sizeof(Xive2Eas), 16 },
+ [VST_ESB] = { "ESB", 1, 16 },
+ [VST_END] = { "ENDT", sizeof(Xive2End), 16 },
- [VST_NVP] = { "NVPT", sizeof(Xive2Nvp), 16 },
- [VST_NVG] = { "NVGT", sizeof(Xive2Nvgc), 16 },
- [VST_NVC] = { "NVCT", sizeof(Xive2Nvgc), 16 },
+ [VST_NVP] = { "NVPT", sizeof(Xive2Nvp), 16 },
+ [VST_NVG] = { "NVGT", sizeof(Xive2Nvgc), 16 },
+ [VST_NVC] = { "NVCT", sizeof(Xive2Nvgc), 16 },
- [VST_IC] = { "IC", 1 /* ? */ , 16 }, /* Topology # */
- [VST_SYNC] = { "SYNC", 1 /* ? */ , 16 }, /* Topology # */
+ [VST_IC] = { "IC", 1, /* ? */ 16 }, /* Topology # */
+ [VST_SYNC] = { "SYNC", sizeof(XiveThreadNA), 16 }, /* Topology # */
/*
* This table contains the backing store pages for the interrupt
@@ -206,6 +217,20 @@ static uint64_t pnv_xive2_vst_addr_indirect(PnvXive2 *xive, uint32_t type,
return pnv_xive2_vst_addr_direct(xive, type, vsd, (idx % vst_per_page));
}
+static uint8_t pnv_xive2_nvc_table_compress_shift(PnvXive2 *xive)
+{
+ uint8_t shift = GETFIELD(PC_NXC_PROC_CONFIG_NVC_TABLE_COMPRESS,
+ xive->pc_regs[PC_NXC_PROC_CONFIG >> 3]);
+ return shift > 8 ? 0 : shift;
+}
+
+static uint8_t pnv_xive2_nvg_table_compress_shift(PnvXive2 *xive)
+{
+ uint8_t shift = GETFIELD(PC_NXC_PROC_CONFIG_NVG_TABLE_COMPRESS,
+ xive->pc_regs[PC_NXC_PROC_CONFIG >> 3]);
+ return shift > 8 ? 0 : shift;
+}
+
static uint64_t pnv_xive2_vst_addr(PnvXive2 *xive, uint32_t type, uint8_t blk,
uint32_t idx)
{
@@ -219,6 +244,11 @@ static uint64_t pnv_xive2_vst_addr(PnvXive2 *xive, uint32_t type, uint8_t blk,
}
vsd = xive->vsds[type][blk];
+ if (vsd == 0) {
+ xive2_error(xive, "VST: vsd == 0 block id %d for VST %s %d !?",
+ blk, info->name, idx);
+ return 0;
+ }
/* Remote VST access */
if (GETFIELD(VSD_MODE, vsd) == VSD_MODE_FORWARD) {
@@ -227,6 +257,12 @@ static uint64_t pnv_xive2_vst_addr(PnvXive2 *xive, uint32_t type, uint8_t blk,
return xive ? pnv_xive2_vst_addr(xive, type, blk, idx) : 0;
}
+ if (type == VST_NVG) {
+ idx >>= pnv_xive2_nvg_table_compress_shift(xive);
+ } else if (type == VST_NVC) {
+ idx >>= pnv_xive2_nvc_table_compress_shift(xive);
+ }
+
if (VSD_INDIRECT & vsd) {
return pnv_xive2_vst_addr_indirect(xive, type, vsd, idx);
}
@@ -329,40 +365,115 @@ static int pnv_xive2_write_end(Xive2Router *xrtr, uint8_t blk, uint32_t idx,
word_number);
}
-static int pnv_xive2_end_update(PnvXive2 *xive)
+static inline int pnv_xive2_get_current_pir(PnvXive2 *xive)
{
- uint8_t blk = GETFIELD(VC_ENDC_WATCH_BLOCK_ID,
- xive->vc_regs[(VC_ENDC_WATCH0_SPEC >> 3)]);
- uint32_t idx = GETFIELD(VC_ENDC_WATCH_INDEX,
- xive->vc_regs[(VC_ENDC_WATCH0_SPEC >> 3)]);
- int i;
+ if (!qtest_enabled()) {
+ PowerPCCPU *cpu = POWERPC_CPU(current_cpu);
+ return ppc_cpu_pir(cpu);
+ }
+ return 0;
+}
+
+/*
+ * After SW injects a Queue Sync or Cache Flush operation, HW will notify
+ * SW of the completion of the operation by writing a byte of all 1's (0xff)
+ * to a specific memory location. The memory location is calculated by first
+ * looking up a base address in the SYNC VSD using the Topology ID of the
+ * originating thread as the "block" number. This points to a
+ * 64k block of memory that is further divided into 128 512 byte chunks of
+ * memory, which is indexed by the thread id of the requesting thread.
+ * Finally, this 512 byte chunk of memory is divided into 16 32 byte
+ * chunks which are indexed by the topology id of the targeted IC's chip.
+ * The values below are the offsets into that 32 byte chunk of memory for
+ * each type of cache flush or queue sync operation.
+ */
+#define PNV_XIVE2_QUEUE_IPI 0x00
+#define PNV_XIVE2_QUEUE_HW 0x01
+#define PNV_XIVE2_QUEUE_NXC 0x02
+#define PNV_XIVE2_QUEUE_INT 0x03
+#define PNV_XIVE2_QUEUE_OS 0x04
+#define PNV_XIVE2_QUEUE_POOL 0x05
+#define PNV_XIVE2_QUEUE_HARD 0x06
+#define PNV_XIVE2_CACHE_ENDC 0x08
+#define PNV_XIVE2_CACHE_ESBC 0x09
+#define PNV_XIVE2_CACHE_EASC 0x0a
+#define PNV_XIVE2_QUEUE_NXC_LD_LCL_NCO 0x10
+#define PNV_XIVE2_QUEUE_NXC_LD_LCL_CO 0x11
+#define PNV_XIVE2_QUEUE_NXC_ST_LCL_NCI 0x12
+#define PNV_XIVE2_QUEUE_NXC_ST_LCL_CI 0x13
+#define PNV_XIVE2_QUEUE_NXC_ST_RMT_NCI 0x14
+#define PNV_XIVE2_QUEUE_NXC_ST_RMT_CI 0x15
+#define PNV_XIVE2_CACHE_NXC 0x18
+
+static int pnv_xive2_inject_notify(PnvXive2 *xive, int type)
+{
+ uint64_t addr;
+ int pir = pnv_xive2_get_current_pir(xive);
+ int thread_nr = PNV10_PIR2THREAD(pir);
+ int thread_topo_id = PNV10_PIR2CHIP(pir);
+ int ic_topo_id = xive->chip->chip_id;
+ uint64_t offset = ic_topo_id * sizeof(XiveSfnBlock);
+ uint8_t byte = 0xff;
+ MemTxResult result;
+
+ /* Retrieve the address of requesting thread's notification area */
+ addr = pnv_xive2_vst_addr(xive, VST_SYNC, thread_topo_id, thread_nr);
+
+ if (!addr) {
+ xive2_error(xive, "VST: no SYNC entry %x/%x !?",
+ thread_topo_id, thread_nr);
+ return -1;
+ }
+
+ address_space_stb(&address_space_memory, addr + offset + type, byte,
+ MEMTXATTRS_UNSPECIFIED, &result);
+ assert(result == MEMTX_OK);
+
+ return 0;
+}
+
+static int pnv_xive2_end_update(PnvXive2 *xive, uint8_t watch_engine)
+{
+ uint8_t blk;
+ uint32_t idx;
+ int i, spec_reg, data_reg;
uint64_t endc_watch[4];
+ assert(watch_engine < ARRAY_SIZE(endc_watch));
+
+ spec_reg = (VC_ENDC_WATCH0_SPEC + watch_engine * 0x40) >> 3;
+ data_reg = (VC_ENDC_WATCH0_DATA0 + watch_engine * 0x40) >> 3;
+ blk = GETFIELD(VC_ENDC_WATCH_BLOCK_ID, xive->vc_regs[spec_reg]);
+ idx = GETFIELD(VC_ENDC_WATCH_INDEX, xive->vc_regs[spec_reg]);
+
for (i = 0; i < ARRAY_SIZE(endc_watch); i++) {
- endc_watch[i] =
- cpu_to_be64(xive->vc_regs[(VC_ENDC_WATCH0_DATA0 >> 3) + i]);
+ endc_watch[i] = cpu_to_be64(xive->vc_regs[data_reg + i]);
}
return pnv_xive2_vst_write(xive, VST_END, blk, idx, endc_watch,
XIVE_VST_WORD_ALL);
}
-static void pnv_xive2_end_cache_load(PnvXive2 *xive)
+static void pnv_xive2_end_cache_load(PnvXive2 *xive, uint8_t watch_engine)
{
- uint8_t blk = GETFIELD(VC_ENDC_WATCH_BLOCK_ID,
- xive->vc_regs[(VC_ENDC_WATCH0_SPEC >> 3)]);
- uint32_t idx = GETFIELD(VC_ENDC_WATCH_INDEX,
- xive->vc_regs[(VC_ENDC_WATCH0_SPEC >> 3)]);
+ uint8_t blk;
+ uint32_t idx;
uint64_t endc_watch[4] = { 0 };
- int i;
+ int i, spec_reg, data_reg;
+
+ assert(watch_engine < ARRAY_SIZE(endc_watch));
+
+ spec_reg = (VC_ENDC_WATCH0_SPEC + watch_engine * 0x40) >> 3;
+ data_reg = (VC_ENDC_WATCH0_DATA0 + watch_engine * 0x40) >> 3;
+ blk = GETFIELD(VC_ENDC_WATCH_BLOCK_ID, xive->vc_regs[spec_reg]);
+ idx = GETFIELD(VC_ENDC_WATCH_INDEX, xive->vc_regs[spec_reg]);
if (pnv_xive2_vst_read(xive, VST_END, blk, idx, endc_watch)) {
xive2_error(xive, "VST: no END entry %x/%x !?", blk, idx);
}
for (i = 0; i < ARRAY_SIZE(endc_watch); i++) {
- xive->vc_regs[(VC_ENDC_WATCH0_DATA0 >> 3) + i] =
- be64_to_cpu(endc_watch[i]);
+ xive->vc_regs[data_reg + i] = be64_to_cpu(endc_watch[i]);
}
}
@@ -379,40 +490,75 @@ static int pnv_xive2_write_nvp(Xive2Router *xrtr, uint8_t blk, uint32_t idx,
word_number);
}
-static int pnv_xive2_nvp_update(PnvXive2 *xive)
+static int pnv_xive2_nxc_to_table_type(uint8_t nxc_type, uint32_t *table_type)
{
- uint8_t blk = GETFIELD(PC_NXC_WATCH_BLOCK_ID,
- xive->pc_regs[(PC_NXC_WATCH0_SPEC >> 3)]);
- uint32_t idx = GETFIELD(PC_NXC_WATCH_INDEX,
- xive->pc_regs[(PC_NXC_WATCH0_SPEC >> 3)]);
- int i;
+ switch (nxc_type) {
+ case PC_NXC_WATCH_NXC_NVP:
+ *table_type = VST_NVP;
+ break;
+ case PC_NXC_WATCH_NXC_NVG:
+ *table_type = VST_NVG;
+ break;
+ case PC_NXC_WATCH_NXC_NVC:
+ *table_type = VST_NVC;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "XIVE: invalid table type for nxc operation\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int pnv_xive2_nxc_update(PnvXive2 *xive, uint8_t watch_engine)
+{
+ uint8_t blk, nxc_type;
+ uint32_t idx, table_type = -1;
+ int i, spec_reg, data_reg;
uint64_t nxc_watch[4];
+ assert(watch_engine < ARRAY_SIZE(nxc_watch));
+
+ spec_reg = (PC_NXC_WATCH0_SPEC + watch_engine * 0x40) >> 3;
+ data_reg = (PC_NXC_WATCH0_DATA0 + watch_engine * 0x40) >> 3;
+ nxc_type = GETFIELD(PC_NXC_WATCH_NXC_TYPE, xive->pc_regs[spec_reg]);
+ blk = GETFIELD(PC_NXC_WATCH_BLOCK_ID, xive->pc_regs[spec_reg]);
+ idx = GETFIELD(PC_NXC_WATCH_INDEX, xive->pc_regs[spec_reg]);
+
+ assert(!pnv_xive2_nxc_to_table_type(nxc_type, &table_type));
+
for (i = 0; i < ARRAY_SIZE(nxc_watch); i++) {
- nxc_watch[i] =
- cpu_to_be64(xive->pc_regs[(PC_NXC_WATCH0_DATA0 >> 3) + i]);
+ nxc_watch[i] = cpu_to_be64(xive->pc_regs[data_reg + i]);
}
- return pnv_xive2_vst_write(xive, VST_NVP, blk, idx, nxc_watch,
+ return pnv_xive2_vst_write(xive, table_type, blk, idx, nxc_watch,
XIVE_VST_WORD_ALL);
}
-static void pnv_xive2_nvp_cache_load(PnvXive2 *xive)
+static void pnv_xive2_nxc_cache_load(PnvXive2 *xive, uint8_t watch_engine)
{
- uint8_t blk = GETFIELD(PC_NXC_WATCH_BLOCK_ID,
- xive->pc_regs[(PC_NXC_WATCH0_SPEC >> 3)]);
- uint32_t idx = GETFIELD(PC_NXC_WATCH_INDEX,
- xive->pc_regs[(PC_NXC_WATCH0_SPEC >> 3)]);
+ uint8_t blk, nxc_type;
+ uint32_t idx, table_type = -1;
uint64_t nxc_watch[4] = { 0 };
- int i;
+ int i, spec_reg, data_reg;
+
+ assert(watch_engine < ARRAY_SIZE(nxc_watch));
+
+ spec_reg = (PC_NXC_WATCH0_SPEC + watch_engine * 0x40) >> 3;
+ data_reg = (PC_NXC_WATCH0_DATA0 + watch_engine * 0x40) >> 3;
+ nxc_type = GETFIELD(PC_NXC_WATCH_NXC_TYPE, xive->pc_regs[spec_reg]);
+ blk = GETFIELD(PC_NXC_WATCH_BLOCK_ID, xive->pc_regs[spec_reg]);
+ idx = GETFIELD(PC_NXC_WATCH_INDEX, xive->pc_regs[spec_reg]);
- if (pnv_xive2_vst_read(xive, VST_NVP, blk, idx, nxc_watch)) {
- xive2_error(xive, "VST: no NVP entry %x/%x !?", blk, idx);
+ assert(!pnv_xive2_nxc_to_table_type(nxc_type, &table_type));
+
+ if (pnv_xive2_vst_read(xive, table_type, blk, idx, nxc_watch)) {
+ xive2_error(xive, "VST: no NXC entry %x/%x in %s table!?",
+ blk, idx, vst_infos[table_type].name);
}
for (i = 0; i < ARRAY_SIZE(nxc_watch); i++) {
- xive->pc_regs[(PC_NXC_WATCH0_DATA0 >> 3) + i] =
- be64_to_cpu(nxc_watch[i]);
+ xive->pc_regs[data_reg + i] = be64_to_cpu(nxc_watch[i]);
}
}
@@ -581,6 +727,7 @@ static int pnv_xive2_stt_set_data(PnvXive2 *xive, uint64_t val)
case CQ_TAR_NVPG:
case CQ_TAR_ESB:
case CQ_TAR_END:
+ case CQ_TAR_NVC:
xive->tables[tsel][entry] = val;
break;
default:
@@ -641,6 +788,9 @@ static void pnv_xive2_vst_set_exclusive(PnvXive2 *xive, uint8_t type,
* entries provisioned by FW (such as skiboot) and resize the
* ESB window accordingly.
*/
+ if (memory_region_is_mapped(&xsrc->esb_mmio)) {
+ memory_region_del_subregion(&xive->esb_mmio, &xsrc->esb_mmio);
+ }
if (!(VSD_INDIRECT & vsd)) {
memory_region_set_size(&xsrc->esb_mmio, vst_tsize * SBE_PER_BYTE
* (1ull << xsrc->esb_shift));
@@ -656,6 +806,9 @@ static void pnv_xive2_vst_set_exclusive(PnvXive2 *xive, uint8_t type,
/*
* Backing store pages for the END.
*/
+ if (memory_region_is_mapped(&end_xsrc->esb_mmio)) {
+ memory_region_del_subregion(&xive->end_mmio, &end_xsrc->esb_mmio);
+ }
if (!(VSD_INDIRECT & vsd)) {
memory_region_set_size(&end_xsrc->esb_mmio, (vst_tsize / info->size)
* (1ull << end_xsrc->esb_shift));
@@ -680,13 +833,10 @@ static void pnv_xive2_vst_set_exclusive(PnvXive2 *xive, uint8_t type,
* Both PC and VC sub-engines are configured as each use the Virtual
* Structure Tables
*/
-static void pnv_xive2_vst_set_data(PnvXive2 *xive, uint64_t vsd)
+static void pnv_xive2_vst_set_data(PnvXive2 *xive, uint64_t vsd,
+ uint8_t type, uint8_t blk)
{
uint8_t mode = GETFIELD(VSD_MODE, vsd);
- uint8_t type = GETFIELD(VC_VSD_TABLE_SELECT,
- xive->vc_regs[VC_VSD_TABLE_ADDR >> 3]);
- uint8_t blk = GETFIELD(VC_VSD_TABLE_ADDRESS,
- xive->vc_regs[VC_VSD_TABLE_ADDR >> 3]);
uint64_t vst_addr = vsd & VSD_ADDRESS_MASK;
if (type > VST_ERQ) {
@@ -721,6 +871,16 @@ static void pnv_xive2_vst_set_data(PnvXive2 *xive, uint64_t vsd)
}
}
+static void pnv_xive2_vc_vst_set_data(PnvXive2 *xive, uint64_t vsd)
+{
+ uint8_t type = GETFIELD(VC_VSD_TABLE_SELECT,
+ xive->vc_regs[VC_VSD_TABLE_ADDR >> 3]);
+ uint8_t blk = GETFIELD(VC_VSD_TABLE_ADDRESS,
+ xive->vc_regs[VC_VSD_TABLE_ADDR >> 3]);
+
+ pnv_xive2_vst_set_data(xive, vsd, type, blk);
+}
+
/*
* MMIO handlers
*/
@@ -964,12 +1124,70 @@ static const MemoryRegionOps pnv_xive2_ic_cq_ops = {
},
};
+static uint8_t pnv_xive2_cache_watch_assign(uint64_t engine_mask,
+ uint64_t *state)
+{
+ uint8_t val = 0xFF;
+ int i;
+
+ for (i = 3; i >= 0; i--) {
+ if (BIT(i) & engine_mask) {
+ if (!(BIT(i) & *state)) {
+ *state |= BIT(i);
+ val = 3 - i;
+ break;
+ }
+ }
+ }
+ return val;
+}
+
+static void pnv_xive2_cache_watch_release(uint64_t *state, uint8_t watch_engine)
+{
+ uint8_t engine_bit = 3 - watch_engine;
+
+ if (*state & BIT(engine_bit)) {
+ *state &= ~BIT(engine_bit);
+ }
+}
+
+static uint8_t pnv_xive2_endc_cache_watch_assign(PnvXive2 *xive)
+{
+ uint64_t engine_mask = GETFIELD(VC_ENDC_CFG_CACHE_WATCH_ASSIGN,
+ xive->vc_regs[VC_ENDC_CFG >> 3]);
+ uint64_t state = xive->vc_regs[VC_ENDC_WATCH_ASSIGN >> 3];
+ uint8_t val;
+
+ /*
+ * We keep track of which engines are currently busy in the
+ * VC_ENDC_WATCH_ASSIGN register directly. When the firmware reads
+ * the register, we don't return its value but the ID of an engine
+ * it can use.
+ * There are 4 engines. 0xFF means no engine is available.
+ */
+ val = pnv_xive2_cache_watch_assign(engine_mask, &state);
+ if (val != 0xFF) {
+ xive->vc_regs[VC_ENDC_WATCH_ASSIGN >> 3] = state;
+ }
+ return val;
+}
+
+static void pnv_xive2_endc_cache_watch_release(PnvXive2 *xive,
+ uint8_t watch_engine)
+{
+ uint64_t state = xive->vc_regs[VC_ENDC_WATCH_ASSIGN >> 3];
+
+ pnv_xive2_cache_watch_release(&state, watch_engine);
+ xive->vc_regs[VC_ENDC_WATCH_ASSIGN >> 3] = state;
+}
+
static uint64_t pnv_xive2_ic_vc_read(void *opaque, hwaddr offset,
unsigned size)
{
PnvXive2 *xive = PNV_XIVE2(opaque);
uint64_t val = 0;
uint32_t reg = offset >> 3;
+ uint8_t watch_engine;
switch (offset) {
/*
@@ -1000,24 +1218,44 @@ static uint64_t pnv_xive2_ic_vc_read(void *opaque, hwaddr offset,
val = xive->vc_regs[reg];
break;
+ case VC_ENDC_WATCH_ASSIGN:
+ val = pnv_xive2_endc_cache_watch_assign(xive);
+ break;
+
+ case VC_ENDC_CFG:
+ val = xive->vc_regs[reg];
+ break;
+
/*
* END cache updates
*/
case VC_ENDC_WATCH0_SPEC:
+ case VC_ENDC_WATCH1_SPEC:
+ case VC_ENDC_WATCH2_SPEC:
+ case VC_ENDC_WATCH3_SPEC:
+ watch_engine = (offset - VC_ENDC_WATCH0_SPEC) >> 6;
xive->vc_regs[reg] &= ~(VC_ENDC_WATCH_FULL | VC_ENDC_WATCH_CONFLICT);
+ pnv_xive2_endc_cache_watch_release(xive, watch_engine);
val = xive->vc_regs[reg];
break;
case VC_ENDC_WATCH0_DATA0:
+ case VC_ENDC_WATCH1_DATA0:
+ case VC_ENDC_WATCH2_DATA0:
+ case VC_ENDC_WATCH3_DATA0:
/*
* Load DATA registers from cache with data requested by the
* SPEC register
*/
- pnv_xive2_end_cache_load(xive);
+ watch_engine = (offset - VC_ENDC_WATCH0_DATA0) >> 6;
+ pnv_xive2_end_cache_load(xive, watch_engine);
val = xive->vc_regs[reg];
break;
case VC_ENDC_WATCH0_DATA1 ... VC_ENDC_WATCH0_DATA3:
+ case VC_ENDC_WATCH1_DATA1 ... VC_ENDC_WATCH1_DATA3:
+ case VC_ENDC_WATCH2_DATA1 ... VC_ENDC_WATCH2_DATA3:
+ case VC_ENDC_WATCH3_DATA1 ... VC_ENDC_WATCH3_DATA3:
val = xive->vc_regs[reg];
break;
@@ -1063,6 +1301,7 @@ static void pnv_xive2_ic_vc_write(void *opaque, hwaddr offset,
{
PnvXive2 *xive = PNV_XIVE2(opaque);
uint32_t reg = offset >> 3;
+ uint8_t watch_engine;
switch (offset) {
/*
@@ -1071,7 +1310,7 @@ static void pnv_xive2_ic_vc_write(void *opaque, hwaddr offset,
case VC_VSD_TABLE_ADDR:
break;
case VC_VSD_TABLE_DATA:
- pnv_xive2_vst_set_data(xive, val);
+ pnv_xive2_vc_vst_set_data(xive, val);
break;
/*
@@ -1083,6 +1322,10 @@ static void pnv_xive2_ic_vc_write(void *opaque, hwaddr offset,
/* ESB update */
break;
+ case VC_ESBC_FLUSH_INJECT:
+ pnv_xive2_inject_notify(xive, PNV_XIVE2_CACHE_ESBC);
+ break;
+
case VC_ESBC_CFG:
break;
@@ -1095,19 +1338,36 @@ static void pnv_xive2_ic_vc_write(void *opaque, hwaddr offset,
/* EAS update */
break;
+ case VC_EASC_FLUSH_INJECT:
+ pnv_xive2_inject_notify(xive, PNV_XIVE2_CACHE_EASC);
+ break;
+
+ case VC_ENDC_CFG:
+ break;
+
/*
* END cache updates
*/
case VC_ENDC_WATCH0_SPEC:
+ case VC_ENDC_WATCH1_SPEC:
+ case VC_ENDC_WATCH2_SPEC:
+ case VC_ENDC_WATCH3_SPEC:
val &= ~VC_ENDC_WATCH_CONFLICT; /* HW will set this bit */
break;
case VC_ENDC_WATCH0_DATA1 ... VC_ENDC_WATCH0_DATA3:
+ case VC_ENDC_WATCH1_DATA1 ... VC_ENDC_WATCH1_DATA3:
+ case VC_ENDC_WATCH2_DATA1 ... VC_ENDC_WATCH2_DATA3:
+ case VC_ENDC_WATCH3_DATA1 ... VC_ENDC_WATCH3_DATA3:
break;
case VC_ENDC_WATCH0_DATA0:
+ case VC_ENDC_WATCH1_DATA0:
+ case VC_ENDC_WATCH2_DATA0:
+ case VC_ENDC_WATCH3_DATA0:
/* writing to DATA0 triggers the cache write */
+ watch_engine = (offset - VC_ENDC_WATCH0_DATA0) >> 6;
xive->vc_regs[reg] = val;
- pnv_xive2_end_update(xive);
+ pnv_xive2_end_update(xive, watch_engine);
break;
@@ -1116,6 +1376,10 @@ static void pnv_xive2_ic_vc_write(void *opaque, hwaddr offset,
xive->vc_regs[VC_ENDC_FLUSH_CTRL >> 3] |= VC_ENDC_FLUSH_CTRL_POLL_VALID;
break;
+ case VC_ENDC_FLUSH_INJECT:
+ pnv_xive2_inject_notify(xive, PNV_XIVE2_CACHE_ENDC);
+ break;
+
/*
* Indirect invalidation
*/
@@ -1157,12 +1421,43 @@ static const MemoryRegionOps pnv_xive2_ic_vc_ops = {
},
};
+static uint8_t pnv_xive2_nxc_cache_watch_assign(PnvXive2 *xive)
+{
+ uint64_t engine_mask = GETFIELD(PC_NXC_PROC_CONFIG_WATCH_ASSIGN,
+ xive->pc_regs[PC_NXC_PROC_CONFIG >> 3]);
+ uint64_t state = xive->pc_regs[PC_NXC_WATCH_ASSIGN >> 3];
+ uint8_t val;
+
+ /*
+ * We keep track of which engines are currently busy in the
+ * PC_NXC_WATCH_ASSIGN register directly. When the firmware reads
+ * the register, we don't return its value but the ID of an engine
+ * it can use.
+ * There are 4 engines. 0xFF means no engine is available.
+ */
+ val = pnv_xive2_cache_watch_assign(engine_mask, &state);
+ if (val != 0xFF) {
+ xive->pc_regs[PC_NXC_WATCH_ASSIGN >> 3] = state;
+ }
+ return val;
+}
+
+static void pnv_xive2_nxc_cache_watch_release(PnvXive2 *xive,
+ uint8_t watch_engine)
+{
+ uint64_t state = xive->pc_regs[PC_NXC_WATCH_ASSIGN >> 3];
+
+ pnv_xive2_cache_watch_release(&state, watch_engine);
+ xive->pc_regs[PC_NXC_WATCH_ASSIGN >> 3] = state;
+}
+
static uint64_t pnv_xive2_ic_pc_read(void *opaque, hwaddr offset,
unsigned size)
{
PnvXive2 *xive = PNV_XIVE2(opaque);
uint64_t val = -1;
uint32_t reg = offset >> 3;
+ uint8_t watch_engine;
switch (offset) {
/*
@@ -1173,24 +1468,44 @@ static uint64_t pnv_xive2_ic_pc_read(void *opaque, hwaddr offset,
val = xive->pc_regs[reg];
break;
+ case PC_NXC_WATCH_ASSIGN:
+ val = pnv_xive2_nxc_cache_watch_assign(xive);
+ break;
+
+ case PC_NXC_PROC_CONFIG:
+ val = xive->pc_regs[reg];
+ break;
+
/*
* cache updates
*/
case PC_NXC_WATCH0_SPEC:
+ case PC_NXC_WATCH1_SPEC:
+ case PC_NXC_WATCH2_SPEC:
+ case PC_NXC_WATCH3_SPEC:
+ watch_engine = (offset - PC_NXC_WATCH0_SPEC) >> 6;
xive->pc_regs[reg] &= ~(PC_NXC_WATCH_FULL | PC_NXC_WATCH_CONFLICT);
+ pnv_xive2_nxc_cache_watch_release(xive, watch_engine);
val = xive->pc_regs[reg];
break;
case PC_NXC_WATCH0_DATA0:
+ case PC_NXC_WATCH1_DATA0:
+ case PC_NXC_WATCH2_DATA0:
+ case PC_NXC_WATCH3_DATA0:
/*
* Load DATA registers from cache with data requested by the
* SPEC register
*/
- pnv_xive2_nvp_cache_load(xive);
+ watch_engine = (offset - PC_NXC_WATCH0_DATA0) >> 6;
+ pnv_xive2_nxc_cache_load(xive, watch_engine);
val = xive->pc_regs[reg];
break;
case PC_NXC_WATCH0_DATA1 ... PC_NXC_WATCH0_DATA3:
+ case PC_NXC_WATCH1_DATA1 ... PC_NXC_WATCH1_DATA3:
+ case PC_NXC_WATCH2_DATA1 ... PC_NXC_WATCH2_DATA3:
+ case PC_NXC_WATCH3_DATA1 ... PC_NXC_WATCH3_DATA3:
val = xive->pc_regs[reg];
break;
@@ -1214,36 +1529,66 @@ static uint64_t pnv_xive2_ic_pc_read(void *opaque, hwaddr offset,
return val;
}
+static void pnv_xive2_pc_vst_set_data(PnvXive2 *xive, uint64_t vsd)
+{
+ uint8_t type = GETFIELD(PC_VSD_TABLE_SELECT,
+ xive->pc_regs[PC_VSD_TABLE_ADDR >> 3]);
+ uint8_t blk = GETFIELD(PC_VSD_TABLE_ADDRESS,
+ xive->pc_regs[PC_VSD_TABLE_ADDR >> 3]);
+
+ pnv_xive2_vst_set_data(xive, vsd, type, blk);
+}
+
static void pnv_xive2_ic_pc_write(void *opaque, hwaddr offset,
uint64_t val, unsigned size)
{
PnvXive2 *xive = PNV_XIVE2(opaque);
uint32_t reg = offset >> 3;
+ uint8_t watch_engine;
switch (offset) {
/*
- * VSD table settings. Only taken into account in the VC
- * sub-engine because the Xive2Router model combines both VC and PC
- * sub-engines
+ * VSD table settings.
+ * The Xive2Router model combines both VC and PC sub-engines. We
+ * allow to configure the tables through both, for the rare cases
+ * where a table only really needs to be configured for one of
+ * them (e.g. the NVG table for the presenter). It assumes that
+ * firmware passes the same address to the VC and PC when tables
+ * are defined for both, which seems acceptable.
*/
case PC_VSD_TABLE_ADDR:
+ break;
case PC_VSD_TABLE_DATA:
+ pnv_xive2_pc_vst_set_data(xive, val);
+ break;
+
+ case PC_NXC_PROC_CONFIG:
break;
/*
* cache updates
*/
case PC_NXC_WATCH0_SPEC:
+ case PC_NXC_WATCH1_SPEC:
+ case PC_NXC_WATCH2_SPEC:
+ case PC_NXC_WATCH3_SPEC:
val &= ~PC_NXC_WATCH_CONFLICT; /* HW will set this bit */
break;
case PC_NXC_WATCH0_DATA1 ... PC_NXC_WATCH0_DATA3:
+ case PC_NXC_WATCH1_DATA1 ... PC_NXC_WATCH1_DATA3:
+ case PC_NXC_WATCH2_DATA1 ... PC_NXC_WATCH2_DATA3:
+ case PC_NXC_WATCH3_DATA1 ... PC_NXC_WATCH3_DATA3:
break;
case PC_NXC_WATCH0_DATA0:
+ case PC_NXC_WATCH1_DATA0:
+ case PC_NXC_WATCH2_DATA0:
+ case PC_NXC_WATCH3_DATA0:
/* writing to DATA0 triggers the cache write */
+ watch_engine = (offset - PC_NXC_WATCH0_DATA0) >> 6;
xive->pc_regs[reg] = val;
- pnv_xive2_nvp_update(xive);
+ pnv_xive2_nxc_update(xive, watch_engine);
break;
/* case PC_NXC_FLUSH_CTRL: */
@@ -1251,6 +1596,10 @@ static void pnv_xive2_ic_pc_write(void *opaque, hwaddr offset,
xive->pc_regs[PC_NXC_FLUSH_CTRL >> 3] |= PC_NXC_FLUSH_CTRL_POLL_VALID;
break;
+ case PC_NXC_FLUSH_INJECT:
+ pnv_xive2_inject_notify(xive, PNV_XIVE2_CACHE_NXC);
+ break;
+
/*
* Indirect invalidation
*/
@@ -1547,13 +1896,19 @@ static const MemoryRegionOps pnv_xive2_ic_lsi_ops = {
/*
* Sync MMIO page (write only)
*/
-#define PNV_XIVE2_SYNC_IPI 0x000
-#define PNV_XIVE2_SYNC_HW 0x080
-#define PNV_XIVE2_SYNC_NxC 0x100
-#define PNV_XIVE2_SYNC_INT 0x180
-#define PNV_XIVE2_SYNC_OS_ESC 0x200
-#define PNV_XIVE2_SYNC_POOL_ESC 0x280
-#define PNV_XIVE2_SYNC_HARD_ESC 0x300
+#define PNV_XIVE2_SYNC_IPI 0x000
+#define PNV_XIVE2_SYNC_HW 0x080
+#define PNV_XIVE2_SYNC_NxC 0x100
+#define PNV_XIVE2_SYNC_INT 0x180
+#define PNV_XIVE2_SYNC_OS_ESC 0x200
+#define PNV_XIVE2_SYNC_POOL_ESC 0x280
+#define PNV_XIVE2_SYNC_HARD_ESC 0x300
+#define PNV_XIVE2_SYNC_NXC_LD_LCL_NCO 0x800
+#define PNV_XIVE2_SYNC_NXC_LD_LCL_CO 0x880
+#define PNV_XIVE2_SYNC_NXC_ST_LCL_NCI 0x900
+#define PNV_XIVE2_SYNC_NXC_ST_LCL_CI 0x980
+#define PNV_XIVE2_SYNC_NXC_ST_RMT_NCI 0xA00
+#define PNV_XIVE2_SYNC_NXC_ST_RMT_CI 0xA80
static uint64_t pnv_xive2_ic_sync_read(void *opaque, hwaddr offset,
unsigned size)
@@ -1565,22 +1920,72 @@ static uint64_t pnv_xive2_ic_sync_read(void *opaque, hwaddr offset,
return -1;
}
+/*
+ * The sync MMIO space spans two pages. The lower page is use for
+ * queue sync "poll" requests while the upper page is used for queue
+ * sync "inject" requests. Inject requests require the HW to write
+ * a byte of all 1's to a predetermined location in memory in order
+ * to signal completion of the request. Both pages have the same
+ * layout, so it is easiest to handle both with a single function.
+ */
static void pnv_xive2_ic_sync_write(void *opaque, hwaddr offset,
uint64_t val, unsigned size)
{
PnvXive2 *xive = PNV_XIVE2(opaque);
+ int inject_type;
+ hwaddr pg_offset_mask = (1ull << xive->ic_shift) - 1;
- switch (offset) {
+ /* adjust offset for inject page */
+ hwaddr adj_offset = offset & pg_offset_mask;
+
+ switch (adj_offset) {
case PNV_XIVE2_SYNC_IPI:
+ inject_type = PNV_XIVE2_QUEUE_IPI;
+ break;
case PNV_XIVE2_SYNC_HW:
+ inject_type = PNV_XIVE2_QUEUE_HW;
+ break;
case PNV_XIVE2_SYNC_NxC:
+ inject_type = PNV_XIVE2_QUEUE_NXC;
+ break;
case PNV_XIVE2_SYNC_INT:
+ inject_type = PNV_XIVE2_QUEUE_INT;
+ break;
case PNV_XIVE2_SYNC_OS_ESC:
+ inject_type = PNV_XIVE2_QUEUE_OS;
+ break;
case PNV_XIVE2_SYNC_POOL_ESC:
+ inject_type = PNV_XIVE2_QUEUE_POOL;
+ break;
case PNV_XIVE2_SYNC_HARD_ESC:
+ inject_type = PNV_XIVE2_QUEUE_HARD;
+ break;
+ case PNV_XIVE2_SYNC_NXC_LD_LCL_NCO:
+ inject_type = PNV_XIVE2_QUEUE_NXC_LD_LCL_NCO;
+ break;
+ case PNV_XIVE2_SYNC_NXC_LD_LCL_CO:
+ inject_type = PNV_XIVE2_QUEUE_NXC_LD_LCL_CO;
+ break;
+ case PNV_XIVE2_SYNC_NXC_ST_LCL_NCI:
+ inject_type = PNV_XIVE2_QUEUE_NXC_ST_LCL_NCI;
+ break;
+ case PNV_XIVE2_SYNC_NXC_ST_LCL_CI:
+ inject_type = PNV_XIVE2_QUEUE_NXC_ST_LCL_CI;
+ break;
+ case PNV_XIVE2_SYNC_NXC_ST_RMT_NCI:
+ inject_type = PNV_XIVE2_QUEUE_NXC_ST_RMT_NCI;
+ break;
+ case PNV_XIVE2_SYNC_NXC_ST_RMT_CI:
+ inject_type = PNV_XIVE2_QUEUE_NXC_ST_RMT_CI;
break;
default:
xive2_error(xive, "SYNC: invalid write @%"HWADDR_PRIx, offset);
+ return;
+ }
+
+ /* Write Queue Sync notification byte if writing to sync inject page */
+ if ((offset & ~pg_offset_mask) != 0) {
+ pnv_xive2_inject_notify(xive, inject_type);
}
}
@@ -1814,6 +2219,12 @@ static void pnv_xive2_reset(void *dev)
xive->cq_regs[CQ_XIVE_CFG >> 3] |=
SETFIELD(CQ_XIVE_CFG_HYP_HARD_BLOCK_ID, 0ull, xive->chip->chip_id);
+ /* VC and PC cache watch assign mechanism */
+ xive->vc_regs[VC_ENDC_CFG >> 3] =
+ SETFIELD(VC_ENDC_CFG_CACHE_WATCH_ASSIGN, 0ull, 0b0111);
+ xive->pc_regs[PC_NXC_PROC_CONFIG >> 3] =
+ SETFIELD(PC_NXC_PROC_CONFIG_WATCH_ASSIGN, 0ull, 0b0111);
+
/* Set default page size to 64k */
xive->ic_shift = xive->esb_shift = xive->end_shift = 16;
xive->nvc_shift = xive->nvpg_shift = xive->tm_shift = 16;
@@ -2025,33 +2436,6 @@ static void pnv_xive2_register_types(void)
type_init(pnv_xive2_register_types)
-static void xive2_nvp_pic_print_info(Xive2Nvp *nvp, uint32_t nvp_idx,
- GString *buf)
-{
- uint8_t eq_blk = xive_get_field32(NVP2_W5_VP_END_BLOCK, nvp->w5);
- uint32_t eq_idx = xive_get_field32(NVP2_W5_VP_END_INDEX, nvp->w5);
-
- if (!xive2_nvp_is_valid(nvp)) {
- return;
- }
-
- g_string_append_printf(buf, " %08x end:%02x/%04x IPB:%02x",
- nvp_idx, eq_blk, eq_idx,
- xive_get_field32(NVP2_W2_IPB, nvp->w2));
- /*
- * When the NVP is HW controlled, more fields are updated
- */
- if (xive2_nvp_is_hw(nvp)) {
- g_string_append_printf(buf, " CPPR:%02x",
- xive_get_field32(NVP2_W2_CPPR, nvp->w2));
- if (xive2_nvp_is_co(nvp)) {
- g_string_append_printf(buf, " CO:%04x",
- xive_get_field32(NVP2_W1_CO_THRID, nvp->w1));
- }
- }
- g_string_append_c(buf, '\n');
-}
-
/*
* If the table is direct, we can compute the number of PQ entries
* provisioned by FW.
diff --git a/hw/intc/pnv_xive2_regs.h b/hw/intc/pnv_xive2_regs.h
index 7165dc8..e8b87b3 100644
--- a/hw/intc/pnv_xive2_regs.h
+++ b/hw/intc/pnv_xive2_regs.h
@@ -232,6 +232,10 @@
#define VC_ESBC_FLUSH_POLL_BLOCK_ID_MASK PPC_BITMASK(32, 35)
#define VC_ESBC_FLUSH_POLL_OFFSET_MASK PPC_BITMASK(36, 63) /* 28-bit */
+/* ESBC cache flush inject register */
+#define X_VC_ESBC_FLUSH_INJECT 0x142
+#define VC_ESBC_FLUSH_INJECT 0x210
+
/* ESBC configuration */
#define X_VC_ESBC_CFG 0x148
#define VC_ESBC_CFG 0x240
@@ -250,6 +254,10 @@
#define VC_EASC_FLUSH_POLL_BLOCK_ID_MASK PPC_BITMASK(32, 35)
#define VC_EASC_FLUSH_POLL_OFFSET_MASK PPC_BITMASK(36, 63) /* 28-bit */
+/* EASC flush inject register */
+#define X_VC_EASC_FLUSH_INJECT 0x162
+#define VC_EASC_FLUSH_INJECT 0x310
+
/*
* VC2
*/
@@ -270,6 +278,10 @@
#define VC_ENDC_FLUSH_POLL_BLOCK_ID_MASK PPC_BITMASK(36, 39)
#define VC_ENDC_FLUSH_POLL_OFFSET_MASK PPC_BITMASK(40, 63) /* 24-bit */
+/* ENDC flush inject register */
+#define X_VC_ENDC_FLUSH_INJECT 0x182
+#define VC_ENDC_FLUSH_INJECT 0x410
+
/* ENDC Sync done */
#define X_VC_ENDC_SYNC_DONE 0x184
#define VC_ENDC_SYNC_DONE 0x420
@@ -283,6 +295,15 @@
#define VC_ENDC_SYNC_QUEUE_HARD PPC_BIT(6)
#define VC_QUEUE_COUNT 7
+/* ENDC cache watch assign */
+#define X_VC_ENDC_WATCH_ASSIGN 0x186
+#define VC_ENDC_WATCH_ASSIGN 0x430
+
+/* ENDC configuration register */
+#define X_VC_ENDC_CFG 0x188
+#define VC_ENDC_CFG 0x440
+#define VC_ENDC_CFG_CACHE_WATCH_ASSIGN PPC_BITMASK(32, 35)
+
/* ENDC cache watch specification 0 */
#define X_VC_ENDC_WATCH0_SPEC 0x1A0
#define VC_ENDC_WATCH0_SPEC 0x500
@@ -302,6 +323,42 @@
#define VC_ENDC_WATCH0_DATA2 0x530
#define VC_ENDC_WATCH0_DATA3 0x538
+/* ENDC cache watch 1 */
+#define X_VC_ENDC_WATCH1_SPEC 0x1A8
+#define VC_ENDC_WATCH1_SPEC 0x540
+#define X_VC_ENDC_WATCH1_DATA0 0x1AC
+#define X_VC_ENDC_WATCH1_DATA1 0x1AD
+#define X_VC_ENDC_WATCH1_DATA2 0x1AE
+#define X_VC_ENDC_WATCH1_DATA3 0x1AF
+#define VC_ENDC_WATCH1_DATA0 0x560
+#define VC_ENDC_WATCH1_DATA1 0x568
+#define VC_ENDC_WATCH1_DATA2 0x570
+#define VC_ENDC_WATCH1_DATA3 0x578
+
+/* ENDC cache watch 2 */
+#define X_VC_ENDC_WATCH2_SPEC 0x1B0
+#define VC_ENDC_WATCH2_SPEC 0x580
+#define X_VC_ENDC_WATCH2_DATA0 0x1B4
+#define X_VC_ENDC_WATCH2_DATA1 0x1B5
+#define X_VC_ENDC_WATCH2_DATA2 0x1B6
+#define X_VC_ENDC_WATCH2_DATA3 0x1B7
+#define VC_ENDC_WATCH2_DATA0 0x5A0
+#define VC_ENDC_WATCH2_DATA1 0x5A8
+#define VC_ENDC_WATCH2_DATA2 0x5B0
+#define VC_ENDC_WATCH2_DATA3 0x5B8
+
+/* ENDC cache watch 3 */
+#define X_VC_ENDC_WATCH3_SPEC 0x1B8
+#define VC_ENDC_WATCH3_SPEC 0x5C0
+#define X_VC_ENDC_WATCH3_DATA0 0x1BC
+#define X_VC_ENDC_WATCH3_DATA1 0x1BD
+#define X_VC_ENDC_WATCH3_DATA2 0x1BE
+#define X_VC_ENDC_WATCH3_DATA3 0x1BF
+#define VC_ENDC_WATCH3_DATA0 0x5E0
+#define VC_ENDC_WATCH3_DATA1 0x5E8
+#define VC_ENDC_WATCH3_DATA2 0x5F0
+#define VC_ENDC_WATCH3_DATA3 0x5F8
+
/*
* PC LSB1
*/
@@ -358,6 +415,21 @@
#define PC_NXC_FLUSH_POLL_BLOCK_ID_MASK PPC_BITMASK(36, 39)
#define PC_NXC_FLUSH_POLL_OFFSET_MASK PPC_BITMASK(40, 63) /* 24-bit */
+/* NxC Cache flush inject */
+#define X_PC_NXC_FLUSH_INJECT 0x282
+#define PC_NXC_FLUSH_INJECT 0x410
+
+/* NxC Cache watch assign */
+#define X_PC_NXC_WATCH_ASSIGN 0x286
+#define PC_NXC_WATCH_ASSIGN 0x430
+
+/* NxC Proc config */
+#define X_PC_NXC_PROC_CONFIG 0x28A
+#define PC_NXC_PROC_CONFIG 0x450
+#define PC_NXC_PROC_CONFIG_WATCH_ASSIGN PPC_BITMASK(0, 3)
+#define PC_NXC_PROC_CONFIG_NVG_TABLE_COMPRESS PPC_BITMASK(32, 35)
+#define PC_NXC_PROC_CONFIG_NVC_TABLE_COMPRESS PPC_BITMASK(36, 39)
+
/* NxC Cache Watch 0 Specification */
#define X_PC_NXC_WATCH0_SPEC 0x2A0
#define PC_NXC_WATCH0_SPEC 0x500
@@ -381,6 +453,42 @@
#define PC_NXC_WATCH0_DATA2 0x530
#define PC_NXC_WATCH0_DATA3 0x538
+/* NxC Cache Watch 1 */
+#define X_PC_NXC_WATCH1_SPEC 0x2A8
+#define PC_NXC_WATCH1_SPEC 0x540
+#define X_PC_NXC_WATCH1_DATA0 0x2AC
+#define X_PC_NXC_WATCH1_DATA1 0x2AD
+#define X_PC_NXC_WATCH1_DATA2 0x2AE
+#define X_PC_NXC_WATCH1_DATA3 0x2AF
+#define PC_NXC_WATCH1_DATA0 0x560
+#define PC_NXC_WATCH1_DATA1 0x568
+#define PC_NXC_WATCH1_DATA2 0x570
+#define PC_NXC_WATCH1_DATA3 0x578
+
+/* NxC Cache Watch 2 */
+#define X_PC_NXC_WATCH2_SPEC 0x2B0
+#define PC_NXC_WATCH2_SPEC 0x580
+#define X_PC_NXC_WATCH2_DATA0 0x2B4
+#define X_PC_NXC_WATCH2_DATA1 0x2B5
+#define X_PC_NXC_WATCH2_DATA2 0x2B6
+#define X_PC_NXC_WATCH2_DATA3 0x2B7
+#define PC_NXC_WATCH2_DATA0 0x5A0
+#define PC_NXC_WATCH2_DATA1 0x5A8
+#define PC_NXC_WATCH2_DATA2 0x5B0
+#define PC_NXC_WATCH2_DATA3 0x5B8
+
+/* NxC Cache Watch 3 */
+#define X_PC_NXC_WATCH3_SPEC 0x2B8
+#define PC_NXC_WATCH3_SPEC 0x5C0
+#define X_PC_NXC_WATCH3_DATA0 0x2BC
+#define X_PC_NXC_WATCH3_DATA1 0x2BD
+#define X_PC_NXC_WATCH3_DATA2 0x2BE
+#define X_PC_NXC_WATCH3_DATA3 0x2BF
+#define PC_NXC_WATCH3_DATA0 0x5E0
+#define PC_NXC_WATCH3_DATA1 0x5E8
+#define PC_NXC_WATCH3_DATA2 0x5F0
+#define PC_NXC_WATCH3_DATA3 0x5F8
+
/*
* TCTXT Registers
*/
diff --git a/hw/intc/ppc-uic.c b/hw/intc/ppc-uic.c
index 9a67f7f..f2a224f 100644
--- a/hw/intc/ppc-uic.c
+++ b/hw/intc/ppc-uic.c
@@ -286,7 +286,7 @@ static void ppc_uic_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = ppc_uic_reset;
+ device_class_set_legacy_reset(dc, ppc_uic_reset);
dc->realize = ppc_uic_realize;
dc->vmsd = &ppc_uic_vmstate;
device_class_set_props(dc, ppc_uic_properties);
diff --git a/hw/intc/riscv_imsic.c b/hw/intc/riscv_imsic.c
index b90f0d7..9ef65d4 100644
--- a/hw/intc/riscv_imsic.c
+++ b/hw/intc/riscv_imsic.c
@@ -55,7 +55,7 @@ static uint32_t riscv_imsic_topei(RISCVIMSICState *imsic, uint32_t page)
(imsic->eithreshold[page] <= imsic->num_irqs)) ?
imsic->eithreshold[page] : imsic->num_irqs;
for (i = 1; i < max_irq; i++) {
- if ((imsic->eistate[base + i] & IMSIC_EISTATE_ENPEND) ==
+ if ((qatomic_read(&imsic->eistate[base + i]) & IMSIC_EISTATE_ENPEND) ==
IMSIC_EISTATE_ENPEND) {
return (i << IMSIC_TOPEI_IID_SHIFT) | i;
}
@@ -66,10 +66,24 @@ static uint32_t riscv_imsic_topei(RISCVIMSICState *imsic, uint32_t page)
static void riscv_imsic_update(RISCVIMSICState *imsic, uint32_t page)
{
+ uint32_t base = page * imsic->num_irqs;
+
+ /*
+ * Lower the interrupt line if necessary, then evaluate the current
+ * IMSIC state.
+ * This sequence ensures that any race between evaluating the eistate and
+ * updating the interrupt line will not result in an incorrectly
+ * deactivated connected CPU IRQ line.
+ * If multiple interrupts are pending, this sequence functions identically
+ * to qemu_irq_pulse.
+ */
+
+ if (qatomic_fetch_and(&imsic->eistate[base], ~IMSIC_EISTATE_ENPEND)) {
+ qemu_irq_lower(imsic->external_irqs[page]);
+ }
if (imsic->eidelivery[page] && riscv_imsic_topei(imsic, page)) {
qemu_irq_raise(imsic->external_irqs[page]);
- } else {
- qemu_irq_lower(imsic->external_irqs[page]);
+ qatomic_or(&imsic->eistate[base], IMSIC_EISTATE_ENPEND);
}
}
@@ -125,12 +139,11 @@ static int riscv_imsic_topei_rmw(RISCVIMSICState *imsic, uint32_t page,
topei >>= IMSIC_TOPEI_IID_SHIFT;
base = page * imsic->num_irqs;
if (topei) {
- imsic->eistate[base + topei] &= ~IMSIC_EISTATE_PENDING;
+ qatomic_and(&imsic->eistate[base + topei], ~IMSIC_EISTATE_PENDING);
}
-
- riscv_imsic_update(imsic, page);
}
+ riscv_imsic_update(imsic, page);
return 0;
}
@@ -139,7 +152,7 @@ static int riscv_imsic_eix_rmw(RISCVIMSICState *imsic,
uint32_t num, bool pend, target_ulong *val,
target_ulong new_val, target_ulong wr_mask)
{
- uint32_t i, base;
+ uint32_t i, base, prev;
target_ulong mask;
uint32_t state = (pend) ? IMSIC_EISTATE_PENDING : IMSIC_EISTATE_ENABLED;
@@ -157,10 +170,6 @@ static int riscv_imsic_eix_rmw(RISCVIMSICState *imsic,
if (val) {
*val = 0;
- for (i = 0; i < xlen; i++) {
- mask = (target_ulong)1 << i;
- *val |= (imsic->eistate[base + i] & state) ? mask : 0;
- }
}
for (i = 0; i < xlen; i++) {
@@ -172,10 +181,15 @@ static int riscv_imsic_eix_rmw(RISCVIMSICState *imsic,
mask = (target_ulong)1 << i;
if (wr_mask & mask) {
if (new_val & mask) {
- imsic->eistate[base + i] |= state;
+ prev = qatomic_fetch_or(&imsic->eistate[base + i], state);
} else {
- imsic->eistate[base + i] &= ~state;
+ prev = qatomic_fetch_and(&imsic->eistate[base + i], ~state);
}
+ } else {
+ prev = qatomic_read(&imsic->eistate[base + i]);
+ }
+ if (val && (prev & state)) {
+ *val |= mask;
}
}
@@ -302,14 +316,14 @@ static void riscv_imsic_write(void *opaque, hwaddr addr, uint64_t value,
page = addr >> IMSIC_MMIO_PAGE_SHIFT;
if ((addr & (IMSIC_MMIO_PAGE_SZ - 1)) == IMSIC_MMIO_PAGE_LE) {
if (value && (value < imsic->num_irqs)) {
- imsic->eistate[(page * imsic->num_irqs) + value] |=
- IMSIC_EISTATE_PENDING;
+ qatomic_or(&imsic->eistate[(page * imsic->num_irqs) + value],
+ IMSIC_EISTATE_PENDING);
+
+ /* Update CPU external interrupt status */
+ riscv_imsic_update(imsic, page);
}
}
- /* Update CPU external interrupt status */
- riscv_imsic_update(imsic, page);
-
return;
err:
diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c
index a91a4a4..c3d2b8d 100644
--- a/hw/intc/s390_flic.c
+++ b/hw/intc/s390_flic.c
@@ -457,7 +457,7 @@ static void qemu_s390_flic_class_init(ObjectClass *oc, void *data)
S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
device_class_set_props(dc, qemu_s390_flic_properties);
- dc->reset = qemu_s390_flic_reset;
+ device_class_set_legacy_reset(dc, qemu_s390_flic_reset);
dc->vmsd = &qemu_s390_flic_vmstate;
fsc->register_io_adapter = qemu_s390_register_io_adapter;
fsc->io_adapter_map = qemu_s390_io_adapter_map;
diff --git a/hw/intc/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c
index 330f08d..7930d72 100644
--- a/hw/intc/s390_flic_kvm.c
+++ b/hw/intc/s390_flic_kvm.c
@@ -679,7 +679,7 @@ static void kvm_s390_flic_class_init(ObjectClass *oc, void *data)
device_class_set_parent_realize(dc, kvm_s390_flic_realize,
&kfsc->parent_realize);
dc->vmsd = &kvm_s390_flic_vmstate;
- dc->reset = kvm_s390_flic_reset;
+ device_class_set_legacy_reset(dc, kvm_s390_flic_reset);
fsc->register_io_adapter = kvm_s390_register_io_adapter;
fsc->io_adapter_map = kvm_s390_io_adapter_map;
fsc->add_adapter_routes = kvm_s390_add_adapter_routes;
diff --git a/hw/intc/sifive_plic.c b/hw/intc/sifive_plic.c
index e559f11..7f43e96 100644
--- a/hw/intc/sifive_plic.c
+++ b/hw/intc/sifive_plic.c
@@ -444,7 +444,7 @@ static void sifive_plic_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = sifive_plic_reset;
+ device_class_set_legacy_reset(dc, sifive_plic_reset);
device_class_set_props(dc, sifive_plic_properties);
dc->realize = sifive_plic_realize;
dc->vmsd = &vmstate_sifive_plic;
diff --git a/hw/intc/slavio_intctl.c b/hw/intc/slavio_intctl.c
index d6e49d2..f83709a 100644
--- a/hw/intc/slavio_intctl.c
+++ b/hw/intc/slavio_intctl.c
@@ -446,7 +446,7 @@ static void slavio_intctl_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass);
- dc->reset = slavio_intctl_reset;
+ device_class_set_legacy_reset(dc, slavio_intctl_reset);
dc->vmsd = &vmstate_intctl;
#ifdef DEBUG_IRQ_COUNT
ic->get_statistics = slavio_intctl_get_statistics;
diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index 70f11f9..5a02dd8 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -692,9 +692,15 @@ void xive_tctx_pic_print_info(XiveTCTX *tctx, GString *buf)
}
}
- g_string_append_printf(buf, "CPU[%04x]: "
- "QW NSR CPPR IPB LSMFB ACK# INC AGE PIPR W2\n",
- cpu_index);
+ if (xive_presenter_get_config(tctx->xptr) & XIVE_PRESENTER_GEN1_TIMA_OS) {
+ g_string_append_printf(buf, "CPU[%04x]: "
+ "QW NSR CPPR IPB LSMFB ACK# INC AGE PIPR"
+ " W2\n", cpu_index);
+ } else {
+ g_string_append_printf(buf, "CPU[%04x]: "
+ "QW NSR CPPR IPB LSMFB - LGS T PIPR"
+ " W2\n", cpu_index);
+ }
for (i = 0; i < XIVE_TM_RING_COUNT; i++) {
char *s = xive_tctx_ring_print(&tctx->regs[i * XIVE_TM_RING_SIZE]);
diff --git a/hw/intc/xive2.c b/hw/intc/xive2.c
index 3e7238c..1f15068 100644
--- a/hw/intc/xive2.c
+++ b/hw/intc/xive2.c
@@ -89,7 +89,7 @@ void xive2_end_pic_print_info(Xive2End *end, uint32_t end_idx, GString *buf)
pq = xive_get_field32(END2_W1_ESn, end->w1);
g_string_append_printf(buf,
- " %08x %c%c %c%c%c%c%c%c%c%c%c%c "
+ " %08x %c%c %c%c%c%c%c%c%c%c%c%c%c %c%c "
"prio:%d nvp:%02x/%04x",
end_idx,
pq & XIVE_ESB_VAL_P ? 'P' : '-',
@@ -98,12 +98,15 @@ void xive2_end_pic_print_info(Xive2End *end, uint32_t end_idx, GString *buf)
xive2_end_is_enqueue(end) ? 'q' : '-',
xive2_end_is_notify(end) ? 'n' : '-',
xive2_end_is_backlog(end) ? 'b' : '-',
+ xive2_end_is_precluded_escalation(end) ? 'p' : '-',
xive2_end_is_escalate(end) ? 'e' : '-',
xive2_end_is_escalate_end(end) ? 'N' : '-',
xive2_end_is_uncond_escalation(end) ? 'u' : '-',
xive2_end_is_silent_escalation(end) ? 's' : '-',
xive2_end_is_firmware1(end) ? 'f' : '-',
xive2_end_is_firmware2(end) ? 'F' : '-',
+ xive2_end_is_ignore(end) ? 'i' : '-',
+ xive2_end_is_crowd(end) ? 'c' : '-',
priority, nvp_blk, nvp_idx);
if (qaddr_base) {
@@ -137,6 +140,32 @@ void xive2_end_eas_pic_print_info(Xive2End *end, uint32_t end_idx,
(uint32_t) xive_get_field64(EAS2_END_DATA, eas->w));
}
+void xive2_nvp_pic_print_info(Xive2Nvp *nvp, uint32_t nvp_idx, GString *buf)
+{
+ uint8_t eq_blk = xive_get_field32(NVP2_W5_VP_END_BLOCK, nvp->w5);
+ uint32_t eq_idx = xive_get_field32(NVP2_W5_VP_END_INDEX, nvp->w5);
+
+ if (!xive2_nvp_is_valid(nvp)) {
+ return;
+ }
+
+ g_string_append_printf(buf, " %08x end:%02x/%04x IPB:%02x",
+ nvp_idx, eq_blk, eq_idx,
+ xive_get_field32(NVP2_W2_IPB, nvp->w2));
+ /*
+ * When the NVP is HW controlled, more fields are updated
+ */
+ if (xive2_nvp_is_hw(nvp)) {
+ g_string_append_printf(buf, " CPPR:%02x",
+ xive_get_field32(NVP2_W2_CPPR, nvp->w2));
+ if (xive2_nvp_is_co(nvp)) {
+ g_string_append_printf(buf, " CO:%04x",
+ xive_get_field32(NVP2_W1_CO_THRID, nvp->w1));
+ }
+ }
+ g_string_append_c(buf, '\n');
+}
+
static void xive2_end_enqueue(Xive2End *end, uint32_t data)
{
uint64_t qaddr_base = xive2_end_qaddr(end);
@@ -650,7 +679,7 @@ static void xive2_router_end_notify(Xive2Router *xrtr, uint8_t end_blk,
}
found = xive_presenter_notify(xrtr->xfb, format, nvp_blk, nvp_idx,
- xive_get_field32(END2_W6_IGNORE, end.w7),
+ xive2_end_is_ignore(&end),
priority,
xive_get_field32(END2_W7_F1_LOG_SERVER_ID, end.w7));
diff --git a/hw/intc/xlnx-pmu-iomod-intc.c b/hw/intc/xlnx-pmu-iomod-intc.c
index 12bd1a3..48cd3ae 100644
--- a/hw/intc/xlnx-pmu-iomod-intc.c
+++ b/hw/intc/xlnx-pmu-iomod-intc.c
@@ -536,7 +536,7 @@ static void xlnx_pmu_io_intc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = xlnx_pmu_io_intc_reset;
+ device_class_set_legacy_reset(dc, xlnx_pmu_io_intc_reset);
dc->realize = xlnx_pmu_io_intc_realize;
dc->vmsd = &vmstate_xlnx_pmu_io_intc;
device_class_set_props(dc, xlnx_pmu_io_intc_properties);
diff --git a/hw/intc/xlnx-zynqmp-ipi.c b/hw/intc/xlnx-zynqmp-ipi.c
index 509ee79..7241377 100644
--- a/hw/intc/xlnx-zynqmp-ipi.c
+++ b/hw/intc/xlnx-zynqmp-ipi.c
@@ -359,7 +359,7 @@ static void xlnx_zynqmp_ipi_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = xlnx_zynqmp_ipi_reset;
+ device_class_set_legacy_reset(dc, xlnx_zynqmp_ipi_reset);
dc->realize = xlnx_zynqmp_ipi_realize;
dc->vmsd = &vmstate_zynqmp_pmu_ipi;
}
diff --git a/hw/isa/isa-superio.c b/hw/isa/isa-superio.c
index a8c8c58..cff756e 100644
--- a/hw/isa/isa-superio.c
+++ b/hw/isa/isa-superio.c
@@ -22,7 +22,7 @@
#include "hw/qdev-properties.h"
#include "hw/input/i8042.h"
#include "hw/char/parallel-isa.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-isa.h"
#include "trace.h"
static void isa_superio_realize(DeviceState *dev, Error **errp)
diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
index bd727b2..dabd121 100644
--- a/hw/isa/lpc_ich9.c
+++ b/hw/isa/lpc_ich9.c
@@ -43,6 +43,7 @@
#include "hw/southbridge/ich9.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/ich9.h"
+#include "hw/acpi/ich9_timer.h"
#include "hw/pci/pci_bus.h"
#include "hw/qdev-properties.h"
#include "sysemu/runstate.h"
@@ -531,6 +532,15 @@ ich9_lpc_pmcon_update(ICH9LPCState *lpc)
uint16_t gen_pmcon_1 = pci_get_word(lpc->d.config + ICH9_LPC_GEN_PMCON_1);
uint16_t wmask;
+ if (lpc->pm.swsmi_timer_enabled) {
+ ich9_pm_update_swsmi_timer(
+ &lpc->pm, lpc->pm.smi_en & ICH9_PMIO_SMI_EN_SWSMI_EN);
+ }
+ if (lpc->pm.periodic_timer_enabled) {
+ ich9_pm_update_periodic_timer(
+ &lpc->pm, lpc->pm.smi_en & ICH9_PMIO_SMI_EN_PERIODIC_EN);
+ }
+
if (gen_pmcon_1 & ICH9_LPC_GEN_PMCON_1_SMI_LOCK) {
wmask = pci_get_word(lpc->d.wmask + ICH9_LPC_GEN_PMCON_1);
wmask &= ~ICH9_LPC_GEN_PMCON_1_SMI_LOCK;
@@ -826,6 +836,10 @@ static Property ich9_lpc_properties[] = {
ICH9_LPC_SMI_F_CPU_HOTPLUG_BIT, true),
DEFINE_PROP_BIT64("x-smi-cpu-hotunplug", ICH9LPCState, smi_host_features,
ICH9_LPC_SMI_F_CPU_HOT_UNPLUG_BIT, true),
+ DEFINE_PROP_BOOL("x-smi-swsmi-timer", ICH9LPCState,
+ pm.swsmi_timer_enabled, true),
+ DEFINE_PROP_BOOL("x-smi-periodic-timer", ICH9LPCState,
+ pm.periodic_timer_enabled, true),
DEFINE_PROP_END_OF_LIST(),
};
@@ -871,7 +885,7 @@ static void ich9_lpc_class_init(ObjectClass *klass, void *data)
AcpiDevAmlIfClass *amldevc = ACPI_DEV_AML_IF_CLASS(klass);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->reset = ich9_lpc_reset;
+ device_class_set_legacy_reset(dc, ich9_lpc_reset);
k->realize = ich9_lpc_realize;
dc->vmsd = &vmstate_ich9_lpc;
device_class_set_props(dc, ich9_lpc_properties);
diff --git a/hw/isa/pc87312.c b/hw/isa/pc87312.c
index 64dd17b..f671554 100644
--- a/hw/isa/pc87312.c
+++ b/hw/isa/pc87312.c
@@ -338,7 +338,7 @@ static void pc87312_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass);
- dc->reset = pc87312_reset;
+ device_class_set_legacy_reset(dc, pc87312_reset);
dc->vmsd = &vmstate_pc87312;
device_class_set_parent_realize(dc, pc87312_realize,
&sc->parent_realize);
diff --git a/hw/isa/piix.c b/hw/isa/piix.c
index 2d30711..b4a402f 100644
--- a/hw/isa/piix.c
+++ b/hw/isa/piix.c
@@ -425,7 +425,7 @@ static void pci_piix_class_init(ObjectClass *klass, void *data)
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
k->config_write = piix_write_config;
- dc->reset = piix_reset;
+ device_class_set_legacy_reset(dc, piix_reset);
dc->desc = "ISA bridge";
dc->hotpluggable = false;
k->vendor_id = PCI_VENDOR_ID_INTEL;
diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
index 505b44c..6f44b38 100644
--- a/hw/isa/vt82c686.c
+++ b/hw/isa/vt82c686.c
@@ -17,7 +17,7 @@
#include "hw/isa/vt82c686.h"
#include "hw/block/fdc.h"
#include "hw/char/parallel-isa.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-isa.h"
#include "hw/pci/pci.h"
#include "hw/qdev-properties.h"
#include "hw/ide/pci.h"
@@ -232,7 +232,7 @@ static void via_pm_class_init(ObjectClass *klass, void *data)
k->device_id = info->device_id;
k->class_id = PCI_CLASS_BRIDGE_OTHER;
k->revision = 0x40;
- dc->reset = via_pm_reset;
+ device_class_set_legacy_reset(dc, via_pm_reset);
/* Reason: part of VIA south bridge, does not exist stand alone */
dc->user_creatable = false;
dc->vmsd = &vmstate_acpi;
@@ -461,7 +461,7 @@ static void vt82c686b_superio_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass);
- dc->reset = vt82c686b_superio_reset;
+ device_class_set_legacy_reset(dc, vt82c686b_superio_reset);
sc->serial.count = 2;
sc->parallel.count = 1;
sc->ide.count = 0; /* emulated by via-ide */
@@ -570,7 +570,7 @@ static void vt8231_superio_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass);
- dc->reset = vt8231_superio_reset;
+ device_class_set_legacy_reset(dc, vt8231_superio_reset);
sc->serial.count = 1;
sc->parallel.count = 1;
sc->ide.count = 0; /* emulated by via-ide */
@@ -592,6 +592,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(ViaISAState, VIA_ISA)
struct ViaISAState {
PCIDevice dev;
+
+ IRQState i8259_irq;
qemu_irq cpu_intr;
qemu_irq *isa_irqs_in;
uint16_t irq_state[ISA_NUM_IRQS];
@@ -715,13 +717,12 @@ static void via_isa_realize(PCIDevice *d, Error **errp)
ViaISAState *s = VIA_ISA(d);
DeviceState *dev = DEVICE(d);
PCIBus *pci_bus = pci_get_bus(d);
- qemu_irq *isa_irq;
ISABus *isa_bus;
int i;
qdev_init_gpio_out_named(dev, &s->cpu_intr, "intr", 1);
qdev_init_gpio_in_named(dev, via_isa_pirq, "pirq", PCI_NUM_PINS);
- isa_irq = qemu_allocate_irqs(via_isa_request_i8259_irq, s, 1);
+ qemu_init_irq(&s->i8259_irq, via_isa_request_i8259_irq, s, 0);
isa_bus = isa_bus_new(dev, pci_address_space(d), pci_address_space_io(d),
errp);
@@ -729,7 +730,7 @@ static void via_isa_realize(PCIDevice *d, Error **errp)
return;
}
- s->isa_irqs_in = i8259_init(isa_bus, *isa_irq);
+ s->isa_irqs_in = i8259_init(isa_bus, &s->i8259_irq);
isa_bus_register_input_irqs(isa_bus, s->isa_irqs_in);
i8254_pit_init(isa_bus, 0x40, 0, NULL);
i8257_dma_init(OBJECT(d), isa_bus, 0);
@@ -843,7 +844,7 @@ static void vt82c686b_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_VIA_82C686B_ISA;
k->class_id = PCI_CLASS_BRIDGE_ISA;
k->revision = 0x40;
- dc->reset = vt82c686b_isa_reset;
+ device_class_set_legacy_reset(dc, vt82c686b_isa_reset);
dc->desc = "ISA bridge";
dc->vmsd = &vmstate_via;
/* Reason: part of VIA VT82C686 southbridge, needs to be wired up */
@@ -908,7 +909,7 @@ static void vt8231_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_VIA_8231_ISA;
k->class_id = PCI_CLASS_BRIDGE_ISA;
k->revision = 0x10;
- dc->reset = vt8231_isa_reset;
+ device_class_set_legacy_reset(dc, vt8231_isa_reset);
dc->desc = "ISA bridge";
dc->vmsd = &vmstate_via;
/* Reason: part of VIA VT8231 southbridge, needs to be wired up */
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index 89be737..fe1c6fe 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -5,14 +5,13 @@ config LOONGARCH_VIRT
select DEVICE_TREE
select PCI
select PCI_EXPRESS_GENERIC_BRIDGE
- imply VIRTIO_VGA
imply PCI_DEVICES
imply NVDIMM
imply TPM_TIS_SYSBUS
- select SERIAL
+ select SERIAL_MM
select VIRTIO_PCI
select PLATFORM_BUS
- select LOONGSON_IPI
+ select LOONGARCH_IPI
select LOONGARCH_PCH_PIC
select LOONGARCH_PCH_MSI
select LOONGARCH_EXTIOI
diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
index 72bfc35..50709bd 100644
--- a/hw/loongarch/acpi-build.c
+++ b/hw/loongarch/acpi-build.c
@@ -31,6 +31,7 @@
#include "hw/acpi/generic_event_device.h"
#include "hw/pci-host/gpex.h"
+#include "sysemu/sysemu.h"
#include "sysemu/tpm.h"
#include "hw/platform-bus.h"
#include "hw/acpi/aml-build.h"
@@ -218,7 +219,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
* highram: [VIRT_HIGHMEM_BASE, +(len - gap))
*/
if (len >= gap) {
- build_srat_memory(table_data, base, len, i, MEM_AFFINITY_ENABLED);
+ build_srat_memory(table_data, base, gap, i, MEM_AFFINITY_ENABLED);
len -= gap;
base = VIRT_HIGHMEM_BASE;
gap = machine->ram_size - VIRT_LOWMEM_SIZE;
@@ -241,6 +242,44 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
acpi_table_end(linker, &table);
}
+/*
+ * Serial Port Console Redirection Table (SPCR)
+ * https://learn.microsoft.com/en-us/windows-hardware/drivers/serports/serial-port-console-redirection-table
+ */
+static void
+spcr_setup(GArray *table_data, BIOSLinker *linker, MachineState *machine)
+{
+ LoongArchVirtMachineState *lvms;
+ AcpiSpcrData serial = {
+ .interface_type = 0, /* 16550 compatible */
+ .base_addr.id = AML_AS_SYSTEM_MEMORY,
+ .base_addr.width = 32,
+ .base_addr.offset = 0,
+ .base_addr.size = 1,
+ .base_addr.addr = VIRT_UART_BASE,
+ .interrupt_type = 0, /* Interrupt not supported */
+ .pc_interrupt = 0,
+ .interrupt = VIRT_UART_IRQ,
+ .baud_rate = 7, /* 115200 */
+ .parity = 0,
+ .stop_bits = 1,
+ .flow_control = 0,
+ .terminal_type = 3, /* ANSI */
+ .language = 0, /* Language */
+ .pci_device_id = 0xffff, /* not a PCI device*/
+ .pci_vendor_id = 0xffff, /* not a PCI device*/
+ .pci_bus = 0,
+ .pci_device = 0,
+ .pci_function = 0,
+ .pci_flags = 0,
+ .pci_segment = 0,
+ };
+
+ lvms = LOONGARCH_VIRT_MACHINE(machine);
+ build_spcr(table_data, linker, &serial, 2, lvms->oem_id,
+ lvms->oem_table_id);
+}
+
typedef
struct AcpiBuildState {
/* Copy of table in RAM (for patching). */
@@ -252,23 +291,27 @@ struct AcpiBuildState {
MemoryRegion *linker_mr;
} AcpiBuildState;
-static void build_uart_device_aml(Aml *table)
+static void build_uart_device_aml(Aml *table, int index)
{
Aml *dev;
Aml *crs;
Aml *pkg0, *pkg1, *pkg2;
- uint32_t uart_irq = VIRT_UART_IRQ;
-
- Aml *scope = aml_scope("_SB");
- dev = aml_device("COMA");
+ Aml *scope;
+ uint32_t uart_irq;
+ uint64_t base;
+
+ uart_irq = VIRT_UART_IRQ + index;
+ base = VIRT_UART_BASE + index * VIRT_UART_SIZE;
+ scope = aml_scope("_SB");
+ dev = aml_device("COM%d", index);
aml_append(dev, aml_name_decl("_HID", aml_string("PNP0501")));
- aml_append(dev, aml_name_decl("_UID", aml_int(0)));
+ aml_append(dev, aml_name_decl("_UID", aml_int(index)));
aml_append(dev, aml_name_decl("_CCA", aml_int(1)));
crs = aml_resource_template();
aml_append(crs,
aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
AML_NON_CACHEABLE, AML_READ_WRITE,
- 0, VIRT_UART_BASE, VIRT_UART_BASE + VIRT_UART_SIZE - 1,
+ 0, base, base + VIRT_UART_SIZE - 1,
0, VIRT_UART_SIZE));
aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
AML_SHARED, &uart_irq, 1));
@@ -401,6 +444,7 @@ static void acpi_dsdt_add_tpm(Aml *scope, LoongArchVirtMachineState *vms)
static void
build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
{
+ int i;
Aml *dsdt, *scope, *pkg;
LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lvms->oem_id,
@@ -408,7 +452,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
acpi_table_begin(&table, table_data);
dsdt = init_aml_allocator();
- build_uart_device_aml(dsdt);
+ for (i = 0; i < VIRT_UART_COUNT; i++)
+ build_uart_device_aml(dsdt, i);
build_pci_device_aml(dsdt, lvms);
build_la_ged_aml(dsdt, machine);
build_flash_aml(dsdt, lvms);
@@ -477,6 +522,8 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine)
acpi_add_table(table_offsets, tables_blob);
build_srat(tables_blob, tables->linker, machine);
+ acpi_add_table(table_offsets, tables_blob);
+ spcr_setup(tables_blob, tables->linker, machine);
if (machine->numa_state->num_nodes) {
if (machine->numa_state->have_numa_distance) {
diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build
index bce7eba..005f017 100644
--- a/hw/loongarch/meson.build
+++ b/hw/loongarch/meson.build
@@ -1,8 +1,8 @@
loongarch_ss = ss.source_set()
loongarch_ss.add(files(
- 'fw_cfg.c',
'boot.c',
))
+common_ss.add(when: 'CONFIG_LOONGARCH_VIRT', if_true: files('fw_cfg.c'))
loongarch_ss.add(when: 'CONFIG_LOONGARCH_VIRT', if_true: files('virt.c'))
loongarch_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-build.c'))
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index e592b1b..9a635d1 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -9,7 +9,7 @@
#include "qemu/datadir.h"
#include "qapi/error.h"
#include "hw/boards.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "sysemu/kvm.h"
#include "sysemu/tcg.h"
#include "sysemu/sysemu.h"
@@ -23,7 +23,7 @@
#include "net/net.h"
#include "hw/loader.h"
#include "elf.h"
-#include "hw/intc/loongson_ipi.h"
+#include "hw/intc/loongarch_ipi.h"
#include "hw/intc/loongarch_extioi.h"
#include "hw/intc/loongarch_pch_pic.h"
#include "hw/intc/loongarch_pch_msi.h"
@@ -48,6 +48,7 @@
#include "hw/block/flash.h"
#include "hw/virtio/virtio-iommu.h"
#include "qemu/error-report.h"
+#include "qemu/guest-random.h"
static bool virt_is_veiointc_enabled(LoongArchVirtMachineState *lvms)
{
@@ -279,11 +280,49 @@ static void fdt_add_rtc_node(LoongArchVirtMachineState *lvms,
g_free(nodename);
}
+static void fdt_add_ged_reset(LoongArchVirtMachineState *lvms)
+{
+ char *name;
+ uint32_t ged_handle;
+ MachineState *ms = MACHINE(lvms);
+ hwaddr base = VIRT_GED_REG_ADDR;
+ hwaddr size = ACPI_GED_REG_COUNT;
+
+ ged_handle = qemu_fdt_alloc_phandle(ms->fdt);
+ name = g_strdup_printf("/ged@%" PRIx64, base);
+ qemu_fdt_add_subnode(ms->fdt, name);
+ qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon");
+ qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0x0, base, 0x0, size);
+ /* 8 bit registers */
+ qemu_fdt_setprop_cell(ms->fdt, name, "reg-shift", 0);
+ qemu_fdt_setprop_cell(ms->fdt, name, "reg-io-width", 1);
+ qemu_fdt_setprop_cell(ms->fdt, name, "phandle", ged_handle);
+ ged_handle = qemu_fdt_get_phandle(ms->fdt, name);
+ g_free(name);
+
+ name = g_strdup_printf("/reboot");
+ qemu_fdt_add_subnode(ms->fdt, name);
+ qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-reboot");
+ qemu_fdt_setprop_cell(ms->fdt, name, "regmap", ged_handle);
+ qemu_fdt_setprop_cell(ms->fdt, name, "offset", ACPI_GED_REG_RESET);
+ qemu_fdt_setprop_cell(ms->fdt, name, "value", ACPI_GED_RESET_VALUE);
+ g_free(name);
+
+ name = g_strdup_printf("/poweroff");
+ qemu_fdt_add_subnode(ms->fdt, name);
+ qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-poweroff");
+ qemu_fdt_setprop_cell(ms->fdt, name, "regmap", ged_handle);
+ qemu_fdt_setprop_cell(ms->fdt, name, "offset", ACPI_GED_REG_SLEEP_CTL);
+ qemu_fdt_setprop_cell(ms->fdt, name, "value", ACPI_GED_SLP_EN |
+ (ACPI_GED_SLP_TYP_S5 << ACPI_GED_SLP_TYP_POS));
+ g_free(name);
+}
+
static void fdt_add_uart_node(LoongArchVirtMachineState *lvms,
- uint32_t *pch_pic_phandle)
+ uint32_t *pch_pic_phandle, hwaddr base,
+ int irq, bool chosen)
{
char *nodename;
- hwaddr base = VIRT_UART_BASE;
hwaddr size = VIRT_UART_SIZE;
MachineState *ms = MACHINE(lvms);
@@ -292,9 +331,9 @@ static void fdt_add_uart_node(LoongArchVirtMachineState *lvms,
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "ns16550a");
qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0, base, 0x0, size);
qemu_fdt_setprop_cell(ms->fdt, nodename, "clock-frequency", 100000000);
- qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename);
- qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
- VIRT_UART_IRQ - VIRT_GSI_BASE, 0x4);
+ if (chosen)
+ qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename);
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts", irq, 0x4);
qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
*pch_pic_phandle);
g_free(nodename);
@@ -303,6 +342,7 @@ static void fdt_add_uart_node(LoongArchVirtMachineState *lvms,
static void create_fdt(LoongArchVirtMachineState *lvms)
{
MachineState *ms = MACHINE(lvms);
+ uint8_t rng_seed[32];
ms->fdt = create_device_tree(&lvms->fdt_size);
if (!ms->fdt) {
@@ -316,6 +356,10 @@ static void create_fdt(LoongArchVirtMachineState *lvms)
qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2);
qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2);
qemu_fdt_add_subnode(ms->fdt, "/chosen");
+
+ /* Pass seed to RNG */
+ qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed));
+ qemu_fdt_setprop(ms->fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed));
}
static void fdt_add_cpu_nodes(const LoongArchVirtMachineState *lvms)
@@ -706,11 +750,18 @@ static void virt_devices_init(DeviceState *pch_pic,
/* Add pcie node */
fdt_add_pcie_node(lvms, pch_pic_phandle, pch_msi_phandle);
- serial_mm_init(get_system_memory(), VIRT_UART_BASE, 0,
- qdev_get_gpio_in(pch_pic,
- VIRT_UART_IRQ - VIRT_GSI_BASE),
- 115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
- fdt_add_uart_node(lvms, pch_pic_phandle);
+ /*
+ * Create uart fdt node in reverse order so that they appear
+ * in the finished device tree lowest address first
+ */
+ for (i = VIRT_UART_COUNT; i --> 0;) {
+ hwaddr base = VIRT_UART_BASE + i * VIRT_UART_SIZE;
+ int irq = VIRT_UART_IRQ + i - VIRT_GSI_BASE;
+ serial_mm_init(get_system_memory(), base, 0,
+ qdev_get_gpio_in(pch_pic, irq),
+ 115200, serial_hd(i), DEVICE_LITTLE_ENDIAN);
+ fdt_add_uart_node(lvms, pch_pic_phandle, base, irq, i == 0);
+ }
/* Network init */
pci_init_nic_devices(pci_bus, mc->default_nic);
@@ -724,6 +775,7 @@ static void virt_devices_init(DeviceState *pch_pic,
qdev_get_gpio_in(pch_pic,
VIRT_RTC_IRQ - VIRT_GSI_BASE));
fdt_add_rtc_node(lvms, pch_pic_phandle);
+ fdt_add_ged_reset(lvms);
/* acpi ged */
lvms->acpi_ged = create_acpi_ged(pch_pic, lvms);
@@ -788,7 +840,7 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
*/
/* Create IPI device */
- ipi = qdev_new(TYPE_LOONGSON_IPI);
+ ipi = qdev_new(TYPE_LOONGARCH_IPI);
qdev_prop_set_uint32(ipi, "num-cpu", ms->smp.cpus);
sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
@@ -1390,6 +1442,7 @@ static void virt_class_init(ObjectClass *oc, void *data)
mc->init = virt_init;
mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("la464");
mc->default_ram_id = "loongarch.ram";
+ mc->desc = "QEMU LoongArch Virtual Machine";
mc->max_cpus = LOONGARCH_MAX_CPUS;
mc->is_default = 1;
mc->default_kernel_irqchip_split = false;
diff --git a/hw/m68k/bootinfo.h b/hw/m68k/bootinfo.h
index 0e6e3ee..0b3e7c4 100644
--- a/hw/m68k/bootinfo.h
+++ b/hw/m68k/bootinfo.h
@@ -1,5 +1,5 @@
/*
- * SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+ * SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
*
* Bootinfo tags from linux bootinfo.h and bootinfo-mac.h:
* This is an easily parsable and extendable structure containing all
@@ -14,39 +14,39 @@
#define BOOTINFO0(base, id) \
do { \
- stw_p(base, id); \
+ stw_be_p(base, id); \
base += 2; \
- stw_p(base, sizeof(struct bi_record)); \
+ stw_be_p(base, sizeof(struct bi_record)); \
base += 2; \
} while (0)
#define BOOTINFO1(base, id, value) \
do { \
- stw_p(base, id); \
+ stw_be_p(base, id); \
base += 2; \
- stw_p(base, sizeof(struct bi_record) + 4); \
+ stw_be_p(base, sizeof(struct bi_record) + 4); \
base += 2; \
- stl_p(base, value); \
+ stl_be_p(base, value); \
base += 4; \
} while (0)
#define BOOTINFO2(base, id, value1, value2) \
do { \
- stw_p(base, id); \
+ stw_be_p(base, id); \
base += 2; \
- stw_p(base, sizeof(struct bi_record) + 8); \
+ stw_be_p(base, sizeof(struct bi_record) + 8); \
base += 2; \
- stl_p(base, value1); \
+ stl_be_p(base, value1); \
base += 4; \
- stl_p(base, value2); \
+ stl_be_p(base, value2); \
base += 4; \
} while (0)
#define BOOTINFOSTR(base, id, string) \
do { \
- stw_p(base, id); \
+ stw_be_p(base, id); \
base += 2; \
- stw_p(base, \
+ stw_be_p(base, \
(sizeof(struct bi_record) + strlen(string) + \
1 /* null termination */ + 3 /* padding */) & ~3); \
base += 2; \
@@ -59,13 +59,13 @@
#define BOOTINFODATA(base, id, data, len) \
do { \
- stw_p(base, id); \
+ stw_be_p(base, id); \
base += 2; \
- stw_p(base, \
+ stw_be_p(base, \
(sizeof(struct bi_record) + len + \
2 /* length field */ + 3 /* padding */) & ~3); \
base += 2; \
- stw_p(base, len); \
+ stw_be_p(base, len); \
base += 2; \
for (unsigned i_ = 0; i_ < len; ++i_) { \
stb_p(base++, data[i_]); \
diff --git a/hw/m68k/mcf5206.c b/hw/m68k/mcf5206.c
index 183fd3c..7247cdb 100644
--- a/hw/m68k/mcf5206.c
+++ b/hw/m68k/mcf5206.c
@@ -614,7 +614,7 @@ static void mcf5206_mbar_class_init(ObjectClass *oc, void *data)
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->desc = "MCF5206 system integration module";
dc->realize = mcf5206_mbar_realize;
- dc->reset = m5206_mbar_reset;
+ device_class_set_legacy_reset(dc, m5206_mbar_reset);
}
static const TypeInfo mcf5206_mbar_info = {
diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c
index ec14096..e37cd50 100644
--- a/hw/m68k/mcf5208.c
+++ b/hw/m68k/mcf5208.c
@@ -4,6 +4,14 @@
* Copyright (c) 2007 CodeSourcery.
*
* This code is licensed under the GPL
+ *
+ * This file models both the MCF5208 SoC, and the
+ * MCF5208EVB evaluation board. For details see
+ *
+ * "MCF5208 Reference Manual"
+ * https://www.nxp.com/docs/en/reference-manual/MCF5208RM.pdf
+ * "M5208EVB-RevB 32-bit Microcontroller User Manual"
+ * https://www.nxp.com/docs/en/reference-manual/M5208EVBUM.pdf
*/
#include "qemu/osdep.h"
@@ -158,7 +166,7 @@ static uint64_t m5208_sys_read(void *opaque, hwaddr addr,
{
int n;
for (n = 0; n < 32; n++) {
- if (current_machine->ram_size < (2u << n)) {
+ if (current_machine->ram_size < (2ULL << n)) {
break;
}
}
@@ -351,7 +359,7 @@ static void mcf5208evb_init(MachineState *machine)
/* Initial PC is always at offset 4 in firmware binaries */
ptr = rom_ptr(0x4, 4);
assert(ptr != NULL);
- env->pc = ldl_p(ptr);
+ env->pc = ldl_be_p(ptr);
}
/* Load kernel. */
diff --git a/hw/m68k/mcf_intc.c b/hw/m68k/mcf_intc.c
index 1d3b34e..9fc30b0 100644
--- a/hw/m68k/mcf_intc.c
+++ b/hw/m68k/mcf_intc.c
@@ -189,7 +189,7 @@ static void mcf_intc_class_init(ObjectClass *oc, void *data)
device_class_set_props(dc, mcf_intc_properties);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->reset = mcf_intc_reset;
+ device_class_set_legacy_reset(dc, mcf_intc_reset);
}
static const TypeInfo mcf_intc_gate_info = {
diff --git a/hw/m68k/next-cube.c b/hw/m68k/next-cube.c
index 9f6f90d..9832213 100644
--- a/hw/m68k/next-cube.c
+++ b/hw/m68k/next-cube.c
@@ -959,7 +959,7 @@ static void next_pc_class_init(ObjectClass *klass, void *data)
dc->desc = "NeXT Peripheral Controller";
dc->realize = next_pc_realize;
- dc->reset = next_pc_reset;
+ device_class_set_legacy_reset(dc, next_pc_reset);
device_class_set_props(dc, next_pc_properties);
dc->vmsd = &next_pc_vmstate;
}
@@ -1036,7 +1036,7 @@ static void next_cube_init(MachineState *machine)
/* Initial PC is always at offset 4 in firmware binaries */
ptr = rom_ptr(0x01000004, 4);
g_assert(ptr != NULL);
- env->pc = ldl_p(ptr);
+ env->pc = ldl_be_p(ptr);
if (env->pc >= 0x01020000) {
error_report("'%s' does not seem to be a valid firmware image.",
bios_name);
diff --git a/hw/m68k/next-kbd.c b/hw/m68k/next-kbd.c
index 0c348c1..bc67810 100644
--- a/hw/m68k/next-kbd.c
+++ b/hw/m68k/next-kbd.c
@@ -271,7 +271,7 @@ static void nextkbd_class_init(ObjectClass *oc, void *data)
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
dc->vmsd = &nextkbd_vmstate;
dc->realize = nextkbd_realize;
- dc->reset = nextkbd_reset;
+ device_class_set_legacy_reset(dc, nextkbd_reset);
}
static const TypeInfo nextkbd_info = {
diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c
index fa7683b..556604e 100644
--- a/hw/m68k/q800.c
+++ b/hw/m68k/q800.c
@@ -684,9 +684,9 @@ static void q800_machine_init(MachineState *machine)
ptr = rom_ptr(MACROM_ADDR, bios_size);
assert(ptr != NULL);
- stl_phys(cs->as, 0, ldl_p(ptr)); /* reset initial SP */
+ stl_phys(cs->as, 0, ldl_be_p(ptr)); /* reset initial SP */
stl_phys(cs->as, 4,
- MACROM_ADDR + ldl_p(ptr + 4)); /* reset initial PC */
+ MACROM_ADDR + ldl_be_p(ptr + 4)); /* reset initial PC */
}
}
}
diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c
index cda199a..ea5c4a5 100644
--- a/hw/m68k/virt.c
+++ b/hw/m68k/virt.c
@@ -366,10 +366,17 @@ type_init(virt_machine_register_types)
#define DEFINE_VIRT_MACHINE(major, minor) \
DEFINE_VIRT_MACHINE_IMPL(false, major, minor)
+static void virt_machine_9_2_options(MachineClass *mc)
+{
+}
+DEFINE_VIRT_MACHINE_AS_LATEST(9, 2)
+
static void virt_machine_9_1_options(MachineClass *mc)
{
+ virt_machine_9_2_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_9_1, hw_compat_9_1_len);
}
-DEFINE_VIRT_MACHINE_AS_LATEST(9, 1)
+DEFINE_VIRT_MACHINE(9, 1)
static void virt_machine_9_0_options(MachineClass *mc)
{
diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c
index 35ac598..235ac40 100644
--- a/hw/mem/cxl_type3.c
+++ b/hw/mem/cxl_type3.c
@@ -737,6 +737,11 @@ static bool cxl_setup_memory(CXLType3Dev *ct3d, Error **errp)
error_setg(errp, "volatile memdev must have backing device");
return false;
}
+ if (host_memory_backend_is_mapped(ct3d->hostvmem)) {
+ error_setg(errp, "memory backend %s can't be used multiple times.",
+ object_get_canonical_path_component(OBJECT(ct3d->hostvmem)));
+ return false;
+ }
memory_region_set_nonvolatile(vmr, false);
memory_region_set_enabled(vmr, true);
host_memory_backend_set_mapped(ct3d->hostvmem, true);
@@ -760,6 +765,11 @@ static bool cxl_setup_memory(CXLType3Dev *ct3d, Error **errp)
error_setg(errp, "persistent memdev must have backing device");
return false;
}
+ if (host_memory_backend_is_mapped(ct3d->hostpmem)) {
+ error_setg(errp, "memory backend %s can't be used multiple times.",
+ object_get_canonical_path_component(OBJECT(ct3d->hostpmem)));
+ return false;
+ }
memory_region_set_nonvolatile(pmr, true);
memory_region_set_enabled(pmr, true);
host_memory_backend_set_mapped(ct3d->hostpmem, true);
@@ -790,6 +800,11 @@ static bool cxl_setup_memory(CXLType3Dev *ct3d, Error **errp)
return false;
}
+ if (host_memory_backend_is_mapped(ct3d->dc.host_dc)) {
+ error_setg(errp, "memory backend %s can't be used multiple times.",
+ object_get_canonical_path_component(OBJECT(ct3d->dc.host_dc)));
+ return false;
+ }
/*
* Set DC regions as volatile for now, non-volatile support can
* be added in the future if needed.
@@ -829,6 +844,7 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp)
uint8_t *pci_conf = pci_dev->config;
unsigned short msix_num = 6;
int i, rc;
+ uint16_t count;
QTAILQ_INIT(&ct3d->error_list);
@@ -893,6 +909,28 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp)
}
cxl_event_init(&ct3d->cxl_dstate, 2);
+ /* Set default value for patrol scrub attributes */
+ ct3d->patrol_scrub_attrs.scrub_cycle_cap =
+ CXL_MEMDEV_PS_SCRUB_CYCLE_CHANGE_CAP_DEFAULT |
+ CXL_MEMDEV_PS_SCRUB_REALTIME_REPORT_CAP_DEFAULT;
+ ct3d->patrol_scrub_attrs.scrub_cycle =
+ CXL_MEMDEV_PS_CUR_SCRUB_CYCLE_DEFAULT |
+ (CXL_MEMDEV_PS_MIN_SCRUB_CYCLE_DEFAULT << 8);
+ ct3d->patrol_scrub_attrs.scrub_flags = CXL_MEMDEV_PS_ENABLE_DEFAULT;
+
+ /* Set default value for DDR5 ECS read attributes */
+ for (count = 0; count < CXL_ECS_NUM_MEDIA_FRUS; count++) {
+ ct3d->ecs_attrs[count].ecs_log_cap =
+ CXL_ECS_LOG_ENTRY_TYPE_DEFAULT;
+ ct3d->ecs_attrs[count].ecs_cap =
+ CXL_ECS_REALTIME_REPORT_CAP_DEFAULT;
+ ct3d->ecs_attrs[count].ecs_config =
+ CXL_ECS_THRESHOLD_COUNT_DEFAULT |
+ (CXL_ECS_MODE_DEFAULT << 3);
+ /* Reserved */
+ ct3d->ecs_attrs[count].ecs_flags = 0;
+ }
+
return;
err_release_cdat:
@@ -1127,7 +1165,7 @@ MemTxResult cxl_type3_read(PCIDevice *d, hwaddr host_addr, uint64_t *data,
return MEMTX_ERROR;
}
- if (sanitize_running(&ct3d->cci)) {
+ if (cxl_dev_media_disabled(&ct3d->cxl_dstate)) {
qemu_guest_getrandom_nofail(data, size);
return MEMTX_OK;
}
@@ -1149,7 +1187,7 @@ MemTxResult cxl_type3_write(PCIDevice *d, hwaddr host_addr, uint64_t data,
return MEMTX_ERROR;
}
- if (sanitize_running(&ct3d->cci)) {
+ if (cxl_dev_media_disabled(&ct3d->cxl_dstate)) {
return MEMTX_OK;
}
@@ -1304,6 +1342,12 @@ void cxl_set_poison_list_overflowed(CXLType3Dev *ct3d)
cxl_device_get_timestamp(&ct3d->cxl_dstate);
}
+void cxl_clear_poison_list_overflowed(CXLType3Dev *ct3d)
+{
+ ct3d->poison_list_overflowed = false;
+ ct3d->poison_list_overflow_ts = 0;
+}
+
void qmp_cxl_inject_poison(const char *path, uint64_t start, uint64_t length,
Error **errp)
{
@@ -1340,19 +1384,21 @@ void qmp_cxl_inject_poison(const char *path, uint64_t start, uint64_t length,
}
}
- if (ct3d->poison_list_cnt == CXL_POISON_LIST_LIMIT) {
- cxl_set_poison_list_overflowed(ct3d);
- return;
- }
-
p = g_new0(CXLPoison, 1);
p->length = length;
p->start = start;
/* Different from injected via the mbox */
p->type = CXL_POISON_TYPE_INTERNAL;
- QLIST_INSERT_HEAD(&ct3d->poison_list, p, node);
- ct3d->poison_list_cnt++;
+ if (ct3d->poison_list_cnt < CXL_POISON_LIST_LIMIT) {
+ QLIST_INSERT_HEAD(&ct3d->poison_list, p, node);
+ ct3d->poison_list_cnt++;
+ } else {
+ if (!ct3d->poison_list_overflowed) {
+ cxl_set_poison_list_overflowed(ct3d);
+ }
+ QLIST_INSERT_HEAD(&ct3d->poison_list_bkp, p, node);
+ }
}
/* For uncorrectable errors include support for multiple header recording */
@@ -2098,7 +2144,7 @@ static void ct3_class_init(ObjectClass *oc, void *data)
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
dc->desc = "CXL Memory Device (Type 3)";
- dc->reset = ct3d_reset;
+ device_class_set_legacy_reset(dc, ct3d_reset);
device_class_set_props(dc, ct3_props);
cvc->get_lsa_size = get_lsa_size;
diff --git a/hw/meson.build b/hw/meson.build
index 1c6308f..b827c82 100644
--- a/hw/meson.build
+++ b/hw/meson.build
@@ -27,7 +27,6 @@ subdir('nvram')
subdir('pci')
subdir('pci-bridge')
subdir('pci-host')
-subdir('pcmcia')
subdir('rtc')
subdir('scsi')
subdir('sd')
@@ -48,7 +47,6 @@ subdir('fsi')
subdir('alpha')
subdir('arm')
subdir('avr')
-subdir('cris')
subdir('hppa')
subdir('i386')
subdir('loongarch')
diff --git a/hw/microblaze/Kconfig b/hw/microblaze/Kconfig
index d78ba84..b0214b2 100644
--- a/hw/microblaze/Kconfig
+++ b/hw/microblaze/Kconfig
@@ -13,7 +13,7 @@ config PETALOGIX_ML605
default y
depends on MICROBLAZE
select PFLASH_CFI01
- select SERIAL
+ select SERIAL_MM
select SSI_M25P80
select XILINX
select XILINX_AXI
diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c
index 0f5fabc..b4183c5 100644
--- a/hw/microblaze/petalogix_ml605_mmu.c
+++ b/hw/microblaze/petalogix_ml605_mmu.c
@@ -34,7 +34,7 @@
#include "hw/block/flash.h"
#include "sysemu/sysemu.h"
#include "hw/boards.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/qdev-properties.h"
#include "exec/address-spaces.h"
#include "hw/ssi/ssi.h"
diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
index 692bede..b09c89a 100644
--- a/hw/mips/Kconfig
+++ b/hw/mips/Kconfig
@@ -10,14 +10,14 @@ config MALTA
select MIPS_CPS
select PIIX
select PFLASH_CFI01
- select SERIAL
+ select SERIAL_MM
select SMBUS_EEPROM
config MIPSSIM
bool
default y
depends on MIPS
- select SERIAL
+ select SERIAL_MM
select MIPSNET
config JAZZ
@@ -37,7 +37,7 @@ config JAZZ
select FDC_SYSBUS
select MC146818RTC
select PCKBD
- select SERIAL
+ select SERIAL_MM
select PARALLEL
select DS1225Y
select JAZZ_LED
@@ -65,7 +65,7 @@ config LOONGSON3V
imply VIRTIO_VGA
imply QXL if SPICE
imply USB_OHCI_PCI
- select SERIAL
+ select SERIAL_MM
select GOLDFISH_RTC
select LOONGSON_IPI
select LOONGSON_LIOINTC
@@ -89,7 +89,7 @@ config MIPS_BOSTON
select MIPS_CPS
select PCI_EXPRESS_XILINX
select AHCI_ICH9
- select SERIAL
+ select SERIAL_MM
config FW_CFG_MIPS
bool
diff --git a/hw/mips/boston.c b/hw/mips/boston.c
index 1b44fb3..1ced1e3 100644
--- a/hw/mips/boston.c
+++ b/hw/mips/boston.c
@@ -22,7 +22,7 @@
#include "elf.h"
#include "hw/boards.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/ide/pci.h"
#include "hw/ide/ahci-pci.h"
#include "hw/loader.h"
diff --git a/hw/mips/cps.c b/hw/mips/cps.c
index 07b73b0..1304662 100644
--- a/hw/mips/cps.c
+++ b/hw/mips/cps.c
@@ -77,6 +77,9 @@ static void mips_cps_realize(DeviceState *dev, Error **errp)
MIPSCPU *cpu = MIPS_CPU(object_new(s->cpu_type));
CPUMIPSState *env = &cpu->env;
+ object_property_set_bool(OBJECT(cpu), "big-endian", s->cpu_is_bigendian,
+ &error_abort);
+
/* All VPs are halted on reset. Leave powering up to CPC. */
object_property_set_bool(OBJECT(cpu), "start-powered-off", true,
&error_abort);
@@ -167,6 +170,7 @@ static Property mips_cps_properties[] = {
DEFINE_PROP_UINT32("num-vp", MIPSCPSState, num_vp, 1),
DEFINE_PROP_UINT32("num-irq", MIPSCPSState, num_irq, 256),
DEFINE_PROP_STRING("cpu-type", MIPSCPSState, cpu_type),
+ DEFINE_PROP_BOOL("cpu-big-endian", MIPSCPSState, cpu_is_bigendian, false),
DEFINE_PROP_END_OF_LIST()
};
diff --git a/hw/mips/fuloong2e.c b/hw/mips/fuloong2e.c
index 6e4303b..7fd8296 100644
--- a/hw/mips/fuloong2e.c
+++ b/hw/mips/fuloong2e.c
@@ -229,7 +229,7 @@ static void mips_fuloong2e_init(MachineState *machine)
clock_set_hz(cpuclk, 533080000); /* ~533 MHz */
/* init CPUs */
- cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk);
+ cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk, false);
env = &cpu->env;
qemu_register_reset(main_cpu_reset, cpu);
diff --git a/hw/mips/jazz.c b/hw/mips/jazz.c
index 1bc17e6..0e43c9f 100644
--- a/hw/mips/jazz.c
+++ b/hw/mips/jazz.c
@@ -28,7 +28,7 @@
#include "hw/mips/mips.h"
#include "hw/intc/i8259.h"
#include "hw/dma/i8257.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/char/parallel.h"
#include "hw/isa/isa.h"
#include "hw/block/fdc.h"
@@ -128,7 +128,7 @@ static void mips_jazz_init_net(IOMMUMemoryRegion *rc4030_dma_mr,
uint8_t *prom;
NICInfo *nd;
- nd = qemu_find_nic_info("dp8393x", true, "dp82932");
+ nd = qemu_find_nic_info("dp8393x", true, "dp83932");
if (!nd) {
return;
}
@@ -212,7 +212,8 @@ static void mips_jazz_init(MachineState *machine,
* ext_clk[jazz_model].pll_mult);
/* init CPUs */
- cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk);
+ cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk,
+ TARGET_BIG_ENDIAN);
env = &cpu->env;
qemu_register_reset(main_cpu_reset, cpu);
diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c
index 4ad36f0..f3b6326 100644
--- a/hw/mips/loongson3_virt.c
+++ b/hw/mips/loongson3_virt.c
@@ -29,7 +29,7 @@
#include "qemu/datadir.h"
#include "qapi/error.h"
#include "elf.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/intc/loongson_liointc.h"
#include "hw/mips/mips.h"
#include "hw/mips/fw_cfg.h"
@@ -97,6 +97,7 @@ struct LoongsonMachineState {
MemoryRegion *pio_alias;
MemoryRegion *mmio_alias;
MemoryRegion *ecam_alias;
+ MemoryRegion *core_iocsr[LOONGSON_MAX_VCPUS];
};
typedef struct LoongsonMachineState LoongsonMachineState;
@@ -355,8 +356,8 @@ static uint64_t load_kernel(CPUMIPSState *env)
kernel_size = load_elf(loaderparams.kernel_filename, NULL,
cpu_mips_kseg0_to_phys, NULL,
- (uint64_t *)&kernel_entry,
- (uint64_t *)&kernel_low, (uint64_t *)&kernel_high,
+ &kernel_entry,
+ &kernel_low, &kernel_high,
NULL, 0, EM_MIPS, 1, 0);
if (kernel_size < 0) {
error_report("could not load kernel '%s': %s",
@@ -493,6 +494,7 @@ static void mips_loongson3_virt_init(MachineState *machine)
const char *kernel_filename = machine->kernel_filename;
const char *initrd_filename = machine->initrd_filename;
ram_addr_t ram_size = machine->ram_size;
+ LoongsonMachineState *s = LOONGSON_MACHINE(machine);
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *ram = g_new(MemoryRegion, 1);
MemoryRegion *bios = g_new(MemoryRegion, 1);
@@ -565,14 +567,14 @@ static void mips_loongson3_virt_init(MachineState *machine)
int ip;
/* init CPUs */
- cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk);
+ cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk, false);
/* Init internal devices */
cpu_mips_irq_init_cpu(cpu);
cpu_mips_clock_init(cpu);
qemu_register_reset(main_cpu_reset, cpu);
- if (ipi) {
+ if (!kvm_enabled()) {
hwaddr base = ((hwaddr)node << 44) + virt_memmap[VIRT_IPI].base;
base += core * 0x100;
qdev_connect_gpio_out(ipi, i, cpu->env.irq[6]);
@@ -586,6 +588,7 @@ static void mips_loongson3_virt_init(MachineState *machine)
iocsr, 0, UINT32_MAX);
memory_region_add_subregion(&MIPS_CPU(cpu)->env.iocsr.mr,
0, core_iocsr);
+ s->core_iocsr[i] = core_iocsr;
}
if (node > 0) {
diff --git a/hw/mips/malta.c b/hw/mips/malta.c
index 664a2ae..198da5b 100644
--- a/hw/mips/malta.c
+++ b/hw/mips/malta.c
@@ -31,7 +31,7 @@
#include "hw/clock.h"
#include "hw/southbridge/piix.h"
#include "hw/isa/superio.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "net/net.h"
#include "hw/boards.h"
#include "hw/i2c/smbus_eeprom.h"
@@ -1034,7 +1034,8 @@ static void create_cpu_without_cps(MachineState *ms, MaltaState *s,
int i;
for (i = 0; i < ms->smp.cpus; i++) {
- cpu = mips_cpu_create_with_clock(ms->cpu_type, s->cpuclk);
+ cpu = mips_cpu_create_with_clock(ms->cpu_type, s->cpuclk,
+ TARGET_BIG_ENDIAN);
/* Init internal devices */
cpu_mips_irq_init_cpu(cpu);
@@ -1054,6 +1055,8 @@ static void create_cps(MachineState *ms, MaltaState *s,
object_initialize_child(OBJECT(s), "cps", &s->cps, TYPE_MIPS_CPS);
object_property_set_str(OBJECT(&s->cps), "cpu-type", ms->cpu_type,
&error_fatal);
+ object_property_set_bool(OBJECT(&s->cps), "cpu-big-endian",
+ TARGET_BIG_ENDIAN, &error_abort);
object_property_set_uint(OBJECT(&s->cps), "num-vp", ms->smp.cpus,
&error_fatal);
qdev_connect_clock_in(DEVICE(&s->cps), "clk-in", s->cpuclk);
diff --git a/hw/mips/meson.build b/hw/mips/meson.build
index ca37c42..fcbee53 100644
--- a/hw/mips/meson.build
+++ b/hw/mips/meson.build
@@ -1,6 +1,6 @@
mips_ss = ss.source_set()
mips_ss.add(files('bootloader.c', 'mips_int.c'))
-mips_ss.add(when: 'CONFIG_FW_CFG_MIPS', if_true: files('fw_cfg.c'))
+common_ss.add(when: 'CONFIG_FW_CFG_MIPS', if_true: files('fw_cfg.c'))
mips_ss.add(when: 'CONFIG_LOONGSON3V', if_true: files('loongson3_bootp.c', 'loongson3_virt.c'))
mips_ss.add(when: 'CONFIG_MALTA', if_true: files('malta.c'))
mips_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('cps.c'))
diff --git a/hw/mips/mipssim.c b/hw/mips/mipssim.c
index 9170d6c..5f4835a 100644
--- a/hw/mips/mipssim.c
+++ b/hw/mips/mipssim.c
@@ -31,7 +31,7 @@
#include "exec/address-spaces.h"
#include "hw/clock.h"
#include "hw/mips/mips.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "net/net.h"
#include "sysemu/sysemu.h"
#include "hw/boards.h"
@@ -160,7 +160,8 @@ mips_mipssim_init(MachineState *machine)
#endif
/* Init CPUs. */
- cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk);
+ cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk,
+ TARGET_BIG_ENDIAN);
env = &cpu->env;
reset_info = g_new0(ResetData, 1);
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index 1e08785..1f1baa5 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -74,7 +74,6 @@ config IVSHMEM_DEVICE
config ECCMEMCTL
bool
- select ECC
config IMX
bool
@@ -82,6 +81,9 @@ config IMX
select SSI
select USB_EHCI_SYSBUS
+config STM32_RCC
+ bool
+
config STM32F2XX_SYSCFG
bool
diff --git a/hw/misc/a9scu.c b/hw/misc/a9scu.c
index 04225df..a40d507 100644
--- a/hw/misc/a9scu.c
+++ b/hw/misc/a9scu.c
@@ -134,7 +134,7 @@ static void a9_scu_class_init(ObjectClass *klass, void *data)
device_class_set_props(dc, a9_scu_properties);
dc->vmsd = &vmstate_a9_scu;
- dc->reset = a9_scu_reset;
+ device_class_set_legacy_reset(dc, a9_scu_reset);
dc->realize = a9_scu_realize;
}
diff --git a/hw/misc/allwinner-cpucfg.c b/hw/misc/allwinner-cpucfg.c
index 31b9780..022f63d 100644
--- a/hw/misc/allwinner-cpucfg.c
+++ b/hw/misc/allwinner-cpucfg.c
@@ -262,7 +262,7 @@ static void allwinner_cpucfg_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = allwinner_cpucfg_reset;
+ device_class_set_legacy_reset(dc, allwinner_cpucfg_reset);
dc->vmsd = &allwinner_cpucfg_vmstate;
}
diff --git a/hw/misc/allwinner-h3-ccu.c b/hw/misc/allwinner-h3-ccu.c
index cfc6852..92e579a 100644
--- a/hw/misc/allwinner-h3-ccu.c
+++ b/hw/misc/allwinner-h3-ccu.c
@@ -222,7 +222,7 @@ static void allwinner_h3_ccu_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = allwinner_h3_ccu_reset;
+ device_class_set_legacy_reset(dc, allwinner_h3_ccu_reset);
dc->vmsd = &allwinner_h3_ccu_vmstate;
}
diff --git a/hw/misc/allwinner-h3-dramc.c b/hw/misc/allwinner-h3-dramc.c
index e168ffe..eeab0dc 100644
--- a/hw/misc/allwinner-h3-dramc.c
+++ b/hw/misc/allwinner-h3-dramc.c
@@ -336,7 +336,7 @@ static void allwinner_h3_dramc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = allwinner_h3_dramc_reset;
+ device_class_set_legacy_reset(dc, allwinner_h3_dramc_reset);
dc->vmsd = &allwinner_h3_dramc_vmstate;
dc->realize = allwinner_h3_dramc_realize;
device_class_set_props(dc, allwinner_h3_dramc_properties);
diff --git a/hw/misc/allwinner-h3-sysctrl.c b/hw/misc/allwinner-h3-sysctrl.c
index 2d29be8..40059e8 100644
--- a/hw/misc/allwinner-h3-sysctrl.c
+++ b/hw/misc/allwinner-h3-sysctrl.c
@@ -120,7 +120,7 @@ static void allwinner_h3_sysctrl_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = allwinner_h3_sysctrl_reset;
+ device_class_set_legacy_reset(dc, allwinner_h3_sysctrl_reset);
dc->vmsd = &allwinner_h3_sysctrl_vmstate;
}
diff --git a/hw/misc/allwinner-r40-ccu.c b/hw/misc/allwinner-r40-ccu.c
index 33baf44..005a15b 100644
--- a/hw/misc/allwinner-r40-ccu.c
+++ b/hw/misc/allwinner-r40-ccu.c
@@ -189,7 +189,7 @@ static void allwinner_r40_ccu_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = allwinner_r40_ccu_reset;
+ device_class_set_legacy_reset(dc, allwinner_r40_ccu_reset);
dc->vmsd = &allwinner_r40_ccu_vmstate;
}
diff --git a/hw/misc/allwinner-r40-dramc.c b/hw/misc/allwinner-r40-dramc.c
index 75b0bef..3ae4890 100644
--- a/hw/misc/allwinner-r40-dramc.c
+++ b/hw/misc/allwinner-r40-dramc.c
@@ -489,7 +489,7 @@ static void allwinner_r40_dramc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = allwinner_r40_dramc_reset;
+ device_class_set_legacy_reset(dc, allwinner_r40_dramc_reset);
dc->vmsd = &allwinner_r40_dramc_vmstate;
dc->realize = allwinner_r40_dramc_realize;
device_class_set_props(dc, allwinner_r40_dramc_properties);
diff --git a/hw/misc/allwinner-sid.c b/hw/misc/allwinner-sid.c
index e5cd431..19ff17d 100644
--- a/hw/misc/allwinner-sid.c
+++ b/hw/misc/allwinner-sid.c
@@ -148,7 +148,7 @@ static void allwinner_sid_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = allwinner_sid_reset;
+ device_class_set_legacy_reset(dc, allwinner_sid_reset);
dc->vmsd = &allwinner_sid_vmstate;
device_class_set_props(dc, allwinner_sid_properties);
}
diff --git a/hw/misc/allwinner-sramc.c b/hw/misc/allwinner-sramc.c
index cf10ca8..a20b0b4 100644
--- a/hw/misc/allwinner-sramc.c
+++ b/hw/misc/allwinner-sramc.c
@@ -139,7 +139,7 @@ static void allwinner_sramc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = allwinner_sramc_reset;
+ device_class_set_legacy_reset(dc, allwinner_sramc_reset);
dc->vmsd = &allwinner_sramc_vmstate;
}
diff --git a/hw/misc/applesmc.c b/hw/misc/applesmc.c
index 59a4899..5b76627 100644
--- a/hw/misc/applesmc.c
+++ b/hw/misc/applesmc.c
@@ -383,7 +383,7 @@ static void qdev_applesmc_class_init(ObjectClass *klass, void *data)
dc->realize = applesmc_isa_realize;
dc->unrealize = applesmc_unrealize;
- dc->reset = qdev_applesmc_isa_reset;
+ device_class_set_legacy_reset(dc, qdev_applesmc_isa_reset);
device_class_set_props(dc, applesmc_isa_properties);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
adevc->build_dev_aml = build_applesmc_aml;
diff --git a/hw/misc/arm_l2x0.c b/hw/misc/arm_l2x0.c
index b14d0a2..1902ebd 100644
--- a/hw/misc/arm_l2x0.c
+++ b/hw/misc/arm_l2x0.c
@@ -184,7 +184,7 @@ static void l2x0_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_l2x0;
device_class_set_props(dc, l2x0_properties);
- dc->reset = l2x0_priv_reset;
+ device_class_set_legacy_reset(dc, l2x0_priv_reset);
}
static const TypeInfo l2x0_info = {
diff --git a/hw/misc/arm_sysctl.c b/hw/misc/arm_sysctl.c
index 5108f3e..9c4dce3 100644
--- a/hw/misc/arm_sysctl.c
+++ b/hw/misc/arm_sysctl.c
@@ -640,7 +640,7 @@ static void arm_sysctl_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = arm_sysctl_realize;
- dc->reset = arm_sysctl_reset;
+ device_class_set_legacy_reset(dc, arm_sysctl_reset);
dc->vmsd = &vmstate_arm_sysctl;
device_class_set_props(dc, arm_sysctl_properties);
}
diff --git a/hw/misc/armsse-cpu-pwrctrl.c b/hw/misc/armsse-cpu-pwrctrl.c
index bfc51d1..2d3a0ac 100644
--- a/hw/misc/armsse-cpu-pwrctrl.c
+++ b/hw/misc/armsse-cpu-pwrctrl.c
@@ -129,7 +129,7 @@ static void pwrctrl_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = pwrctrl_reset;
+ device_class_set_legacy_reset(dc, pwrctrl_reset);
dc->vmsd = &pwrctrl_vmstate;
}
diff --git a/hw/misc/armsse-mhu.c b/hw/misc/armsse-mhu.c
index 55625b2..91c4910 100644
--- a/hw/misc/armsse-mhu.c
+++ b/hw/misc/armsse-mhu.c
@@ -180,7 +180,7 @@ static void armsse_mhu_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = armsse_mhu_reset;
+ device_class_set_legacy_reset(dc, armsse_mhu_reset);
dc->vmsd = &armsse_mhu_vmstate;
}
diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c
index c06c04d..bc1d66a 100644
--- a/hw/misc/aspeed_hace.c
+++ b/hw/misc/aspeed_hace.c
@@ -1,6 +1,7 @@
/*
* ASPEED Hash and Crypto Engine
*
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
* Copyright (C) 2021 IBM Corp.
*
* Joel Stanley <joel@jms.id.au>
@@ -68,15 +69,15 @@
static const struct {
uint32_t mask;
- QCryptoHashAlgorithm algo;
+ QCryptoHashAlgo algo;
} hash_algo_map[] = {
- { HASH_ALGO_MD5, QCRYPTO_HASH_ALG_MD5 },
- { HASH_ALGO_SHA1, QCRYPTO_HASH_ALG_SHA1 },
- { HASH_ALGO_SHA224, QCRYPTO_HASH_ALG_SHA224 },
- { HASH_ALGO_SHA256, QCRYPTO_HASH_ALG_SHA256 },
- { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA512, QCRYPTO_HASH_ALG_SHA512 },
- { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA384, QCRYPTO_HASH_ALG_SHA384 },
- { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA256, QCRYPTO_HASH_ALG_SHA256 },
+ { HASH_ALGO_MD5, QCRYPTO_HASH_ALGO_MD5 },
+ { HASH_ALGO_SHA1, QCRYPTO_HASH_ALGO_SHA1 },
+ { HASH_ALGO_SHA224, QCRYPTO_HASH_ALGO_SHA224 },
+ { HASH_ALGO_SHA256, QCRYPTO_HASH_ALGO_SHA256 },
+ { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA512, QCRYPTO_HASH_ALGO_SHA512 },
+ { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA384, QCRYPTO_HASH_ALGO_SHA384 },
+ { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA256, QCRYPTO_HASH_ALGO_SHA256 },
};
static int hash_algo_lookup(uint32_t reg)
@@ -151,49 +152,28 @@ static int reconstruct_iov(AspeedHACEState *s, struct iovec *iov, int id,
return iov_count;
}
-/**
- * Generate iov for accumulative mode.
- *
- * @param s aspeed hace state object
- * @param iov iov of the current request
- * @param id index of the current iov
- * @param req_len length of the current request
- *
- * @return count of iov
- */
-static int gen_acc_mode_iov(AspeedHACEState *s, struct iovec *iov, int id,
- hwaddr *req_len)
-{
- uint32_t pad_offset;
- uint32_t total_msg_len;
- s->total_req_len += *req_len;
-
- if (has_padding(s, &iov[id], *req_len, &total_msg_len, &pad_offset)) {
- if (s->iov_count) {
- return reconstruct_iov(s, iov, id, &pad_offset);
- }
-
- *req_len -= s->total_req_len - total_msg_len;
- s->total_req_len = 0;
- iov[id].iov_len = *req_len;
- } else {
- s->iov_cache[s->iov_count].iov_base = iov->iov_base;
- s->iov_cache[s->iov_count].iov_len = *req_len;
- ++s->iov_count;
- }
-
- return id + 1;
-}
-
static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode,
bool acc_mode)
{
struct iovec iov[ASPEED_HACE_MAX_SG];
+ uint32_t total_msg_len;
+ uint32_t pad_offset;
g_autofree uint8_t *digest_buf = NULL;
size_t digest_len = 0;
- int niov = 0;
+ bool sg_acc_mode_final_request = false;
int i;
void *haddr;
+ Error *local_err = NULL;
+
+ if (acc_mode && s->hash_ctx == NULL) {
+ s->hash_ctx = qcrypto_hash_new(algo, &local_err);
+ if (s->hash_ctx == NULL) {
+ qemu_log_mask(LOG_GUEST_ERROR, "qcrypto hash failed : %s",
+ error_get_pretty(local_err));
+ error_free(local_err);
+ return;
+ }
+ }
if (sg_mode) {
uint32_t len = 0;
@@ -226,8 +206,16 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode,
}
iov[i].iov_base = haddr;
if (acc_mode) {
- niov = gen_acc_mode_iov(s, iov, i, &plen);
-
+ s->total_req_len += plen;
+
+ if (has_padding(s, &iov[i], plen, &total_msg_len,
+ &pad_offset)) {
+ /* Padding being present indicates the final request */
+ sg_acc_mode_final_request = true;
+ iov[i].iov_len = pad_offset;
+ } else {
+ iov[i].iov_len = plen;
+ }
} else {
iov[i].iov_len = plen;
}
@@ -252,21 +240,42 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode,
* required to check whether cache is empty. If no, we should
* combine cached iov and the current iov.
*/
- uint32_t total_msg_len;
- uint32_t pad_offset;
s->total_req_len += len;
if (has_padding(s, iov, len, &total_msg_len, &pad_offset)) {
- niov = reconstruct_iov(s, iov, 0, &pad_offset);
+ i = reconstruct_iov(s, iov, 0, &pad_offset);
}
}
}
- if (niov) {
- i = niov;
- }
+ if (acc_mode) {
+ if (qcrypto_hash_updatev(s->hash_ctx, iov, i, &local_err) < 0) {
+ qemu_log_mask(LOG_GUEST_ERROR, "qcrypto hash update failed : %s",
+ error_get_pretty(local_err));
+ error_free(local_err);
+ return;
+ }
+
+ if (sg_acc_mode_final_request) {
+ if (qcrypto_hash_finalize_bytes(s->hash_ctx, &digest_buf,
+ &digest_len, &local_err)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "qcrypto hash finalize failed : %s",
+ error_get_pretty(local_err));
+ error_free(local_err);
+ local_err = NULL;
+ }
- if (qcrypto_hash_bytesv(algo, iov, i, &digest_buf, &digest_len, NULL) < 0) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto failed\n", __func__);
+ qcrypto_hash_free(s->hash_ctx);
+
+ s->hash_ctx = NULL;
+ s->iov_count = 0;
+ s->total_req_len = 0;
+ }
+ } else if (qcrypto_hash_bytesv(algo, iov, i, &digest_buf,
+ &digest_len, &local_err) < 0) {
+ qemu_log_mask(LOG_GUEST_ERROR, "qcrypto hash bytesv failed : %s",
+ error_get_pretty(local_err));
+ error_free(local_err);
return;
}
@@ -397,6 +406,11 @@ static void aspeed_hace_reset(DeviceState *dev)
{
struct AspeedHACEState *s = ASPEED_HACE(dev);
+ if (s->hash_ctx != NULL) {
+ qcrypto_hash_free(s->hash_ctx);
+ s->hash_ctx = NULL;
+ }
+
memset(s->regs, 0, sizeof(s->regs));
s->iov_count = 0;
s->total_req_len = 0;
@@ -446,7 +460,7 @@ static void aspeed_hace_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_hace_realize;
- dc->reset = aspeed_hace_reset;
+ device_class_set_legacy_reset(dc, aspeed_hace_reset);
device_class_set_props(dc, aspeed_hace_properties);
dc->vmsd = &vmstate_aspeed_hace;
}
diff --git a/hw/misc/aspeed_i3c.c b/hw/misc/aspeed_i3c.c
index 827c9e5..371ee7d 100644
--- a/hw/misc/aspeed_i3c.c
+++ b/hw/misc/aspeed_i3c.c
@@ -334,7 +334,7 @@ static void aspeed_i3c_device_class_init(ObjectClass *klass, void *data)
dc->desc = "Aspeed I3C Device";
dc->realize = aspeed_i3c_device_realize;
- dc->reset = aspeed_i3c_device_reset;
+ device_class_set_legacy_reset(dc, aspeed_i3c_device_reset);
device_class_set_props(dc, aspeed_i3c_device_properties);
}
@@ -362,7 +362,7 @@ static void aspeed_i3c_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_i3c_realize;
- dc->reset = aspeed_i3c_reset;
+ device_class_set_legacy_reset(dc, aspeed_i3c_reset);
dc->desc = "Aspeed I3C Controller";
dc->vmsd = &vmstate_aspeed_i3c;
}
diff --git a/hw/misc/aspeed_lpc.c b/hw/misc/aspeed_lpc.c
index 193f0de..f2d4ca6 100644
--- a/hw/misc/aspeed_lpc.c
+++ b/hw/misc/aspeed_lpc.c
@@ -464,7 +464,7 @@ static void aspeed_lpc_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_lpc_realize;
- dc->reset = aspeed_lpc_reset;
+ device_class_set_legacy_reset(dc, aspeed_lpc_reset);
dc->desc = "Aspeed LPC Controller",
dc->vmsd = &vmstate_aspeed_lpc;
device_class_set_props(dc, aspeed_lpc_properties);
diff --git a/hw/misc/aspeed_peci.c b/hw/misc/aspeed_peci.c
index 93cc672..9025b35 100644
--- a/hw/misc/aspeed_peci.c
+++ b/hw/misc/aspeed_peci.c
@@ -135,7 +135,7 @@ static void aspeed_peci_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_peci_realize;
- dc->reset = aspeed_peci_reset;
+ device_class_set_legacy_reset(dc, aspeed_peci_reset);
dc->desc = "Aspeed PECI Controller";
}
diff --git a/hw/misc/aspeed_sbc.c b/hw/misc/aspeed_sbc.c
index 8bb1f90..f5eb2a0 100644
--- a/hw/misc/aspeed_sbc.c
+++ b/hw/misc/aspeed_sbc.c
@@ -147,7 +147,7 @@ static void aspeed_sbc_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_sbc_realize;
- dc->reset = aspeed_sbc_reset;
+ device_class_set_legacy_reset(dc, aspeed_sbc_reset);
dc->vmsd = &vmstate_aspeed_sbc;
device_class_set_props(dc, aspeed_sbc_properties);
}
diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c
index 451e837..2c91934 100644
--- a/hw/misc/aspeed_scu.c
+++ b/hw/misc/aspeed_scu.c
@@ -614,7 +614,7 @@ static void aspeed_scu_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_scu_realize;
- dc->reset = aspeed_scu_reset;
+ device_class_set_legacy_reset(dc, aspeed_scu_reset);
dc->desc = "ASPEED System Control Unit";
dc->vmsd = &vmstate_aspeed_scu;
device_class_set_props(dc, aspeed_scu_properties);
@@ -831,7 +831,7 @@ static void aspeed_2600_scu_class_init(ObjectClass *klass, void *data)
AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
dc->desc = "ASPEED 2600 System Control Unit";
- dc->reset = aspeed_ast2600_scu_reset;
+ device_class_set_legacy_reset(dc, aspeed_ast2600_scu_reset);
asc->resets = ast2600_a3_resets;
asc->calc_hpll = aspeed_2600_scu_calc_hpll;
asc->get_apb = aspeed_2600_scu_get_apb_freq;
@@ -947,7 +947,7 @@ static void aspeed_2700_scu_class_init(ObjectClass *klass, void *data)
AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
dc->desc = "ASPEED 2700 System Control Unit";
- dc->reset = aspeed_ast2700_scu_reset;
+ device_class_set_legacy_reset(dc, aspeed_ast2700_scu_reset);
asc->resets = ast2700_a0_resets;
asc->calc_hpll = aspeed_2600_scu_calc_hpll;
asc->get_apb = aspeed_2700_scu_get_apb_freq;
@@ -1061,7 +1061,7 @@ static void aspeed_2700_scuio_class_init(ObjectClass *klass, void *data)
AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
dc->desc = "ASPEED 2700 System Control Unit I/O";
- dc->reset = aspeed_ast2700_scu_reset;
+ device_class_set_legacy_reset(dc, aspeed_ast2700_scu_reset);
asc->resets = ast2700_a0_resets_io;
asc->calc_hpll = aspeed_2600_scu_calc_hpll;
asc->get_apb = aspeed_2700_scuio_get_apb_freq;
@@ -1119,7 +1119,7 @@ static void aspeed_1030_scu_class_init(ObjectClass *klass, void *data)
AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
dc->desc = "ASPEED 1030 System Control Unit";
- dc->reset = aspeed_ast1030_scu_reset;
+ device_class_set_legacy_reset(dc, aspeed_ast1030_scu_reset);
asc->resets = ast1030_a1_resets;
asc->calc_hpll = aspeed_2600_scu_calc_hpll;
asc->get_apb = aspeed_1030_scu_get_apb_freq;
diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c
index ebf139c..4bc9faf 100644
--- a/hw/misc/aspeed_sdmc.c
+++ b/hw/misc/aspeed_sdmc.c
@@ -304,7 +304,7 @@ static void aspeed_sdmc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_sdmc_realize;
- dc->reset = aspeed_sdmc_reset;
+ device_class_set_legacy_reset(dc, aspeed_sdmc_reset);
dc->desc = "ASPEED SDRAM Memory Controller";
dc->vmsd = &vmstate_aspeed_sdmc;
device_class_set_props(dc, aspeed_sdmc_properties);
@@ -677,7 +677,7 @@ static void aspeed_2700_sdmc_class_init(ObjectClass *klass, void *data)
AspeedSDMCClass *asc = ASPEED_SDMC_CLASS(klass);
dc->desc = "ASPEED 2700 SDRAM Memory Controller";
- dc->reset = aspeed_2700_sdmc_reset;
+ device_class_set_legacy_reset(dc, aspeed_2700_sdmc_reset);
asc->is_bus64bit = true;
asc->max_ram_size = 8 * GiB;
diff --git a/hw/misc/aspeed_xdma.c b/hw/misc/aspeed_xdma.c
index 76ab846..1dd32f7 100644
--- a/hw/misc/aspeed_xdma.c
+++ b/hw/misc/aspeed_xdma.c
@@ -222,7 +222,7 @@ static void aspeed_xdma_class_init(ObjectClass *classp, void *data)
DeviceClass *dc = DEVICE_CLASS(classp);
dc->realize = aspeed_xdma_realize;
- dc->reset = aspeed_xdma_reset;
+ device_class_set_legacy_reset(dc, aspeed_xdma_reset);
dc->vmsd = &aspeed_xdma_vmstate;
}
diff --git a/hw/misc/avr_power.c b/hw/misc/avr_power.c
index a5412f2..ac7b96f 100644
--- a/hw/misc/avr_power.c
+++ b/hw/misc/avr_power.c
@@ -94,7 +94,7 @@ static void avr_mask_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = avr_mask_reset;
+ device_class_set_legacy_reset(dc, avr_mask_reset);
}
static const TypeInfo avr_mask_info = {
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
index 91c8f7b..63e1045 100644
--- a/hw/misc/bcm2835_cprman.c
+++ b/hw/misc/bcm2835_cprman.c
@@ -135,7 +135,7 @@ static void pll_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = pll_reset;
+ device_class_set_legacy_reset(dc, pll_reset);
dc->vmsd = &pll_vmstate;
}
@@ -239,7 +239,7 @@ static void pll_channel_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = pll_channel_reset;
+ device_class_set_legacy_reset(dc, pll_channel_reset);
dc->vmsd = &pll_channel_vmstate;
}
@@ -360,7 +360,7 @@ static void clock_mux_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = clock_mux_reset;
+ device_class_set_legacy_reset(dc, clock_mux_reset);
dc->vmsd = &clock_mux_vmstate;
}
@@ -788,7 +788,7 @@ static void cprman_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = cprman_realize;
- dc->reset = cprman_reset;
+ device_class_set_legacy_reset(dc, cprman_reset);
dc->vmsd = &cprman_vmstate;
device_class_set_props(dc, cprman_properties);
}
diff --git a/hw/misc/bcm2835_mbox.c b/hw/misc/bcm2835_mbox.c
index 67bfc3b..ed6dbea 100644
--- a/hw/misc/bcm2835_mbox.c
+++ b/hw/misc/bcm2835_mbox.c
@@ -319,7 +319,7 @@ static void bcm2835_mbox_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = bcm2835_mbox_realize;
- dc->reset = bcm2835_mbox_reset;
+ device_class_set_legacy_reset(dc, bcm2835_mbox_reset);
dc->vmsd = &vmstate_bcm2835_mbox;
}
diff --git a/hw/misc/bcm2835_mphi.c b/hw/misc/bcm2835_mphi.c
index f1eeda2..7309cf2 100644
--- a/hw/misc/bcm2835_mphi.c
+++ b/hw/misc/bcm2835_mphi.c
@@ -171,7 +171,7 @@ static void mphi_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = mphi_realize;
- dc->reset = mphi_reset;
+ device_class_set_legacy_reset(dc, mphi_reset);
dc->vmsd = &vmstate_mphi_state;
}
diff --git a/hw/misc/bcm2835_powermgt.c b/hw/misc/bcm2835_powermgt.c
index 1649da8..d88689a 100644
--- a/hw/misc/bcm2835_powermgt.c
+++ b/hw/misc/bcm2835_powermgt.c
@@ -140,7 +140,7 @@ static void bcm2835_powermgt_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = bcm2835_powermgt_reset;
+ device_class_set_legacy_reset(dc, bcm2835_powermgt_reset);
dc->vmsd = &vmstate_bcm2835_powermgt;
}
diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c
index 63de3db..8ca3128 100644
--- a/hw/misc/bcm2835_property.c
+++ b/hw/misc/bcm2835_property.c
@@ -25,14 +25,7 @@
static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
{
- uint32_t tag;
- uint32_t bufsize;
uint32_t tot_len;
- size_t resplen;
- uint32_t tmp;
- int n;
- uint32_t offset, length, color;
- uint32_t start_num, number, otp_row;
/*
* Copy the current state of the framebuffer config; we will update
@@ -51,10 +44,10 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
/* @(addr + 4) : Buffer response code */
value = s->addr + 8;
while (value + 8 <= s->addr + tot_len) {
- tag = ldl_le_phys(&s->dma_as, value);
- bufsize = ldl_le_phys(&s->dma_as, value + 4);
+ uint32_t tag = ldl_le_phys(&s->dma_as, value);
+ uint32_t bufsize = ldl_le_phys(&s->dma_as, value + 4);
/* @(value + 8) : Request/response indicator */
- resplen = 0;
+ size_t resplen = 0;
switch (tag) {
case RPI_FWREQ_PROPERTY_END:
break;
@@ -98,13 +91,16 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
resplen = 8;
break;
case RPI_FWREQ_SET_POWER_STATE:
- /* Assume that whatever device they asked for exists,
- * and we'll just claim we set it to the desired state
+ {
+ /*
+ * Assume that whatever device they asked for exists,
+ * and we'll just claim we set it to the desired state.
*/
- tmp = ldl_le_phys(&s->dma_as, value + 16);
- stl_le_phys(&s->dma_as, value + 16, (tmp & 1));
+ uint32_t state = ldl_le_phys(&s->dma_as, value + 16);
+ stl_le_phys(&s->dma_as, value + 16, (state & 1));
resplen = 8;
break;
+ }
/* Clocks */
@@ -274,19 +270,25 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
resplen = 16;
break;
case RPI_FWREQ_FRAMEBUFFER_SET_PALETTE:
- offset = ldl_le_phys(&s->dma_as, value + 12);
- length = ldl_le_phys(&s->dma_as, value + 16);
- n = 0;
- while (n < length - offset) {
- color = ldl_le_phys(&s->dma_as, value + 20 + (n << 2));
- stl_le_phys(&s->dma_as,
- s->fbdev->vcram_base + ((offset + n) << 2), color);
- n++;
+ {
+ uint32_t offset = ldl_le_phys(&s->dma_as, value + 12);
+ uint32_t length = ldl_le_phys(&s->dma_as, value + 16);
+ int resp;
+
+ if (offset > 255 || length < 1 || length > 256) {
+ resp = 1; /* invalid request */
+ } else {
+ for (uint32_t e = 0; e < length; e++) {
+ uint32_t color = ldl_le_phys(&s->dma_as, value + 20 + (e << 2));
+ stl_le_phys(&s->dma_as,
+ s->fbdev->vcram_base + ((offset + e) << 2), color);
+ }
+ resp = 0;
}
- stl_le_phys(&s->dma_as, value + 12, 0);
+ stl_le_phys(&s->dma_as, value + 12, resp);
resplen = 4;
break;
-
+ }
case RPI_FWREQ_FRAMEBUFFER_GET_NUM_DISPLAYS:
stl_le_phys(&s->dma_as, value + 12, 1);
resplen = 4;
@@ -327,22 +329,25 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
/* Customer OTP */
case RPI_FWREQ_GET_CUSTOMER_OTP:
- start_num = ldl_le_phys(&s->dma_as, value + 12);
- number = ldl_le_phys(&s->dma_as, value + 16);
+ {
+ uint32_t start_num = ldl_le_phys(&s->dma_as, value + 12);
+ uint32_t number = ldl_le_phys(&s->dma_as, value + 16);
resplen = 8 + 4 * number;
- for (n = start_num; n < start_num + number &&
+ for (uint32_t n = start_num; n < start_num + number &&
n < BCM2835_OTP_CUSTOMER_OTP_LEN; n++) {
- otp_row = bcm2835_otp_get_row(s->otp,
+ uint32_t otp_row = bcm2835_otp_get_row(s->otp,
BCM2835_OTP_CUSTOMER_OTP + n);
stl_le_phys(&s->dma_as,
value + 20 + ((n - start_num) << 2), otp_row);
}
break;
+ }
case RPI_FWREQ_SET_CUSTOMER_OTP:
- start_num = ldl_le_phys(&s->dma_as, value + 12);
- number = ldl_le_phys(&s->dma_as, value + 16);
+ {
+ uint32_t start_num = ldl_le_phys(&s->dma_as, value + 12);
+ uint32_t number = ldl_le_phys(&s->dma_as, value + 16);
resplen = 4;
@@ -361,34 +366,37 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
break;
}
- for (n = start_num; n < start_num + number &&
+ for (uint32_t n = start_num; n < start_num + number &&
n < BCM2835_OTP_CUSTOMER_OTP_LEN; n++) {
- otp_row = ldl_le_phys(&s->dma_as,
+ uint32_t otp_row = ldl_le_phys(&s->dma_as,
value + 20 + ((n - start_num) << 2));
bcm2835_otp_set_row(s->otp,
BCM2835_OTP_CUSTOMER_OTP + n, otp_row);
}
break;
+ }
/* Device-specific private key */
-
case RPI_FWREQ_GET_PRIVATE_KEY:
- start_num = ldl_le_phys(&s->dma_as, value + 12);
- number = ldl_le_phys(&s->dma_as, value + 16);
+ {
+ uint32_t start_num = ldl_le_phys(&s->dma_as, value + 12);
+ uint32_t number = ldl_le_phys(&s->dma_as, value + 16);
resplen = 8 + 4 * number;
- for (n = start_num; n < start_num + number &&
+ for (uint32_t n = start_num; n < start_num + number &&
n < BCM2835_OTP_PRIVATE_KEY_LEN; n++) {
- otp_row = bcm2835_otp_get_row(s->otp,
+ uint32_t otp_row = bcm2835_otp_get_row(s->otp,
BCM2835_OTP_PRIVATE_KEY + n);
stl_le_phys(&s->dma_as,
value + 20 + ((n - start_num) << 2), otp_row);
}
break;
+ }
case RPI_FWREQ_SET_PRIVATE_KEY:
- start_num = ldl_le_phys(&s->dma_as, value + 12);
- number = ldl_le_phys(&s->dma_as, value + 16);
+ {
+ uint32_t start_num = ldl_le_phys(&s->dma_as, value + 12);
+ uint32_t number = ldl_le_phys(&s->dma_as, value + 16);
resplen = 4;
@@ -398,14 +406,15 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
break;
}
- for (n = start_num; n < start_num + number &&
+ for (uint32_t n = start_num; n < start_num + number &&
n < BCM2835_OTP_PRIVATE_KEY_LEN; n++) {
- otp_row = ldl_le_phys(&s->dma_as,
+ uint32_t otp_row = ldl_le_phys(&s->dma_as,
value + 20 + ((n - start_num) << 2));
bcm2835_otp_set_row(s->otp,
BCM2835_OTP_PRIVATE_KEY + n, otp_row);
}
break;
+ }
default:
qemu_log_mask(LOG_UNIMP,
"bcm2835_property: unhandled tag 0x%08x\n", tag);
diff --git a/hw/misc/bcm2835_rng.c b/hw/misc/bcm2835_rng.c
index 10e741b..06f4081 100644
--- a/hw/misc/bcm2835_rng.c
+++ b/hw/misc/bcm2835_rng.c
@@ -127,7 +127,7 @@ static void bcm2835_rng_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = bcm2835_rng_reset;
+ device_class_set_legacy_reset(dc, bcm2835_rng_reset);
dc->vmsd = &vmstate_bcm2835_rng;
}
diff --git a/hw/misc/bcm2835_thermal.c b/hw/misc/bcm2835_thermal.c
index 0c49c08..1c1b067 100644
--- a/hw/misc/bcm2835_thermal.c
+++ b/hw/misc/bcm2835_thermal.c
@@ -118,7 +118,7 @@ static void bcm2835_thermal_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = bcm2835_thermal_realize;
- dc->reset = bcm2835_thermal_reset;
+ device_class_set_legacy_reset(dc, bcm2835_thermal_reset);
dc->vmsd = &bcm2835_thermal_vmstate;
}
diff --git a/hw/misc/cbus.c b/hw/misc/cbus.c
deleted file mode 100644
index 653e8dd..0000000
--- a/hw/misc/cbus.c
+++ /dev/null
@@ -1,619 +0,0 @@
-/*
- * CBUS three-pin bus and the Retu / Betty / Tahvo / Vilma / Avilma /
- * Hinku / Vinku / Ahne / Pihi chips used in various Nokia platforms.
- * Based on reverse-engineering of a linux driver.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/irq.h"
-#include "hw/misc/cbus.h"
-#include "sysemu/runstate.h"
-
-//#define DEBUG
-
-typedef struct {
- void *opaque;
- void (*io)(void *opaque, int rw, int reg, uint16_t *val);
- int addr;
-} CBusSlave;
-
-typedef struct {
- CBus cbus;
-
- int sel;
- int dat;
- int clk;
- int bit;
- int dir;
- uint16_t val;
- qemu_irq dat_out;
-
- int addr;
- int reg;
- int rw;
- enum {
- cbus_address,
- cbus_value,
- } cycle;
-
- CBusSlave *slave[8];
-} CBusPriv;
-
-static void cbus_io(CBusPriv *s)
-{
- if (s->slave[s->addr])
- s->slave[s->addr]->io(s->slave[s->addr]->opaque,
- s->rw, s->reg, &s->val);
- else
- hw_error("%s: bad slave address %i\n", __func__, s->addr);
-}
-
-static void cbus_cycle(CBusPriv *s)
-{
- switch (s->cycle) {
- case cbus_address:
- s->addr = (s->val >> 6) & 7;
- s->rw = (s->val >> 5) & 1;
- s->reg = (s->val >> 0) & 0x1f;
-
- s->cycle = cbus_value;
- s->bit = 15;
- s->dir = !s->rw;
- s->val = 0;
-
- if (s->rw)
- cbus_io(s);
- break;
-
- case cbus_value:
- if (!s->rw)
- cbus_io(s);
-
- s->cycle = cbus_address;
- s->bit = 8;
- s->dir = 1;
- s->val = 0;
- break;
- }
-}
-
-static void cbus_clk(void *opaque, int line, int level)
-{
- CBusPriv *s = (CBusPriv *) opaque;
-
- if (!s->sel && level && !s->clk) {
- if (s->dir)
- s->val |= s->dat << (s->bit --);
- else
- qemu_set_irq(s->dat_out, (s->val >> (s->bit --)) & 1);
-
- if (s->bit < 0)
- cbus_cycle(s);
- }
-
- s->clk = level;
-}
-
-static void cbus_dat(void *opaque, int line, int level)
-{
- CBusPriv *s = (CBusPriv *) opaque;
-
- s->dat = level;
-}
-
-static void cbus_sel(void *opaque, int line, int level)
-{
- CBusPriv *s = (CBusPriv *) opaque;
-
- if (!level) {
- s->dir = 1;
- s->bit = 8;
- s->val = 0;
- }
-
- s->sel = level;
-}
-
-CBus *cbus_init(qemu_irq dat)
-{
- CBusPriv *s = g_malloc0(sizeof(*s));
-
- s->dat_out = dat;
- s->cbus.clk = qemu_allocate_irq(cbus_clk, s, 0);
- s->cbus.dat = qemu_allocate_irq(cbus_dat, s, 0);
- s->cbus.sel = qemu_allocate_irq(cbus_sel, s, 0);
-
- s->sel = 1;
- s->clk = 0;
- s->dat = 0;
-
- return &s->cbus;
-}
-
-void cbus_attach(CBus *bus, void *slave_opaque)
-{
- CBusSlave *slave = (CBusSlave *) slave_opaque;
- CBusPriv *s = (CBusPriv *) bus;
-
- s->slave[slave->addr] = slave;
-}
-
-/* Retu/Vilma */
-typedef struct {
- uint16_t irqst;
- uint16_t irqen;
- uint16_t cc[2];
- int channel;
- uint16_t result[16];
- uint16_t sample;
- uint16_t status;
-
- struct {
- uint16_t cal;
- } rtc;
-
- int is_vilma;
- qemu_irq irq;
- CBusSlave cbus;
-} CBusRetu;
-
-static void retu_interrupt_update(CBusRetu *s)
-{
- qemu_set_irq(s->irq, s->irqst & ~s->irqen);
-}
-
-#define RETU_REG_ASICR 0x00 /* (RO) ASIC ID & revision */
-#define RETU_REG_IDR 0x01 /* (T) Interrupt ID */
-#define RETU_REG_IMR 0x02 /* (RW) Interrupt mask */
-#define RETU_REG_RTCDSR 0x03 /* (RW) RTC seconds register */
-#define RETU_REG_RTCHMR 0x04 /* (RO) RTC hours and minutes reg */
-#define RETU_REG_RTCHMAR 0x05 /* (RW) RTC hours and minutes set reg */
-#define RETU_REG_RTCCALR 0x06 /* (RW) RTC calibration register */
-#define RETU_REG_ADCR 0x08 /* (RW) ADC result register */
-#define RETU_REG_ADCSCR 0x09 /* (RW) ADC sample control register */
-#define RETU_REG_AFCR 0x0a /* (RW) AFC register */
-#define RETU_REG_ANTIFR 0x0b /* (RW) AntiF register */
-#define RETU_REG_CALIBR 0x0c /* (RW) CalibR register*/
-#define RETU_REG_CCR1 0x0d /* (RW) Common control register 1 */
-#define RETU_REG_CCR2 0x0e /* (RW) Common control register 2 */
-#define RETU_REG_RCTRL_CLR 0x0f /* (T) Regulator clear register */
-#define RETU_REG_RCTRL_SET 0x10 /* (T) Regulator set register */
-#define RETU_REG_TXCR 0x11 /* (RW) TxC register */
-#define RETU_REG_STATUS 0x16 /* (RO) Status register */
-#define RETU_REG_WATCHDOG 0x17 /* (RW) Watchdog register */
-#define RETU_REG_AUDTXR 0x18 /* (RW) Audio Codec Tx register */
-#define RETU_REG_AUDPAR 0x19 /* (RW) AudioPA register */
-#define RETU_REG_AUDRXR1 0x1a /* (RW) Audio receive register 1 */
-#define RETU_REG_AUDRXR2 0x1b /* (RW) Audio receive register 2 */
-#define RETU_REG_SGR1 0x1c /* (RW) */
-#define RETU_REG_SCR1 0x1d /* (RW) */
-#define RETU_REG_SGR2 0x1e /* (RW) */
-#define RETU_REG_SCR2 0x1f /* (RW) */
-
-/* Retu Interrupt sources */
-enum {
- retu_int_pwr = 0, /* Power button */
- retu_int_char = 1, /* Charger */
- retu_int_rtcs = 2, /* Seconds */
- retu_int_rtcm = 3, /* Minutes */
- retu_int_rtcd = 4, /* Days */
- retu_int_rtca = 5, /* Alarm */
- retu_int_hook = 6, /* Hook */
- retu_int_head = 7, /* Headset */
- retu_int_adcs = 8, /* ADC sample */
-};
-
-/* Retu ADC channel wiring */
-enum {
- retu_adc_bsi = 1, /* BSI */
- retu_adc_batt_temp = 2, /* Battery temperature */
- retu_adc_chg_volt = 3, /* Charger voltage */
- retu_adc_head_det = 4, /* Headset detection */
- retu_adc_hook_det = 5, /* Hook detection */
- retu_adc_rf_gp = 6, /* RF GP */
- retu_adc_tx_det = 7, /* Wideband Tx detection */
- retu_adc_batt_volt = 8, /* Battery voltage */
- retu_adc_sens = 10, /* Light sensor */
- retu_adc_sens_temp = 11, /* Light sensor temperature */
- retu_adc_bbatt_volt = 12, /* Backup battery voltage */
- retu_adc_self_temp = 13, /* RETU temperature */
-};
-
-static inline uint16_t retu_read(CBusRetu *s, int reg)
-{
-#ifdef DEBUG
- printf("RETU read at %02x\n", reg);
-#endif
-
- switch (reg) {
- case RETU_REG_ASICR:
- return 0x0215 | (s->is_vilma << 7);
-
- case RETU_REG_IDR: /* TODO: Or is this ffs(s->irqst)? */
- return s->irqst;
-
- case RETU_REG_IMR:
- return s->irqen;
-
- case RETU_REG_RTCDSR:
- case RETU_REG_RTCHMR:
- case RETU_REG_RTCHMAR:
- /* TODO */
- return 0x0000;
-
- case RETU_REG_RTCCALR:
- return s->rtc.cal;
-
- case RETU_REG_ADCR:
- return (s->channel << 10) | s->result[s->channel];
- case RETU_REG_ADCSCR:
- return s->sample;
-
- case RETU_REG_AFCR:
- case RETU_REG_ANTIFR:
- case RETU_REG_CALIBR:
- /* TODO */
- return 0x0000;
-
- case RETU_REG_CCR1:
- return s->cc[0];
- case RETU_REG_CCR2:
- return s->cc[1];
-
- case RETU_REG_RCTRL_CLR:
- case RETU_REG_RCTRL_SET:
- case RETU_REG_TXCR:
- /* TODO */
- return 0x0000;
-
- case RETU_REG_STATUS:
- return s->status;
-
- case RETU_REG_WATCHDOG:
- case RETU_REG_AUDTXR:
- case RETU_REG_AUDPAR:
- case RETU_REG_AUDRXR1:
- case RETU_REG_AUDRXR2:
- case RETU_REG_SGR1:
- case RETU_REG_SCR1:
- case RETU_REG_SGR2:
- case RETU_REG_SCR2:
- /* TODO */
- return 0x0000;
-
- default:
- hw_error("%s: bad register %02x\n", __func__, reg);
- }
-}
-
-static inline void retu_write(CBusRetu *s, int reg, uint16_t val)
-{
-#ifdef DEBUG
- printf("RETU write of %04x at %02x\n", val, reg);
-#endif
-
- switch (reg) {
- case RETU_REG_IDR:
- s->irqst ^= val;
- retu_interrupt_update(s);
- break;
-
- case RETU_REG_IMR:
- s->irqen = val;
- retu_interrupt_update(s);
- break;
-
- case RETU_REG_RTCDSR:
- case RETU_REG_RTCHMAR:
- /* TODO */
- break;
-
- case RETU_REG_RTCCALR:
- s->rtc.cal = val;
- break;
-
- case RETU_REG_ADCR:
- s->channel = (val >> 10) & 0xf;
- s->irqst |= 1 << retu_int_adcs;
- retu_interrupt_update(s);
- break;
- case RETU_REG_ADCSCR:
- s->sample &= ~val;
- break;
-
- case RETU_REG_AFCR:
- case RETU_REG_ANTIFR:
- case RETU_REG_CALIBR:
-
- case RETU_REG_CCR1:
- s->cc[0] = val;
- break;
- case RETU_REG_CCR2:
- s->cc[1] = val;
- break;
-
- case RETU_REG_RCTRL_CLR:
- case RETU_REG_RCTRL_SET:
- /* TODO */
- break;
-
- case RETU_REG_WATCHDOG:
- if (val == 0 && (s->cc[0] & 2))
- qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
- break;
-
- case RETU_REG_TXCR:
- case RETU_REG_AUDTXR:
- case RETU_REG_AUDPAR:
- case RETU_REG_AUDRXR1:
- case RETU_REG_AUDRXR2:
- case RETU_REG_SGR1:
- case RETU_REG_SCR1:
- case RETU_REG_SGR2:
- case RETU_REG_SCR2:
- /* TODO */
- break;
-
- default:
- hw_error("%s: bad register %02x\n", __func__, reg);
- }
-}
-
-static void retu_io(void *opaque, int rw, int reg, uint16_t *val)
-{
- CBusRetu *s = (CBusRetu *) opaque;
-
- if (rw)
- *val = retu_read(s, reg);
- else
- retu_write(s, reg, *val);
-}
-
-void *retu_init(qemu_irq irq, int vilma)
-{
- CBusRetu *s = g_malloc0(sizeof(*s));
-
- s->irq = irq;
- s->irqen = 0xffff;
- s->irqst = 0x0000;
- s->status = 0x0020;
- s->is_vilma = !!vilma;
- s->rtc.cal = 0x01;
- s->result[retu_adc_bsi] = 0x3c2;
- s->result[retu_adc_batt_temp] = 0x0fc;
- s->result[retu_adc_chg_volt] = 0x165;
- s->result[retu_adc_head_det] = 123;
- s->result[retu_adc_hook_det] = 1023;
- s->result[retu_adc_rf_gp] = 0x11;
- s->result[retu_adc_tx_det] = 0x11;
- s->result[retu_adc_batt_volt] = 0x250;
- s->result[retu_adc_sens] = 2;
- s->result[retu_adc_sens_temp] = 0x11;
- s->result[retu_adc_bbatt_volt] = 0x3d0;
- s->result[retu_adc_self_temp] = 0x330;
-
- s->cbus.opaque = s;
- s->cbus.io = retu_io;
- s->cbus.addr = 1;
-
- return &s->cbus;
-}
-
-void retu_key_event(void *retu, int state)
-{
- CBusSlave *slave = (CBusSlave *) retu;
- CBusRetu *s = (CBusRetu *) slave->opaque;
-
- s->irqst |= 1 << retu_int_pwr;
- retu_interrupt_update(s);
-
- if (state)
- s->status &= ~(1 << 5);
- else
- s->status |= 1 << 5;
-}
-
-#if 0
-static void retu_head_event(void *retu, int state)
-{
- CBusSlave *slave = (CBusSlave *) retu;
- CBusRetu *s = (CBusRetu *) slave->opaque;
-
- if ((s->cc[0] & 0x500) == 0x500) { /* TODO: Which bits? */
- /* TODO: reissue the interrupt every 100ms or so. */
- s->irqst |= 1 << retu_int_head;
- retu_interrupt_update(s);
- }
-
- if (state)
- s->result[retu_adc_head_det] = 50;
- else
- s->result[retu_adc_head_det] = 123;
-}
-
-static void retu_hook_event(void *retu, int state)
-{
- CBusSlave *slave = (CBusSlave *) retu;
- CBusRetu *s = (CBusRetu *) slave->opaque;
-
- if ((s->cc[0] & 0x500) == 0x500) {
- /* TODO: reissue the interrupt every 100ms or so. */
- s->irqst |= 1 << retu_int_hook;
- retu_interrupt_update(s);
- }
-
- if (state)
- s->result[retu_adc_hook_det] = 50;
- else
- s->result[retu_adc_hook_det] = 123;
-}
-#endif
-
-/* Tahvo/Betty */
-typedef struct {
- uint16_t irqst;
- uint16_t irqen;
- uint8_t charger;
- uint8_t backlight;
- uint16_t usbr;
- uint16_t power;
-
- int is_betty;
- qemu_irq irq;
- CBusSlave cbus;
-} CBusTahvo;
-
-static void tahvo_interrupt_update(CBusTahvo *s)
-{
- qemu_set_irq(s->irq, s->irqst & ~s->irqen);
-}
-
-#define TAHVO_REG_ASICR 0x00 /* (RO) ASIC ID & revision */
-#define TAHVO_REG_IDR 0x01 /* (T) Interrupt ID */
-#define TAHVO_REG_IDSR 0x02 /* (RO) Interrupt status */
-#define TAHVO_REG_IMR 0x03 /* (RW) Interrupt mask */
-#define TAHVO_REG_CHAPWMR 0x04 /* (RW) Charger PWM */
-#define TAHVO_REG_LEDPWMR 0x05 /* (RW) LED PWM */
-#define TAHVO_REG_USBR 0x06 /* (RW) USB control */
-#define TAHVO_REG_RCR 0x07 /* (RW) Some kind of power management */
-#define TAHVO_REG_CCR1 0x08 /* (RW) Common control register 1 */
-#define TAHVO_REG_CCR2 0x09 /* (RW) Common control register 2 */
-#define TAHVO_REG_TESTR1 0x0a /* (RW) Test register 1 */
-#define TAHVO_REG_TESTR2 0x0b /* (RW) Test register 2 */
-#define TAHVO_REG_NOPR 0x0c /* (RW) Number of periods */
-#define TAHVO_REG_FRR 0x0d /* (RO) FR */
-
-static inline uint16_t tahvo_read(CBusTahvo *s, int reg)
-{
-#ifdef DEBUG
- printf("TAHVO read at %02x\n", reg);
-#endif
-
- switch (reg) {
- case TAHVO_REG_ASICR:
- return 0x0021 | (s->is_betty ? 0x0b00 : 0x0300); /* 22 in N810 */
-
- case TAHVO_REG_IDR:
- case TAHVO_REG_IDSR: /* XXX: what does this do? */
- return s->irqst;
-
- case TAHVO_REG_IMR:
- return s->irqen;
-
- case TAHVO_REG_CHAPWMR:
- return s->charger;
-
- case TAHVO_REG_LEDPWMR:
- return s->backlight;
-
- case TAHVO_REG_USBR:
- return s->usbr;
-
- case TAHVO_REG_RCR:
- return s->power;
-
- case TAHVO_REG_CCR1:
- case TAHVO_REG_CCR2:
- case TAHVO_REG_TESTR1:
- case TAHVO_REG_TESTR2:
- case TAHVO_REG_NOPR:
- case TAHVO_REG_FRR:
- return 0x0000;
-
- default:
- hw_error("%s: bad register %02x\n", __func__, reg);
- }
-}
-
-static inline void tahvo_write(CBusTahvo *s, int reg, uint16_t val)
-{
-#ifdef DEBUG
- printf("TAHVO write of %04x at %02x\n", val, reg);
-#endif
-
- switch (reg) {
- case TAHVO_REG_IDR:
- s->irqst ^= val;
- tahvo_interrupt_update(s);
- break;
-
- case TAHVO_REG_IMR:
- s->irqen = val;
- tahvo_interrupt_update(s);
- break;
-
- case TAHVO_REG_CHAPWMR:
- s->charger = val;
- break;
-
- case TAHVO_REG_LEDPWMR:
- if (s->backlight != (val & 0x7f)) {
- s->backlight = val & 0x7f;
- printf("%s: LCD backlight now at %i / 127\n",
- __func__, s->backlight);
- }
- break;
-
- case TAHVO_REG_USBR:
- s->usbr = val;
- break;
-
- case TAHVO_REG_RCR:
- s->power = val;
- break;
-
- case TAHVO_REG_CCR1:
- case TAHVO_REG_CCR2:
- case TAHVO_REG_TESTR1:
- case TAHVO_REG_TESTR2:
- case TAHVO_REG_NOPR:
- case TAHVO_REG_FRR:
- break;
-
- default:
- hw_error("%s: bad register %02x\n", __func__, reg);
- }
-}
-
-static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val)
-{
- CBusTahvo *s = (CBusTahvo *) opaque;
-
- if (rw)
- *val = tahvo_read(s, reg);
- else
- tahvo_write(s, reg, *val);
-}
-
-void *tahvo_init(qemu_irq irq, int betty)
-{
- CBusTahvo *s = g_malloc0(sizeof(*s));
-
- s->irq = irq;
- s->irqen = 0xffff;
- s->irqst = 0x0000;
- s->is_betty = !!betty;
-
- s->cbus.opaque = s;
- s->cbus.io = tahvo_io;
- s->cbus.addr = 2;
-
- return &s->cbus;
-}
diff --git a/hw/misc/eccmemctl.c b/hw/misc/eccmemctl.c
index 5a14a48..0f68fbe 100644
--- a/hw/misc/eccmemctl.c
+++ b/hw/misc/eccmemctl.c
@@ -335,7 +335,7 @@ static void ecc_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = ecc_realize;
- dc->reset = ecc_reset;
+ device_class_set_legacy_reset(dc, ecc_reset);
dc->vmsd = &vmstate_ecc;
device_class_set_props(dc, ecc_properties);
}
diff --git a/hw/misc/exynos4210_clk.c b/hw/misc/exynos4210_clk.c
index 4566a42..886d10b 100644
--- a/hw/misc/exynos4210_clk.c
+++ b/hw/misc/exynos4210_clk.c
@@ -145,7 +145,7 @@ static void exynos4210_clk_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = exynos4210_clk_reset;
+ device_class_set_legacy_reset(dc, exynos4210_clk_reset);
dc->vmsd = &exynos4210_clk_vmstate;
}
diff --git a/hw/misc/exynos4210_pmu.c b/hw/misc/exynos4210_pmu.c
index 7e28e79..9d3c2e8 100644
--- a/hw/misc/exynos4210_pmu.c
+++ b/hw/misc/exynos4210_pmu.c
@@ -502,7 +502,7 @@ static void exynos4210_pmu_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = exynos4210_pmu_reset;
+ device_class_set_legacy_reset(dc, exynos4210_pmu_reset);
dc->vmsd = &exynos4210_pmu_vmstate;
}
diff --git a/hw/misc/exynos4210_rng.c b/hw/misc/exynos4210_rng.c
index 674d8ee..a741cf1 100644
--- a/hw/misc/exynos4210_rng.c
+++ b/hw/misc/exynos4210_rng.c
@@ -259,7 +259,7 @@ static void exynos4210_rng_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = exynos4210_rng_reset;
+ device_class_set_legacy_reset(dc, exynos4210_rng_reset);
dc->vmsd = &exynos4210_rng_vmstate;
}
diff --git a/hw/misc/imx25_ccm.c b/hw/misc/imx25_ccm.c
index faa726a..9654d23 100644
--- a/hw/misc/imx25_ccm.c
+++ b/hw/misc/imx25_ccm.c
@@ -297,7 +297,7 @@ static void imx25_ccm_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
- dc->reset = imx25_ccm_reset;
+ device_class_set_legacy_reset(dc, imx25_ccm_reset);
dc->vmsd = &vmstate_imx25_ccm;
dc->desc = "i.MX25 Clock Control Module";
diff --git a/hw/misc/imx31_ccm.c b/hw/misc/imx31_ccm.c
index 125d4fc..93130b2 100644
--- a/hw/misc/imx31_ccm.c
+++ b/hw/misc/imx31_ccm.c
@@ -324,7 +324,7 @@ static void imx31_ccm_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
- dc->reset = imx31_ccm_reset;
+ device_class_set_legacy_reset(dc, imx31_ccm_reset);
dc->vmsd = &vmstate_imx31_ccm;
dc->desc = "i.MX31 Clock Control Module";
diff --git a/hw/misc/imx6_ccm.c b/hw/misc/imx6_ccm.c
index b1def7f..7d522ed 100644
--- a/hw/misc/imx6_ccm.c
+++ b/hw/misc/imx6_ccm.c
@@ -301,7 +301,6 @@ static uint64_t imx6_analog_get_periph_clk(IMX6CCMState *dev)
default:
/* We should never get there */
g_assert_not_reached();
- break;
}
trace_imx6_analog_get_periph_clk(freq);
@@ -747,7 +746,7 @@ static void imx6_ccm_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
- dc->reset = imx6_ccm_reset;
+ device_class_set_legacy_reset(dc, imx6_ccm_reset);
dc->vmsd = &vmstate_imx6_ccm;
dc->desc = "i.MX6 Clock Control Module";
diff --git a/hw/misc/imx6_src.c b/hw/misc/imx6_src.c
index 3766bdf..dc6a2b9 100644
--- a/hw/misc/imx6_src.c
+++ b/hw/misc/imx6_src.c
@@ -291,7 +291,7 @@ static void imx6_src_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = imx6_src_realize;
- dc->reset = imx6_src_reset;
+ device_class_set_legacy_reset(dc, imx6_src_reset);
dc->vmsd = &vmstate_imx6_src;
dc->desc = "i.MX6 System Reset Controller";
}
diff --git a/hw/misc/imx6ul_ccm.c b/hw/misc/imx6ul_ccm.c
index 0ac49ea..c836dfe 100644
--- a/hw/misc/imx6ul_ccm.c
+++ b/hw/misc/imx6ul_ccm.c
@@ -909,7 +909,7 @@ static void imx6ul_ccm_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
- dc->reset = imx6ul_ccm_reset;
+ device_class_set_legacy_reset(dc, imx6ul_ccm_reset);
dc->vmsd = &vmstate_imx6ul_ccm;
dc->desc = "i.MX6UL Clock Control Module";
diff --git a/hw/misc/imx7_ccm.c b/hw/misc/imx7_ccm.c
index 88354f0..c3ecfd7 100644
--- a/hw/misc/imx7_ccm.c
+++ b/hw/misc/imx7_ccm.c
@@ -267,7 +267,7 @@ static void imx7_ccm_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
- dc->reset = imx7_ccm_reset;
+ device_class_set_legacy_reset(dc, imx7_ccm_reset);
dc->vmsd = &vmstate_imx7_ccm;
dc->desc = "i.MX7 Clock Control Module";
@@ -297,7 +297,7 @@ static void imx7_analog_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = imx7_analog_reset;
+ device_class_set_legacy_reset(dc, imx7_analog_reset);
dc->vmsd = &vmstate_imx7_analog;
dc->desc = "i.MX7 Analog Module";
}
diff --git a/hw/misc/imx7_snvs.c b/hw/misc/imx7_snvs.c
index edb2df2..070d553 100644
--- a/hw/misc/imx7_snvs.c
+++ b/hw/misc/imx7_snvs.c
@@ -147,7 +147,7 @@ static void imx7_snvs_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = imx7_snvs_reset;
+ device_class_set_legacy_reset(dc, imx7_snvs_reset);
dc->vmsd = &vmstate_imx7_snvs;
dc->desc = "i.MX7 Secure Non-Volatile Storage Module";
}
diff --git a/hw/misc/imx7_src.c b/hw/misc/imx7_src.c
index d19f045..35341c6 100644
--- a/hw/misc/imx7_src.c
+++ b/hw/misc/imx7_src.c
@@ -256,7 +256,7 @@ static void imx7_src_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = imx7_src_realize;
- dc->reset = imx7_src_reset;
+ device_class_set_legacy_reset(dc, imx7_src_reset);
dc->vmsd = &vmstate_imx7_src;
dc->desc = "i.MX6 System Reset Controller";
}
diff --git a/hw/misc/imx_rngc.c b/hw/misc/imx_rngc.c
index ab7775e..0cbf28d 100644
--- a/hw/misc/imx_rngc.c
+++ b/hw/misc/imx_rngc.c
@@ -259,7 +259,7 @@ static void imx_rngc_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = imx_rngc_realize;
- dc->reset = imx_rngc_reset;
+ device_class_set_legacy_reset(dc, imx_rngc_reset);
dc->desc = RNGC_NAME,
dc->vmsd = &vmstate_imx_rngc;
}
diff --git a/hw/misc/iotkit-secctl.c b/hw/misc/iotkit-secctl.c
index f9c45f6..6e22f2a 100644
--- a/hw/misc/iotkit-secctl.c
+++ b/hw/misc/iotkit-secctl.c
@@ -824,7 +824,7 @@ static void iotkit_secctl_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &iotkit_secctl_vmstate;
- dc->reset = iotkit_secctl_reset;
+ device_class_set_legacy_reset(dc, iotkit_secctl_reset);
dc->realize = iotkit_secctl_realize;
device_class_set_props(dc, iotkit_secctl_props);
}
diff --git a/hw/misc/iotkit-sysctl.c b/hw/misc/iotkit-sysctl.c
index 45393e8..c1b357e 100644
--- a/hw/misc/iotkit-sysctl.c
+++ b/hw/misc/iotkit-sysctl.c
@@ -850,7 +850,7 @@ static void iotkit_sysctl_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &iotkit_sysctl_vmstate;
- dc->reset = iotkit_sysctl_reset;
+ device_class_set_legacy_reset(dc, iotkit_sysctl_reset);
device_class_set_props(dc, iotkit_sysctl_props);
dc->realize = iotkit_sysctl_realize;
}
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index de49d1b..5ce3fc0 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -991,7 +991,7 @@ static void ivshmem_common_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_IVSHMEM;
k->class_id = PCI_CLASS_MEMORY_RAM;
k->revision = 1;
- dc->reset = ivshmem_reset;
+ device_class_set_legacy_reset(dc, ivshmem_reset);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->desc = "Inter-VM shared memory";
}
diff --git a/hw/misc/lasi.c b/hw/misc/lasi.c
index 970fc98..5dc209c 100644
--- a/hw/misc/lasi.c
+++ b/hw/misc/lasi.c
@@ -267,7 +267,7 @@ static void lasi_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = lasi_reset;
+ device_class_set_legacy_reset(dc, lasi_reset);
dc->vmsd = &vmstate_lasi;
}
diff --git a/hw/misc/led.c b/hw/misc/led.c
index d9998ab..4bb6ce8 100644
--- a/hw/misc/led.c
+++ b/hw/misc/led.c
@@ -114,7 +114,7 @@ static void led_class_init(ObjectClass *klass, void *data)
dc->desc = "LED";
dc->vmsd = &vmstate_led;
- dc->reset = led_reset;
+ device_class_set_legacy_reset(dc, led_reset);
dc->realize = led_realize;
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
device_class_set_props(dc, led_properties);
diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c
index 652395b..af2b2b1 100644
--- a/hw/misc/mac_via.c
+++ b/hw/misc/mac_via.c
@@ -495,7 +495,6 @@ static void via1_rtc_update(MOS6522Q800VIA1State *v1s)
break;
default:
g_assert_not_reached();
- break;
}
return;
}
@@ -556,7 +555,6 @@ static void via1_rtc_update(MOS6522Q800VIA1State *v1s)
break;
default:
g_assert_not_reached();
- break;
}
return;
}
diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c
index beab0ff..1db7ebf 100644
--- a/hw/misc/macio/cuda.c
+++ b/hw/misc/macio/cuda.c
@@ -564,7 +564,7 @@ static void cuda_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = cuda_realize;
- dc->reset = cuda_reset;
+ device_class_set_legacy_reset(dc, cuda_reset);
dc->vmsd = &vmstate_cuda;
device_class_set_props(dc, cuda_properties);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
diff --git a/hw/misc/macio/gpio.c b/hw/misc/macio/gpio.c
index 5495637..7cad628 100644
--- a/hw/misc/macio/gpio.c
+++ b/hw/misc/macio/gpio.c
@@ -194,7 +194,7 @@ static void macio_gpio_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
NMIClass *nc = NMI_CLASS(oc);
- dc->reset = macio_gpio_reset;
+ device_class_set_legacy_reset(dc, macio_gpio_reset);
dc->vmsd = &vmstate_macio_gpio;
nc->nmi_monitor_handler = macio_gpio_nmi;
}
diff --git a/hw/misc/macio/mac_dbdma.c b/hw/misc/macio/mac_dbdma.c
index 2a528ea..74c2cb3 100644
--- a/hw/misc/macio/mac_dbdma.c
+++ b/hw/misc/macio/mac_dbdma.c
@@ -922,7 +922,7 @@ static void mac_dbdma_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = mac_dbdma_realize;
- dc->reset = mac_dbdma_reset;
+ device_class_set_legacy_reset(dc, mac_dbdma_reset);
dc->vmsd = &vmstate_dbdma;
}
diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c
index 238da58..4b451e0 100644
--- a/hw/misc/macio/pmu.c
+++ b/hw/misc/macio/pmu.c
@@ -770,7 +770,7 @@ static void pmu_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = pmu_realize;
- dc->reset = pmu_reset;
+ device_class_set_legacy_reset(dc, pmu_reset);
dc->vmsd = &vmstate_pmu;
device_class_set_props(dc, pmu_properties);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 2ca8717..d02d96e 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -51,7 +51,6 @@ system_ss.add(when: 'CONFIG_ALLWINNER_R40', if_true: files('allwinner-r40-ccu.c'
system_ss.add(when: 'CONFIG_ALLWINNER_R40', if_true: files('allwinner-r40-dramc.c'))
system_ss.add(when: 'CONFIG_AXP2XX_PMU', if_true: files('axp2xx.c'))
system_ss.add(when: 'CONFIG_REALVIEW', if_true: files('arm_sysctl.c'))
-system_ss.add(when: 'CONFIG_NSERIES', if_true: files('cbus.c'))
system_ss.add(when: 'CONFIG_ECCMEMCTL', if_true: files('eccmemctl.c'))
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_pmu.c', 'exynos4210_clk.c', 'exynos4210_rng.c'))
system_ss.add(when: 'CONFIG_IMX', if_true: files(
@@ -67,7 +66,6 @@ system_ss.add(when: 'CONFIG_IMX', if_true: files(
'imx_ccm.c',
'imx_rngc.c',
))
-system_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mst_fpga.c'))
system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
'npcm7xx_clk.c',
'npcm7xx_gcr.c',
@@ -77,10 +75,6 @@ system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
))
system_ss.add(when: 'CONFIG_OMAP', if_true: files(
'omap_clk.c',
- 'omap_gpmc.c',
- 'omap_l4.c',
- 'omap_sdrc.c',
- 'omap_tap.c',
))
system_ss.add(when: 'CONFIG_RASPI', if_true: files(
'bcm2835_mbox.c',
@@ -106,6 +100,7 @@ system_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files(
system_ss.add(when: 'CONFIG_XLNX_VERSAL_TRNG', if_true: files(
'xlnx-versal-trng.c',
))
+system_ss.add(when: 'CONFIG_STM32_RCC', if_true: files('stm32_rcc.c'))
system_ss.add(when: 'CONFIG_STM32F2XX_SYSCFG', if_true: files('stm32f2xx_syscfg.c'))
system_ss.add(when: 'CONFIG_STM32F4XX_SYSCFG', if_true: files('stm32f4xx_syscfg.c'))
system_ss.add(when: 'CONFIG_STM32F4XX_EXTI', if_true: files('stm32f4xx_exti.c'))
diff --git a/hw/misc/mips_cmgcr.c b/hw/misc/mips_cmgcr.c
index 2703040..04256aa 100644
--- a/hw/misc/mips_cmgcr.c
+++ b/hw/misc/mips_cmgcr.c
@@ -235,7 +235,7 @@ static void mips_gcr_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_props(dc, mips_gcr_properties);
dc->vmsd = &vmstate_mips_gcr;
- dc->reset = mips_gcr_reset;
+ device_class_set_legacy_reset(dc, mips_gcr_reset);
dc->realize = mips_gcr_realize;
}
diff --git a/hw/misc/mips_cpc.c b/hw/misc/mips_cpc.c
index 1e8fd2e..2f7fb81 100644
--- a/hw/misc/mips_cpc.c
+++ b/hw/misc/mips_cpc.c
@@ -174,7 +174,7 @@ static void mips_cpc_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = mips_cpc_realize;
- dc->reset = mips_cpc_reset;
+ device_class_set_legacy_reset(dc, mips_cpc_reset);
dc->vmsd = &vmstate_mips_cpc;
device_class_set_props(dc, mips_cpc_properties);
}
diff --git a/hw/misc/mips_itu.c b/hw/misc/mips_itu.c
index f8acfb3..c5214c8 100644
--- a/hw/misc/mips_itu.c
+++ b/hw/misc/mips_itu.c
@@ -547,7 +547,7 @@ static void mips_itu_class_init(ObjectClass *klass, void *data)
device_class_set_props(dc, mips_itu_properties);
dc->realize = mips_itu_realize;
- dc->reset = mips_itu_reset;
+ device_class_set_legacy_reset(dc, mips_itu_reset);
}
static const TypeInfo mips_itu_info = {
diff --git a/hw/misc/mps2-fpgaio.c b/hw/misc/mps2-fpgaio.c
index aa1bb83..2035925 100644
--- a/hw/misc/mps2-fpgaio.c
+++ b/hw/misc/mps2-fpgaio.c
@@ -335,7 +335,7 @@ static void mps2_fpgaio_class_init(ObjectClass *klass, void *data)
dc->vmsd = &mps2_fpgaio_vmstate;
dc->realize = mps2_fpgaio_realize;
- dc->reset = mps2_fpgaio_reset;
+ device_class_set_legacy_reset(dc, mps2_fpgaio_reset);
device_class_set_props(dc, mps2_fpgaio_properties);
}
diff --git a/hw/misc/mps2-scc.c b/hw/misc/mps2-scc.c
index 18be741..d45ff77 100644
--- a/hw/misc/mps2-scc.c
+++ b/hw/misc/mps2-scc.c
@@ -481,7 +481,7 @@ static void mps2_scc_class_init(ObjectClass *klass, void *data)
dc->realize = mps2_scc_realize;
dc->vmsd = &mps2_scc_vmstate;
- dc->reset = mps2_scc_reset;
+ device_class_set_legacy_reset(dc, mps2_scc_reset);
device_class_set_props(dc, mps2_scc_properties);
}
diff --git a/hw/misc/msf2-sysreg.c b/hw/misc/msf2-sysreg.c
index f54382a..b8dde19 100644
--- a/hw/misc/msf2-sysreg.c
+++ b/hw/misc/msf2-sysreg.c
@@ -142,7 +142,7 @@ static void msf2_sysreg_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_msf2_sysreg;
- dc->reset = msf2_sysreg_reset;
+ device_class_set_legacy_reset(dc, msf2_sysreg_reset);
device_class_set_props(dc, msf2_sysreg_properties);
dc->realize = msf2_sysreg_realize;
}
diff --git a/hw/misc/mst_fpga.c b/hw/misc/mst_fpga.c
deleted file mode 100644
index 2d7bfa5..0000000
--- a/hw/misc/mst_fpga.c
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * PXA270-based Intel Mainstone platforms.
- * FPGA driver
- *
- * Copyright (c) 2007 by Armin Kuster <akuster@kama-aina.net> or
- * <akuster@mvista.com>
- *
- * This code is licensed under the GNU GPL v2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/irq.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-/* Mainstone FPGA for extern irqs */
-#define FPGA_GPIO_PIN 0
-#define MST_NUM_IRQS 16
-#define MST_LEDDAT1 0x10
-#define MST_LEDDAT2 0x14
-#define MST_LEDCTRL 0x40
-#define MST_GPSWR 0x60
-#define MST_MSCWR1 0x80
-#define MST_MSCWR2 0x84
-#define MST_MSCWR3 0x88
-#define MST_MSCRD 0x90
-#define MST_INTMSKENA 0xc0
-#define MST_INTSETCLR 0xd0
-#define MST_PCMCIA0 0xe0
-#define MST_PCMCIA1 0xe4
-
-#define MST_PCMCIAx_READY (1 << 10)
-#define MST_PCMCIAx_nCD (1 << 5)
-
-#define MST_PCMCIA_CD0_IRQ 9
-#define MST_PCMCIA_CD1_IRQ 13
-
-#define TYPE_MAINSTONE_FPGA "mainstone-fpga"
-OBJECT_DECLARE_SIMPLE_TYPE(mst_irq_state, MAINSTONE_FPGA)
-
-struct mst_irq_state {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
-
- qemu_irq parent;
-
- uint32_t prev_level;
- uint32_t leddat1;
- uint32_t leddat2;
- uint32_t ledctrl;
- uint32_t gpswr;
- uint32_t mscwr1;
- uint32_t mscwr2;
- uint32_t mscwr3;
- uint32_t mscrd;
- uint32_t intmskena;
- uint32_t intsetclr;
- uint32_t pcmcia0;
- uint32_t pcmcia1;
-};
-
-static void
-mst_fpga_set_irq(void *opaque, int irq, int level)
-{
- mst_irq_state *s = (mst_irq_state *)opaque;
- uint32_t oldint = s->intsetclr & s->intmskena;
-
- if (level)
- s->prev_level |= 1u << irq;
- else
- s->prev_level &= ~(1u << irq);
-
- switch(irq) {
- case MST_PCMCIA_CD0_IRQ:
- if (level)
- s->pcmcia0 &= ~MST_PCMCIAx_nCD;
- else
- s->pcmcia0 |= MST_PCMCIAx_nCD;
- break;
- case MST_PCMCIA_CD1_IRQ:
- if (level)
- s->pcmcia1 &= ~MST_PCMCIAx_nCD;
- else
- s->pcmcia1 |= MST_PCMCIAx_nCD;
- break;
- }
-
- if ((s->intmskena & (1u << irq)) && level)
- s->intsetclr |= 1u << irq;
-
- if (oldint != (s->intsetclr & s->intmskena))
- qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
-}
-
-
-static uint64_t
-mst_fpga_readb(void *opaque, hwaddr addr, unsigned size)
-{
- mst_irq_state *s = (mst_irq_state *) opaque;
-
- switch (addr) {
- case MST_LEDDAT1:
- return s->leddat1;
- case MST_LEDDAT2:
- return s->leddat2;
- case MST_LEDCTRL:
- return s->ledctrl;
- case MST_GPSWR:
- return s->gpswr;
- case MST_MSCWR1:
- return s->mscwr1;
- case MST_MSCWR2:
- return s->mscwr2;
- case MST_MSCWR3:
- return s->mscwr3;
- case MST_MSCRD:
- return s->mscrd;
- case MST_INTMSKENA:
- return s->intmskena;
- case MST_INTSETCLR:
- return s->intsetclr;
- case MST_PCMCIA0:
- return s->pcmcia0;
- case MST_PCMCIA1:
- return s->pcmcia1;
- default:
- printf("Mainstone - mst_fpga_readb: Bad register offset "
- "0x" HWADDR_FMT_plx "\n", addr);
- }
- return 0;
-}
-
-static void
-mst_fpga_writeb(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- mst_irq_state *s = (mst_irq_state *) opaque;
- value &= 0xffffffff;
-
- switch (addr) {
- case MST_LEDDAT1:
- s->leddat1 = value;
- break;
- case MST_LEDDAT2:
- s->leddat2 = value;
- break;
- case MST_LEDCTRL:
- s->ledctrl = value;
- break;
- case MST_GPSWR:
- s->gpswr = value;
- break;
- case MST_MSCWR1:
- s->mscwr1 = value;
- break;
- case MST_MSCWR2:
- s->mscwr2 = value;
- break;
- case MST_MSCWR3:
- s->mscwr3 = value;
- break;
- case MST_MSCRD:
- s->mscrd = value;
- break;
- case MST_INTMSKENA: /* Mask interrupt */
- s->intmskena = (value & 0xFEEFF);
- qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
- break;
- case MST_INTSETCLR: /* clear or set interrupt */
- s->intsetclr = (value & 0xFEEFF);
- qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
- break;
- /* For PCMCIAx allow the to change only power and reset */
- case MST_PCMCIA0:
- s->pcmcia0 = (value & 0x1f) | (s->pcmcia0 & ~0x1f);
- break;
- case MST_PCMCIA1:
- s->pcmcia1 = (value & 0x1f) | (s->pcmcia1 & ~0x1f);
- break;
- default:
- printf("Mainstone - mst_fpga_writeb: Bad register offset "
- "0x" HWADDR_FMT_plx "\n", addr);
- }
-}
-
-static const MemoryRegionOps mst_fpga_ops = {
- .read = mst_fpga_readb,
- .write = mst_fpga_writeb,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int mst_fpga_post_load(void *opaque, int version_id)
-{
- mst_irq_state *s = (mst_irq_state *) opaque;
-
- qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
- return 0;
-}
-
-static void mst_fpga_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- mst_irq_state *s = MAINSTONE_FPGA(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- s->pcmcia0 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD;
- s->pcmcia1 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD;
-
- sysbus_init_irq(sbd, &s->parent);
-
- /* alloc the external 16 irqs */
- qdev_init_gpio_in(dev, mst_fpga_set_irq, MST_NUM_IRQS);
-
- memory_region_init_io(&s->iomem, obj, &mst_fpga_ops, s,
- "fpga", 0x00100000);
- sysbus_init_mmio(sbd, &s->iomem);
-}
-
-static const VMStateDescription vmstate_mst_fpga_regs = {
- .name = "mainstone_fpga",
- .version_id = 0,
- .minimum_version_id = 0,
- .post_load = mst_fpga_post_load,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32(prev_level, mst_irq_state),
- VMSTATE_UINT32(leddat1, mst_irq_state),
- VMSTATE_UINT32(leddat2, mst_irq_state),
- VMSTATE_UINT32(ledctrl, mst_irq_state),
- VMSTATE_UINT32(gpswr, mst_irq_state),
- VMSTATE_UINT32(mscwr1, mst_irq_state),
- VMSTATE_UINT32(mscwr2, mst_irq_state),
- VMSTATE_UINT32(mscwr3, mst_irq_state),
- VMSTATE_UINT32(mscrd, mst_irq_state),
- VMSTATE_UINT32(intmskena, mst_irq_state),
- VMSTATE_UINT32(intsetclr, mst_irq_state),
- VMSTATE_UINT32(pcmcia0, mst_irq_state),
- VMSTATE_UINT32(pcmcia1, mst_irq_state),
- VMSTATE_END_OF_LIST(),
- },
-};
-
-static void mst_fpga_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->desc = "Mainstone II FPGA";
- dc->vmsd = &vmstate_mst_fpga_regs;
-}
-
-static const TypeInfo mst_fpga_info = {
- .name = TYPE_MAINSTONE_FPGA,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(mst_irq_state),
- .instance_init = mst_fpga_init,
- .class_init = mst_fpga_class_init,
-};
-
-static void mst_fpga_register_types(void)
-{
- type_register_static(&mst_fpga_info);
-}
-
-type_init(mst_fpga_register_types)
diff --git a/hw/misc/nrf51_rng.c b/hw/misc/nrf51_rng.c
index 2d76c45..bf1eb0c 100644
--- a/hw/misc/nrf51_rng.c
+++ b/hw/misc/nrf51_rng.c
@@ -247,7 +247,7 @@ static void nrf51_rng_class_init(ObjectClass *klass, void *data)
device_class_set_props(dc, nrf51_rng_properties);
dc->vmsd = &vmstate_rng;
- dc->reset = nrf51_rng_reset;
+ device_class_set_legacy_reset(dc, nrf51_rng_reset);
}
static const TypeInfo nrf51_rng_info = {
diff --git a/hw/misc/omap_clk.c b/hw/misc/omap_clk.c
index c77ca2f..0157c9b 100644
--- a/hw/misc/omap_clk.c
+++ b/hw/misc/omap_clk.c
@@ -35,9 +35,6 @@ struct clk {
#define CLOCK_IN_OMAP730 (1 << 11)
#define CLOCK_IN_OMAP1510 (1 << 12)
#define CLOCK_IN_OMAP16XX (1 << 13)
-#define CLOCK_IN_OMAP242X (1 << 14)
-#define CLOCK_IN_OMAP243X (1 << 15)
-#define CLOCK_IN_OMAP343X (1 << 16)
uint32_t flags;
int id;
@@ -59,8 +56,7 @@ static struct clk xtal_osc12m = {
static struct clk xtal_osc32k = {
.name = "xtal_osc_32k",
.rate = 32768,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
- CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
};
static struct clk ck_ref = {
@@ -507,449 +503,10 @@ static struct clk i2c_ick = {
static struct clk clk32k = {
.name = "clk32-kHz",
.flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+ ALWAYS_ENABLED,
.parent = &xtal_osc32k,
};
-static struct clk ref_clk = {
- .name = "ref_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .rate = 12000000, /* 12 MHz or 13 MHz or 19.2 MHz */
- /*.parent = sys.xtalin */
-};
-
-static struct clk apll_96m = {
- .name = "apll_96m",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .rate = 96000000,
- /*.parent = ref_clk */
-};
-
-static struct clk apll_54m = {
- .name = "apll_54m",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .rate = 54000000,
- /*.parent = ref_clk */
-};
-
-static struct clk sys_clk = {
- .name = "sys_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .rate = 32768,
- /*.parent = sys.xtalin */
-};
-
-static struct clk sleep_clk = {
- .name = "sleep_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .rate = 32768,
- /*.parent = sys.xtalin */
-};
-
-static struct clk dpll_ck = {
- .name = "dpll",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .parent = &ref_clk,
-};
-
-static struct clk dpll_x2_ck = {
- .name = "dpll_x2",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .parent = &ref_clk,
-};
-
-static struct clk wdt1_sys_clk = {
- .name = "wdt1_sys_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
- .rate = 32768,
- /*.parent = sys.xtalin */
-};
-
-static struct clk func_96m_clk = {
- .name = "func_96m_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .divisor = 1,
- .parent = &apll_96m,
-};
-
-static struct clk func_48m_clk = {
- .name = "func_48m_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .divisor = 2,
- .parent = &apll_96m,
-};
-
-static struct clk func_12m_clk = {
- .name = "func_12m_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .divisor = 8,
- .parent = &apll_96m,
-};
-
-static struct clk func_54m_clk = {
- .name = "func_54m_clk",
- .flags = CLOCK_IN_OMAP242X,
- .divisor = 1,
- .parent = &apll_54m,
-};
-
-static struct clk sys_clkout = {
- .name = "clkout",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk sys_clkout2 = {
- .name = "clkout2",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_clk = {
- .name = "core_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &dpll_x2_ck, /* Switchable between dpll_ck and clk32k */
-};
-
-static struct clk l3_clk = {
- .name = "l3_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_clk,
-};
-
-static struct clk core_l4_iclk = {
- .name = "core_l4_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &l3_clk,
-};
-
-static struct clk wu_l4_iclk = {
- .name = "wu_l4_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &l3_clk,
-};
-
-static struct clk core_l3_iclk = {
- .name = "core_l3_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_clk,
-};
-
-static struct clk core_l4_usb_clk = {
- .name = "core_l4_usb_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &l3_clk,
-};
-
-static struct clk wu_gpt1_clk = {
- .name = "wu_gpt1_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk wu_32k_clk = {
- .name = "wu_32k_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk uart1_fclk = {
- .name = "uart1_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_48m_clk,
-};
-
-static struct clk uart1_iclk = {
- .name = "uart1_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
-};
-
-static struct clk uart2_fclk = {
- .name = "uart2_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_48m_clk,
-};
-
-static struct clk uart2_iclk = {
- .name = "uart2_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
-};
-
-static struct clk uart3_fclk = {
- .name = "uart3_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_48m_clk,
-};
-
-static struct clk uart3_iclk = {
- .name = "uart3_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
-};
-
-static struct clk mpu_fclk = {
- .name = "mpu_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_clk,
-};
-
-static struct clk mpu_iclk = {
- .name = "mpu_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_clk,
-};
-
-static struct clk int_m_fclk = {
- .name = "int_m_fclk",
- .alias = "mpu_intc_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_clk,
-};
-
-static struct clk int_m_iclk = {
- .name = "int_m_iclk",
- .alias = "mpu_intc_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_clk,
-};
-
-static struct clk core_gpt2_clk = {
- .name = "core_gpt2_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt3_clk = {
- .name = "core_gpt3_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt4_clk = {
- .name = "core_gpt4_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt5_clk = {
- .name = "core_gpt5_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt6_clk = {
- .name = "core_gpt6_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt7_clk = {
- .name = "core_gpt7_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt8_clk = {
- .name = "core_gpt8_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt9_clk = {
- .name = "core_gpt9_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt10_clk = {
- .name = "core_gpt10_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt11_clk = {
- .name = "core_gpt11_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk core_gpt12_clk = {
- .name = "core_gpt12_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
-};
-
-static struct clk mcbsp1_clk = {
- .name = "mcbsp1_cg",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .divisor = 2,
- .parent = &func_96m_clk,
-};
-
-static struct clk mcbsp2_clk = {
- .name = "mcbsp2_cg",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .divisor = 2,
- .parent = &func_96m_clk,
-};
-
-static struct clk emul_clk = {
- .name = "emul_ck",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_54m_clk,
-};
-
-static struct clk sdma_fclk = {
- .name = "sdma_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &l3_clk,
-};
-
-static struct clk sdma_iclk = {
- .name = "sdma_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l3_iclk, /* core_l4_iclk for the configuration port */
-};
-
-static struct clk i2c1_fclk = {
- .name = "i2c1.fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_12m_clk,
- .divisor = 1,
-};
-
-static struct clk i2c1_iclk = {
- .name = "i2c1.iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
-};
-
-static struct clk i2c2_fclk = {
- .name = "i2c2.fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_12m_clk,
- .divisor = 1,
-};
-
-static struct clk i2c2_iclk = {
- .name = "i2c2.iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
-};
-
-static struct clk gpio_dbclk[5] = {
- {
- .name = "gpio1_dbclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &wu_32k_clk,
- }, {
- .name = "gpio2_dbclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &wu_32k_clk,
- }, {
- .name = "gpio3_dbclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &wu_32k_clk,
- }, {
- .name = "gpio4_dbclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &wu_32k_clk,
- }, {
- .name = "gpio5_dbclk",
- .flags = CLOCK_IN_OMAP243X,
- .parent = &wu_32k_clk,
- },
-};
-
-static struct clk gpio_iclk = {
- .name = "gpio_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &wu_l4_iclk,
-};
-
-static struct clk mmc_fck = {
- .name = "mmc_fclk",
- .flags = CLOCK_IN_OMAP242X,
- .parent = &func_96m_clk,
-};
-
-static struct clk mmc_ick = {
- .name = "mmc_iclk",
- .flags = CLOCK_IN_OMAP242X,
- .parent = &core_l4_iclk,
-};
-
-static struct clk spi_fclk[3] = {
- {
- .name = "spi1_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_48m_clk,
- }, {
- .name = "spi2_fclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_48m_clk,
- }, {
- .name = "spi3_fclk",
- .flags = CLOCK_IN_OMAP243X,
- .parent = &func_48m_clk,
- },
-};
-
-static struct clk dss_clk[2] = {
- {
- .name = "dss_clk1",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_clk,
- }, {
- .name = "dss_clk2",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &sys_clk,
- },
-};
-
-static struct clk dss_54m_clk = {
- .name = "dss_54m_clk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &func_54m_clk,
-};
-
-static struct clk dss_l3_iclk = {
- .name = "dss_l3_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l3_iclk,
-};
-
-static struct clk dss_l4_iclk = {
- .name = "dss_l4_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
-};
-
-static struct clk spi_iclk[3] = {
- {
- .name = "spi1_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
- }, {
- .name = "spi2_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
- }, {
- .name = "spi3_iclk",
- .flags = CLOCK_IN_OMAP243X,
- .parent = &core_l4_iclk,
- },
-};
-
-static struct clk omapctrl_clk = {
- .name = "omapctrl_iclk",
- .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
- /* XXX Should be in WKUP domain */
- .parent = &core_l4_iclk,
-};
-
static struct clk *onchip_clks[] = {
/* OMAP 1 */
@@ -1019,80 +576,6 @@ static struct clk *onchip_clks[] = {
&i2c_fck,
&i2c_ick,
- /* OMAP 2 */
-
- &ref_clk,
- &apll_96m,
- &apll_54m,
- &sys_clk,
- &sleep_clk,
- &dpll_ck,
- &dpll_x2_ck,
- &wdt1_sys_clk,
- &func_96m_clk,
- &func_48m_clk,
- &func_12m_clk,
- &func_54m_clk,
- &sys_clkout,
- &sys_clkout2,
- &core_clk,
- &l3_clk,
- &core_l4_iclk,
- &wu_l4_iclk,
- &core_l3_iclk,
- &core_l4_usb_clk,
- &wu_gpt1_clk,
- &wu_32k_clk,
- &uart1_fclk,
- &uart1_iclk,
- &uart2_fclk,
- &uart2_iclk,
- &uart3_fclk,
- &uart3_iclk,
- &mpu_fclk,
- &mpu_iclk,
- &int_m_fclk,
- &int_m_iclk,
- &core_gpt2_clk,
- &core_gpt3_clk,
- &core_gpt4_clk,
- &core_gpt5_clk,
- &core_gpt6_clk,
- &core_gpt7_clk,
- &core_gpt8_clk,
- &core_gpt9_clk,
- &core_gpt10_clk,
- &core_gpt11_clk,
- &core_gpt12_clk,
- &mcbsp1_clk,
- &mcbsp2_clk,
- &emul_clk,
- &sdma_fclk,
- &sdma_iclk,
- &i2c1_fclk,
- &i2c1_iclk,
- &i2c2_fclk,
- &i2c2_iclk,
- &gpio_dbclk[0],
- &gpio_dbclk[1],
- &gpio_dbclk[2],
- &gpio_dbclk[3],
- &gpio_iclk,
- &mmc_fck,
- &mmc_ick,
- &spi_fclk[0],
- &spi_iclk[0],
- &spi_fclk[1],
- &spi_iclk[1],
- &spi_fclk[2],
- &spi_iclk[2],
- &dss_clk[0],
- &dss_clk[1],
- &dss_54m_clk,
- &dss_l3_iclk,
- &dss_l4_iclk,
- &omapctrl_clk,
-
NULL
};
@@ -1230,12 +713,6 @@ void omap_clk_init(struct omap_mpu_state_s *mpu)
flag = CLOCK_IN_OMAP310;
else if (cpu_is_omap1510(mpu))
flag = CLOCK_IN_OMAP1510;
- else if (cpu_is_omap2410(mpu) || cpu_is_omap2420(mpu))
- flag = CLOCK_IN_OMAP242X;
- else if (cpu_is_omap2430(mpu))
- flag = CLOCK_IN_OMAP243X;
- else if (cpu_is_omap3430(mpu))
- flag = CLOCK_IN_OMAP243X;
else
return;
diff --git a/hw/misc/omap_gpmc.c b/hw/misc/omap_gpmc.c
deleted file mode 100644
index 67158eb..0000000
--- a/hw/misc/omap_gpmc.c
+++ /dev/null
@@ -1,898 +0,0 @@
-/*
- * TI OMAP general purpose memory controller emulation.
- *
- * Copyright (C) 2007-2009 Nokia Corporation
- * Original code written by Andrzej Zaborowski <andrew@openedhand.com>
- * Enhancements for OMAP3 and NAND support written by Juha RiihimƤki
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/irq.h"
-#include "hw/block/flash.h"
-#include "hw/arm/omap.h"
-#include "exec/memory.h"
-#include "exec/address-spaces.h"
-
-/* General-Purpose Memory Controller */
-struct omap_gpmc_s {
- qemu_irq irq;
- qemu_irq drq;
- MemoryRegion iomem;
- int accept_256;
-
- uint8_t revision;
- uint8_t sysconfig;
- uint16_t irqst;
- uint16_t irqen;
- uint16_t lastirq;
- uint16_t timeout;
- uint16_t config;
- struct omap_gpmc_cs_file_s {
- uint32_t config[7];
- MemoryRegion *iomem;
- MemoryRegion container;
- MemoryRegion nandiomem;
- DeviceState *dev;
- } cs_file[8];
- int ecc_cs;
- int ecc_ptr;
- uint32_t ecc_cfg;
- ECCState ecc[9];
- struct prefetch {
- uint32_t config1; /* GPMC_PREFETCH_CONFIG1 */
- uint32_t transfercount; /* GPMC_PREFETCH_CONFIG2:TRANSFERCOUNT */
- int startengine; /* GPMC_PREFETCH_CONTROL:STARTENGINE */
- int fifopointer; /* GPMC_PREFETCH_STATUS:FIFOPOINTER */
- int count; /* GPMC_PREFETCH_STATUS:COUNTVALUE */
- MemoryRegion iomem;
- uint8_t fifo[64];
- } prefetch;
-};
-
-#define OMAP_GPMC_8BIT 0
-#define OMAP_GPMC_16BIT 1
-#define OMAP_GPMC_NOR 0
-#define OMAP_GPMC_NAND 2
-
-static int omap_gpmc_devtype(struct omap_gpmc_cs_file_s *f)
-{
- return (f->config[0] >> 10) & 3;
-}
-
-static int omap_gpmc_devsize(struct omap_gpmc_cs_file_s *f)
-{
- /* devsize field is really 2 bits but we ignore the high
- * bit to ensure consistent behaviour if the guest sets
- * it (values 2 and 3 are reserved in the TRM)
- */
- return (f->config[0] >> 12) & 1;
-}
-
-/* Extract the chip-select value from the prefetch config1 register */
-static int prefetch_cs(uint32_t config1)
-{
- return (config1 >> 24) & 7;
-}
-
-static int prefetch_threshold(uint32_t config1)
-{
- return (config1 >> 8) & 0x7f;
-}
-
-static void omap_gpmc_int_update(struct omap_gpmc_s *s)
-{
- /* The TRM is a bit unclear, but it seems to say that
- * the TERMINALCOUNTSTATUS bit is set only on the
- * transition when the prefetch engine goes from
- * active to inactive, whereas the FIFOEVENTSTATUS
- * bit is held high as long as the fifo has at
- * least THRESHOLD bytes available.
- * So we do the latter here, but TERMINALCOUNTSTATUS
- * is set elsewhere.
- */
- if (s->prefetch.fifopointer >= prefetch_threshold(s->prefetch.config1)) {
- s->irqst |= 1;
- }
- if ((s->irqen & s->irqst) != s->lastirq) {
- s->lastirq = s->irqen & s->irqst;
- qemu_set_irq(s->irq, s->lastirq);
- }
-}
-
-static void omap_gpmc_dma_update(struct omap_gpmc_s *s, int value)
-{
- if (s->prefetch.config1 & 4) {
- qemu_set_irq(s->drq, value);
- }
-}
-
-/* Access functions for when a NAND-like device is mapped into memory:
- * all addresses in the region behave like accesses to the relevant
- * GPMC_NAND_DATA_i register (which is actually implemented to call these)
- */
-static uint64_t omap_nand_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_gpmc_cs_file_s *f = opaque;
- uint64_t v;
- nand_setpins(f->dev, 0, 0, 0, 1, 0);
- switch (omap_gpmc_devsize(f)) {
- case OMAP_GPMC_8BIT:
- v = nand_getio(f->dev);
- if (size == 1) {
- return v;
- }
- v |= (nand_getio(f->dev) << 8);
- if (size == 2) {
- return v;
- }
- v |= (nand_getio(f->dev) << 16);
- v |= (nand_getio(f->dev) << 24);
- return v;
- case OMAP_GPMC_16BIT:
- v = nand_getio(f->dev);
- if (size == 1) {
- /* 8 bit read from 16 bit device : probably a guest bug */
- return v & 0xff;
- }
- if (size == 2) {
- return v;
- }
- v |= (nand_getio(f->dev) << 16);
- return v;
- default:
- abort();
- }
-}
-
-static void omap_nand_setio(DeviceState *dev, uint64_t value,
- int nandsize, int size)
-{
- /* Write the specified value to the NAND device, respecting
- * both size of the NAND device and size of the write access.
- */
- switch (nandsize) {
- case OMAP_GPMC_8BIT:
- switch (size) {
- case 1:
- nand_setio(dev, value & 0xff);
- break;
- case 2:
- nand_setio(dev, value & 0xff);
- nand_setio(dev, (value >> 8) & 0xff);
- break;
- case 4:
- default:
- nand_setio(dev, value & 0xff);
- nand_setio(dev, (value >> 8) & 0xff);
- nand_setio(dev, (value >> 16) & 0xff);
- nand_setio(dev, (value >> 24) & 0xff);
- break;
- }
- break;
- case OMAP_GPMC_16BIT:
- switch (size) {
- case 1:
- /* writing to a 16bit device with 8bit access is probably a guest
- * bug; pass the value through anyway.
- */
- case 2:
- nand_setio(dev, value & 0xffff);
- break;
- case 4:
- default:
- nand_setio(dev, value & 0xffff);
- nand_setio(dev, (value >> 16) & 0xffff);
- break;
- }
- break;
- }
-}
-
-static void omap_nand_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_gpmc_cs_file_s *f = opaque;
- nand_setpins(f->dev, 0, 0, 0, 1, 0);
- omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
-}
-
-static const MemoryRegionOps omap_nand_ops = {
- .read = omap_nand_read,
- .write = omap_nand_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void fill_prefetch_fifo(struct omap_gpmc_s *s)
-{
- /* Fill the prefetch FIFO by reading data from NAND.
- * We do this synchronously, unlike the hardware which
- * will do this asynchronously. We refill when the
- * FIFO has THRESHOLD bytes free, and we always refill
- * as much data as possible starting at the top end
- * of the FIFO.
- * (We have to refill at THRESHOLD rather than waiting
- * for the FIFO to empty to allow for the case where
- * the FIFO size isn't an exact multiple of THRESHOLD
- * and we're doing DMA transfers.)
- * This means we never need to handle wrap-around in
- * the fifo-reading code, and the next byte of data
- * to read is always fifo[63 - fifopointer].
- */
- int fptr;
- int cs = prefetch_cs(s->prefetch.config1);
- int is16bit = (((s->cs_file[cs].config[0] >> 12) & 3) != 0);
- int bytes;
- /* Don't believe the bit of the OMAP TRM that says that COUNTVALUE
- * and TRANSFERCOUNT are in units of 16 bit words for 16 bit NAND.
- * Instead believe the bit that says it is always a byte count.
- */
- bytes = 64 - s->prefetch.fifopointer;
- if (bytes > s->prefetch.count) {
- bytes = s->prefetch.count;
- }
- if (is16bit) {
- bytes &= ~1;
- }
-
- s->prefetch.count -= bytes;
- s->prefetch.fifopointer += bytes;
- fptr = 64 - s->prefetch.fifopointer;
- /* Move the existing data in the FIFO so it sits just
- * before what we're about to read in
- */
- while (fptr < (64 - bytes)) {
- s->prefetch.fifo[fptr] = s->prefetch.fifo[fptr + bytes];
- fptr++;
- }
- while (fptr < 64) {
- if (is16bit) {
- uint32_t v = omap_nand_read(&s->cs_file[cs], 0, 2);
- s->prefetch.fifo[fptr++] = v & 0xff;
- s->prefetch.fifo[fptr++] = (v >> 8) & 0xff;
- } else {
- s->prefetch.fifo[fptr++] = omap_nand_read(&s->cs_file[cs], 0, 1);
- }
- }
- if (s->prefetch.startengine && (s->prefetch.count == 0)) {
- /* This was the final transfer: raise TERMINALCOUNTSTATUS */
- s->irqst |= 2;
- s->prefetch.startengine = 0;
- }
- /* If there are any bytes in the FIFO at this point then
- * we must raise a DMA request (either this is a final part
- * transfer, or we filled the FIFO in which case we certainly
- * have THRESHOLD bytes available)
- */
- if (s->prefetch.fifopointer != 0) {
- omap_gpmc_dma_update(s, 1);
- }
- omap_gpmc_int_update(s);
-}
-
-/* Access functions for a NAND-like device when the prefetch/postwrite
- * engine is enabled -- all addresses in the region behave alike:
- * data is read or written to the FIFO.
- */
-static uint64_t omap_gpmc_prefetch_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_gpmc_s *s = opaque;
- uint32_t data;
- if (s->prefetch.config1 & 1) {
- /* The TRM doesn't define the behaviour if you read from the
- * FIFO when the prefetch engine is in write mode. We choose
- * to always return zero.
- */
- return 0;
- }
- /* Note that trying to read an empty fifo repeats the last byte */
- if (s->prefetch.fifopointer) {
- s->prefetch.fifopointer--;
- }
- data = s->prefetch.fifo[63 - s->prefetch.fifopointer];
- if (s->prefetch.fifopointer ==
- (64 - prefetch_threshold(s->prefetch.config1))) {
- /* We've drained THRESHOLD bytes now. So deassert the
- * DMA request, then refill the FIFO (which will probably
- * assert it again.)
- */
- omap_gpmc_dma_update(s, 0);
- fill_prefetch_fifo(s);
- }
- omap_gpmc_int_update(s);
- return data;
-}
-
-static void omap_gpmc_prefetch_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_gpmc_s *s = opaque;
- int cs = prefetch_cs(s->prefetch.config1);
- if ((s->prefetch.config1 & 1) == 0) {
- /* The TRM doesn't define the behaviour of writing to the
- * FIFO when the prefetch engine is in read mode. We
- * choose to ignore the write.
- */
- return;
- }
- if (s->prefetch.count == 0) {
- /* The TRM doesn't define the behaviour of writing to the
- * FIFO if the transfer is complete. We choose to ignore.
- */
- return;
- }
- /* The only reason we do any data buffering in postwrite
- * mode is if we are talking to a 16 bit NAND device, in
- * which case we need to buffer the first byte of the
- * 16 bit word until the other byte arrives.
- */
- int is16bit = (((s->cs_file[cs].config[0] >> 12) & 3) != 0);
- if (is16bit) {
- /* fifopointer alternates between 64 (waiting for first
- * byte of word) and 63 (waiting for second byte)
- */
- if (s->prefetch.fifopointer == 64) {
- s->prefetch.fifo[0] = value;
- s->prefetch.fifopointer--;
- } else {
- value = (value << 8) | s->prefetch.fifo[0];
- omap_nand_write(&s->cs_file[cs], 0, value, 2);
- s->prefetch.count--;
- s->prefetch.fifopointer = 64;
- }
- } else {
- /* Just write the byte : fifopointer remains 64 at all times */
- omap_nand_write(&s->cs_file[cs], 0, value, 1);
- s->prefetch.count--;
- }
- if (s->prefetch.count == 0) {
- /* Final transfer: raise TERMINALCOUNTSTATUS */
- s->irqst |= 2;
- s->prefetch.startengine = 0;
- }
- omap_gpmc_int_update(s);
-}
-
-static const MemoryRegionOps omap_prefetch_ops = {
- .read = omap_gpmc_prefetch_read,
- .write = omap_gpmc_prefetch_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .impl.min_access_size = 1,
- .impl.max_access_size = 1,
-};
-
-static MemoryRegion *omap_gpmc_cs_memregion(struct omap_gpmc_s *s, int cs)
-{
- /* Return the MemoryRegion* to map/unmap for this chipselect */
- struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
- if (omap_gpmc_devtype(f) == OMAP_GPMC_NOR) {
- return f->iomem;
- }
- if ((s->prefetch.config1 & 0x80) &&
- (prefetch_cs(s->prefetch.config1) == cs)) {
- /* The prefetch engine is enabled for this CS: map the FIFO */
- return &s->prefetch.iomem;
- }
- return &f->nandiomem;
-}
-
-static void omap_gpmc_cs_map(struct omap_gpmc_s *s, int cs)
-{
- struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
- uint32_t mask = (f->config[6] >> 8) & 0xf;
- uint32_t base = f->config[6] & 0x3f;
- uint32_t size;
-
- if (!f->iomem && !f->dev) {
- return;
- }
-
- if (!(f->config[6] & (1 << 6))) {
- /* Do nothing unless CSVALID */
- return;
- }
-
- /* TODO: check for overlapping regions and report access errors */
- if (mask != 0x8 && mask != 0xc && mask != 0xe && mask != 0xf
- && !(s->accept_256 && !mask)) {
- fprintf(stderr, "%s: invalid chip-select mask address (0x%x)\n",
- __func__, mask);
- }
-
- base <<= 24;
- size = (0x0fffffff & ~(mask << 24)) + 1;
- /* TODO: rather than setting the size of the mapping (which should be
- * constant), the mask should cause wrapping of the address space, so
- * that the same memory becomes accessible at every <i>size</i> bytes
- * starting from <i>base</i>. */
- memory_region_init(&f->container, NULL, "omap-gpmc-file", size);
- memory_region_add_subregion(&f->container, 0,
- omap_gpmc_cs_memregion(s, cs));
- memory_region_add_subregion(get_system_memory(), base,
- &f->container);
-}
-
-static void omap_gpmc_cs_unmap(struct omap_gpmc_s *s, int cs)
-{
- struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
- if (!(f->config[6] & (1 << 6))) {
- /* Do nothing unless CSVALID */
- return;
- }
- if (!f->iomem && !f->dev) {
- return;
- }
- memory_region_del_subregion(get_system_memory(), &f->container);
- memory_region_del_subregion(&f->container, omap_gpmc_cs_memregion(s, cs));
- object_unparent(OBJECT(&f->container));
-}
-
-void omap_gpmc_reset(struct omap_gpmc_s *s)
-{
- int i;
-
- s->sysconfig = 0;
- s->irqst = 0;
- s->irqen = 0;
- omap_gpmc_int_update(s);
- for (i = 0; i < 8; i++) {
- /* This has to happen before we change any of the config
- * used to determine which memory regions are mapped or unmapped.
- */
- omap_gpmc_cs_unmap(s, i);
- }
- s->timeout = 0;
- s->config = 0xa00;
- s->prefetch.config1 = 0x00004000;
- s->prefetch.transfercount = 0x00000000;
- s->prefetch.startengine = 0;
- s->prefetch.fifopointer = 0;
- s->prefetch.count = 0;
- for (i = 0; i < 8; i ++) {
- s->cs_file[i].config[1] = 0x101001;
- s->cs_file[i].config[2] = 0x020201;
- s->cs_file[i].config[3] = 0x10031003;
- s->cs_file[i].config[4] = 0x10f1111;
- s->cs_file[i].config[5] = 0;
- s->cs_file[i].config[6] = 0xf00;
- /* In theory we could probe attached devices for some CFG1
- * bits here, but we just retain them across resets as they
- * were set initially by omap_gpmc_attach().
- */
- if (i == 0) {
- s->cs_file[i].config[0] &= 0x00433e00;
- s->cs_file[i].config[6] |= 1 << 6; /* CSVALID */
- omap_gpmc_cs_map(s, i);
- } else {
- s->cs_file[i].config[0] &= 0x00403c00;
- }
- }
- s->ecc_cs = 0;
- s->ecc_ptr = 0;
- s->ecc_cfg = 0x3fcff000;
- for (i = 0; i < 9; i ++)
- ecc_reset(&s->ecc[i]);
-}
-
-static int gpmc_wordaccess_only(hwaddr addr)
-{
- /* Return true if the register offset is to a register that
- * only permits word width accesses.
- * Non-word accesses are only OK for GPMC_NAND_DATA/ADDRESS/COMMAND
- * for any chipselect.
- */
- if (addr >= 0x60 && addr <= 0x1d4) {
- int cs = (addr - 0x60) / 0x30;
- addr -= cs * 0x30;
- if (addr >= 0x7c && addr < 0x88) {
- /* GPMC_NAND_COMMAND, GPMC_NAND_ADDRESS, GPMC_NAND_DATA */
- return 0;
- }
- }
- return 1;
-}
-
-static uint64_t omap_gpmc_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_gpmc_s *s = opaque;
- int cs;
- struct omap_gpmc_cs_file_s *f;
-
- if (size != 4 && gpmc_wordaccess_only(addr)) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x000: /* GPMC_REVISION */
- return s->revision;
-
- case 0x010: /* GPMC_SYSCONFIG */
- return s->sysconfig;
-
- case 0x014: /* GPMC_SYSSTATUS */
- return 1; /* RESETDONE */
-
- case 0x018: /* GPMC_IRQSTATUS */
- return s->irqst;
-
- case 0x01c: /* GPMC_IRQENABLE */
- return s->irqen;
-
- case 0x040: /* GPMC_TIMEOUT_CONTROL */
- return s->timeout;
-
- case 0x044: /* GPMC_ERR_ADDRESS */
- case 0x048: /* GPMC_ERR_TYPE */
- return 0;
-
- case 0x050: /* GPMC_CONFIG */
- return s->config;
-
- case 0x054: /* GPMC_STATUS */
- return 0x001;
-
- case 0x060 ... 0x1d4:
- cs = (addr - 0x060) / 0x30;
- addr -= cs * 0x30;
- f = s->cs_file + cs;
- switch (addr) {
- case 0x60: /* GPMC_CONFIG1 */
- return f->config[0];
- case 0x64: /* GPMC_CONFIG2 */
- return f->config[1];
- case 0x68: /* GPMC_CONFIG3 */
- return f->config[2];
- case 0x6c: /* GPMC_CONFIG4 */
- return f->config[3];
- case 0x70: /* GPMC_CONFIG5 */
- return f->config[4];
- case 0x74: /* GPMC_CONFIG6 */
- return f->config[5];
- case 0x78: /* GPMC_CONFIG7 */
- return f->config[6];
- case 0x84 ... 0x87: /* GPMC_NAND_DATA */
- if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
- return omap_nand_read(f, 0, size);
- }
- return 0;
- }
- break;
-
- case 0x1e0: /* GPMC_PREFETCH_CONFIG1 */
- return s->prefetch.config1;
- case 0x1e4: /* GPMC_PREFETCH_CONFIG2 */
- return s->prefetch.transfercount;
- case 0x1ec: /* GPMC_PREFETCH_CONTROL */
- return s->prefetch.startengine;
- case 0x1f0: /* GPMC_PREFETCH_STATUS */
- /* NB: The OMAP3 TRM is inconsistent about whether the GPMC
- * FIFOTHRESHOLDSTATUS bit should be set when
- * FIFOPOINTER > FIFOTHRESHOLD or when it is >= FIFOTHRESHOLD.
- * Apparently the underlying functional spec from which the TRM was
- * created states that the behaviour is ">=", and this also
- * makes more conceptual sense.
- */
- return (s->prefetch.fifopointer << 24) |
- ((s->prefetch.fifopointer >=
- ((s->prefetch.config1 >> 8) & 0x7f) ? 1 : 0) << 16) |
- s->prefetch.count;
-
- case 0x1f4: /* GPMC_ECC_CONFIG */
- return s->ecc_cs;
- case 0x1f8: /* GPMC_ECC_CONTROL */
- return s->ecc_ptr;
- case 0x1fc: /* GPMC_ECC_SIZE_CONFIG */
- return s->ecc_cfg;
- case 0x200 ... 0x220: /* GPMC_ECC_RESULT */
- cs = (addr & 0x1f) >> 2;
- /* TODO: check correctness */
- return
- ((s->ecc[cs].cp & 0x07) << 0) |
- ((s->ecc[cs].cp & 0x38) << 13) |
- ((s->ecc[cs].lp[0] & 0x1ff) << 3) |
- ((s->ecc[cs].lp[1] & 0x1ff) << 19);
-
- case 0x230: /* GPMC_TESTMODE_CTRL */
- return 0;
- case 0x234: /* GPMC_PSA_LSB */
- case 0x238: /* GPMC_PSA_MSB */
- return 0x00000000;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_gpmc_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_gpmc_s *s = opaque;
- int cs;
- struct omap_gpmc_cs_file_s *f;
-
- if (size != 4 && gpmc_wordaccess_only(addr)) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x000: /* GPMC_REVISION */
- case 0x014: /* GPMC_SYSSTATUS */
- case 0x054: /* GPMC_STATUS */
- case 0x1f0: /* GPMC_PREFETCH_STATUS */
- case 0x200 ... 0x220: /* GPMC_ECC_RESULT */
- case 0x234: /* GPMC_PSA_LSB */
- case 0x238: /* GPMC_PSA_MSB */
- OMAP_RO_REG(addr);
- break;
-
- case 0x010: /* GPMC_SYSCONFIG */
- if ((value >> 3) == 0x3)
- fprintf(stderr, "%s: bad SDRAM idle mode %"PRIi64"\n",
- __func__, value >> 3);
- if (value & 2)
- omap_gpmc_reset(s);
- s->sysconfig = value & 0x19;
- break;
-
- case 0x018: /* GPMC_IRQSTATUS */
- s->irqst &= ~value;
- omap_gpmc_int_update(s);
- break;
-
- case 0x01c: /* GPMC_IRQENABLE */
- s->irqen = value & 0xf03;
- omap_gpmc_int_update(s);
- break;
-
- case 0x040: /* GPMC_TIMEOUT_CONTROL */
- s->timeout = value & 0x1ff1;
- break;
-
- case 0x044: /* GPMC_ERR_ADDRESS */
- case 0x048: /* GPMC_ERR_TYPE */
- break;
-
- case 0x050: /* GPMC_CONFIG */
- s->config = value & 0xf13;
- break;
-
- case 0x060 ... 0x1d4:
- cs = (addr - 0x060) / 0x30;
- addr -= cs * 0x30;
- f = s->cs_file + cs;
- switch (addr) {
- case 0x60: /* GPMC_CONFIG1 */
- f->config[0] = value & 0xffef3e13;
- break;
- case 0x64: /* GPMC_CONFIG2 */
- f->config[1] = value & 0x001f1f8f;
- break;
- case 0x68: /* GPMC_CONFIG3 */
- f->config[2] = value & 0x001f1f8f;
- break;
- case 0x6c: /* GPMC_CONFIG4 */
- f->config[3] = value & 0x1f8f1f8f;
- break;
- case 0x70: /* GPMC_CONFIG5 */
- f->config[4] = value & 0x0f1f1f1f;
- break;
- case 0x74: /* GPMC_CONFIG6 */
- f->config[5] = value & 0x00000fcf;
- break;
- case 0x78: /* GPMC_CONFIG7 */
- if ((f->config[6] ^ value) & 0xf7f) {
- omap_gpmc_cs_unmap(s, cs);
- f->config[6] = value & 0x00000f7f;
- omap_gpmc_cs_map(s, cs);
- }
- break;
- case 0x7c ... 0x7f: /* GPMC_NAND_COMMAND */
- if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
- nand_setpins(f->dev, 1, 0, 0, 1, 0); /* CLE */
- omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
- }
- break;
- case 0x80 ... 0x83: /* GPMC_NAND_ADDRESS */
- if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
- nand_setpins(f->dev, 0, 1, 0, 1, 0); /* ALE */
- omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
- }
- break;
- case 0x84 ... 0x87: /* GPMC_NAND_DATA */
- if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
- omap_nand_write(f, 0, value, size);
- }
- break;
- default:
- goto bad_reg;
- }
- break;
-
- case 0x1e0: /* GPMC_PREFETCH_CONFIG1 */
- if (!s->prefetch.startengine) {
- uint32_t newconfig1 = value & 0x7f8f7fbf;
- uint32_t changed;
- changed = newconfig1 ^ s->prefetch.config1;
- if (changed & (0x80 | 0x7000000)) {
- /* Turning the engine on or off, or mapping it somewhere else.
- * cs_map() and cs_unmap() check the prefetch config and
- * overall CSVALID bits, so it is sufficient to unmap-and-map
- * both the old cs and the new one. Note that we adhere to
- * the "unmap/change config/map" order (and not unmap twice
- * if newcs == oldcs), otherwise we'll try to delete the wrong
- * memory region.
- */
- int oldcs = prefetch_cs(s->prefetch.config1);
- int newcs = prefetch_cs(newconfig1);
- omap_gpmc_cs_unmap(s, oldcs);
- if (oldcs != newcs) {
- omap_gpmc_cs_unmap(s, newcs);
- }
- s->prefetch.config1 = newconfig1;
- omap_gpmc_cs_map(s, oldcs);
- if (oldcs != newcs) {
- omap_gpmc_cs_map(s, newcs);
- }
- } else {
- s->prefetch.config1 = newconfig1;
- }
- }
- break;
-
- case 0x1e4: /* GPMC_PREFETCH_CONFIG2 */
- if (!s->prefetch.startengine) {
- s->prefetch.transfercount = value & 0x3fff;
- }
- break;
-
- case 0x1ec: /* GPMC_PREFETCH_CONTROL */
- if (s->prefetch.startengine != (value & 1)) {
- s->prefetch.startengine = value & 1;
- if (s->prefetch.startengine) {
- /* Prefetch engine start */
- s->prefetch.count = s->prefetch.transfercount;
- if (s->prefetch.config1 & 1) {
- /* Write */
- s->prefetch.fifopointer = 64;
- } else {
- /* Read */
- s->prefetch.fifopointer = 0;
- fill_prefetch_fifo(s);
- }
- } else {
- /* Prefetch engine forcibly stopped. The TRM
- * doesn't define the behaviour if you do this.
- * We clear the prefetch count, which means that
- * we permit no more writes, and don't read any
- * more data from NAND. The CPU can still drain
- * the FIFO of unread data.
- */
- s->prefetch.count = 0;
- }
- omap_gpmc_int_update(s);
- }
- break;
-
- case 0x1f4: /* GPMC_ECC_CONFIG */
- s->ecc_cs = 0x8f;
- break;
- case 0x1f8: /* GPMC_ECC_CONTROL */
- if (value & (1 << 8))
- for (cs = 0; cs < 9; cs ++)
- ecc_reset(&s->ecc[cs]);
- s->ecc_ptr = value & 0xf;
- if (s->ecc_ptr == 0 || s->ecc_ptr > 9) {
- s->ecc_ptr = 0;
- s->ecc_cs &= ~1;
- }
- break;
- case 0x1fc: /* GPMC_ECC_SIZE_CONFIG */
- s->ecc_cfg = value & 0x3fcff1ff;
- break;
- case 0x230: /* GPMC_TESTMODE_CTRL */
- if (value & 7)
- fprintf(stderr, "%s: test mode enable attempt\n", __func__);
- break;
-
- default:
- bad_reg:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_gpmc_ops = {
- .read = omap_gpmc_read,
- .write = omap_gpmc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_gpmc_s *omap_gpmc_init(struct omap_mpu_state_s *mpu,
- hwaddr base,
- qemu_irq irq, qemu_irq drq)
-{
- int cs;
- struct omap_gpmc_s *s = g_new0(struct omap_gpmc_s, 1);
-
- memory_region_init_io(&s->iomem, NULL, &omap_gpmc_ops, s, "omap-gpmc", 0x1000);
- memory_region_add_subregion(get_system_memory(), base, &s->iomem);
-
- s->irq = irq;
- s->drq = drq;
- s->accept_256 = cpu_is_omap3630(mpu);
- s->revision = cpu_class_omap3(mpu) ? 0x50 : 0x20;
- s->lastirq = 0;
- omap_gpmc_reset(s);
-
- /* We have to register a different IO memory handler for each
- * chip select region in case a NAND device is mapped there. We
- * make the region the worst-case size of 256MB and rely on the
- * container memory region in cs_map to chop it down to the actual
- * guest-requested size.
- */
- for (cs = 0; cs < 8; cs++) {
- memory_region_init_io(&s->cs_file[cs].nandiomem, NULL,
- &omap_nand_ops,
- &s->cs_file[cs],
- "omap-nand",
- 256 * 1024 * 1024);
- }
-
- memory_region_init_io(&s->prefetch.iomem, NULL, &omap_prefetch_ops, s,
- "omap-gpmc-prefetch", 256 * 1024 * 1024);
- return s;
-}
-
-void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, MemoryRegion *iomem)
-{
- struct omap_gpmc_cs_file_s *f;
- assert(iomem);
-
- if (cs < 0 || cs >= 8) {
- fprintf(stderr, "%s: bad chip-select %i\n", __func__, cs);
- exit(-1);
- }
- f = &s->cs_file[cs];
-
- omap_gpmc_cs_unmap(s, cs);
- f->config[0] &= ~(0xf << 10);
- f->iomem = iomem;
- omap_gpmc_cs_map(s, cs);
-}
-
-void omap_gpmc_attach_nand(struct omap_gpmc_s *s, int cs, DeviceState *nand)
-{
- struct omap_gpmc_cs_file_s *f;
- assert(nand);
-
- if (cs < 0 || cs >= 8) {
- fprintf(stderr, "%s: bad chip-select %i\n", __func__, cs);
- exit(-1);
- }
- f = &s->cs_file[cs];
-
- omap_gpmc_cs_unmap(s, cs);
- f->config[0] &= ~(0xf << 10);
- f->config[0] |= (OMAP_GPMC_NAND << 10);
- f->dev = nand;
- if (nand_getbuswidth(f->dev) == 16) {
- f->config[0] |= OMAP_GPMC_16BIT << 12;
- }
- omap_gpmc_cs_map(s, cs);
-}
diff --git a/hw/misc/omap_l4.c b/hw/misc/omap_l4.c
deleted file mode 100644
index b787548..0000000
--- a/hw/misc/omap_l4.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * TI OMAP L4 interconnect emulation.
- *
- * Copyright (C) 2007-2009 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "hw/arm/omap.h"
-
-struct omap_l4_s {
- MemoryRegion *address_space;
- hwaddr base;
- int ta_num;
- struct omap_target_agent_s ta[];
-};
-
-struct omap_l4_s *omap_l4_init(MemoryRegion *address_space,
- hwaddr base, int ta_num)
-{
- struct omap_l4_s *bus = g_malloc0(
- sizeof(*bus) + ta_num * sizeof(*bus->ta));
-
- bus->address_space = address_space;
- bus->ta_num = ta_num;
- bus->base = base;
-
- return bus;
-}
-
-hwaddr omap_l4_region_base(struct omap_target_agent_s *ta,
- int region)
-{
- return ta->bus->base + ta->start[region].offset;
-}
-
-hwaddr omap_l4_region_size(struct omap_target_agent_s *ta,
- int region)
-{
- return ta->start[region].size;
-}
-
-static uint64_t omap_l4ta_read(void *opaque, hwaddr addr, unsigned size)
-{
- struct omap_target_agent_s *s = opaque;
-
- if (size != 2) {
- return omap_badwidth_read16(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* COMPONENT */
- return s->component;
-
- case 0x20: /* AGENT_CONTROL */
- return s->control;
-
- case 0x28: /* AGENT_STATUS */
- return s->status;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_l4ta_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_target_agent_s *s = opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* COMPONENT */
- case 0x28: /* AGENT_STATUS */
- OMAP_RO_REG(addr);
- break;
-
- case 0x20: /* AGENT_CONTROL */
- s->control = value & 0x01000700;
- if (value & 1) /* OCP_RESET */
- s->status &= ~1; /* REQ_TIMEOUT */
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_l4ta_ops = {
- .read = omap_l4ta_read,
- .write = omap_l4ta_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus,
- const struct omap_l4_region_s *regions,
- const struct omap_l4_agent_info_s *agents,
- int cs)
-{
- int i;
- struct omap_target_agent_s *ta = NULL;
- const struct omap_l4_agent_info_s *info = NULL;
-
- for (i = 0; i < bus->ta_num; i ++)
- if (agents[i].ta == cs) {
- ta = &bus->ta[i];
- info = &agents[i];
- break;
- }
- if (!ta) {
- fprintf(stderr, "%s: bad target agent (%i)\n", __func__, cs);
- exit(-1);
- }
-
- ta->bus = bus;
- ta->start = &regions[info->region];
- ta->regions = info->regions;
-
- ta->component = ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
- ta->status = 0x00000000;
- ta->control = 0x00000200; /* XXX 01000200 for L4TAO */
-
- memory_region_init_io(&ta->iomem, NULL, &omap_l4ta_ops, ta, "omap.l4ta",
- omap_l4_region_size(ta, info->ta_region));
- omap_l4_attach(ta, info->ta_region, &ta->iomem);
-
- return ta;
-}
-
-hwaddr omap_l4_attach(struct omap_target_agent_s *ta,
- int region, MemoryRegion *mr)
-{
- hwaddr base;
-
- if (region < 0 || region >= ta->regions) {
- fprintf(stderr, "%s: bad io region (%i)\n", __func__, region);
- exit(-1);
- }
-
- base = ta->bus->base + ta->start[region].offset;
- if (mr) {
- memory_region_add_subregion(ta->bus->address_space, base, mr);
- }
-
- return base;
-}
diff --git a/hw/misc/omap_sdrc.c b/hw/misc/omap_sdrc.c
deleted file mode 100644
index 6aa1b3e..0000000
--- a/hw/misc/omap_sdrc.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * TI OMAP SDRAM controller emulation.
- *
- * Copyright (C) 2007-2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "hw/arm/omap.h"
-
-/* SDRAM Controller Subsystem */
-struct omap_sdrc_s {
- MemoryRegion iomem;
- uint8_t config;
-};
-
-void omap_sdrc_reset(struct omap_sdrc_s *s)
-{
- s->config = 0x10;
-}
-
-static uint64_t omap_sdrc_read(void *opaque, hwaddr addr, unsigned size)
-{
- struct omap_sdrc_s *s = opaque;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* SDRC_REVISION */
- return 0x20;
-
- case 0x10: /* SDRC_SYSCONFIG */
- return s->config;
-
- case 0x14: /* SDRC_SYSSTATUS */
- return 1; /* RESETDONE */
-
- case 0x40: /* SDRC_CS_CFG */
- case 0x44: /* SDRC_SHARING */
- case 0x48: /* SDRC_ERR_ADDR */
- case 0x4c: /* SDRC_ERR_TYPE */
- case 0x60: /* SDRC_DLLA_SCTRL */
- case 0x64: /* SDRC_DLLA_STATUS */
- case 0x68: /* SDRC_DLLB_CTRL */
- case 0x6c: /* SDRC_DLLB_STATUS */
- case 0x70: /* SDRC_POWER */
- case 0x80: /* SDRC_MCFG_0 */
- case 0x84: /* SDRC_MR_0 */
- case 0x88: /* SDRC_EMR1_0 */
- case 0x8c: /* SDRC_EMR2_0 */
- case 0x90: /* SDRC_EMR3_0 */
- case 0x94: /* SDRC_DCDL1_CTRL */
- case 0x98: /* SDRC_DCDL2_CTRL */
- case 0x9c: /* SDRC_ACTIM_CTRLA_0 */
- case 0xa0: /* SDRC_ACTIM_CTRLB_0 */
- case 0xa4: /* SDRC_RFR_CTRL_0 */
- case 0xa8: /* SDRC_MANUAL_0 */
- case 0xb0: /* SDRC_MCFG_1 */
- case 0xb4: /* SDRC_MR_1 */
- case 0xb8: /* SDRC_EMR1_1 */
- case 0xbc: /* SDRC_EMR2_1 */
- case 0xc0: /* SDRC_EMR3_1 */
- case 0xc4: /* SDRC_ACTIM_CTRLA_1 */
- case 0xc8: /* SDRC_ACTIM_CTRLB_1 */
- case 0xd4: /* SDRC_RFR_CTRL_1 */
- case 0xd8: /* SDRC_MANUAL_1 */
- return 0x00;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_sdrc_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_sdrc_s *s = opaque;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* SDRC_REVISION */
- case 0x14: /* SDRC_SYSSTATUS */
- case 0x48: /* SDRC_ERR_ADDR */
- case 0x64: /* SDRC_DLLA_STATUS */
- case 0x6c: /* SDRC_DLLB_STATUS */
- OMAP_RO_REG(addr);
- return;
-
- case 0x10: /* SDRC_SYSCONFIG */
- if ((value >> 3) != 0x2)
- fprintf(stderr, "%s: bad SDRAM idle mode %i\n",
- __func__, (unsigned)value >> 3);
- if (value & 2)
- omap_sdrc_reset(s);
- s->config = value & 0x18;
- break;
-
- case 0x40: /* SDRC_CS_CFG */
- case 0x44: /* SDRC_SHARING */
- case 0x4c: /* SDRC_ERR_TYPE */
- case 0x60: /* SDRC_DLLA_SCTRL */
- case 0x68: /* SDRC_DLLB_CTRL */
- case 0x70: /* SDRC_POWER */
- case 0x80: /* SDRC_MCFG_0 */
- case 0x84: /* SDRC_MR_0 */
- case 0x88: /* SDRC_EMR1_0 */
- case 0x8c: /* SDRC_EMR2_0 */
- case 0x90: /* SDRC_EMR3_0 */
- case 0x94: /* SDRC_DCDL1_CTRL */
- case 0x98: /* SDRC_DCDL2_CTRL */
- case 0x9c: /* SDRC_ACTIM_CTRLA_0 */
- case 0xa0: /* SDRC_ACTIM_CTRLB_0 */
- case 0xa4: /* SDRC_RFR_CTRL_0 */
- case 0xa8: /* SDRC_MANUAL_0 */
- case 0xb0: /* SDRC_MCFG_1 */
- case 0xb4: /* SDRC_MR_1 */
- case 0xb8: /* SDRC_EMR1_1 */
- case 0xbc: /* SDRC_EMR2_1 */
- case 0xc0: /* SDRC_EMR3_1 */
- case 0xc4: /* SDRC_ACTIM_CTRLA_1 */
- case 0xc8: /* SDRC_ACTIM_CTRLB_1 */
- case 0xd4: /* SDRC_RFR_CTRL_1 */
- case 0xd8: /* SDRC_MANUAL_1 */
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_sdrc_ops = {
- .read = omap_sdrc_read,
- .write = omap_sdrc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_sdrc_s *omap_sdrc_init(MemoryRegion *sysmem,
- hwaddr base)
-{
- struct omap_sdrc_s *s = g_new0(struct omap_sdrc_s, 1);
-
- omap_sdrc_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_sdrc_ops, s, "omap.sdrc", 0x1000);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-
- return s;
-}
diff --git a/hw/misc/omap_tap.c b/hw/misc/omap_tap.c
deleted file mode 100644
index 4d7fb7d..0000000
--- a/hw/misc/omap_tap.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * TI OMAP TEST-Chip-level TAP emulation.
- *
- * Copyright (C) 2007-2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/hw.h"
-#include "hw/arm/omap.h"
-
-/* TEST-Chip-level TAP */
-static uint64_t omap_tap_read(void *opaque, hwaddr addr, unsigned size)
-{
- struct omap_mpu_state_s *s = opaque;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x204: /* IDCODE_reg */
- switch (s->mpu_model) {
- case omap2420:
- case omap2422:
- case omap2423:
- return 0x5b5d902f; /* ES 2.2 */
- case omap2430:
- return 0x5b68a02f; /* ES 2.2 */
- case omap3430:
- return 0x1b7ae02f; /* ES 2 */
- default:
- hw_error("%s: Bad mpu model\n", __func__);
- }
-
- case 0x208: /* PRODUCTION_ID_reg for OMAP2 */
- case 0x210: /* PRODUCTION_ID_reg for OMAP3 */
- switch (s->mpu_model) {
- case omap2420:
- return 0x000254f0; /* POP ESHS2.1.1 in N91/93/95, ES2 in N800 */
- case omap2422:
- return 0x000400f0;
- case omap2423:
- return 0x000800f0;
- case omap2430:
- return 0x000000f0;
- case omap3430:
- return 0x000000f0;
- default:
- hw_error("%s: Bad mpu model\n", __func__);
- }
-
- case 0x20c:
- switch (s->mpu_model) {
- case omap2420:
- case omap2422:
- case omap2423:
- return 0xcafeb5d9; /* ES 2.2 */
- case omap2430:
- return 0xcafeb68a; /* ES 2.2 */
- case omap3430:
- return 0xcafeb7ae; /* ES 2 */
- default:
- hw_error("%s: Bad mpu model\n", __func__);
- }
-
- case 0x218: /* DIE_ID_reg */
- return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
- case 0x21c: /* DIE_ID_reg */
- return 0x54 << 24;
- case 0x220: /* DIE_ID_reg */
- return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
- case 0x224: /* DIE_ID_reg */
- return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_tap_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- OMAP_BAD_REG(addr);
-}
-
-static const MemoryRegionOps omap_tap_ops = {
- .read = omap_tap_read,
- .write = omap_tap_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-void omap_tap_init(struct omap_target_agent_s *ta,
- struct omap_mpu_state_s *mpu)
-{
- memory_region_init_io(&mpu->tap_iomem, NULL, &omap_tap_ops, mpu, "omap.tap",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &mpu->tap_iomem);
-}
diff --git a/hw/misc/pci-testdev.c b/hw/misc/pci-testdev.c
index acedd0f..0b5f236 100644
--- a/hw/misc/pci-testdev.c
+++ b/hw/misc/pci-testdev.c
@@ -337,7 +337,7 @@ static void pci_testdev_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_OTHERS;
dc->desc = "PCI Test Device";
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->reset = qdev_pci_testdev_reset;
+ device_class_set_legacy_reset(dc, qdev_pci_testdev_reset);
device_class_set_props(dc, pci_testdev_properties);
}
diff --git a/hw/misc/sifive_e_aon.c b/hw/misc/sifive_e_aon.c
index 4656457..f819fc1 100644
--- a/hw/misc/sifive_e_aon.c
+++ b/hw/misc/sifive_e_aon.c
@@ -299,7 +299,7 @@ static void sifive_e_aon_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
- dc->reset = sifive_e_aon_reset;
+ device_class_set_legacy_reset(dc, sifive_e_aon_reset);
device_class_set_props(dc, sifive_e_aon_properties);
}
diff --git a/hw/misc/sifive_u_prci.c b/hw/misc/sifive_u_prci.c
index 5d9d446..cafe6a6 100644
--- a/hw/misc/sifive_u_prci.c
+++ b/hw/misc/sifive_u_prci.c
@@ -151,7 +151,7 @@ static void sifive_u_prci_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = sifive_u_prci_realize;
- dc->reset = sifive_u_prci_reset;
+ device_class_set_legacy_reset(dc, sifive_u_prci_reset);
}
static const TypeInfo sifive_u_prci_info = {
diff --git a/hw/misc/slavio_misc.c b/hw/misc/slavio_misc.c
index 94369e4..c790594 100644
--- a/hw/misc/slavio_misc.c
+++ b/hw/misc/slavio_misc.c
@@ -487,7 +487,7 @@ static void slavio_misc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = slavio_misc_reset;
+ device_class_set_legacy_reset(dc, slavio_misc_reset);
dc->vmsd = &vmstate_misc;
}
diff --git a/hw/misc/stm32_rcc.c b/hw/misc/stm32_rcc.c
new file mode 100644
index 0000000..26672b5
--- /dev/null
+++ b/hw/misc/stm32_rcc.c
@@ -0,0 +1,162 @@
+/*
+ * STM32 RCC (only reset and enable registers are implemented)
+ *
+ * Copyright (c) 2024 RomƔn CƔrdenas <rcardenas.rod@gmail.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 "qemu/log.h"
+#include "trace.h"
+#include "hw/irq.h"
+#include "migration/vmstate.h"
+#include "hw/misc/stm32_rcc.h"
+
+static void stm32_rcc_reset(DeviceState *dev)
+{
+ STM32RccState *s = STM32_RCC(dev);
+
+ for (int i = 0; i < STM32_RCC_NREGS; i++) {
+ s->regs[i] = 0;
+ }
+}
+
+static uint64_t stm32_rcc_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ STM32RccState *s = STM32_RCC(opaque);
+
+ uint32_t value = 0;
+ if (addr > STM32_RCC_DCKCFGR2) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
+ __func__, addr);
+ } else {
+ value = s->regs[addr >> 2];
+ }
+ trace_stm32_rcc_read(addr, value);
+ return value;
+}
+
+static void stm32_rcc_write(void *opaque, hwaddr addr,
+ uint64_t val64, unsigned int size)
+{
+ STM32RccState *s = STM32_RCC(opaque);
+ uint32_t value = val64;
+ uint32_t prev_value, new_value, irq_offset;
+
+ trace_stm32_rcc_write(value, addr);
+
+ if (addr > STM32_RCC_DCKCFGR2) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"HWADDR_PRIx"\n",
+ __func__, addr);
+ return;
+ }
+
+ switch (addr) {
+ case STM32_RCC_AHB1_RSTR...STM32_RCC_APB2_RSTR:
+ prev_value = s->regs[addr / 4];
+ s->regs[addr / 4] = value;
+
+ irq_offset = ((addr - STM32_RCC_AHB1_RSTR) / 4) * 32;
+ for (int i = 0; i < 32; i++) {
+ new_value = extract32(value, i, 1);
+ if (extract32(prev_value, i, 1) && !new_value) {
+ trace_stm32_rcc_pulse_reset(irq_offset + i, new_value);
+ qemu_set_irq(s->reset_irq[irq_offset + i], new_value);
+ }
+ }
+ return;
+ case STM32_RCC_AHB1_ENR...STM32_RCC_APB2_ENR:
+ prev_value = s->regs[addr / 4];
+ s->regs[addr / 4] = value;
+
+ irq_offset = ((addr - STM32_RCC_AHB1_ENR) / 4) * 32;
+ for (int i = 0; i < 32; i++) {
+ new_value = extract32(value, i, 1);
+ if (!extract32(prev_value, i, 1) && new_value) {
+ trace_stm32_rcc_pulse_enable(irq_offset + i, new_value);
+ qemu_set_irq(s->enable_irq[irq_offset + i], new_value);
+ }
+ }
+ return;
+ default:
+ qemu_log_mask(
+ LOG_UNIMP,
+ "%s: The RCC peripheral only supports enable and reset in QEMU\n",
+ __func__
+ );
+ s->regs[addr >> 2] = value;
+ }
+}
+
+static const MemoryRegionOps stm32_rcc_ops = {
+ .read = stm32_rcc_read,
+ .write = stm32_rcc_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void stm32_rcc_init(Object *obj)
+{
+ STM32RccState *s = STM32_RCC(obj);
+
+ memory_region_init_io(&s->mmio, obj, &stm32_rcc_ops, s,
+ TYPE_STM32_RCC, STM32_RCC_PERIPHERAL_SIZE);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+
+ qdev_init_gpio_out(DEVICE(obj), s->reset_irq, STM32_RCC_NIRQS);
+ qdev_init_gpio_out(DEVICE(obj), s->enable_irq, STM32_RCC_NIRQS);
+
+ for (int i = 0; i < STM32_RCC_NIRQS; i++) {
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->reset_irq[i]);
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->enable_irq[i]);
+ }
+}
+
+static const VMStateDescription vmstate_stm32_rcc = {
+ .name = TYPE_STM32_RCC,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(regs, STM32RccState, STM32_RCC_NREGS),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void stm32_rcc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_stm32_rcc;
+ device_class_set_legacy_reset(dc, stm32_rcc_reset);
+}
+
+static const TypeInfo stm32_rcc_info = {
+ .name = TYPE_STM32_RCC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(STM32RccState),
+ .instance_init = stm32_rcc_init,
+ .class_init = stm32_rcc_class_init,
+};
+
+static void stm32_rcc_register_types(void)
+{
+ type_register_static(&stm32_rcc_info);
+}
+
+type_init(stm32_rcc_register_types)
diff --git a/hw/misc/stm32f2xx_syscfg.c b/hw/misc/stm32f2xx_syscfg.c
index 19c1e86..6c7b722 100644
--- a/hw/misc/stm32f2xx_syscfg.c
+++ b/hw/misc/stm32f2xx_syscfg.c
@@ -142,7 +142,7 @@ static void stm32f2xx_syscfg_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = stm32f2xx_syscfg_reset;
+ device_class_set_legacy_reset(dc, stm32f2xx_syscfg_reset);
}
static const TypeInfo stm32f2xx_syscfg_info = {
diff --git a/hw/misc/stm32f4xx_exti.c b/hw/misc/stm32f4xx_exti.c
index 7bd3afc..efd996d 100644
--- a/hw/misc/stm32f4xx_exti.c
+++ b/hw/misc/stm32f4xx_exti.c
@@ -168,7 +168,7 @@ static void stm32f4xx_exti_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = stm32f4xx_exti_reset;
+ device_class_set_legacy_reset(dc, stm32f4xx_exti_reset);
dc->vmsd = &vmstate_stm32f4xx_exti;
}
diff --git a/hw/misc/stm32f4xx_syscfg.c b/hw/misc/stm32f4xx_syscfg.c
index 854fce6..7d0f3eb 100644
--- a/hw/misc/stm32f4xx_syscfg.c
+++ b/hw/misc/stm32f4xx_syscfg.c
@@ -151,7 +151,7 @@ static void stm32f4xx_syscfg_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = stm32f4xx_syscfg_reset;
+ device_class_set_legacy_reset(dc, stm32f4xx_syscfg_reset);
dc->vmsd = &vmstate_stm32f4xx_syscfg;
}
diff --git a/hw/misc/stm32l4x5_rcc.c b/hw/misc/stm32l4x5_rcc.c
index 417bd5e..59d428f 100644
--- a/hw/misc/stm32l4x5_rcc.c
+++ b/hw/misc/stm32l4x5_rcc.c
@@ -543,19 +543,31 @@ static void rcc_update_cfgr_register(Stm32l4x5RccState *s)
uint32_t val;
/* MCOPRE */
val = FIELD_EX32(s->cfgr, CFGR, MCOPRE);
- assert(val <= 0b100);
- clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_MCO],
- 1, 1 << val);
+ if (val > 0b100) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Invalid MCOPRE value: 0x%"PRIx32"\n",
+ __func__, val);
+ clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_MCO], false);
+ } else {
+ clock_mux_set_factor(&s->clock_muxes[RCC_CLOCK_MUX_MCO],
+ 1, 1 << val);
+ }
/* MCOSEL */
val = FIELD_EX32(s->cfgr, CFGR, MCOSEL);
- assert(val <= 0b111);
- if (val == 0) {
+ if (val > 0b111) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Invalid MCOSEL value: 0x%"PRIx32"\n",
+ __func__, val);
clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_MCO], false);
} else {
- clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_MCO], true);
- clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_MCO],
- val - 1);
+ if (val == 0) {
+ clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_MCO], false);
+ } else {
+ clock_mux_set_enable(&s->clock_muxes[RCC_CLOCK_MUX_MCO], true);
+ clock_mux_set_source(&s->clock_muxes[RCC_CLOCK_MUX_MCO],
+ val - 1);
+ }
}
/* STOPWUCK */
diff --git a/hw/misc/stm32l4x5_syscfg.c b/hw/misc/stm32l4x5_syscfg.c
index a5a1ce2..a947a9e 100644
--- a/hw/misc/stm32l4x5_syscfg.c
+++ b/hw/misc/stm32l4x5_syscfg.c
@@ -26,6 +26,9 @@
#include "trace.h"
#include "hw/irq.h"
#include "migration/vmstate.h"
+#include "hw/clock.h"
+#include "hw/qdev-clock.h"
+#include "qapi/error.h"
#include "hw/misc/stm32l4x5_syscfg.h"
#include "hw/gpio/stm32l4x5_gpio.h"
@@ -225,12 +228,22 @@ static void stm32l4x5_syscfg_init(Object *obj)
qdev_init_gpio_in(DEVICE(obj), stm32l4x5_syscfg_set_irq,
GPIO_NUM_PINS * NUM_GPIOS);
qdev_init_gpio_out(DEVICE(obj), s->gpio_out, GPIO_NUM_PINS);
+ s->clk = qdev_init_clock_in(DEVICE(s), "clk", NULL, s, 0);
+}
+
+static void stm32l4x5_syscfg_realize(DeviceState *dev, Error **errp)
+{
+ Stm32l4x5SyscfgState *s = STM32L4X5_SYSCFG(dev);
+ if (!clock_has_source(s->clk)) {
+ error_setg(errp, "SYSCFG: clk input must be connected");
+ return;
+ }
}
static const VMStateDescription vmstate_stm32l4x5_syscfg = {
.name = TYPE_STM32L4X5_SYSCFG,
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (VMStateField[]) {
VMSTATE_UINT32(memrmp, Stm32l4x5SyscfgState),
VMSTATE_UINT32(cfgr1, Stm32l4x5SyscfgState),
@@ -241,6 +254,7 @@ static const VMStateDescription vmstate_stm32l4x5_syscfg = {
VMSTATE_UINT32(swpr, Stm32l4x5SyscfgState),
VMSTATE_UINT32(skr, Stm32l4x5SyscfgState),
VMSTATE_UINT32(swpr2, Stm32l4x5SyscfgState),
+ VMSTATE_CLOCK(clk, Stm32l4x5SyscfgState),
VMSTATE_END_OF_LIST()
}
};
@@ -251,6 +265,7 @@ static void stm32l4x5_syscfg_class_init(ObjectClass *klass, void *data)
ResettableClass *rc = RESETTABLE_CLASS(klass);
dc->vmsd = &vmstate_stm32l4x5_syscfg;
+ dc->realize = stm32l4x5_syscfg_realize;
rc->phases.hold = stm32l4x5_syscfg_hold_reset;
}
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index 1be0717..b9fbcb0 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -156,6 +156,12 @@ npcm7xx_pwm_write(const char *id, uint64_t offset, uint32_t value) "%s offset: 0
npcm7xx_pwm_update_freq(const char *id, uint8_t index, uint32_t old_value, uint32_t new_value) "%s pwm[%u] Update Freq: old_freq: %u, new_freq: %u"
npcm7xx_pwm_update_duty(const char *id, uint8_t index, uint32_t old_value, uint32_t new_value) "%s pwm[%u] Update Duty: old_duty: %u, new_duty: %u"
+# stm32_rcc.c
+stm32_rcc_read(uint64_t addr, uint64_t data) "reg read: addr: 0x%" PRIx64 " val: 0x%" PRIx64 ""
+stm32_rcc_write(uint64_t addr, uint64_t data) "reg write: addr: 0x%" PRIx64 " val: 0x%" PRIx64 ""
+stm32_rcc_pulse_enable(int line, int level) "Enable: %d to %d"
+stm32_rcc_pulse_reset(int line, int level) "Reset: %d to %d"
+
# stm32f4xx_syscfg.c
stm32f4xx_syscfg_set_irq(int gpio, int line, int level) "Interrupt: GPIO: %d, Line: %d; Level: %d"
stm32f4xx_pulse_exti(int irq) "Pulse EXTI: %d"
diff --git a/hw/misc/tz-mpc.c b/hw/misc/tz-mpc.c
index 92b9949..66a46a7 100644
--- a/hw/misc/tz-mpc.c
+++ b/hw/misc/tz-mpc.c
@@ -599,7 +599,7 @@ static void tz_mpc_class_init(ObjectClass *klass, void *data)
dc->realize = tz_mpc_realize;
dc->vmsd = &tz_mpc_vmstate;
- dc->reset = tz_mpc_reset;
+ device_class_set_legacy_reset(dc, tz_mpc_reset);
device_class_set_props(dc, tz_mpc_properties);
}
diff --git a/hw/misc/tz-msc.c b/hw/misc/tz-msc.c
index de5a312..82ccaa0 100644
--- a/hw/misc/tz-msc.c
+++ b/hw/misc/tz-msc.c
@@ -292,7 +292,7 @@ static void tz_msc_class_init(ObjectClass *klass, void *data)
dc->realize = tz_msc_realize;
dc->vmsd = &tz_msc_vmstate;
- dc->reset = tz_msc_reset;
+ device_class_set_legacy_reset(dc, tz_msc_reset);
device_class_set_props(dc, tz_msc_properties);
}
diff --git a/hw/misc/tz-ppc.c b/hw/misc/tz-ppc.c
index 6450778..922dcf7 100644
--- a/hw/misc/tz-ppc.c
+++ b/hw/misc/tz-ppc.c
@@ -332,7 +332,7 @@ static void tz_ppc_class_init(ObjectClass *klass, void *data)
dc->realize = tz_ppc_realize;
dc->vmsd = &tz_ppc_vmstate;
- dc->reset = tz_ppc_reset;
+ device_class_set_legacy_reset(dc, tz_ppc_reset);
device_class_set_props(dc, tz_ppc_properties);
}
diff --git a/hw/misc/virt_ctrl.c b/hw/misc/virt_ctrl.c
index 1a6c744..aa00d6c 100644
--- a/hw/misc/virt_ctrl.c
+++ b/hw/misc/virt_ctrl.c
@@ -129,7 +129,7 @@ static void virt_ctrl_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
- dc->reset = virt_ctrl_reset;
+ device_class_set_legacy_reset(dc, virt_ctrl_reset);
dc->realize = virt_ctrl_realize;
dc->vmsd = &vmstate_virt_ctrl;
}
diff --git a/hw/misc/xlnx-versal-cfu.c b/hw/misc/xlnx-versal-cfu.c
index 6bb82e5..94f8581 100644
--- a/hw/misc/xlnx-versal-cfu.c
+++ b/hw/misc/xlnx-versal-cfu.c
@@ -397,6 +397,13 @@ static void cfu_fdro_init(Object *obj)
fifo32_create(&s->fdro_data, 8 * KiB / sizeof(uint32_t));
}
+static void cfu_fdro_finalize(Object *obj)
+{
+ XlnxVersalCFUFDRO *s = XLNX_VERSAL_CFU_FDRO(obj);
+
+ fifo32_destroy(&s->fdro_data);
+}
+
static void cfu_fdro_reset_enter(Object *obj, ResetType type)
{
XlnxVersalCFUFDRO *s = XLNX_VERSAL_CFU_FDRO(obj);
@@ -495,7 +502,7 @@ static void cfu_apb_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = cfu_apb_reset;
+ device_class_set_legacy_reset(dc, cfu_apb_reset);
dc->vmsd = &vmstate_cfu_apb;
device_class_set_props(dc, cfu_props);
}
@@ -539,6 +546,7 @@ static const TypeInfo cfu_fdro_info = {
.instance_size = sizeof(XlnxVersalCFUFDRO),
.class_init = cfu_fdro_class_init,
.instance_init = cfu_fdro_init,
+ .instance_finalize = cfu_fdro_finalize,
.interfaces = (InterfaceInfo[]) {
{ TYPE_XLNX_CFI_IF },
{ }
diff --git a/hw/misc/xlnx-versal-trng.c b/hw/misc/xlnx-versal-trng.c
index 51eb760..8690547 100644
--- a/hw/misc/xlnx-versal-trng.c
+++ b/hw/misc/xlnx-versal-trng.c
@@ -608,9 +608,8 @@ static void trng_init(Object *obj)
{
XlnxVersalTRng *s = XLNX_VERSAL_TRNG(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- RegisterInfoArray *reg_array;
- reg_array =
+ s->reg_array =
register_init_block32(DEVICE(obj), trng_regs_info,
ARRAY_SIZE(trng_regs_info),
s->regs_info, s->regs,
@@ -618,16 +617,17 @@ static void trng_init(Object *obj)
XLNX_VERSAL_TRNG_ERR_DEBUG,
R_MAX * 4);
- sysbus_init_mmio(sbd, &reg_array->mem);
+ sysbus_init_mmio(sbd, &s->reg_array->mem);
sysbus_init_irq(sbd, &s->irq);
s->prng = g_rand_new();
}
-static void trng_unrealize(DeviceState *dev)
+static void trng_finalize(Object *obj)
{
- XlnxVersalTRng *s = XLNX_VERSAL_TRNG(dev);
+ XlnxVersalTRng *s = XLNX_VERSAL_TRNG(obj);
+ register_finalize_block(s->reg_array);
g_rand_free(s->prng);
s->prng = NULL;
}
@@ -689,7 +689,6 @@ static void trng_class_init(ObjectClass *klass, void *data)
ResettableClass *rc = RESETTABLE_CLASS(klass);
dc->vmsd = &vmstate_trng;
- dc->unrealize = trng_unrealize;
rc->phases.hold = trng_reset_hold;
/* Clone uint64 property with set allowed after realized */
@@ -706,6 +705,7 @@ static const TypeInfo trng_info = {
.instance_size = sizeof(XlnxVersalTRng),
.class_init = trng_class_init,
.instance_init = trng_init,
+ .instance_finalize = trng_finalize,
};
static void trng_register_types(void)
diff --git a/hw/net/allwinner-sun8i-emac.c b/hw/net/allwinner-sun8i-emac.c
index 108ae9c..cdae74f 100644
--- a/hw/net/allwinner-sun8i-emac.c
+++ b/hw/net/allwinner-sun8i-emac.c
@@ -881,7 +881,7 @@ static void allwinner_sun8i_emac_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = allwinner_sun8i_emac_realize;
- dc->reset = allwinner_sun8i_emac_reset;
+ device_class_set_legacy_reset(dc, allwinner_sun8i_emac_reset);
dc->vmsd = &vmstate_aw_emac;
device_class_set_props(dc, allwinner_sun8i_emac_properties);
}
diff --git a/hw/net/allwinner_emac.c b/hw/net/allwinner_emac.c
index 9898397..c104c25 100644
--- a/hw/net/allwinner_emac.c
+++ b/hw/net/allwinner_emac.c
@@ -349,7 +349,7 @@ static void aw_emac_write(void *opaque, hwaddr offset, uint64_t value,
"allwinner_emac: TX length > fifo data length\n");
}
if (len > 0) {
- data = fifo8_pop_buf(fifo, len, &ret);
+ data = fifo8_pop_bufptr(fifo, len, &ret);
qemu_send_packet(nc, data, ret);
aw_emac_tx_reset(s, chan);
/* Raise TX interrupt */
@@ -521,7 +521,7 @@ static void aw_emac_class_init(ObjectClass *klass, void *data)
dc->realize = aw_emac_realize;
device_class_set_props(dc, aw_emac_properties);
- dc->reset = aw_emac_reset;
+ device_class_set_legacy_reset(dc, aw_emac_reset);
dc->vmsd = &vmstate_aw_emac;
}
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index ec7bf56..5267398 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -23,7 +23,7 @@
*/
#include "qemu/osdep.h"
-#include <zlib.h> /* For crc32 */
+#include <zlib.h> /* for crc32 */
#include "hw/irq.h"
#include "hw/net/cadence_gem.h"
@@ -1809,7 +1809,7 @@ static void gem_class_init(ObjectClass *klass, void *data)
dc->realize = gem_realize;
device_class_set_props(dc, gem_properties);
dc->vmsd = &vmstate_cadence_gem;
- dc->reset = gem_reset;
+ device_class_set_legacy_reset(dc, gem_reset);
}
static const TypeInfo gem_info = {
diff --git a/hw/net/can/can_kvaser_pci.c b/hw/net/can/can_kvaser_pci.c
index bf41e6b..38434d3 100644
--- a/hw/net/can/can_kvaser_pci.c
+++ b/hw/net/can/can_kvaser_pci.c
@@ -299,7 +299,7 @@ static void kvaser_pci_class_init(ObjectClass *klass, void *data)
k->class_id = 0x00ff00;
dc->desc = "Kvaser PCICANx";
dc->vmsd = &vmstate_kvaser_pci;
- dc->reset = kvaser_pci_reset;
+ device_class_set_legacy_reset(dc, kvaser_pci_reset);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
diff --git a/hw/net/can/can_mioe3680_pci.c b/hw/net/can/can_mioe3680_pci.c
index 308b17e..21659b7 100644
--- a/hw/net/can/can_mioe3680_pci.c
+++ b/hw/net/can/can_mioe3680_pci.c
@@ -243,7 +243,7 @@ static void mioe3680_pci_class_init(ObjectClass *klass, void *data)
dc->desc = "Mioe3680 PCICANx";
dc->vmsd = &vmstate_mioe3680_pci;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->reset = mioe3680_pci_reset;
+ device_class_set_legacy_reset(dc, mioe3680_pci_reset);
}
static const TypeInfo mioe3680_pci_info = {
diff --git a/hw/net/can/can_pcm3680_pci.c b/hw/net/can/can_pcm3680_pci.c
index e4c8d93..af21dc6 100644
--- a/hw/net/can/can_pcm3680_pci.c
+++ b/hw/net/can/can_pcm3680_pci.c
@@ -244,7 +244,7 @@ static void pcm3680i_pci_class_init(ObjectClass *klass, void *data)
dc->desc = "Pcm3680i PCICANx";
dc->vmsd = &vmstate_pcm3680i_pci;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->reset = pcm3680i_pci_reset;
+ device_class_set_legacy_reset(dc, pcm3680i_pci_reset);
}
static const TypeInfo pcm3680i_pci_info = {
diff --git a/hw/net/can/ctucan_pci.c b/hw/net/can/ctucan_pci.c
index d8f7344d..65f1f82 100644
--- a/hw/net/can/ctucan_pci.c
+++ b/hw/net/can/ctucan_pci.c
@@ -257,7 +257,7 @@ static void ctucan_pci_class_init(ObjectClass *klass, void *data)
dc->desc = "CTU CAN PCI";
dc->vmsd = &vmstate_ctucan_pci;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->reset = ctucan_pci_reset;
+ device_class_set_legacy_reset(dc, ctucan_pci_reset);
}
static const TypeInfo ctucan_pci_info = {
diff --git a/hw/net/can/xlnx-versal-canfd.c b/hw/net/can/xlnx-versal-canfd.c
index 5f083c2..e148bd7 100644
--- a/hw/net/can/xlnx-versal-canfd.c
+++ b/hw/net/can/xlnx-versal-canfd.c
@@ -678,12 +678,10 @@ REG32(RB_DW15_REGISTER_1, 0x4144)
FIELD(RB_DW15_REGISTER_1, DATA_BYTES62, 8, 8)
FIELD(RB_DW15_REGISTER_1, DATA_BYTES63, 0, 8)
-static uint8_t canfd_dlc_array[8] = {8, 12, 16, 20, 24, 32, 48, 64};
-
static void canfd_update_irq(XlnxVersalCANFDState *s)
{
- unsigned int irq = s->regs[R_INTERRUPT_STATUS_REGISTER] &
- s->regs[R_INTERRUPT_ENABLE_REGISTER];
+ const bool irq = (s->regs[R_INTERRUPT_STATUS_REGISTER] &
+ s->regs[R_INTERRUPT_ENABLE_REGISTER]) != 0;
g_autofree char *path = object_get_canonical_path(OBJECT(s));
/* RX watermark interrupts. */
@@ -869,6 +867,10 @@ static void regs2frame(XlnxVersalCANFDState *s, qemu_can_frame *frame,
uint32_t val = 0;
uint32_t dlc_reg_val = 0;
uint32_t dlc_value = 0;
+ uint32_t id_reg_val = 0;
+ bool is_rtr = false;
+
+ frame->flags = 0;
/* Check that reg_num should be within TX register space. */
assert(reg_num <= R_TB_ID_REGISTER + (NUM_REGS_PER_MSG_SPACE *
@@ -877,56 +879,37 @@ static void regs2frame(XlnxVersalCANFDState *s, qemu_can_frame *frame,
dlc_reg_val = s->regs[reg_num + 1];
dlc_value = FIELD_EX32(dlc_reg_val, TB0_DLC_REGISTER, DLC);
- frame->can_id = s->regs[reg_num];
+ id_reg_val = s->regs[reg_num];
+ if (FIELD_EX32(id_reg_val, TB_ID_REGISTER, IDE)) {
+ frame->can_id = (FIELD_EX32(id_reg_val, TB_ID_REGISTER, ID) << 18) |
+ (FIELD_EX32(id_reg_val, TB_ID_REGISTER, ID_EXT)) |
+ QEMU_CAN_EFF_FLAG;
+ if (FIELD_EX32(id_reg_val, TB_ID_REGISTER, RTR_RRS)) {
+ is_rtr = true;
+ }
+ } else {
+ frame->can_id = FIELD_EX32(id_reg_val, TB_ID_REGISTER, ID);
+ if (FIELD_EX32(id_reg_val, TB_ID_REGISTER, SRR_RTR_RRS)) {
+ is_rtr = true;
+ }
+ }
if (FIELD_EX32(dlc_reg_val, TB0_DLC_REGISTER, FDF)) {
- /*
- * CANFD frame.
- * Converting dlc(0 to 15) 4 Byte data to plain length(i.e. 0 to 64)
- * 1 Byte data. This is done to make it work with SocketCAN.
- * On actual CANFD frame, this value can't be more than 0xF.
- * Conversion table for DLC to plain length:
- *
- * DLC Plain Length
- * 0 - 8 0 - 8
- * 9 9 - 12
- * 10 13 - 16
- * 11 17 - 20
- * 12 21 - 24
- * 13 25 - 32
- * 14 33 - 48
- * 15 49 - 64
- */
-
- frame->flags = QEMU_CAN_FRMF_TYPE_FD;
+ frame->flags |= QEMU_CAN_FRMF_TYPE_FD;
- if (dlc_value < 8) {
- frame->can_dlc = dlc_value;
- } else {
- assert((dlc_value - 8) < ARRAY_SIZE(canfd_dlc_array));
- frame->can_dlc = canfd_dlc_array[dlc_value - 8];
+ if (FIELD_EX32(dlc_reg_val, TB0_DLC_REGISTER, BRS)) {
+ frame->flags |= QEMU_CAN_FRMF_BRS;
}
} else {
- /*
- * FD Format bit not set that means it is a CAN Frame.
- * Conversion table for classic CAN:
- *
- * DLC Plain Length
- * 0 - 7 0 - 7
- * 8 - 15 8
- */
-
- if (dlc_value > 8) {
- frame->can_dlc = 8;
- qemu_log_mask(LOG_GUEST_ERROR, "Maximum DLC value for Classic CAN"
- " frame is 8. Only 8 byte data will be sent.\n");
- } else {
- frame->can_dlc = dlc_value;
+ if (is_rtr) {
+ frame->can_id |= QEMU_CAN_RTR_FLAG;
}
}
+ frame->can_dlc = can_dlc2len(dlc_value);
+
for (j = 0; j < frame->can_dlc; j++) {
- val = 8 * i;
+ val = 8 * (3 - i);
frame->data[j] = extract32(s->regs[reg_num + 2 + (j / 4)], val, 8);
i++;
@@ -948,6 +931,33 @@ static void process_cancellation_requests(XlnxVersalCANFDState *s)
canfd_update_irq(s);
}
+static uint32_t frame_to_reg_id(const qemu_can_frame *frame)
+{
+ uint32_t id_reg_val = 0;
+ const bool is_canfd_frame = frame->flags & QEMU_CAN_FRMF_TYPE_FD;
+ const bool is_rtr = !is_canfd_frame && (frame->can_id & QEMU_CAN_RTR_FLAG);
+
+ if (frame->can_id & QEMU_CAN_EFF_FLAG) {
+ id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, ID,
+ (frame->can_id & QEMU_CAN_EFF_MASK) >> 18);
+ id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, ID_EXT,
+ frame->can_id & QEMU_CAN_EFF_MASK);
+ id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, IDE, 1);
+ id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, SRR_RTR_RRS, 1);
+ if (is_rtr) {
+ id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, RTR_RRS, 1);
+ }
+ } else {
+ id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, ID,
+ frame->can_id & QEMU_CAN_SFF_MASK);
+ if (is_rtr) {
+ id_reg_val |= FIELD_DP32(0, RB_ID_REGISTER, SRR_RTR_RRS, 1);
+ }
+ }
+
+ return id_reg_val;
+}
+
static void store_rx_sequential(XlnxVersalCANFDState *s,
const qemu_can_frame *frame,
uint32_t fill_level, uint32_t read_index,
@@ -955,7 +965,6 @@ static void store_rx_sequential(XlnxVersalCANFDState *s,
bool rx_fifo_id, uint8_t filter_index)
{
int i;
- bool is_canfd_frame;
uint8_t dlc = frame->can_dlc;
uint8_t rx_reg_num = 0;
uint32_t dlc_reg_val = 0;
@@ -999,30 +1008,21 @@ static void store_rx_sequential(XlnxVersalCANFDState *s,
NUM_REGS_PER_MSG_SPACE));
}
- s->regs[store_location] = frame->can_id;
+ s->regs[store_location] = frame_to_reg_id(frame);
- dlc = frame->can_dlc;
+ dlc_reg_val = FIELD_DP32(0, RB_DLC_REGISTER, DLC, can_len2dlc(dlc));
- if (frame->flags == QEMU_CAN_FRMF_TYPE_FD) {
- is_canfd_frame = true;
+ if (frame->flags & QEMU_CAN_FRMF_TYPE_FD) {
+ dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, FDF, 1);
- /* Store dlc value in Xilinx specific format. */
- for (i = 0; i < ARRAY_SIZE(canfd_dlc_array); i++) {
- if (canfd_dlc_array[i] == frame->can_dlc) {
- dlc_reg_val = FIELD_DP32(0, RB_DLC_REGISTER, DLC, 8 + i);
- }
+ if (frame->flags & QEMU_CAN_FRMF_BRS) {
+ dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, BRS, 1);
}
- } else {
- is_canfd_frame = false;
-
- if (frame->can_dlc > 8) {
- dlc = 8;
+ if (frame->flags & QEMU_CAN_FRMF_ESI) {
+ dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, ESI, 1);
}
-
- dlc_reg_val = FIELD_DP32(0, RB_DLC_REGISTER, DLC, dlc);
}
- dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, FDF, is_canfd_frame);
dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, TIMESTAMP, rx_timestamp);
dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, MATCHED_FILTER_INDEX,
filter_index);
@@ -1034,19 +1034,19 @@ static void store_rx_sequential(XlnxVersalCANFDState *s,
case 0:
rx_reg_num = i / 4;
- data_reg_val = FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES3,
+ data_reg_val = FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES0,
frame->data[i]);
break;
case 1:
- data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES2,
+ data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES1,
frame->data[i]);
break;
case 2:
- data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES1,
+ data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES2,
frame->data[i]);
break;
case 3:
- data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES0,
+ data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES3,
frame->data[i]);
/*
* Last Bytes data which means we have all 4 bytes ready to
@@ -1090,11 +1090,12 @@ static void update_rx_sequential(XlnxVersalCANFDState *s,
if (s->regs[R_ACCEPTANCE_FILTER_CONTROL_REGISTER]) {
uint32_t acceptance_filter_status =
s->regs[R_ACCEPTANCE_FILTER_CONTROL_REGISTER];
+ const uint32_t reg_id = frame_to_reg_id(frame);
for (i = 0; i < 32; i++) {
if (acceptance_filter_status & 0x1) {
uint32_t msg_id_masked = s->regs[R_AFMR_REGISTER + 2 * i] &
- frame->can_id;
+ reg_id;
uint32_t afir_id_masked = s->regs[R_AFIR_REGISTER + 2 * i] &
s->regs[R_AFMR_REGISTER + 2 * i];
uint16_t std_msg_id_masked = FIELD_EX32(msg_id_masked,
@@ -1143,18 +1144,8 @@ static void update_rx_sequential(XlnxVersalCANFDState *s,
read_index = ARRAY_FIELD_EX32(s->regs, RX_FIFO_STATUS_REGISTER, RI);
store_index = read_index + fill_level;
- if (read_index == s->cfg.rx0_fifo - 1) {
- /*
- * When ri is s->cfg.rx0_fifo - 1 i.e. max, it goes cyclic that
- * means we reset the ri to 0x0.
- */
- read_index = 0;
- ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, RI,
- read_index);
- }
-
if (store_index > s->cfg.rx0_fifo - 1) {
- store_index -= s->cfg.rx0_fifo - 1;
+ store_index -= s->cfg.rx0_fifo;
}
store_location = R_RB_ID_REGISTER +
@@ -1171,18 +1162,8 @@ static void update_rx_sequential(XlnxVersalCANFDState *s,
RI_1);
store_index = read_index + fill_level;
- if (read_index == s->cfg.rx1_fifo - 1) {
- /*
- * When ri is s->cfg.rx1_fifo - 1 i.e. max, it goes cyclic that
- * means we reset the ri to 0x0.
- */
- read_index = 0;
- ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, RI_1,
- read_index);
- }
-
if (store_index > s->cfg.rx1_fifo - 1) {
- store_index -= s->cfg.rx1_fifo - 1;
+ store_index -= s->cfg.rx1_fifo;
}
store_location = R_RB_ID_REGISTER_1 +
@@ -1264,18 +1245,8 @@ static void tx_fifo_stamp(XlnxVersalCANFDState *s, uint32_t tb0_regid)
" Discarding the message\n");
ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, TXEOFLW, 1);
} else {
- if (read_index == s->cfg.tx_fifo - 1) {
- /*
- * When ri is s->cfg.tx_fifo - 1 i.e. max, it goes cyclic that
- * means we reset the ri to 0x0.
- */
- read_index = 0;
- ARRAY_FIELD_DP32(s->regs, TX_EVENT_FIFO_STATUS_REGISTER, TXE_RI,
- read_index);
- }
-
if (store_index > s->cfg.tx_fifo - 1) {
- store_index -= s->cfg.tx_fifo - 1;
+ store_index -= s->cfg.tx_fifo;
}
assert(store_index < s->cfg.tx_fifo);
@@ -2088,7 +2059,7 @@ static void canfd_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = canfd_reset;
+ device_class_set_legacy_reset(dc, canfd_reset);
dc->realize = canfd_realize;
device_class_set_props(dc, canfd_core_properties);
dc->vmsd = &vmstate_canfd;
diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c
index bf0652d..c097730 100644
--- a/hw/net/dp8393x.c
+++ b/hw/net/dp8393x.c
@@ -27,7 +27,7 @@
#include "qapi/error.h"
#include "qemu/module.h"
#include "qemu/timer.h"
-#include <zlib.h>
+#include <zlib.h> /* for crc32 */
#include "qom/object.h"
#include "trace.h"
@@ -946,7 +946,7 @@ static void dp8393x_class_init(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->realize = dp8393x_realize;
- dc->reset = dp8393x_reset;
+ device_class_set_legacy_reset(dc, dp8393x_reset);
dc->vmsd = &vmstate_dp8393x;
device_class_set_props(dc, dp8393x_properties);
}
diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c
index 3ae2a18..2e4c50d 100644
--- a/hw/net/e1000e_core.c
+++ b/hw/net/e1000e_core.c
@@ -561,8 +561,7 @@ e1000e_rss_calc_hash(E1000ECore *core,
type = NetPktRssIpV6Ex;
break;
default:
- assert(false);
- return 0;
+ g_assert_not_reached();
}
return net_rx_pkt_calc_rss_hash(pkt, type, (uint8_t *) &core->mac[RSSRK]);
@@ -841,7 +840,6 @@ e1000e_ring_free_descr_num(E1000ECore *core, const E1000ERingInfo *r)
}
g_assert_not_reached();
- return 0;
}
static inline bool
diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c
index d9a70c4..c8a88b9 100644
--- a/hw/net/eepro100.c
+++ b/hw/net/eepro100.c
@@ -6,10 +6,12 @@
* Portions of the code are copies from grub / etherboot eepro100.c
* and linux e100.c.
*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
* 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) version 3 or any later version.
+ * (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
diff --git a/hw/net/etraxfs_eth.c b/hw/net/etraxfs_eth.c
deleted file mode 100644
index 5faf20c..0000000
--- a/hw/net/etraxfs_eth.c
+++ /dev/null
@@ -1,688 +0,0 @@
-/*
- * QEMU ETRAX Ethernet Controller.
- *
- * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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 "qapi/error.h"
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include "hw/cris/etraxfs.h"
-#include "qemu/error-report.h"
-#include "qemu/module.h"
-#include "trace.h"
-#include "qom/object.h"
-
-#define D(x)
-
-/* Advertisement control register. */
-#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
-#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
-#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
-#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
-
-/*
- * The MDIO extensions in the TDK PHY model were reversed engineered from the
- * linux driver (PHYID and Diagnostics reg).
- * TODO: Add friendly names for the register nums.
- */
-struct qemu_phy
-{
- uint32_t regs[32];
-
- int link;
-
- unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
- void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data);
-};
-
-static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
-{
- int regnum;
- unsigned r = 0;
-
- regnum = req & 0x1f;
-
- switch (regnum) {
- case 1:
- if (!phy->link) {
- break;
- }
- /* MR1. */
- /* Speeds and modes. */
- r |= (1 << 13) | (1 << 14);
- r |= (1 << 11) | (1 << 12);
- r |= (1 << 5); /* Autoneg complete. */
- r |= (1 << 3); /* Autoneg able. */
- r |= (1 << 2); /* link. */
- break;
- case 5:
- /* Link partner ability.
- We are kind; always agree with whatever best mode
- the guest advertises. */
- r = 1 << 14; /* Success. */
- /* Copy advertised modes. */
- r |= phy->regs[4] & (15 << 5);
- /* Autoneg support. */
- r |= 1;
- break;
- case 18:
- {
- /* Diagnostics reg. */
- int duplex = 0;
- int speed_100 = 0;
-
- if (!phy->link) {
- break;
- }
-
- /* Are we advertising 100 half or 100 duplex ? */
- speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
- speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
-
- /* Are we advertising 10 duplex or 100 duplex ? */
- duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
- duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
- r = (speed_100 << 10) | (duplex << 11);
- }
- break;
-
- default:
- r = phy->regs[regnum];
- break;
- }
- trace_mdio_phy_read(regnum, r);
- return r;
-}
-
-static void
-tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
-{
- int regnum;
-
- regnum = req & 0x1f;
- trace_mdio_phy_write(regnum, data);
- switch (regnum) {
- default:
- phy->regs[regnum] = data;
- break;
- }
-}
-
-static void
-tdk_reset(struct qemu_phy *phy)
-{
- phy->regs[0] = 0x3100;
- /* PHY Id. */
- phy->regs[2] = 0x0300;
- phy->regs[3] = 0xe400;
- /* Autonegotiation advertisement reg. */
- phy->regs[4] = 0x01E1;
- phy->link = 1;
-}
-
-struct qemu_mdio
-{
- /* bus. */
- int mdc;
- int mdio;
-
- /* decoder. */
- enum {
- PREAMBLE,
- SOF,
- OPC,
- ADDR,
- REQ,
- TURNAROUND,
- DATA
- } state;
- unsigned int drive;
-
- unsigned int cnt;
- unsigned int addr;
- unsigned int opc;
- unsigned int req;
- unsigned int data;
-
- struct qemu_phy *devs[32];
-};
-
-static void
-mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
-{
- bus->devs[addr & 0x1f] = phy;
-}
-
-#ifdef USE_THIS_DEAD_CODE
-static void
-mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
-{
- bus->devs[addr & 0x1f] = NULL;
-}
-#endif
-
-static void mdio_read_req(struct qemu_mdio *bus)
-{
- struct qemu_phy *phy;
-
- phy = bus->devs[bus->addr];
- if (phy && phy->read) {
- bus->data = phy->read(phy, bus->req);
- } else {
- bus->data = 0xffff;
- }
-}
-
-static void mdio_write_req(struct qemu_mdio *bus)
-{
- struct qemu_phy *phy;
-
- phy = bus->devs[bus->addr];
- if (phy && phy->write) {
- phy->write(phy, bus->req, bus->data);
- }
-}
-
-static void mdio_cycle(struct qemu_mdio *bus)
-{
- bus->cnt++;
-
- trace_mdio_bitbang(bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive);
-#if 0
- if (bus->mdc) {
- printf("%d", bus->mdio);
- }
-#endif
- switch (bus->state) {
- case PREAMBLE:
- if (bus->mdc) {
- if (bus->cnt >= (32 * 2) && !bus->mdio) {
- bus->cnt = 0;
- bus->state = SOF;
- bus->data = 0;
- }
- }
- break;
- case SOF:
- if (bus->mdc) {
- if (bus->mdio != 1) {
- printf("WARNING: no SOF\n");
- }
- if (bus->cnt == 1*2) {
- bus->cnt = 0;
- bus->opc = 0;
- bus->state = OPC;
- }
- }
- break;
- case OPC:
- if (bus->mdc) {
- bus->opc <<= 1;
- bus->opc |= bus->mdio & 1;
- if (bus->cnt == 2*2) {
- bus->cnt = 0;
- bus->addr = 0;
- bus->state = ADDR;
- }
- }
- break;
- case ADDR:
- if (bus->mdc) {
- bus->addr <<= 1;
- bus->addr |= bus->mdio & 1;
-
- if (bus->cnt == 5*2) {
- bus->cnt = 0;
- bus->req = 0;
- bus->state = REQ;
- }
- }
- break;
- case REQ:
- if (bus->mdc) {
- bus->req <<= 1;
- bus->req |= bus->mdio & 1;
- if (bus->cnt == 5*2) {
- bus->cnt = 0;
- bus->state = TURNAROUND;
- }
- }
- break;
- case TURNAROUND:
- if (bus->mdc && bus->cnt == 2*2) {
- bus->mdio = 0;
- bus->cnt = 0;
-
- if (bus->opc == 2) {
- bus->drive = 1;
- mdio_read_req(bus);
- bus->mdio = bus->data & 1;
- }
- bus->state = DATA;
- }
- break;
- case DATA:
- if (!bus->mdc) {
- if (bus->drive) {
- bus->mdio = !!(bus->data & (1 << 15));
- bus->data <<= 1;
- }
- } else {
- if (!bus->drive) {
- bus->data <<= 1;
- bus->data |= bus->mdio;
- }
- if (bus->cnt == 16 * 2) {
- bus->cnt = 0;
- bus->state = PREAMBLE;
- if (!bus->drive) {
- mdio_write_req(bus);
- }
- bus->drive = 0;
- }
- }
- break;
- default:
- break;
- }
-}
-
-/* ETRAX-FS Ethernet MAC block starts here. */
-
-#define RW_MA0_LO 0x00
-#define RW_MA0_HI 0x01
-#define RW_MA1_LO 0x02
-#define RW_MA1_HI 0x03
-#define RW_GA_LO 0x04
-#define RW_GA_HI 0x05
-#define RW_GEN_CTRL 0x06
-#define RW_REC_CTRL 0x07
-#define RW_TR_CTRL 0x08
-#define RW_CLR_ERR 0x09
-#define RW_MGM_CTRL 0x0a
-#define R_STAT 0x0b
-#define FS_ETH_MAX_REGS 0x17
-
-#define TYPE_ETRAX_FS_ETH "etraxfs-eth"
-OBJECT_DECLARE_SIMPLE_TYPE(ETRAXFSEthState, ETRAX_FS_ETH)
-
-struct ETRAXFSEthState {
- SysBusDevice parent_obj;
-
- MemoryRegion mmio;
- NICState *nic;
- NICConf conf;
-
- /* Two addrs in the filter. */
- uint8_t macaddr[2][6];
- uint32_t regs[FS_ETH_MAX_REGS];
-
- struct etraxfs_dma_client *dma_out;
- struct etraxfs_dma_client *dma_in;
-
- /* MDIO bus. */
- struct qemu_mdio mdio_bus;
- unsigned int phyaddr;
- int duplex_mismatch;
-
- /* PHY. */
- struct qemu_phy phy;
-};
-
-static void eth_validate_duplex(ETRAXFSEthState *eth)
-{
- struct qemu_phy *phy;
- unsigned int phy_duplex;
- unsigned int mac_duplex;
- int new_mm = 0;
-
- phy = eth->mdio_bus.devs[eth->phyaddr];
- phy_duplex = !!(phy->read(phy, 18) & (1 << 11));
- mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128);
-
- if (mac_duplex != phy_duplex) {
- new_mm = 1;
- }
-
- if (eth->regs[RW_GEN_CTRL] & 1) {
- if (new_mm != eth->duplex_mismatch) {
- if (new_mm) {
- printf("HW: WARNING ETH duplex mismatch MAC=%d PHY=%d\n",
- mac_duplex, phy_duplex);
- } else {
- printf("HW: ETH duplex ok.\n");
- }
- }
- eth->duplex_mismatch = new_mm;
- }
-}
-
-static uint64_t
-eth_read(void *opaque, hwaddr addr, unsigned int size)
-{
- ETRAXFSEthState *eth = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
-
- switch (addr) {
- case R_STAT:
- r = eth->mdio_bus.mdio & 1;
- break;
- default:
- r = eth->regs[addr];
- D(printf("%s %x\n", __func__, addr * 4));
- break;
- }
- return r;
-}
-
-static void eth_update_ma(ETRAXFSEthState *eth, int ma)
-{
- int reg;
- int i = 0;
-
- ma &= 1;
-
- reg = RW_MA0_LO;
- if (ma) {
- reg = RW_MA1_LO;
- }
-
- eth->macaddr[ma][i++] = eth->regs[reg];
- eth->macaddr[ma][i++] = eth->regs[reg] >> 8;
- eth->macaddr[ma][i++] = eth->regs[reg] >> 16;
- eth->macaddr[ma][i++] = eth->regs[reg] >> 24;
- eth->macaddr[ma][i++] = eth->regs[reg + 1];
- eth->macaddr[ma][i] = eth->regs[reg + 1] >> 8;
-
- D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma,
- eth->macaddr[ma][0], eth->macaddr[ma][1],
- eth->macaddr[ma][2], eth->macaddr[ma][3],
- eth->macaddr[ma][4], eth->macaddr[ma][5]));
-}
-
-static void
-eth_write(void *opaque, hwaddr addr,
- uint64_t val64, unsigned int size)
-{
- ETRAXFSEthState *eth = opaque;
- uint32_t value = val64;
-
- addr >>= 2;
- switch (addr) {
- case RW_MA0_LO:
- case RW_MA0_HI:
- eth->regs[addr] = value;
- eth_update_ma(eth, 0);
- break;
- case RW_MA1_LO:
- case RW_MA1_HI:
- eth->regs[addr] = value;
- eth_update_ma(eth, 1);
- break;
-
- case RW_MGM_CTRL:
- /* Attach an MDIO/PHY abstraction. */
- if (value & 2) {
- eth->mdio_bus.mdio = value & 1;
- }
- if (eth->mdio_bus.mdc != (value & 4)) {
- mdio_cycle(&eth->mdio_bus);
- eth_validate_duplex(eth);
- }
- eth->mdio_bus.mdc = !!(value & 4);
- eth->regs[addr] = value;
- break;
-
- case RW_REC_CTRL:
- eth->regs[addr] = value;
- eth_validate_duplex(eth);
- break;
-
- default:
- eth->regs[addr] = value;
- D(printf("%s %x %x\n", __func__, addr, value));
- break;
- }
-}
-
-/* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom
- filter dropping group addresses we have not joined. The filter has 64
- bits (m). The has function is a simple nible xor of the group addr. */
-static int eth_match_groupaddr(ETRAXFSEthState *eth, const unsigned char *sa)
-{
- unsigned int hsh;
- int m_individual = eth->regs[RW_REC_CTRL] & 4;
- int match;
-
- /* First bit on the wire of a MAC address signals multicast or
- physical address. */
- if (!m_individual && !(sa[0] & 1)) {
- return 0;
- }
-
- /* Calculate the hash index for the GA registers. */
- hsh = 0;
- hsh ^= (*sa) & 0x3f;
- hsh ^= ((*sa) >> 6) & 0x03;
- ++sa;
- hsh ^= ((*sa) << 2) & 0x03c;
- hsh ^= ((*sa) >> 4) & 0xf;
- ++sa;
- hsh ^= ((*sa) << 4) & 0x30;
- hsh ^= ((*sa) >> 2) & 0x3f;
- ++sa;
- hsh ^= (*sa) & 0x3f;
- hsh ^= ((*sa) >> 6) & 0x03;
- ++sa;
- hsh ^= ((*sa) << 2) & 0x03c;
- hsh ^= ((*sa) >> 4) & 0xf;
- ++sa;
- hsh ^= ((*sa) << 4) & 0x30;
- hsh ^= ((*sa) >> 2) & 0x3f;
-
- hsh &= 63;
- if (hsh > 31) {
- match = eth->regs[RW_GA_HI] & (1 << (hsh - 32));
- } else {
- match = eth->regs[RW_GA_LO] & (1 << hsh);
- }
- D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh,
- eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match));
- return match;
-}
-
-static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
- unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- ETRAXFSEthState *eth = qemu_get_nic_opaque(nc);
- int use_ma0 = eth->regs[RW_REC_CTRL] & 1;
- int use_ma1 = eth->regs[RW_REC_CTRL] & 2;
- int r_bcast = eth->regs[RW_REC_CTRL] & 8;
-
- if (size < 12) {
- return -1;
- }
-
- D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n",
- buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
- use_ma0, use_ma1, r_bcast));
-
- /* Does the frame get through the address filters? */
- if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6))
- && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6))
- && (!r_bcast || memcmp(buf, sa_bcast, 6))
- && !eth_match_groupaddr(eth, buf)) {
- return size;
- }
-
- /* FIXME: Find another way to pass on the fake csum. */
- etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1);
-
- return size;
-}
-
-static int eth_tx_push(void *opaque, unsigned char *buf, int len, bool eop)
-{
- ETRAXFSEthState *eth = opaque;
-
- D(printf("%s buf=%p len=%d\n", __func__, buf, len));
- qemu_send_packet(qemu_get_queue(eth->nic), buf, len);
- return len;
-}
-
-static void eth_set_link(NetClientState *nc)
-{
- ETRAXFSEthState *eth = qemu_get_nic_opaque(nc);
- D(printf("%s %d\n", __func__, nc->link_down));
- eth->phy.link = !nc->link_down;
-}
-
-static const MemoryRegionOps eth_ops = {
- .read = eth_read,
- .write = eth_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4
- }
-};
-
-static NetClientInfo net_etraxfs_info = {
- .type = NET_CLIENT_DRIVER_NIC,
- .size = sizeof(NICState),
- .receive = eth_receive,
- .link_status_changed = eth_set_link,
-};
-
-static void etraxfs_eth_reset(DeviceState *dev)
-{
- ETRAXFSEthState *s = ETRAX_FS_ETH(dev);
-
- memset(s->regs, 0, sizeof(s->regs));
- memset(s->macaddr, 0, sizeof(s->macaddr));
- s->duplex_mismatch = 0;
-
- s->mdio_bus.mdc = 0;
- s->mdio_bus.mdio = 0;
- s->mdio_bus.state = 0;
- s->mdio_bus.drive = 0;
- s->mdio_bus.cnt = 0;
- s->mdio_bus.addr = 0;
- s->mdio_bus.opc = 0;
- s->mdio_bus.req = 0;
- s->mdio_bus.data = 0;
-
- tdk_reset(&s->phy);
-}
-
-static void etraxfs_eth_realize(DeviceState *dev, Error **errp)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- ETRAXFSEthState *s = ETRAX_FS_ETH(dev);
-
- if (!s->dma_out || !s->dma_in) {
- error_setg(errp, "Unconnected ETRAX-FS Ethernet MAC");
- return;
- }
-
- s->dma_out->client.push = eth_tx_push;
- s->dma_out->client.opaque = s;
- s->dma_in->client.opaque = s;
- s->dma_in->client.pull = NULL;
-
- memory_region_init_io(&s->mmio, OBJECT(dev), &eth_ops, s,
- "etraxfs-eth", 0x5c);
- sysbus_init_mmio(sbd, &s->mmio);
-
- qemu_macaddr_default_if_unset(&s->conf.macaddr);
- s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf,
- object_get_typename(OBJECT(s)), dev->id,
- &dev->mem_reentrancy_guard, s);
- qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
- s->phy.read = tdk_read;
- s->phy.write = tdk_write;
- mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr);
-}
-
-static Property etraxfs_eth_properties[] = {
- DEFINE_PROP_UINT32("phyaddr", ETRAXFSEthState, phyaddr, 1),
- DEFINE_NIC_PROPERTIES(ETRAXFSEthState, conf),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void etraxfs_eth_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = etraxfs_eth_realize;
- dc->reset = etraxfs_eth_reset;
- device_class_set_props(dc, etraxfs_eth_properties);
- /* Reason: dma_out, dma_in are not user settable */
- dc->user_creatable = false;
-}
-
-
-/* Instantiate an ETRAXFS Ethernet MAC. */
-DeviceState *
-etraxfs_eth_init(hwaddr base, int phyaddr,
- struct etraxfs_dma_client *dma_out,
- struct etraxfs_dma_client *dma_in)
-{
- DeviceState *dev;
-
- dev = qdev_new("etraxfs-eth");
- qemu_configure_nic_device(dev, true, "fseth");
- qdev_prop_set_uint32(dev, "phyaddr", phyaddr);
-
- /*
- * TODO: QOM design, define a QOM interface for "I am an etraxfs
- * DMA client" (which replaces the current 'struct
- * etraxfs_dma_client' ad-hoc interface), implement it on the
- * ethernet device, and then have QOM link properties on the DMA
- * controller device so that you can pass the interface
- * implementations to it.
- */
- ETRAX_FS_ETH(dev)->dma_out = dma_out;
- ETRAX_FS_ETH(dev)->dma_in = dma_in;
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-
- return dev;
-}
-
-static const TypeInfo etraxfs_eth_info = {
- .name = TYPE_ETRAX_FS_ETH,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(ETRAXFSEthState),
- .class_init = etraxfs_eth_class_init,
-};
-
-static void etraxfs_eth_register_types(void)
-{
- type_register_static(&etraxfs_eth_info);
-}
-
-type_init(etraxfs_eth_register_types)
diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c
index 00315f3..3fdd16e 100644
--- a/hw/net/fsl_etsec/etsec.c
+++ b/hw/net/fsl_etsec/etsec.c
@@ -425,7 +425,7 @@ static void etsec_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = etsec_realize;
- dc->reset = etsec_reset;
+ device_class_set_legacy_reset(dc, etsec_reset);
device_class_set_props(dc, etsec_properties);
/* Supported by ppce500 machine */
dc->user_creatable = true;
diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c
index 80f9cd5..478356e 100644
--- a/hw/net/ftgmac100.c
+++ b/hw/net/ftgmac100.c
@@ -24,8 +24,7 @@
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
-/* For crc32 */
-#include <zlib.h>
+#include <zlib.h> /* for crc32 */
/*
* FTGMAC100 registers
@@ -1267,7 +1266,7 @@ static void ftgmac100_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_ftgmac100;
- dc->reset = ftgmac100_reset;
+ device_class_set_legacy_reset(dc, ftgmac100_reset);
device_class_set_props(dc, ftgmac100_properties);
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->realize = ftgmac100_realize;
@@ -1427,7 +1426,7 @@ static void aspeed_mii_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_aspeed_mii;
- dc->reset = aspeed_mii_reset;
+ device_class_set_legacy_reset(dc, aspeed_mii_reset);
dc->realize = aspeed_mii_realize;
dc->desc = "Aspeed MII controller";
device_class_set_props(dc, aspeed_mii_properties);
diff --git a/hw/net/i82596.c b/hw/net/i82596.c
index 6cc8292..ee919da 100644
--- a/hw/net/i82596.c
+++ b/hw/net/i82596.c
@@ -19,7 +19,7 @@
#include "qemu/module.h"
#include "trace.h"
#include "i82596.h"
-#include <zlib.h> /* For crc32 */
+#include <zlib.h> /* for crc32 */
#if defined(ENABLE_DEBUG)
#define DBG(x) x
@@ -282,7 +282,7 @@ static void command_loop(I82596State *s)
case CmdDump:
case CmdDiagnose:
printf("FIXME Command %d !!\n", cmd & 7);
- assert(0);
+ g_assert_not_reached();
}
/* update status */
diff --git a/hw/net/igb.c b/hw/net/igb.c
index b6ca2f1..b92bba4 100644
--- a/hw/net/igb.c
+++ b/hw/net/igb.c
@@ -446,16 +446,9 @@ static void igb_pci_realize(PCIDevice *pci_dev, Error **errp)
pcie_ari_init(pci_dev, 0x150);
- if (!pcie_sriov_pf_init(pci_dev, IGB_CAP_SRIOV_OFFSET,
- TYPE_IGBVF, IGB_82576_VF_DEV_ID,
- IGB_MAX_VF_FUNCTIONS, IGB_MAX_VF_FUNCTIONS,
- IGB_VF_OFFSET, IGB_VF_STRIDE,
- errp)) {
- pcie_cap_exit(pci_dev);
- igb_cleanup_msix(s);
- msi_uninit(pci_dev);
- return;
- }
+ pcie_sriov_pf_init(pci_dev, IGB_CAP_SRIOV_OFFSET, TYPE_IGBVF,
+ IGB_82576_VF_DEV_ID, IGB_MAX_VF_FUNCTIONS, IGB_MAX_VF_FUNCTIONS,
+ IGB_VF_OFFSET, IGB_VF_STRIDE);
pcie_sriov_pf_init_vf_bar(pci_dev, IGBVF_MMIO_BAR_IDX,
PCI_BASE_ADDRESS_MEM_TYPE_64 | PCI_BASE_ADDRESS_MEM_PREFETCH,
diff --git a/hw/net/igb_core.c b/hw/net/igb_core.c
index bcd5f6c..5dffa12 100644
--- a/hw/net/igb_core.c
+++ b/hw/net/igb_core.c
@@ -397,8 +397,7 @@ igb_rss_calc_hash(IGBCore *core, struct NetRxPkt *pkt, E1000E_RSSInfo *info)
type = NetPktRssIpV6Udp;
break;
default:
- assert(false);
- return 0;
+ g_assert_not_reached();
}
return net_rx_pkt_calc_rss_hash(pkt, type, (uint8_t *) &core->mac[RSSRK]);
@@ -747,7 +746,6 @@ igb_ring_free_descr_num(IGBCore *core, const E1000ERingInfo *r)
}
g_assert_not_reached();
- return 0;
}
static inline bool
diff --git a/hw/net/igb_regs.h b/hw/net/igb_regs.h
index e5a47ea..4dc4c31 100644
--- a/hw/net/igb_regs.h
+++ b/hw/net/igb_regs.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* This is copied + edited from kernel header files in
* drivers/net/ethernet/intel/igb
diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c
index 8c91d20..6294d29 100644
--- a/hw/net/imx_fec.c
+++ b/hw/net/imx_fec.c
@@ -33,8 +33,7 @@
#include "net/eth.h"
#include "trace.h"
-/* For crc32 */
-#include <zlib.h>
+#include <zlib.h> /* for crc32 */
#define IMX_MAX_DESC 1024
@@ -1354,7 +1353,7 @@ static void imx_eth_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_imx_eth;
- dc->reset = imx_eth_reset;
+ device_class_set_legacy_reset(dc, imx_eth_reset);
device_class_set_props(dc, imx_eth_properties);
dc->realize = imx_eth_realize;
dc->desc = "i.MX FEC/ENET Ethernet Controller";
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
index 91d81b4..db28a0e 100644
--- a/hw/net/lan9118.c
+++ b/hw/net/lan9118.c
@@ -22,8 +22,7 @@
#include "qapi/error.h"
#include "qemu/log.h"
#include "qemu/module.h"
-/* For crc32 */
-#include <zlib.h>
+#include <zlib.h> /* for crc32 */
#include "qom/object.h"
//#define DEBUG_LAN9118
@@ -1408,7 +1407,7 @@ static void lan9118_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = lan9118_reset;
+ device_class_set_legacy_reset(dc, lan9118_reset);
device_class_set_props(dc, lan9118_properties);
dc->vmsd = &vmstate_lan9118;
dc->realize = lan9118_realize;
diff --git a/hw/net/lance.c b/hw/net/lance.c
index e1ed24c..269615b 100644
--- a/hw/net/lance.c
+++ b/hw/net/lance.c
@@ -151,7 +151,7 @@ static void lance_class_init(ObjectClass *klass, void *data)
dc->realize = lance_realize;
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->fw_name = "ethernet";
- dc->reset = lance_reset;
+ device_class_set_legacy_reset(dc, lance_reset);
dc->vmsd = &vmstate_lance;
device_class_set_props(dc, lance_properties);
}
diff --git a/hw/net/lasi_i82596.c b/hw/net/lasi_i82596.c
index fcf7fae..183fab8 100644
--- a/hw/net/lasi_i82596.c
+++ b/hw/net/lasi_i82596.c
@@ -170,7 +170,7 @@ static void lasi_82596_class_init(ObjectClass *klass, void *data)
dc->realize = lasi_82596_realize;
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->fw_name = "ethernet";
- dc->reset = lasi_82596_reset;
+ device_class_set_legacy_reset(dc, lasi_82596_reset);
dc->vmsd = &vmstate_lasi_82596;
dc->user_creatable = false;
device_class_set_props(dc, lasi_82596_properties);
diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c
index e690271..037cd20 100644
--- a/hw/net/mcf_fec.c
+++ b/hw/net/mcf_fec.c
@@ -16,8 +16,7 @@
#include "hw/net/mii.h"
#include "hw/qdev-properties.h"
#include "hw/sysbus.h"
-/* For crc32 */
-#include <zlib.h>
+#include <zlib.h> /* for crc32 */
//#define DEBUG_FEC 1
@@ -673,7 +672,7 @@ static void mcf_fec_class_init(ObjectClass *oc, void *data)
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->realize = mcf_fec_realize;
dc->desc = "MCF Fast Ethernet Controller network device";
- dc->reset = mcf_fec_reset;
+ device_class_set_legacy_reset(dc, mcf_fec_reset);
device_class_set_props(dc, mcf_fec_properties);
}
diff --git a/hw/net/meson.build b/hw/net/meson.build
index b742687..00a9e9d 100644
--- a/hw/net/meson.build
+++ b/hw/net/meson.build
@@ -40,7 +40,6 @@ system_ss.add(when: 'CONFIG_FTGMAC100', if_true: files('ftgmac100.c'))
system_ss.add(when: 'CONFIG_SUNGEM', if_true: files('sungem.c'))
system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_emc.c', 'npcm_gmac.c'))
-system_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_eth.c'))
system_ss.add(when: 'CONFIG_COLDFIRE', if_true: files('mcf_fec.c'))
specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_llan.c'))
system_ss.add(when: 'CONFIG_XILINX_ETHLITE', if_true: files('xilinx_ethlite.c'))
diff --git a/hw/net/mipsnet.c b/hw/net/mipsnet.c
index df5101a..31bbd6f 100644
--- a/hw/net/mipsnet.c
+++ b/hw/net/mipsnet.c
@@ -278,7 +278,7 @@ static void mipsnet_class_init(ObjectClass *klass, void *data)
dc->realize = mipsnet_realize;
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->desc = "MIPS Simulator network device";
- dc->reset = mipsnet_sysbus_reset;
+ device_class_set_legacy_reset(dc, mipsnet_sysbus_reset);
dc->vmsd = &vmstate_mipsnet;
device_class_set_props(dc, mipsnet_properties);
}
diff --git a/hw/net/msf2-emac.c b/hw/net/msf2-emac.c
index c1fc10d..d28fc6c 100644
--- a/hw/net/msf2-emac.c
+++ b/hw/net/msf2-emac.c
@@ -571,7 +571,7 @@ static void msf2_emac_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = msf2_emac_realize;
- dc->reset = msf2_emac_reset;
+ device_class_set_legacy_reset(dc, msf2_emac_reset);
dc->vmsd = &vmstate_msf2_emac;
device_class_set_props(dc, msf2_emac_properties);
}
diff --git a/hw/net/net_rx_pkt.c b/hw/net/net_rx_pkt.c
index 32e5f3f..f87b6f0 100644
--- a/hw/net/net_rx_pkt.c
+++ b/hw/net/net_rx_pkt.c
@@ -209,12 +209,6 @@ void net_rx_pkt_get_protocols(struct NetRxPkt *pkt,
*l4hdr_proto = pkt->l4hdr_info.proto;
}
-size_t net_rx_pkt_get_l3_hdr_offset(struct NetRxPkt *pkt)
-{
- assert(pkt);
- return pkt->l3hdr_off;
-}
-
size_t net_rx_pkt_get_l4_hdr_offset(struct NetRxPkt *pkt)
{
assert(pkt);
@@ -375,8 +369,7 @@ net_rx_pkt_calc_rss_hash(struct NetRxPkt *pkt,
_net_rx_rss_prepare_udp(&rss_input[0], pkt, &rss_length);
break;
default:
- assert(false);
- break;
+ g_assert_not_reached();
}
net_toeplitz_key_init(&key_data, key);
@@ -427,13 +420,6 @@ struct iovec *net_rx_pkt_get_iovec(struct NetRxPkt *pkt)
return pkt->vec;
}
-uint16_t net_rx_pkt_get_iovec_len(struct NetRxPkt *pkt)
-{
- assert(pkt);
-
- return pkt->vec_len;
-}
-
void net_rx_pkt_set_vhdr(struct NetRxPkt *pkt,
struct virtio_net_hdr *vhdr)
{
diff --git a/hw/net/net_rx_pkt.h b/hw/net/net_rx_pkt.h
index 55ec67a..ea077f5 100644
--- a/hw/net/net_rx_pkt.h
+++ b/hw/net/net_rx_pkt.h
@@ -78,14 +78,6 @@ void net_rx_pkt_get_protocols(struct NetRxPkt *pkt,
EthL4HdrProto *l4hdr_proto);
/**
-* fetches L3 header offset
-*
-* @pkt: packet
-*
-*/
-size_t net_rx_pkt_get_l3_hdr_offset(struct NetRxPkt *pkt);
-
-/**
* fetches L4 header offset
*
* @pkt: packet
@@ -268,15 +260,6 @@ net_rx_pkt_attach_data(struct NetRxPkt *pkt, const void *data,
struct iovec *net_rx_pkt_get_iovec(struct NetRxPkt *pkt);
/**
-* returns io vector length that holds the attached data
-*
-* @pkt: packet
-* @ret: IOVec length
-*
-*/
-uint16_t net_rx_pkt_get_iovec_len(struct NetRxPkt *pkt);
-
-/**
* prints rx packet data if debug is enabled
*
* @pkt: packet
diff --git a/hw/net/npcm7xx_emc.c b/hw/net/npcm7xx_emc.c
index d1583b6..7307a13 100644
--- a/hw/net/npcm7xx_emc.c
+++ b/hw/net/npcm7xx_emc.c
@@ -29,8 +29,7 @@
#include "qemu/osdep.h"
-/* For crc32 */
-#include <zlib.h>
+#include <zlib.h> /* for crc32 */
#include "hw/irq.h"
#include "hw/qdev-clock.h"
@@ -859,7 +858,7 @@ static void npcm7xx_emc_class_init(ObjectClass *klass, void *data)
dc->desc = "NPCM7xx EMC Controller";
dc->realize = npcm7xx_emc_realize;
dc->unrealize = npcm7xx_emc_unrealize;
- dc->reset = npcm7xx_emc_reset;
+ device_class_set_legacy_reset(dc, npcm7xx_emc_reset);
dc->vmsd = &vmstate_npcm7xx_emc;
device_class_set_props(dc, npcm7xx_emc_properties);
}
diff --git a/hw/net/npcm_gmac.c b/hw/net/npcm_gmac.c
index 1b71e25..6fa6bec 100644
--- a/hw/net/npcm_gmac.c
+++ b/hw/net/npcm_gmac.c
@@ -926,7 +926,7 @@ static void npcm_gmac_class_init(ObjectClass *klass, void *data)
dc->desc = "NPCM GMAC Controller";
dc->realize = npcm_gmac_realize;
dc->unrealize = npcm_gmac_unrealize;
- dc->reset = npcm_gmac_reset;
+ device_class_set_legacy_reset(dc, npcm_gmac_reset);
dc->vmsd = &vmstate_npcm_gmac;
device_class_set_props(dc, npcm_gmac_properties);
}
diff --git a/hw/net/opencores_eth.c b/hw/net/opencores_eth.c
index f96d6ea..2c0ebda 100644
--- a/hw/net/opencores_eth.c
+++ b/hw/net/opencores_eth.c
@@ -755,7 +755,7 @@ static void open_eth_class_init(ObjectClass *klass, void *data)
dc->realize = sysbus_open_eth_realize;
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->desc = "Opencores 10/100 Mbit Ethernet";
- dc->reset = qdev_open_eth_reset;
+ device_class_set_legacy_reset(dc, qdev_open_eth_reset);
device_class_set_props(dc, open_eth_properties);
}
diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c
index fe1a845..6190b76 100644
--- a/hw/net/pcnet-pci.c
+++ b/hw/net/pcnet-pci.c
@@ -269,7 +269,7 @@ static void pcnet_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_AMD_LANCE;
k->revision = 0x10;
k->class_id = PCI_CLASS_NETWORK_ETHERNET;
- dc->reset = pci_reset;
+ device_class_set_legacy_reset(dc, pci_reset);
dc->vmsd = &vmstate_pci_pcnet;
device_class_set_props(dc, pcnet_properties);
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c
index 7ea8eb6..5e74acc 100644
--- a/hw/net/rocker/rocker.c
+++ b/hw/net/rocker/rocker.c
@@ -134,11 +134,6 @@ RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp)
return list;
}
-uint32_t rocker_fp_ports(Rocker *r)
-{
- return r->fp_ports;
-}
-
static uint32_t rocker_get_pport_by_tx_ring(Rocker *r,
DescRing *ring)
{
@@ -1494,7 +1489,7 @@ static void rocker_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_NETWORK_OTHER;
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
dc->desc = "Rocker Switch";
- dc->reset = rocker_reset;
+ device_class_set_legacy_reset(dc, rocker_reset);
device_class_set_props(dc, rocker_properties);
dc->vmsd = &rocker_vmsd;
}
diff --git a/hw/net/rocker/rocker.h b/hw/net/rocker/rocker.h
index f85354d..6e0962f 100644
--- a/hw/net/rocker/rocker.h
+++ b/hw/net/rocker/rocker.h
@@ -72,7 +72,6 @@ DECLARE_INSTANCE_CHECKER(Rocker, ROCKER,
TYPE_ROCKER)
Rocker *rocker_find(const char *name);
-uint32_t rocker_fp_ports(Rocker *r);
int rocker_event_link_changed(Rocker *r, uint32_t pport, bool link_up);
int rocker_event_mac_vlan_seen(Rocker *r, uint32_t pport, uint8_t *addr,
uint16_t vlan_id);
diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
index 897c86e..bc56075 100644
--- a/hw/net/rtl8139.c
+++ b/hw/net/rtl8139.c
@@ -48,10 +48,8 @@
* 2011-Mar-22 Benjamin Poirier: Implemented VLAN offloading
*/
-/* For crc32 */
-
#include "qemu/osdep.h"
-#include <zlib.h>
+#include <zlib.h> /* for crc32 */
#include "hw/pci/pci_device.h"
#include "hw/qdev-properties.h"
@@ -2738,7 +2736,11 @@ static void rtl8139_io_writeb(void *opaque, uint8_t addr, uint32_t val)
}
break;
-
+ case RxConfig:
+ DPRINTF("RxConfig write(b) val=0x%02x\n", val);
+ rtl8139_RxConfig_write(s,
+ (rtl8139_RxConfig_read(s) & 0xFFFFFF00) | val);
+ break;
default:
DPRINTF("not implemented write(b) addr=0x%x val=0x%02x\n", addr,
val);
@@ -3425,7 +3427,7 @@ static void rtl8139_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_REALTEK_8139;
k->revision = RTL8139_PCI_REVID; /* >=0x20 is for 8139C+ */
k->class_id = PCI_CLASS_NETWORK_ETHERNET;
- dc->reset = rtl8139_reset;
+ device_class_set_legacy_reset(dc, rtl8139_reset);
dc->vmsd = &vmstate_rtl8139;
device_class_set_props(dc, rtl8139_properties);
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
diff --git a/hw/net/smc91c111.c b/hw/net/smc91c111.c
index 702d0e8..180ba5c 100644
--- a/hw/net/smc91c111.c
+++ b/hw/net/smc91c111.c
@@ -17,8 +17,7 @@
#include "qapi/error.h"
#include "qemu/log.h"
#include "qemu/module.h"
-/* For crc32 */
-#include <zlib.h>
+#include <zlib.h> /* for crc32 */
#include "qom/object.h"
/* Number of 2k memory pages available. */
@@ -799,7 +798,7 @@ static void smc91c111_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = smc91c111_realize;
- dc->reset = smc91c111_reset;
+ device_class_set_legacy_reset(dc, smc91c111_reset);
dc->vmsd = &vmstate_smc91c111;
device_class_set_props(dc, smc91c111_properties);
}
diff --git a/hw/net/stellaris_enet.c b/hw/net/stellaris_enet.c
index db95766..9ebff29 100644
--- a/hw/net/stellaris_enet.c
+++ b/hw/net/stellaris_enet.c
@@ -15,7 +15,7 @@
#include "net/net.h"
#include "qemu/log.h"
#include "qemu/module.h"
-#include <zlib.h>
+#include <zlib.h> /* for crc32 */
#include "qom/object.h"
//#define DEBUG_STELLARIS_ENET 1
@@ -507,7 +507,7 @@ static void stellaris_enet_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = stellaris_enet_realize;
- dc->reset = stellaris_enet_reset;
+ device_class_set_legacy_reset(dc, stellaris_enet_reset);
device_class_set_props(dc, stellaris_enet_properties);
dc->vmsd = &vmstate_stellaris_enet;
}
diff --git a/hw/net/sungem.c b/hw/net/sungem.c
index dd1b4a1..67087e9 100644
--- a/hw/net/sungem.c
+++ b/hw/net/sungem.c
@@ -1467,7 +1467,7 @@ static void sungem_class_init(ObjectClass *klass, void *data)
k->revision = 0x01;
k->class_id = PCI_CLASS_NETWORK_ETHERNET;
dc->vmsd = &vmstate_sungem;
- dc->reset = sungem_reset;
+ device_class_set_legacy_reset(dc, sungem_reset);
device_class_set_props(dc, sungem_properties);
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
}
diff --git a/hw/net/sunhme.c b/hw/net/sunhme.c
index ae8452e..0e6c655 100644
--- a/hw/net/sunhme.c
+++ b/hw/net/sunhme.c
@@ -948,7 +948,7 @@ static void sunhme_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_SUN_HME;
k->class_id = PCI_CLASS_NETWORK_ETHERNET;
dc->vmsd = &vmstate_hme;
- dc->reset = sunhme_reset;
+ device_class_set_legacy_reset(dc, sunhme_reset);
device_class_set_props(dc, sunhme_properties);
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
}
diff --git a/hw/net/trace-events b/hw/net/trace-events
index 78efa2e..91a3d0c 100644
--- a/hw/net/trace-events
+++ b/hw/net/trace-events
@@ -10,11 +10,6 @@ allwinner_sun8i_emac_set_link(bool active) "Set link: active=%u"
allwinner_sun8i_emac_read(uint64_t offset, uint64_t val) "MMIO read: offset=0x%" PRIx64 " value=0x%" PRIx64
allwinner_sun8i_emac_write(uint64_t offset, uint64_t val) "MMIO write: offset=0x%" PRIx64 " value=0x%" PRIx64
-# etraxfs_eth.c
-mdio_phy_read(int regnum, uint16_t value) "read phy_reg:%d value:0x%04x"
-mdio_phy_write(int regnum, uint16_t value) "write phy_reg:%d value:0x%04x"
-mdio_bitbang(bool mdc, bool mdio, int state, uint16_t cnt, unsigned int drive) "bitbang mdc=%u mdio=%u state=%d cnt=%u drv=%d"
-
# lance.c
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"
@@ -399,9 +394,11 @@ virtio_net_announce_notify(void) ""
virtio_net_announce_timer(int round) "%d"
virtio_net_handle_announce(int round) "%d"
virtio_net_post_load_device(void)
-virtio_net_rss_disable(void)
-virtio_net_rss_error(const char *msg, uint32_t value) "%s, value 0x%08x"
-virtio_net_rss_enable(uint32_t p1, uint16_t p2, uint8_t p3) "hashes 0x%x, table of %d, key of %d"
+virtio_net_rss_load(void *nic, size_t nfds, void *fds) "nic=%p nfds=%zu fds=%p"
+virtio_net_rss_attach_ebpf(void *nic, int prog_fd) "nic=%p prog-fd=%d"
+virtio_net_rss_disable(void *nic) "nic=%p"
+virtio_net_rss_error(void *nic, const char *msg, uint32_t value) "nic=%p msg=%s, value 0x%08x"
+virtio_net_rss_enable(void *nic, uint32_t p1, uint16_t p2, uint8_t p3) "nic=%p hashes 0x%x, table of %d, key of %d"
# tulip.c
tulip_reg_write(uint64_t addr, const char *name, int size, uint64_t val) "addr 0x%02"PRIx64" (%s) size %d value 0x%08"PRIx64
diff --git a/hw/net/tulip.c b/hw/net/tulip.c
index 1f2ef20..9df3e17 100644
--- a/hw/net/tulip.c
+++ b/hw/net/tulip.c
@@ -1026,7 +1026,7 @@ static void tulip_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_NETWORK_ETHERNET;
dc->vmsd = &vmstate_pci_tulip;
device_class_set_props(dc, tulip_properties);
- dc->reset = tulip_qdev_reset;
+ device_class_set_legacy_reset(dc, tulip_qdev_reset);
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
}
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 18898af..997aab0 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -48,7 +48,9 @@ static const int kernel_feature_bits[] = {
VIRTIO_F_IOMMU_PLATFORM,
VIRTIO_F_RING_PACKED,
VIRTIO_F_RING_RESET,
+ VIRTIO_F_IN_ORDER,
VIRTIO_F_NOTIFICATION_DATA,
+ VIRTIO_NET_F_RSC_EXT,
VIRTIO_NET_F_HASH_REPORT,
VHOST_INVALID_FEATURE_BIT
};
@@ -78,7 +80,9 @@ static const int user_feature_bits[] = {
VIRTIO_F_IOMMU_PLATFORM,
VIRTIO_F_RING_PACKED,
VIRTIO_F_RING_RESET,
+ VIRTIO_F_IN_ORDER,
VIRTIO_NET_F_RSS,
+ VIRTIO_NET_F_RSC_EXT,
VIRTIO_NET_F_HASH_REPORT,
VIRTIO_NET_F_GUEST_USO4,
VIRTIO_NET_F_GUEST_USO6,
@@ -158,6 +162,135 @@ void vhost_net_save_acked_features(NetClientState *nc)
#endif
}
+static void vhost_net_disable_notifiers_nvhosts(VirtIODevice *dev,
+ NetClientState *ncs, int data_queue_pairs, int nvhosts)
+{
+ VirtIONet *n = VIRTIO_NET(dev);
+ BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
+ struct vhost_net *net;
+ struct vhost_dev *hdev;
+ int r, i, j;
+ NetClientState *peer;
+
+ /*
+ * Batch all the host notifiers in a single transaction to avoid
+ * quadratic time complexity in address_space_update_ioeventfds().
+ */
+ memory_region_transaction_begin();
+
+ for (i = 0; i < nvhosts; i++) {
+ if (i < data_queue_pairs) {
+ peer = qemu_get_peer(ncs, i);
+ } else {
+ peer = qemu_get_peer(ncs, n->max_queue_pairs);
+ }
+
+ net = get_vhost_net(peer);
+ hdev = &net->dev;
+ for (j = 0; j < hdev->nvqs; j++) {
+ r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus),
+ hdev->vq_index + j,
+ false);
+ if (r < 0) {
+ error_report("vhost %d VQ %d notifier cleanup failed: %d",
+ i, j, -r);
+ }
+ assert(r >= 0);
+ }
+ }
+ /*
+ * The transaction expects the ioeventfds to be open when it
+ * commits. Do it now, before the cleanup loop.
+ */
+ memory_region_transaction_commit();
+
+ for (i = 0; i < nvhosts; i++) {
+ if (i < data_queue_pairs) {
+ peer = qemu_get_peer(ncs, i);
+ } else {
+ peer = qemu_get_peer(ncs, n->max_queue_pairs);
+ }
+
+ net = get_vhost_net(peer);
+ hdev = &net->dev;
+ for (j = 0; j < hdev->nvqs; j++) {
+ virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus),
+ hdev->vq_index + j);
+ }
+ virtio_device_release_ioeventfd(dev);
+ }
+}
+
+static int vhost_net_enable_notifiers(VirtIODevice *dev,
+ NetClientState *ncs, int data_queue_pairs, int cvq)
+{
+ VirtIONet *n = VIRTIO_NET(dev);
+ BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
+ int nvhosts = data_queue_pairs + cvq;
+ struct vhost_net *net;
+ struct vhost_dev *hdev;
+ int r, i, j;
+ NetClientState *peer;
+
+ /*
+ * Batch all the host notifiers in a single transaction to avoid
+ * quadratic time complexity in address_space_update_ioeventfds().
+ */
+ memory_region_transaction_begin();
+
+ for (i = 0; i < nvhosts; i++) {
+ if (i < data_queue_pairs) {
+ peer = qemu_get_peer(ncs, i);
+ } else {
+ peer = qemu_get_peer(ncs, n->max_queue_pairs);
+ }
+
+ net = get_vhost_net(peer);
+ hdev = &net->dev;
+ /*
+ * We will pass the notifiers to the kernel, make sure that QEMU
+ * doesn't interfere.
+ */
+ r = virtio_device_grab_ioeventfd(dev);
+ if (r < 0) {
+ error_report("binding does not support host notifiers");
+ memory_region_transaction_commit();
+ goto fail_nvhosts;
+ }
+
+ for (j = 0; j < hdev->nvqs; j++) {
+ r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus),
+ hdev->vq_index + j,
+ true);
+ if (r < 0) {
+ error_report("vhost %d VQ %d notifier binding failed: %d",
+ i, j, -r);
+ memory_region_transaction_commit();
+ vhost_dev_disable_notifiers_nvqs(hdev, dev, j);
+ goto fail_nvhosts;
+ }
+ }
+ }
+
+ memory_region_transaction_commit();
+
+ return 0;
+fail_nvhosts:
+ vhost_net_disable_notifiers_nvhosts(dev, ncs, data_queue_pairs, i);
+ return r;
+}
+
+/*
+ * Stop processing guest IO notifications in qemu.
+ * Start processing them in vhost in kernel.
+ */
+static void vhost_net_disable_notifiers(VirtIODevice *dev,
+ NetClientState *ncs, int data_queue_pairs, int cvq)
+{
+ vhost_net_disable_notifiers_nvhosts(dev, ncs, data_queue_pairs,
+ data_queue_pairs + cvq);
+}
+
static int vhost_net_get_fd(NetClientState *backend)
{
switch (backend->info->type) {
@@ -268,11 +401,6 @@ static int vhost_net_start_one(struct vhost_net *net,
}
}
- r = vhost_dev_enable_notifiers(&net->dev, dev);
- if (r < 0) {
- goto fail_notifiers;
- }
-
r = vhost_dev_start(&net->dev, dev, false);
if (r < 0) {
goto fail_start;
@@ -324,8 +452,6 @@ fail:
}
vhost_dev_stop(&net->dev, dev, false);
fail_start:
- vhost_dev_disable_notifiers(&net->dev, dev);
-fail_notifiers:
return r;
}
@@ -347,7 +473,6 @@ static void vhost_net_stop_one(struct vhost_net *net,
if (net->nc->info->stop) {
net->nc->info->stop(net->nc);
}
- vhost_dev_disable_notifiers(&net->dev, dev);
}
int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
@@ -392,10 +517,16 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
}
}
+ r = vhost_net_enable_notifiers(dev, ncs, data_queue_pairs, cvq);
+ if (r < 0) {
+ error_report("Error enabling host notifiers: %d", -r);
+ goto err;
+ }
+
r = k->set_guest_notifiers(qbus->parent, total_notifiers, true);
if (r < 0) {
error_report("Error binding guest notifier: %d", -r);
- goto err;
+ goto err_host_notifiers;
}
for (i = 0; i < nvhosts; i++) {
@@ -410,19 +541,19 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
r = vhost_set_vring_enable(peer, peer->vring_enable);
if (r < 0) {
- goto err_start;
+ goto err_guest_notifiers;
}
}
r = vhost_net_start_one(get_vhost_net(peer), dev);
if (r < 0) {
- goto err_start;
+ goto err_guest_notifiers;
}
}
return 0;
-err_start:
+err_guest_notifiers:
while (--i >= 0) {
peer = qemu_get_peer(ncs, i < data_queue_pairs ?
i : n->max_queue_pairs);
@@ -433,6 +564,8 @@ err_start:
fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", e);
fflush(stderr);
}
+err_host_notifiers:
+ vhost_net_disable_notifiers(dev, ncs, data_queue_pairs, cvq);
err:
return r;
}
@@ -464,6 +597,8 @@ void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
fflush(stderr);
}
assert(r >= 0);
+
+ vhost_net_disable_notifiers(dev, ncs, data_queue_pairs, cvq);
}
void vhost_net_cleanup(struct vhost_net *net)
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 8f30972..f2104ed 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -40,6 +40,7 @@
#include "migration/misc.h"
#include "standard-headers/linux/ethtool.h"
#include "sysemu/sysemu.h"
+#include "sysemu/replay.h"
#include "trace.h"
#include "monitor/qdev.h"
#include "monitor/monitor.h"
@@ -417,7 +418,7 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
timer_mod(q->tx_timer,
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout);
} else {
- qemu_bh_schedule(q->tx_bh);
+ replay_bh_schedule_event(q->tx_bh);
}
} else {
if (q->tx_timer) {
@@ -1240,6 +1241,7 @@ static bool virtio_net_attach_ebpf_to_backend(NICState *nic, int prog_fd)
return false;
}
+ trace_virtio_net_rss_attach_ebpf(nic, prog_fd);
return nc->info->set_steering_ebpf(nc, prog_fd);
}
@@ -1253,7 +1255,7 @@ static void rss_data_to_rss_config(struct VirtioNetRssData *data,
config->default_queue = data->default_queue;
}
-static bool virtio_net_attach_epbf_rss(VirtIONet *n)
+static bool virtio_net_attach_ebpf_rss(VirtIONet *n)
{
struct EBPFRSSConfig config = {};
@@ -1264,7 +1266,8 @@ static bool virtio_net_attach_epbf_rss(VirtIONet *n)
rss_data_to_rss_config(&n->rss_data, &config);
if (!ebpf_rss_set_all(&n->ebpf_rss, &config,
- n->rss_data.indirections_table, n->rss_data.key)) {
+ n->rss_data.indirections_table, n->rss_data.key,
+ NULL)) {
return false;
}
@@ -1275,7 +1278,7 @@ static bool virtio_net_attach_epbf_rss(VirtIONet *n)
return true;
}
-static void virtio_net_detach_epbf_rss(VirtIONet *n)
+static void virtio_net_detach_ebpf_rss(VirtIONet *n)
{
virtio_net_attach_ebpf_to_backend(n->nic, -1);
}
@@ -1285,8 +1288,8 @@ static void virtio_net_commit_rss_config(VirtIONet *n)
if (n->rss_data.enabled) {
n->rss_data.enabled_software_rss = n->rss_data.populate_hash;
if (n->rss_data.populate_hash) {
- virtio_net_detach_epbf_rss(n);
- } else if (!virtio_net_attach_epbf_rss(n)) {
+ virtio_net_detach_ebpf_rss(n);
+ } else if (!virtio_net_attach_ebpf_rss(n)) {
if (get_vhost_net(qemu_get_queue(n->nic)->peer)) {
warn_report("Can't load eBPF RSS for vhost");
} else {
@@ -1295,12 +1298,13 @@ static void virtio_net_commit_rss_config(VirtIONet *n)
}
}
- trace_virtio_net_rss_enable(n->rss_data.hash_types,
+ trace_virtio_net_rss_enable(n,
+ n->rss_data.hash_types,
n->rss_data.indirections_len,
sizeof(n->rss_data.key));
} else {
- virtio_net_detach_epbf_rss(n);
- trace_virtio_net_rss_disable();
+ virtio_net_detach_ebpf_rss(n);
+ trace_virtio_net_rss_disable(n);
}
}
@@ -1314,28 +1318,27 @@ static void virtio_net_disable_rss(VirtIONet *n)
virtio_net_commit_rss_config(n);
}
-static bool virtio_net_load_ebpf_fds(VirtIONet *n)
+static bool virtio_net_load_ebpf_fds(VirtIONet *n, Error **errp)
{
int fds[EBPF_RSS_MAX_FDS] = { [0 ... EBPF_RSS_MAX_FDS - 1] = -1};
int ret = true;
int i = 0;
if (n->nr_ebpf_rss_fds != EBPF_RSS_MAX_FDS) {
- warn_report("Expected %d file descriptors but got %d",
- EBPF_RSS_MAX_FDS, n->nr_ebpf_rss_fds);
- return false;
- }
+ error_setg(errp, "Expected %d file descriptors but got %d",
+ EBPF_RSS_MAX_FDS, n->nr_ebpf_rss_fds);
+ return false;
+ }
for (i = 0; i < n->nr_ebpf_rss_fds; i++) {
- fds[i] = monitor_fd_param(monitor_cur(), n->ebpf_rss_fds[i],
- &error_warn);
+ fds[i] = monitor_fd_param(monitor_cur(), n->ebpf_rss_fds[i], errp);
if (fds[i] < 0) {
ret = false;
goto exit;
}
}
- ret = ebpf_rss_load_fds(&n->ebpf_rss, fds[0], fds[1], fds[2], fds[3]);
+ ret = ebpf_rss_load_fds(&n->ebpf_rss, fds[0], fds[1], fds[2], fds[3], errp);
exit:
if (!ret) {
@@ -1347,13 +1350,16 @@ exit:
return ret;
}
-static bool virtio_net_load_ebpf(VirtIONet *n)
+static bool virtio_net_load_ebpf(VirtIONet *n, Error **errp)
{
bool ret = false;
if (virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
- if (!(n->ebpf_rss_fds && virtio_net_load_ebpf_fds(n))) {
- ret = ebpf_rss_load(&n->ebpf_rss);
+ trace_virtio_net_rss_load(n, n->nr_ebpf_rss_fds, n->ebpf_rss_fds);
+ if (n->ebpf_rss_fds) {
+ ret = virtio_net_load_ebpf_fds(n, errp);
+ } else {
+ ret = ebpf_rss_load(&n->ebpf_rss, errp);
}
}
@@ -1400,17 +1406,17 @@ static uint16_t virtio_net_handle_rss(VirtIONet *n,
n->rss_data.hash_types = virtio_ldl_p(vdev, &cfg.hash_types);
n->rss_data.indirections_len =
virtio_lduw_p(vdev, &cfg.indirection_table_mask);
- n->rss_data.indirections_len++;
if (!do_rss) {
- n->rss_data.indirections_len = 1;
+ n->rss_data.indirections_len = 0;
}
- if (!is_power_of_2(n->rss_data.indirections_len)) {
- err_msg = "Invalid size of indirection table";
+ if (n->rss_data.indirections_len >= VIRTIO_NET_RSS_MAX_TABLE_LEN) {
+ err_msg = "Too large indirection table";
err_value = n->rss_data.indirections_len;
goto error;
}
- if (n->rss_data.indirections_len > VIRTIO_NET_RSS_MAX_TABLE_LEN) {
- err_msg = "Too large indirection table";
+ n->rss_data.indirections_len++;
+ if (!is_power_of_2(n->rss_data.indirections_len)) {
+ err_msg = "Invalid size of indirection table";
err_value = n->rss_data.indirections_len;
goto error;
}
@@ -1481,7 +1487,7 @@ static uint16_t virtio_net_handle_rss(VirtIONet *n,
virtio_net_commit_rss_config(n);
return queue_pairs;
error:
- trace_virtio_net_rss_error(err_msg, err_value);
+ trace_virtio_net_rss_error(n, err_msg, err_value);
virtio_net_disable_rss(n);
return 0;
}
@@ -1641,24 +1647,28 @@ static bool virtio_net_can_receive(NetClientState *nc)
static int virtio_net_has_buffers(VirtIONetQueue *q, int bufsize)
{
+ int opaque;
+ unsigned int in_bytes;
VirtIONet *n = q->n;
- if (virtio_queue_empty(q->rx_vq) ||
- (n->mergeable_rx_bufs &&
- !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) {
- virtio_queue_set_notification(q->rx_vq, 1);
-
- /* To avoid a race condition where the guest has made some buffers
- * available after the above check but before notification was
- * enabled, check for available buffers again.
- */
- if (virtio_queue_empty(q->rx_vq) ||
- (n->mergeable_rx_bufs &&
- !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) {
+
+ while (virtio_queue_empty(q->rx_vq) || n->mergeable_rx_bufs) {
+ opaque = virtqueue_get_avail_bytes(q->rx_vq, &in_bytes, NULL,
+ bufsize, 0);
+ /* Buffer is enough, disable notifiaction */
+ if (bufsize <= in_bytes) {
+ break;
+ }
+
+ if (virtio_queue_enable_notification_and_check(q->rx_vq, opaque)) {
+ /* Guest has added some buffers, try again */
+ continue;
+ } else {
return 0;
}
}
virtio_queue_set_notification(q->rx_vq, 0);
+
return 1;
}
@@ -1905,7 +1915,8 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
if (!no_rss && n->rss_data.enabled && n->rss_data.enabled_software_rss) {
int index = virtio_net_process_rss(nc, buf, size, &extra_hdr);
if (index >= 0) {
- NetClientState *nc2 = qemu_get_subqueue(n->nic, index);
+ NetClientState *nc2 =
+ qemu_get_subqueue(n->nic, index % n->curr_queue_pairs);
return virtio_net_receive_rcu(nc2, buf, size, true);
}
}
@@ -2118,7 +2129,7 @@ static void virtio_net_rsc_purge(void *opq)
chain->stat.timer++;
if (!QTAILQ_EMPTY(&chain->buffers)) {
timer_mod(chain->drain_timer,
- qemu_clock_get_ns(QEMU_CLOCK_HOST) + chain->n->rsc_timeout);
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + chain->n->rsc_timeout);
}
}
@@ -2354,7 +2365,7 @@ static size_t virtio_net_rsc_do_coalesce(VirtioNetRscChain *chain,
chain->stat.empty_cache++;
virtio_net_rsc_cache_buf(chain, nc, buf, size);
timer_mod(chain->drain_timer,
- qemu_clock_get_ns(QEMU_CLOCK_HOST) + chain->n->rsc_timeout);
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + chain->n->rsc_timeout);
return size;
}
@@ -2592,7 +2603,7 @@ static VirtioNetRscChain *virtio_net_rsc_lookup_chain(VirtIONet *n,
chain->max_payload = VIRTIO_NET_MAX_IP6_PAYLOAD;
chain->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
}
- chain->drain_timer = timer_new_ns(QEMU_CLOCK_HOST,
+ chain->drain_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
virtio_net_rsc_purge, chain);
memset(&chain->stat, 0, sizeof(chain->stat));
@@ -2667,7 +2678,7 @@ static void virtio_net_tx_complete(NetClientState *nc, ssize_t len)
*/
virtio_queue_set_notification(q->tx_vq, 0);
if (q->tx_bh) {
- qemu_bh_schedule(q->tx_bh);
+ replay_bh_schedule_event(q->tx_bh);
} else {
timer_mod(q->tx_timer,
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout);
@@ -2833,7 +2844,7 @@ static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq)
return;
}
virtio_queue_set_notification(vq, 0);
- qemu_bh_schedule(q->tx_bh);
+ replay_bh_schedule_event(q->tx_bh);
}
static void virtio_net_tx_timer(void *opaque)
@@ -2916,7 +2927,7 @@ static void virtio_net_tx_bh(void *opaque)
/* If we flush a full burst of packets, assume there are
* more coming and immediately reschedule */
if (ret >= n->tx_burst) {
- qemu_bh_schedule(q->tx_bh);
+ replay_bh_schedule_event(q->tx_bh);
q->tx_waiting = 1;
return;
}
@@ -2930,7 +2941,7 @@ static void virtio_net_tx_bh(void *opaque)
return;
} else if (ret > 0) {
virtio_queue_set_notification(q->tx_vq, 0);
- qemu_bh_schedule(q->tx_bh);
+ replay_bh_schedule_event(q->tx_bh);
q->tx_waiting = 1;
}
}
@@ -3754,7 +3765,23 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
net_rx_pkt_init(&n->rx_pkt);
if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) {
- virtio_net_load_ebpf(n);
+ Error *err = NULL;
+ if (!virtio_net_load_ebpf(n, &err)) {
+ /*
+ * If user explicitly gave QEMU RSS FDs to use, then
+ * failing to use them must be considered a fatal
+ * error. If no RSS FDs were provided, QEMU is trying
+ * eBPF on a "best effort" basis only, so report a
+ * warning and allow fallback to software RSS.
+ */
+ if (n->ebpf_rss_fds) {
+ error_propagate(errp, err);
+ } else {
+ warn_report("unable to load eBPF RSS: %s",
+ error_get_pretty(err));
+ error_free(err);
+ }
+ }
}
}
@@ -3890,8 +3917,23 @@ static bool dev_unplug_pending(void *opaque)
static struct vhost_dev *virtio_net_get_vhost(VirtIODevice *vdev)
{
VirtIONet *n = VIRTIO_NET(vdev);
- NetClientState *nc = qemu_get_queue(n->nic);
- struct vhost_net *net = get_vhost_net(nc->peer);
+ NetClientState *nc;
+ struct vhost_net *net;
+
+ if (!n->nic) {
+ return NULL;
+ }
+
+ nc = qemu_get_queue(n->nic);
+ if (!nc) {
+ return NULL;
+ }
+
+ net = get_vhost_net(nc->peer);
+ if (!net) {
+ return NULL;
+ }
+
return &net->dev;
}
diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
index 63a9187..8aa8c46 100644
--- a/hw/net/vmxnet3.c
+++ b/hw/net/vmxnet3.c
@@ -456,7 +456,6 @@ vmxnet3_setup_tx_offloads(VMXNET3State *s)
default:
g_assert_not_reached();
- return false;
}
return true;
@@ -2512,7 +2511,7 @@ static void vmxnet3_class_init(ObjectClass *class, void *data)
device_class_set_parent_realize(dc, vmxnet3_realize,
&vc->parent_dc_realize);
dc->desc = "VMWare Paravirtualized Ethernet v3";
- dc->reset = vmxnet3_qdev_reset;
+ device_class_set_legacy_reset(dc, vmxnet3_qdev_reset);
dc->vmsd = &vmstate_vmxnet3;
device_class_set_props(dc, vmxnet3_properties);
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c
index 05d41bd..faf2794 100644
--- a/hw/net/xilinx_axienet.c
+++ b/hw/net/xilinx_axienet.c
@@ -1014,7 +1014,7 @@ static void xilinx_enet_class_init(ObjectClass *klass, void *data)
dc->realize = xilinx_enet_realize;
device_class_set_props(dc, xilinx_enet_properties);
- dc->reset = xilinx_axienet_reset;
+ device_class_set_legacy_reset(dc, xilinx_axienet_reset);
}
static void xilinx_enet_control_stream_class_init(ObjectClass *klass,
diff --git a/hw/net/xilinx_ethlite.c b/hw/net/xilinx_ethlite.c
index 989afaf..bd81290 100644
--- a/hw/net/xilinx_ethlite.c
+++ b/hw/net/xilinx_ethlite.c
@@ -263,7 +263,7 @@ static void xilinx_ethlite_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = xilinx_ethlite_realize;
- dc->reset = xilinx_ethlite_reset;
+ device_class_set_legacy_reset(dc, xilinx_ethlite_reset);
device_class_set_props(dc, xilinx_ethlite_properties);
}
diff --git a/hw/nubus/nubus-device.c b/hw/nubus/nubus-device.c
index be4cb24..26fbcf2 100644
--- a/hw/nubus/nubus-device.c
+++ b/hw/nubus/nubus-device.c
@@ -35,6 +35,13 @@ static void nubus_device_realize(DeviceState *dev, Error **errp)
uint8_t *rom_ptr;
int ret;
+ if (nd->slot < 0 || nd->slot >= NUBUS_SLOT_NB) {
+ error_setg(errp,
+ "'slot' value %d out of range (must be between 0 and %d)",
+ nd->slot, NUBUS_SLOT_NB - 1);
+ return;
+ }
+
/* Super */
slot_offset = nd->slot * NUBUS_SUPER_SLOT_SIZE;
diff --git a/hw/nubus/nubus-virtio-mmio.c b/hw/nubus/nubus-virtio-mmio.c
index 58a63c8..7a98731 100644
--- a/hw/nubus/nubus-virtio-mmio.c
+++ b/hw/nubus/nubus-virtio-mmio.c
@@ -7,6 +7,7 @@
*/
#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "hw/nubus/nubus-virtio-mmio.h"
@@ -23,6 +24,7 @@ static void nubus_virtio_mmio_set_input_irq(void *opaque, int n, int level)
static void nubus_virtio_mmio_realize(DeviceState *dev, Error **errp)
{
+ ERRP_GUARD();
NubusVirtioMMIODeviceClass *nvmdc = NUBUS_VIRTIO_MMIO_GET_CLASS(dev);
NubusVirtioMMIO *s = NUBUS_VIRTIO_MMIO(dev);
NubusDevice *nd = NUBUS_DEVICE(dev);
diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index 5b1b0ca..f4e8920 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -40,6 +40,9 @@
* sriov_vi_flexible=<N[optional]> \
* sriov_max_vi_per_vf=<N[optional]> \
* sriov_max_vq_per_vf=<N[optional]> \
+ * atomic.dn=<on|off[optional]>, \
+ * atomic.awun<N[optional]>, \
+ * atomic.awupf<N[optional]>, \
* subsys=<subsys_id>
* -device nvme-ns,drive=<drive_id>,bus=<bus_name>,nsid=<nsid>,\
* zoned=<true|false[optional]>, \
@@ -203,6 +206,7 @@
#include "sysemu/hostmem.h"
#include "hw/pci/msix.h"
#include "hw/pci/pcie_sriov.h"
+#include "sysemu/spdm-socket.h"
#include "migration/vmstate.h"
#include "nvme.h"
@@ -253,6 +257,7 @@ static const uint32_t nvme_feature_cap[NVME_FID_MAX] = {
[NVME_ERROR_RECOVERY] = NVME_FEAT_CAP_CHANGE | NVME_FEAT_CAP_NS,
[NVME_VOLATILE_WRITE_CACHE] = NVME_FEAT_CAP_CHANGE,
[NVME_NUMBER_OF_QUEUES] = NVME_FEAT_CAP_CHANGE,
+ [NVME_WRITE_ATOMICITY] = NVME_FEAT_CAP_CHANGE,
[NVME_ASYNCHRONOUS_EVENT_CONF] = NVME_FEAT_CAP_CHANGE,
[NVME_TIMESTAMP] = NVME_FEAT_CAP_CHANGE,
[NVME_HOST_BEHAVIOR_SUPPORT] = NVME_FEAT_CAP_CHANGE,
@@ -1648,9 +1653,16 @@ static void nvme_smart_event(NvmeCtrl *n, uint8_t event)
static void nvme_clear_events(NvmeCtrl *n, uint8_t event_type)
{
+ NvmeAsyncEvent *event, *next;
+
n->aer_mask &= ~(1 << event_type);
- if (!QTAILQ_EMPTY(&n->aer_queue)) {
- nvme_process_aers(n);
+
+ QTAILQ_FOREACH_SAFE(event, &n->aer_queue, entry, next) {
+ if (event->result.event_type == event_type) {
+ QTAILQ_REMOVE(&n->aer_queue, event, entry);
+ n->aer_queued--;
+ g_free(event);
+ }
}
}
@@ -1758,6 +1770,10 @@ static void nvme_aio_err(NvmeRequest *req, int ret)
break;
}
+ if (ret == -ECANCELED) {
+ status = NVME_CMD_ABORT_REQ;
+ }
+
trace_pci_nvme_err_aio(nvme_cid(req), strerror(-ret), status);
error_setg_errno(&local_err, -ret, "aio failed");
@@ -1811,7 +1827,7 @@ static uint16_t nvme_check_zone_state_for_write(NvmeZone *zone)
trace_pci_nvme_err_zone_is_read_only(zslba);
return NVME_ZONE_READ_ONLY;
default:
- assert(false);
+ g_assert_not_reached();
}
return NVME_INTERNAL_DEV_ERROR;
@@ -1865,7 +1881,7 @@ static uint16_t nvme_check_zone_state_for_read(NvmeZone *zone)
trace_pci_nvme_err_zone_is_offline(zone->d.zslba);
return NVME_ZONE_OFFLINE;
default:
- assert(false);
+ g_assert_not_reached();
}
return NVME_INTERNAL_DEV_ERROR;
@@ -2591,6 +2607,7 @@ next:
done:
iocb->aiocb = NULL;
iocb->common.cb(iocb->common.opaque, iocb->ret);
+ g_free(iocb->range);
qemu_aio_unref(iocb);
}
@@ -2640,6 +2657,7 @@ static uint16_t nvme_verify(NvmeCtrl *n, NvmeRequest *req)
uint64_t slba = le64_to_cpu(rw->slba);
uint32_t nlb = le16_to_cpu(rw->nlb) + 1;
size_t len = nvme_l2b(ns, nlb);
+ size_t data_len = len;
int64_t offset = nvme_l2b(ns, slba);
uint8_t prinfo = NVME_RW_PRINFO(le16_to_cpu(rw->control));
uint32_t reftag = le32_to_cpu(rw->reftag);
@@ -2659,7 +2677,11 @@ static uint16_t nvme_verify(NvmeCtrl *n, NvmeRequest *req)
}
}
- if (len > n->page_size << n->params.vsl) {
+ if (nvme_ns_ext(ns) && !(NVME_ID_CTRL_CTRATT_MEM(n->id_ctrl.ctratt))) {
+ data_len += nvme_m2b(ns, nlb);
+ }
+
+ if (data_len > (n->page_size << n->params.vsl)) {
return NVME_INVALID_FIELD | NVME_DNR;
}
@@ -2695,6 +2717,7 @@ typedef struct NvmeCopyAIOCB {
BlockAIOCB common;
BlockAIOCB *aiocb;
NvmeRequest *req;
+ NvmeCtrl *n;
int ret;
void *ranges;
@@ -2713,6 +2736,8 @@ typedef struct NvmeCopyAIOCB {
uint64_t slba;
NvmeZone *zone;
+ NvmeNamespace *sns;
+ uint32_t tcl;
} NvmeCopyAIOCB;
static void nvme_copy_cancel(BlockAIOCB *aiocb)
@@ -2759,13 +2784,19 @@ static void nvme_copy_done(NvmeCopyAIOCB *iocb)
static void nvme_do_copy(NvmeCopyAIOCB *iocb);
-static void nvme_copy_source_range_parse_format0(void *ranges, int idx,
- uint64_t *slba, uint32_t *nlb,
- uint16_t *apptag,
- uint16_t *appmask,
- uint64_t *reftag)
+static void nvme_copy_source_range_parse_format0_2(void *ranges,
+ int idx, uint64_t *slba,
+ uint32_t *nlb,
+ uint32_t *snsid,
+ uint16_t *apptag,
+ uint16_t *appmask,
+ uint64_t *reftag)
{
- NvmeCopySourceRangeFormat0 *_ranges = ranges;
+ NvmeCopySourceRangeFormat0_2 *_ranges = ranges;
+
+ if (snsid) {
+ *snsid = le32_to_cpu(_ranges[idx].sparams);
+ }
if (slba) {
*slba = le64_to_cpu(_ranges[idx].slba);
@@ -2788,13 +2819,19 @@ static void nvme_copy_source_range_parse_format0(void *ranges, int idx,
}
}
-static void nvme_copy_source_range_parse_format1(void *ranges, int idx,
- uint64_t *slba, uint32_t *nlb,
- uint16_t *apptag,
- uint16_t *appmask,
- uint64_t *reftag)
+static void nvme_copy_source_range_parse_format1_3(void *ranges, int idx,
+ uint64_t *slba,
+ uint32_t *nlb,
+ uint32_t *snsid,
+ uint16_t *apptag,
+ uint16_t *appmask,
+ uint64_t *reftag)
{
- NvmeCopySourceRangeFormat1 *_ranges = ranges;
+ NvmeCopySourceRangeFormat1_3 *_ranges = ranges;
+
+ if (snsid) {
+ *snsid = le32_to_cpu(_ranges[idx].sparams);
+ }
if (slba) {
*slba = le64_to_cpu(_ranges[idx].slba);
@@ -2826,18 +2863,20 @@ static void nvme_copy_source_range_parse_format1(void *ranges, int idx,
static void nvme_copy_source_range_parse(void *ranges, int idx, uint8_t format,
uint64_t *slba, uint32_t *nlb,
- uint16_t *apptag, uint16_t *appmask,
- uint64_t *reftag)
+ uint32_t *snsid, uint16_t *apptag,
+ uint16_t *appmask, uint64_t *reftag)
{
switch (format) {
case NVME_COPY_FORMAT_0:
- nvme_copy_source_range_parse_format0(ranges, idx, slba, nlb, apptag,
- appmask, reftag);
+ case NVME_COPY_FORMAT_2:
+ nvme_copy_source_range_parse_format0_2(ranges, idx, slba, nlb, snsid,
+ apptag, appmask, reftag);
break;
case NVME_COPY_FORMAT_1:
- nvme_copy_source_range_parse_format1(ranges, idx, slba, nlb, apptag,
- appmask, reftag);
+ case NVME_COPY_FORMAT_3:
+ nvme_copy_source_range_parse_format1_3(ranges, idx, slba, nlb, snsid,
+ apptag, appmask, reftag);
break;
default:
@@ -2853,10 +2892,10 @@ static inline uint16_t nvme_check_copy_mcl(NvmeNamespace *ns,
for (int idx = 0; idx < nr; idx++) {
uint32_t nlb;
nvme_copy_source_range_parse(iocb->ranges, idx, iocb->format, NULL,
- &nlb, NULL, NULL, NULL);
+ &nlb, NULL, NULL, NULL, NULL);
copy_len += nlb;
}
-
+ iocb->tcl = copy_len;
if (copy_len > ns->id_ns.mcl) {
return NVME_CMD_SIZE_LIMIT | NVME_DNR;
}
@@ -2868,11 +2907,11 @@ static void nvme_copy_out_completed_cb(void *opaque, int ret)
{
NvmeCopyAIOCB *iocb = opaque;
NvmeRequest *req = iocb->req;
- NvmeNamespace *ns = req->ns;
+ NvmeNamespace *dns = req->ns;
uint32_t nlb;
nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, NULL,
- &nlb, NULL, NULL, NULL);
+ &nlb, NULL, NULL, NULL, NULL);
if (ret < 0) {
iocb->ret = ret;
@@ -2881,8 +2920,8 @@ static void nvme_copy_out_completed_cb(void *opaque, int ret)
goto out;
}
- if (ns->params.zoned) {
- nvme_advance_zone_wp(ns, iocb->zone, nlb);
+ if (dns->params.zoned) {
+ nvme_advance_zone_wp(dns, iocb->zone, nlb);
}
iocb->idx++;
@@ -2895,25 +2934,25 @@ static void nvme_copy_out_cb(void *opaque, int ret)
{
NvmeCopyAIOCB *iocb = opaque;
NvmeRequest *req = iocb->req;
- NvmeNamespace *ns = req->ns;
+ NvmeNamespace *dns = req->ns;
uint32_t nlb;
size_t mlen;
uint8_t *mbounce;
- if (ret < 0 || iocb->ret < 0 || !ns->lbaf.ms) {
+ if (ret < 0 || iocb->ret < 0 || !dns->lbaf.ms) {
goto out;
}
nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, NULL,
- &nlb, NULL, NULL, NULL);
+ &nlb, NULL, NULL, NULL, NULL);
- mlen = nvme_m2b(ns, nlb);
- mbounce = iocb->bounce + nvme_l2b(ns, nlb);
+ mlen = nvme_m2b(dns, nlb);
+ mbounce = iocb->bounce + nvme_l2b(dns, nlb);
qemu_iovec_reset(&iocb->iov);
qemu_iovec_add(&iocb->iov, mbounce, mlen);
- iocb->aiocb = blk_aio_pwritev(ns->blkconf.blk, nvme_moff(ns, iocb->slba),
+ iocb->aiocb = blk_aio_pwritev(dns->blkconf.blk, nvme_moff(dns, iocb->slba),
&iocb->iov, 0, nvme_copy_out_completed_cb,
iocb);
@@ -2927,12 +2966,15 @@ static void nvme_copy_in_completed_cb(void *opaque, int ret)
{
NvmeCopyAIOCB *iocb = opaque;
NvmeRequest *req = iocb->req;
- NvmeNamespace *ns = req->ns;
+ NvmeNamespace *sns = iocb->sns;
+ NvmeNamespace *dns = req->ns;
+ NvmeCopyCmd *copy = NULL;
+ uint8_t *mbounce = NULL;
uint32_t nlb;
uint64_t slba;
uint16_t apptag, appmask;
uint64_t reftag;
- size_t len;
+ size_t len, mlen;
uint16_t status;
if (ret < 0) {
@@ -2943,43 +2985,51 @@ static void nvme_copy_in_completed_cb(void *opaque, int ret)
}
nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, &slba,
- &nlb, &apptag, &appmask, &reftag);
- len = nvme_l2b(ns, nlb);
+ &nlb, NULL, &apptag, &appmask, &reftag);
trace_pci_nvme_copy_out(iocb->slba, nlb);
- if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) {
- NvmeCopyCmd *copy = (NvmeCopyCmd *)&req->cmd;
+ len = nvme_l2b(sns, nlb);
+
+ if (NVME_ID_NS_DPS_TYPE(sns->id_ns.dps)) {
+ copy = (NvmeCopyCmd *)&req->cmd;
uint16_t prinfor = ((copy->control[0] >> 4) & 0xf);
- uint16_t prinfow = ((copy->control[2] >> 2) & 0xf);
- size_t mlen = nvme_m2b(ns, nlb);
- uint8_t *mbounce = iocb->bounce + nvme_l2b(ns, nlb);
+ mlen = nvme_m2b(sns, nlb);
+ mbounce = iocb->bounce + nvme_l2b(sns, nlb);
- status = nvme_dif_mangle_mdata(ns, mbounce, mlen, slba);
+ status = nvme_dif_mangle_mdata(sns, mbounce, mlen, slba);
if (status) {
goto invalid;
}
- status = nvme_dif_check(ns, iocb->bounce, len, mbounce, mlen, prinfor,
+ status = nvme_dif_check(sns, iocb->bounce, len, mbounce, mlen, prinfor,
slba, apptag, appmask, &reftag);
if (status) {
goto invalid;
}
+ }
+
+ if (NVME_ID_NS_DPS_TYPE(dns->id_ns.dps)) {
+ copy = (NvmeCopyCmd *)&req->cmd;
+ uint16_t prinfow = ((copy->control[2] >> 2) & 0xf);
+
+ mlen = nvme_m2b(dns, nlb);
+ mbounce = iocb->bounce + nvme_l2b(dns, nlb);
apptag = le16_to_cpu(copy->apptag);
appmask = le16_to_cpu(copy->appmask);
if (prinfow & NVME_PRINFO_PRACT) {
- status = nvme_check_prinfo(ns, prinfow, iocb->slba, iocb->reftag);
+ status = nvme_check_prinfo(dns, prinfow, iocb->slba, iocb->reftag);
if (status) {
goto invalid;
}
- nvme_dif_pract_generate_dif(ns, iocb->bounce, len, mbounce, mlen,
+ nvme_dif_pract_generate_dif(dns, iocb->bounce, len, mbounce, mlen,
apptag, &iocb->reftag);
} else {
- status = nvme_dif_check(ns, iocb->bounce, len, mbounce, mlen,
+ status = nvme_dif_check(dns, iocb->bounce, len, mbounce, mlen,
prinfow, iocb->slba, apptag, appmask,
&iocb->reftag);
if (status) {
@@ -2988,13 +3038,13 @@ static void nvme_copy_in_completed_cb(void *opaque, int ret)
}
}
- status = nvme_check_bounds(ns, iocb->slba, nlb);
+ status = nvme_check_bounds(dns, iocb->slba, nlb);
if (status) {
goto invalid;
}
- if (ns->params.zoned) {
- status = nvme_check_zone_write(ns, iocb->zone, iocb->slba, nlb);
+ if (dns->params.zoned) {
+ status = nvme_check_zone_write(dns, iocb->zone, iocb->slba, nlb);
if (status) {
goto invalid;
}
@@ -3007,7 +3057,10 @@ static void nvme_copy_in_completed_cb(void *opaque, int ret)
qemu_iovec_reset(&iocb->iov);
qemu_iovec_add(&iocb->iov, iocb->bounce, len);
- iocb->aiocb = blk_aio_pwritev(ns->blkconf.blk, nvme_l2b(ns, iocb->slba),
+ block_acct_start(blk_get_stats(dns->blkconf.blk), &iocb->acct.write, 0,
+ BLOCK_ACCT_WRITE);
+
+ iocb->aiocb = blk_aio_pwritev(dns->blkconf.blk, nvme_l2b(dns, iocb->slba),
&iocb->iov, 0, nvme_copy_out_cb, iocb);
return;
@@ -3022,23 +3075,22 @@ out:
static void nvme_copy_in_cb(void *opaque, int ret)
{
NvmeCopyAIOCB *iocb = opaque;
- NvmeRequest *req = iocb->req;
- NvmeNamespace *ns = req->ns;
+ NvmeNamespace *sns = iocb->sns;
uint64_t slba;
uint32_t nlb;
- if (ret < 0 || iocb->ret < 0 || !ns->lbaf.ms) {
+ if (ret < 0 || iocb->ret < 0 || !sns->lbaf.ms) {
goto out;
}
nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, &slba,
- &nlb, NULL, NULL, NULL);
+ &nlb, NULL, NULL, NULL, NULL);
qemu_iovec_reset(&iocb->iov);
- qemu_iovec_add(&iocb->iov, iocb->bounce + nvme_l2b(ns, nlb),
- nvme_m2b(ns, nlb));
+ qemu_iovec_add(&iocb->iov, iocb->bounce + nvme_l2b(sns, nlb),
+ nvme_m2b(sns, nlb));
- iocb->aiocb = blk_aio_preadv(ns->blkconf.blk, nvme_moff(ns, slba),
+ iocb->aiocb = blk_aio_preadv(sns->blkconf.blk, nvme_moff(sns, slba),
&iocb->iov, 0, nvme_copy_in_completed_cb,
iocb);
return;
@@ -3047,14 +3099,78 @@ out:
nvme_copy_in_completed_cb(iocb, ret);
}
+static inline bool nvme_csi_supports_copy(uint8_t csi)
+{
+ return csi == NVME_CSI_NVM || csi == NVME_CSI_ZONED;
+}
+
+static inline bool nvme_copy_ns_format_match(NvmeNamespace *sns,
+ NvmeNamespace *dns)
+{
+ return sns->lbaf.ds == dns->lbaf.ds && sns->lbaf.ms == dns->lbaf.ms;
+}
+
+static bool nvme_copy_matching_ns_format(NvmeNamespace *sns, NvmeNamespace *dns,
+ bool pi_enable)
+{
+ if (!nvme_csi_supports_copy(sns->csi) ||
+ !nvme_csi_supports_copy(dns->csi)) {
+ return false;
+ }
+
+ if (!pi_enable && !nvme_copy_ns_format_match(sns, dns)) {
+ return false;
+ }
+
+ if (pi_enable && (!nvme_copy_ns_format_match(sns, dns) ||
+ sns->id_ns.dps != dns->id_ns.dps)) {
+ return false;
+ }
+
+ return true;
+}
+
+static inline bool nvme_copy_corresp_pi_match(NvmeNamespace *sns,
+ NvmeNamespace *dns)
+{
+ return sns->lbaf.ms == 0 &&
+ ((dns->lbaf.ms == 8 && dns->pif == 0) ||
+ (dns->lbaf.ms == 16 && dns->pif == 1));
+}
+
+static bool nvme_copy_corresp_pi_format(NvmeNamespace *sns, NvmeNamespace *dns,
+ bool sns_pi_en)
+{
+ if (!nvme_csi_supports_copy(sns->csi) ||
+ !nvme_csi_supports_copy(dns->csi)) {
+ return false;
+ }
+
+ if (!sns_pi_en && !nvme_copy_corresp_pi_match(sns, dns)) {
+ return false;
+ }
+
+ if (sns_pi_en && !nvme_copy_corresp_pi_match(dns, sns)) {
+ return false;
+ }
+
+ return true;
+}
+
static void nvme_do_copy(NvmeCopyAIOCB *iocb)
{
NvmeRequest *req = iocb->req;
- NvmeNamespace *ns = req->ns;
+ NvmeNamespace *sns;
+ NvmeNamespace *dns = req->ns;
+ NvmeCopyCmd *copy = (NvmeCopyCmd *)&req->cmd;
+ uint16_t prinfor = ((copy->control[0] >> 4) & 0xf);
+ uint16_t prinfow = ((copy->control[2] >> 2) & 0xf);
uint64_t slba;
uint32_t nlb;
size_t len;
uint16_t status;
+ uint32_t dnsid = le32_to_cpu(req->cmd.nsid);
+ uint32_t snsid = dnsid;
if (iocb->ret < 0) {
goto done;
@@ -3064,40 +3180,124 @@ static void nvme_do_copy(NvmeCopyAIOCB *iocb)
goto done;
}
- nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, &slba,
- &nlb, NULL, NULL, NULL);
- len = nvme_l2b(ns, nlb);
+ if (iocb->format == 2 || iocb->format == 3) {
+ nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format,
+ &slba, &nlb, &snsid, NULL, NULL, NULL);
+ if (snsid != dnsid) {
+ if (snsid == NVME_NSID_BROADCAST ||
+ !nvme_nsid_valid(iocb->n, snsid)) {
+ status = NVME_INVALID_NSID | NVME_DNR;
+ goto invalid;
+ }
+ iocb->sns = nvme_ns(iocb->n, snsid);
+ if (unlikely(!iocb->sns)) {
+ status = NVME_INVALID_FIELD | NVME_DNR;
+ goto invalid;
+ }
+ } else {
+ if (((slba + nlb) > iocb->slba) &&
+ ((slba + nlb) < (iocb->slba + iocb->tcl))) {
+ status = NVME_CMD_OVERLAP_IO_RANGE | NVME_DNR;
+ goto invalid;
+ }
+ }
+ } else {
+ nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format,
+ &slba, &nlb, NULL, NULL, NULL, NULL);
+ }
+
+ sns = iocb->sns;
+ if ((snsid == dnsid) && NVME_ID_NS_DPS_TYPE(sns->id_ns.dps) &&
+ ((prinfor & NVME_PRINFO_PRACT) != (prinfow & NVME_PRINFO_PRACT))) {
+ status = NVME_INVALID_FIELD | NVME_DNR;
+ goto invalid;
+ } else if (snsid != dnsid) {
+ if (!NVME_ID_NS_DPS_TYPE(sns->id_ns.dps) &&
+ !NVME_ID_NS_DPS_TYPE(dns->id_ns.dps)) {
+ if (!nvme_copy_matching_ns_format(sns, dns, false)) {
+ status = NVME_CMD_INCOMP_NS_OR_FMT | NVME_DNR;
+ goto invalid;
+ }
+ }
+ if (NVME_ID_NS_DPS_TYPE(sns->id_ns.dps) &&
+ NVME_ID_NS_DPS_TYPE(dns->id_ns.dps)) {
+ if ((prinfor & NVME_PRINFO_PRACT) !=
+ (prinfow & NVME_PRINFO_PRACT)) {
+ status = NVME_CMD_INCOMP_NS_OR_FMT | NVME_DNR;
+ goto invalid;
+ } else {
+ if (!nvme_copy_matching_ns_format(sns, dns, true)) {
+ status = NVME_CMD_INCOMP_NS_OR_FMT | NVME_DNR;
+ goto invalid;
+ }
+ }
+ }
+
+ if (!NVME_ID_NS_DPS_TYPE(sns->id_ns.dps) &&
+ NVME_ID_NS_DPS_TYPE(dns->id_ns.dps)) {
+ if (!(prinfow & NVME_PRINFO_PRACT)) {
+ status = NVME_CMD_INCOMP_NS_OR_FMT | NVME_DNR;
+ goto invalid;
+ } else {
+ if (!nvme_copy_corresp_pi_format(sns, dns, false)) {
+ status = NVME_CMD_INCOMP_NS_OR_FMT | NVME_DNR;
+ goto invalid;
+ }
+ }
+ }
+
+ if (NVME_ID_NS_DPS_TYPE(sns->id_ns.dps) &&
+ !NVME_ID_NS_DPS_TYPE(dns->id_ns.dps)) {
+ if (!(prinfor & NVME_PRINFO_PRACT)) {
+ status = NVME_CMD_INCOMP_NS_OR_FMT | NVME_DNR;
+ goto invalid;
+ } else {
+ if (!nvme_copy_corresp_pi_format(sns, dns, true)) {
+ status = NVME_CMD_INCOMP_NS_OR_FMT | NVME_DNR;
+ goto invalid;
+ }
+ }
+ }
+ }
+ len = nvme_l2b(sns, nlb);
trace_pci_nvme_copy_source_range(slba, nlb);
- if (nlb > le16_to_cpu(ns->id_ns.mssrl)) {
+ if (nlb > le16_to_cpu(sns->id_ns.mssrl)) {
status = NVME_CMD_SIZE_LIMIT | NVME_DNR;
goto invalid;
}
- status = nvme_check_bounds(ns, slba, nlb);
+ status = nvme_check_bounds(sns, slba, nlb);
if (status) {
goto invalid;
}
- if (NVME_ERR_REC_DULBE(ns->features.err_rec)) {
- status = nvme_check_dulbe(ns, slba, nlb);
+ if (NVME_ERR_REC_DULBE(sns->features.err_rec)) {
+ status = nvme_check_dulbe(sns, slba, nlb);
if (status) {
goto invalid;
}
}
- if (ns->params.zoned) {
- status = nvme_check_zone_read(ns, slba, nlb);
+ if (sns->params.zoned) {
+ status = nvme_check_zone_read(sns, slba, nlb);
if (status) {
goto invalid;
}
}
+ g_free(iocb->bounce);
+ iocb->bounce = g_malloc_n(le16_to_cpu(sns->id_ns.mssrl),
+ sns->lbasz + sns->lbaf.ms);
+
qemu_iovec_reset(&iocb->iov);
qemu_iovec_add(&iocb->iov, iocb->bounce, len);
- iocb->aiocb = blk_aio_preadv(ns->blkconf.blk, nvme_l2b(ns, slba),
+ block_acct_start(blk_get_stats(sns->blkconf.blk), &iocb->acct.read, 0,
+ BLOCK_ACCT_READ);
+
+ iocb->aiocb = blk_aio_preadv(sns->blkconf.blk, nvme_l2b(sns, slba),
&iocb->iov, 0, nvme_copy_in_cb, iocb);
return;
@@ -3116,9 +3316,7 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req)
nvme_misc_cb, req);
uint16_t nr = copy->nr + 1;
uint8_t format = copy->control[0] & 0xf;
- uint16_t prinfor = ((copy->control[0] >> 4) & 0xf);
- uint16_t prinfow = ((copy->control[2] >> 2) & 0xf);
- size_t len = sizeof(NvmeCopySourceRangeFormat0);
+ size_t len = sizeof(NvmeCopySourceRangeFormat0_2);
uint16_t status;
@@ -3127,13 +3325,9 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req)
iocb->ranges = NULL;
iocb->zone = NULL;
- if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps) &&
- ((prinfor & NVME_PRINFO_PRACT) != (prinfow & NVME_PRINFO_PRACT))) {
- status = NVME_INVALID_FIELD | NVME_DNR;
- goto invalid;
- }
-
- if (!(n->id_ctrl.ocfs & (1 << format))) {
+ if (!(n->id_ctrl.ocfs & (1 << format)) ||
+ ((format == 2 || format == 3) &&
+ !(n->features.hbs.cdfe & (1 << format)))) {
trace_pci_nvme_err_copy_invalid_format(format);
status = NVME_INVALID_FIELD | NVME_DNR;
goto invalid;
@@ -3144,14 +3338,14 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req)
goto invalid;
}
- if ((ns->pif == 0x0 && format != 0x0) ||
- (ns->pif != 0x0 && format != 0x1)) {
+ if ((ns->pif == 0x0 && (format != 0x0 && format != 0x2)) ||
+ (ns->pif != 0x0 && (format != 0x1 && format != 0x3))) {
status = NVME_INVALID_FORMAT | NVME_DNR;
goto invalid;
}
if (ns->pif) {
- len = sizeof(NvmeCopySourceRangeFormat1);
+ len = sizeof(NvmeCopySourceRangeFormat1_3);
}
iocb->format = format;
@@ -3187,17 +3381,13 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req)
iocb->idx = 0;
iocb->reftag = le32_to_cpu(copy->reftag);
iocb->reftag |= (uint64_t)le32_to_cpu(copy->cdw3) << 32;
- iocb->bounce = g_malloc_n(le16_to_cpu(ns->id_ns.mssrl),
- ns->lbasz + ns->lbaf.ms);
qemu_iovec_init(&iocb->iov, 1);
- block_acct_start(blk_get_stats(ns->blkconf.blk), &iocb->acct.read, 0,
- BLOCK_ACCT_READ);
- block_acct_start(blk_get_stats(ns->blkconf.blk), &iocb->acct.write, 0,
- BLOCK_ACCT_WRITE);
-
req->aiocb = &iocb->common;
+ iocb->sns = req->ns;
+ iocb->n = n;
+ iocb->bounce = NULL;
nvme_do_copy(iocb);
return NVME_NO_COMPLETE;
@@ -3232,7 +3422,11 @@ static uint16_t nvme_compare(NvmeCtrl *n, NvmeRequest *req)
len += nvme_m2b(ns, nlb);
}
- status = nvme_check_mdts(n, len);
+ if (NVME_ID_CTRL_CTRATT_MEM(n->id_ctrl.ctratt)) {
+ status = nvme_check_mdts(n, data_len);
+ } else {
+ status = nvme_check_mdts(n, len);
+ }
if (status) {
return status;
}
@@ -3409,7 +3603,7 @@ static uint16_t nvme_read(NvmeCtrl *n, NvmeRequest *req)
BlockBackend *blk = ns->blkconf.blk;
uint16_t status;
- if (nvme_ns_ext(ns)) {
+ if (nvme_ns_ext(ns) && !(NVME_ID_CTRL_CTRATT_MEM(n->id_ctrl.ctratt))) {
mapped_size += nvme_m2b(ns, nlb);
if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) {
@@ -3521,7 +3715,7 @@ static uint16_t nvme_do_write(NvmeCtrl *n, NvmeRequest *req, bool append,
BlockBackend *blk = ns->blkconf.blk;
uint16_t status;
- if (nvme_ns_ext(ns)) {
+ if (nvme_ns_ext(ns) && !(NVME_ID_CTRL_CTRATT_MEM(n->id_ctrl.ctratt))) {
mapped_size += nvme_m2b(ns, nlb);
if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) {
@@ -4167,7 +4361,7 @@ static bool nvme_zone_matches_filter(uint32_t zafs, NvmeZone *zl)
static uint16_t nvme_zone_mgmt_recv(NvmeCtrl *n, NvmeRequest *req)
{
- NvmeCmd *cmd = (NvmeCmd *)&req->cmd;
+ NvmeCmd *cmd = &req->cmd;
NvmeNamespace *ns = req->ns;
/* cdw12 is zero-based number of dwords to return. Convert to bytes */
uint32_t data_size = (le32_to_cpu(cmd->cdw12) + 1) << 2;
@@ -4300,7 +4494,7 @@ static uint16_t nvme_io_mgmt_recv_ruhs(NvmeCtrl *n, NvmeRequest *req,
nruhsd = ns->fdp.nphs * endgrp->fdp.nrg;
trans_len = sizeof(NvmeRuhStatus) + nruhsd * sizeof(NvmeRuhStatusDescr);
- buf = g_malloc(trans_len);
+ buf = g_malloc0(trans_len);
trans_len = MIN(trans_len, len);
@@ -4406,10 +4600,6 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req)
trace_pci_nvme_io_cmd(nvme_cid(req), nsid, nvme_sqid(req),
req->cmd.opcode, nvme_io_opc_str(req->cmd.opcode));
- if (!nvme_nsid_valid(n, nsid)) {
- return NVME_INVALID_NSID | NVME_DNR;
- }
-
/*
* In the base NVM command set, Flush may apply to all namespaces
* (indicated by NSID being set to FFFFFFFFh). But if that feature is used
@@ -4429,10 +4619,15 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req)
* device only supports namespace types that includes the NVM Flush command
* (NVM and Zoned), so always do an NVM Flush.
*/
+
if (req->cmd.opcode == NVME_CMD_FLUSH) {
return nvme_flush(n, req);
}
+ if (!nvme_nsid_valid(n, nsid) || nsid == NVME_NSID_BROADCAST) {
+ return NVME_INVALID_NSID | NVME_DNR;
+ }
+
ns = nvme_ns(n, nsid);
if (unlikely(!ns)) {
return NVME_INVALID_FIELD | NVME_DNR;
@@ -4479,7 +4674,7 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req)
case NVME_CMD_IO_MGMT_SEND:
return nvme_io_mgmt_send(n, req);
default:
- assert(false);
+ g_assert_not_reached();
}
return NVME_INVALID_OPCODE | NVME_DNR;
@@ -5780,12 +5975,40 @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeRequest *req)
static uint16_t nvme_abort(NvmeCtrl *n, NvmeRequest *req)
{
uint16_t sqid = le32_to_cpu(req->cmd.cdw10) & 0xffff;
+ uint16_t cid = (le32_to_cpu(req->cmd.cdw10) >> 16) & 0xffff;
+ NvmeSQueue *sq = n->sq[sqid];
+ NvmeRequest *r, *next;
+ int i;
req->cqe.result = 1;
if (nvme_check_sqid(n, sqid)) {
return NVME_INVALID_FIELD | NVME_DNR;
}
+ if (sqid == 0) {
+ for (i = 0; i < n->outstanding_aers; i++) {
+ NvmeRequest *re = n->aer_reqs[i];
+ if (re->cqe.cid == cid) {
+ memmove(n->aer_reqs + i, n->aer_reqs + i + 1,
+ (n->outstanding_aers - i - 1) * sizeof(NvmeRequest *));
+ n->outstanding_aers--;
+ re->status = NVME_CMD_ABORT_REQ;
+ req->cqe.result = 0;
+ nvme_enqueue_req_completion(&n->admin_cq, re);
+ return NVME_SUCCESS;
+ }
+ }
+ }
+
+ QTAILQ_FOREACH_SAFE(r, &sq->out_req_list, entry, next) {
+ if (r->cqe.cid == cid) {
+ if (r->aiocb) {
+ blk_aio_cancel_async(r->aiocb);
+ }
+ break;
+ }
+ }
+
return NVME_SUCCESS;
}
@@ -6090,8 +6313,10 @@ defaults:
if (ret) {
return ret;
}
- goto out;
+ break;
+ case NVME_WRITE_ATOMICITY:
+ result = n->dn;
break;
default:
result = nvme_feature_default[fid];
@@ -6175,6 +6400,8 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req)
uint8_t save = NVME_SETFEAT_SAVE(dw10);
uint16_t status;
int i;
+ NvmeIdCtrl *id = &n->id_ctrl;
+ NvmeAtomic *atomic = &n->atomic;
trace_pci_nvme_setfeat(nvme_cid(req), nsid, fid, save, dw11);
@@ -6327,6 +6554,22 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req)
return NVME_CMD_SEQ_ERROR | NVME_DNR;
case NVME_FDP_EVENTS:
return nvme_set_feature_fdp_events(n, ns, req);
+ case NVME_WRITE_ATOMICITY:
+
+ n->dn = 0x1 & dw11;
+
+ if (n->dn) {
+ atomic->atomic_max_write_size = le16_to_cpu(id->awupf) + 1;
+ } else {
+ atomic->atomic_max_write_size = le16_to_cpu(id->awun) + 1;
+ }
+
+ if (atomic->atomic_max_write_size == 1) {
+ atomic->atomic_writes = 0;
+ } else {
+ atomic->atomic_writes = 1;
+ }
+ break;
default:
return NVME_FEAT_NOT_CHANGEABLE | NVME_DNR;
}
@@ -7002,7 +7245,7 @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeRequest *req)
case NVME_ADM_CMD_DIRECTIVE_RECV:
return nvme_directive_receive(n, req);
default:
- assert(false);
+ g_assert_not_reached();
}
return NVME_INVALID_OPCODE | NVME_DNR;
@@ -7024,6 +7267,81 @@ static void nvme_update_sq_tail(NvmeSQueue *sq)
trace_pci_nvme_update_sq_tail(sq->sqid, sq->tail);
}
+#define NVME_ATOMIC_NO_START 0
+#define NVME_ATOMIC_START_ATOMIC 1
+#define NVME_ATOMIC_START_NONATOMIC 2
+
+static int nvme_atomic_write_check(NvmeCtrl *n, NvmeCmd *cmd,
+ NvmeAtomic *atomic)
+{
+ NvmeRwCmd *rw = (NvmeRwCmd *)cmd;
+ uint64_t slba = le64_to_cpu(rw->slba);
+ uint32_t nlb = (uint32_t)le16_to_cpu(rw->nlb);
+ uint64_t elba = slba + nlb;
+ bool cmd_atomic_wr = true;
+ int i;
+
+ if ((cmd->opcode == NVME_CMD_READ) || ((cmd->opcode == NVME_CMD_WRITE) &&
+ ((rw->nlb + 1) > atomic->atomic_max_write_size))) {
+ cmd_atomic_wr = false;
+ }
+
+ /*
+ * Walk the queues to see if there are any atomic conflicts.
+ */
+ for (i = 1; i < n->params.max_ioqpairs + 1; i++) {
+ NvmeSQueue *sq;
+ NvmeRequest *req;
+ NvmeRwCmd *req_rw;
+ uint64_t req_slba;
+ uint32_t req_nlb;
+ uint64_t req_elba;
+
+ sq = n->sq[i];
+ if (!sq) {
+ continue;
+ }
+
+ /*
+ * Walk all the requests on a given queue.
+ */
+ QTAILQ_FOREACH(req, &sq->out_req_list, entry) {
+ req_rw = (NvmeRwCmd *)&req->cmd;
+
+ if (((req_rw->opcode == NVME_CMD_WRITE) ||
+ (req_rw->opcode == NVME_CMD_READ)) &&
+ (cmd->nsid == req->ns->params.nsid)) {
+ req_slba = le64_to_cpu(req_rw->slba);
+ req_nlb = (uint32_t)le16_to_cpu(req_rw->nlb);
+ req_elba = req_slba + req_nlb;
+
+ if (cmd_atomic_wr) {
+ if ((elba >= req_slba) && (slba <= req_elba)) {
+ return NVME_ATOMIC_NO_START;
+ }
+ } else {
+ if (req->atomic_write && ((elba >= req_slba) &&
+ (slba <= req_elba))) {
+ return NVME_ATOMIC_NO_START;
+ }
+ }
+ }
+ }
+ }
+ if (cmd_atomic_wr) {
+ return NVME_ATOMIC_START_ATOMIC;
+ }
+ return NVME_ATOMIC_START_NONATOMIC;
+}
+
+static NvmeAtomic *nvme_get_atomic(NvmeCtrl *n, NvmeCmd *cmd)
+{
+ if (n->atomic.atomic_writes) {
+ return &n->atomic;
+ }
+ return NULL;
+}
+
static void nvme_process_sq(void *opaque)
{
NvmeSQueue *sq = opaque;
@@ -7040,6 +7358,9 @@ static void nvme_process_sq(void *opaque)
}
while (!(nvme_sq_empty(sq) || QTAILQ_EMPTY(&sq->req_list))) {
+ NvmeAtomic *atomic;
+ bool cmd_is_atomic;
+
addr = sq->dma_addr + (sq->head << NVME_SQES);
if (nvme_addr_read(n, addr, (void *)&cmd, sizeof(cmd))) {
trace_pci_nvme_err_addr_read(addr);
@@ -7047,6 +7368,26 @@ static void nvme_process_sq(void *opaque)
stl_le_p(&n->bar.csts, NVME_CSTS_FAILED);
break;
}
+
+ atomic = nvme_get_atomic(n, &cmd);
+
+ cmd_is_atomic = false;
+ if (sq->sqid && atomic) {
+ int ret;
+
+ ret = nvme_atomic_write_check(n, &cmd, atomic);
+ switch (ret) {
+ case NVME_ATOMIC_NO_START:
+ qemu_bh_schedule(sq->bh);
+ return;
+ case NVME_ATOMIC_START_ATOMIC:
+ cmd_is_atomic = true;
+ break;
+ case NVME_ATOMIC_START_NONATOMIC:
+ default:
+ break;
+ }
+ }
nvme_inc_sq_head(sq);
req = QTAILQ_FIRST(&sq->req_list);
@@ -7056,6 +7397,10 @@ static void nvme_process_sq(void *opaque)
req->cqe.cid = cmd.cid;
memcpy(&req->cmd, &cmd, sizeof(NvmeCmd));
+ if (sq->sqid && atomic) {
+ req->atomic_write = cmd_is_atomic;
+ }
+
status = sq->sqid ? nvme_io_cmd(n, req) :
nvme_admin_cmd(n, req);
if (status != NVME_NO_COMPLETE) {
@@ -7159,6 +7504,8 @@ static void nvme_ctrl_reset(NvmeCtrl *n, NvmeResetType rst)
n->outstanding_aers = 0;
n->qs_created = false;
+ n->dn = n->params.atomic_dn; /* Set Disable Normal */
+
nvme_update_msixcap_ts(pci_dev, n->conf_msix_qsize);
if (pci_is_vf(pci_dev)) {
@@ -7935,6 +8282,8 @@ static void nvme_init_state(NvmeCtrl *n)
NvmeSecCtrlEntry *list = n->sec_ctrl_list;
NvmeSecCtrlEntry *sctrl;
PCIDevice *pci = PCI_DEVICE(n);
+ NvmeAtomic *atomic = &n->atomic;
+ NvmeIdCtrl *id = &n->id_ctrl;
uint8_t max_vfs;
int i;
@@ -7992,6 +8341,29 @@ static void nvme_init_state(NvmeCtrl *n)
cpu_to_le16(n->params.sriov_max_vi_per_vf) :
cap->vifrt / MAX(max_vfs, 1);
}
+
+ /* Atomic Write */
+ id->awun = cpu_to_le16(n->params.atomic_awun);
+ id->awupf = cpu_to_le16(n->params.atomic_awupf);
+ n->dn = n->params.atomic_dn;
+
+ if (id->awun || id->awupf) {
+ if (id->awupf > id->awun) {
+ id->awupf = 0;
+ }
+
+ if (n->dn) {
+ atomic->atomic_max_write_size = id->awupf + 1;
+ } else {
+ atomic->atomic_max_write_size = id->awun + 1;
+ }
+
+ if (atomic->atomic_max_write_size == 1) {
+ atomic->atomic_writes = 0;
+ } else {
+ atomic->atomic_writes = 1;
+ }
+ }
}
static void nvme_init_cmb(NvmeCtrl *n, PCIDevice *pci_dev)
@@ -8068,8 +8440,7 @@ out:
return pow2ceil(bar_size);
}
-static bool nvme_init_sriov(NvmeCtrl *n, PCIDevice *pci_dev, uint16_t offset,
- Error **errp)
+static void nvme_init_sriov(NvmeCtrl *n, PCIDevice *pci_dev, uint16_t offset)
{
uint16_t vf_dev_id = n->params.use_intel_id ?
PCI_DEVICE_ID_INTEL_NVME : PCI_DEVICE_ID_REDHAT_NVME;
@@ -8078,17 +8449,12 @@ static bool nvme_init_sriov(NvmeCtrl *n, PCIDevice *pci_dev, uint16_t offset,
le16_to_cpu(cap->vifrsm),
NULL, NULL);
- if (!pcie_sriov_pf_init(pci_dev, offset, "nvme", vf_dev_id,
- n->params.sriov_max_vfs, n->params.sriov_max_vfs,
- NVME_VF_OFFSET, NVME_VF_STRIDE,
- errp)) {
- return false;
- }
+ pcie_sriov_pf_init(pci_dev, offset, "nvme", vf_dev_id,
+ n->params.sriov_max_vfs, n->params.sriov_max_vfs,
+ NVME_VF_OFFSET, NVME_VF_STRIDE);
pcie_sriov_pf_init_vf_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY |
PCI_BASE_ADDRESS_MEM_TYPE_64, bar_size);
-
- return true;
}
static int nvme_add_pm_capability(PCIDevice *pci_dev, uint8_t offset)
@@ -8113,6 +8479,27 @@ static int nvme_add_pm_capability(PCIDevice *pci_dev, uint8_t offset)
return 0;
}
+static bool pcie_doe_spdm_rsp(DOECap *doe_cap)
+{
+ void *req = pcie_doe_get_write_mbox_ptr(doe_cap);
+ uint32_t req_len = pcie_doe_get_obj_len(req) * 4;
+ void *rsp = doe_cap->read_mbox;
+ uint32_t rsp_len = SPDM_SOCKET_MAX_MESSAGE_BUFFER_SIZE;
+
+ uint32_t recvd = spdm_socket_rsp(doe_cap->spdm_socket,
+ SPDM_SOCKET_TRANSPORT_TYPE_PCI_DOE,
+ req, req_len, rsp, rsp_len);
+ doe_cap->read_mbox_len += DIV_ROUND_UP(recvd, 4);
+
+ return recvd != 0;
+}
+
+static DOEProtocol doe_spdm_prot[] = {
+ { PCI_VENDOR_ID_PCI_SIG, PCI_SIG_DOE_CMA, pcie_doe_spdm_rsp },
+ { PCI_VENDOR_ID_PCI_SIG, PCI_SIG_DOE_SECURED_CMA, pcie_doe_spdm_rsp },
+ { }
+};
+
static bool nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
{
ERRP_GUARD();
@@ -8192,14 +8579,27 @@ static bool nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
return false;
}
- if (!pci_is_vf(pci_dev) && n->params.sriov_max_vfs &&
- !nvme_init_sriov(n, pci_dev, 0x120, errp)) {
- msix_uninit(pci_dev, &n->bar0, &n->bar0);
- return false;
- }
-
nvme_update_msixcap_ts(pci_dev, n->conf_msix_qsize);
+ pcie_cap_deverr_init(pci_dev);
+
+ /* DOE Initialisation */
+ if (pci_dev->spdm_port) {
+ uint16_t doe_offset = n->params.sriov_max_vfs ?
+ PCI_CONFIG_SPACE_SIZE + PCI_ARI_SIZEOF
+ : PCI_CONFIG_SPACE_SIZE;
+
+ pcie_doe_init(pci_dev, &pci_dev->doe_spdm, doe_offset,
+ doe_spdm_prot, true, 0);
+
+ pci_dev->doe_spdm.spdm_socket = spdm_socket_connect(pci_dev->spdm_port,
+ errp);
+
+ if (pci_dev->doe_spdm.spdm_socket < 0) {
+ return false;
+ }
+ }
+
if (n->params.cmb_size_mb) {
nvme_init_cmb(n, pci_dev);
}
@@ -8208,6 +8608,10 @@ static bool nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
nvme_init_pmr(n, pci_dev);
}
+ if (!pci_is_vf(pci_dev) && n->params.sriov_max_vfs) {
+ nvme_init_sriov(n, pci_dev, 0x120);
+ }
+
return true;
}
@@ -8241,7 +8645,11 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
id->cntlid = cpu_to_le16(n->cntlid);
id->oaes = cpu_to_le32(NVME_OAES_NS_ATTR);
+
ctratt = NVME_CTRATT_ELBAS;
+ if (n->params.ctratt.mem) {
+ ctratt |= NVME_CTRATT_MEM;
+ }
id->rab = 6;
@@ -8287,7 +8695,8 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
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);
+ NVME_ONCS_COMPARE | NVME_ONCS_COPY |
+ NVME_ONCS_NVMCSA | NVME_ONCS_NVMAFC);
/*
* NOTE: If this device ever supports a command set that does NOT use 0x0
@@ -8298,8 +8707,10 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
*/
id->vwc = NVME_VWC_NSID_BROADCAST_SUPPORT | NVME_VWC_PRESENT;
- id->ocfs = cpu_to_le16(NVME_OCFS_COPY_FORMAT_0 | NVME_OCFS_COPY_FORMAT_1);
- id->sgls = cpu_to_le32(NVME_CTRL_SGLS_SUPPORT_NO_ALIGN);
+ id->ocfs = cpu_to_le16(NVME_OCFS_COPY_FORMAT_0 | NVME_OCFS_COPY_FORMAT_1 |
+ NVME_OCFS_COPY_FORMAT_2 | NVME_OCFS_COPY_FORMAT_3);
+ id->sgls = cpu_to_le32(NVME_CTRL_SGLS_SUPPORT_NO_ALIGN |
+ NVME_CTRL_SGLS_MPTR_SGL);
nvme_init_subnqn(n);
@@ -8446,6 +8857,11 @@ static void nvme_exit(PCIDevice *pci_dev)
g_free(n->cmb.buf);
}
+ if (pci_dev->doe_spdm.spdm_socket > 0) {
+ spdm_socket_close(pci_dev->doe_spdm.spdm_socket,
+ SPDM_SOCKET_TRANSPORT_TYPE_PCI_DOE);
+ }
+
if (n->pmr.dev) {
host_memory_backend_set_mapped(n->pmr.dev, false);
}
@@ -8491,6 +8907,11 @@ static Property nvme_props[] = {
DEFINE_PROP_BOOL("msix-exclusive-bar", NvmeCtrl, params.msix_exclusive_bar,
false),
DEFINE_PROP_UINT16("mqes", NvmeCtrl, params.mqes, 0x7ff),
+ DEFINE_PROP_UINT16("spdm_port", PCIDevice, spdm_port, 0),
+ DEFINE_PROP_BOOL("ctratt.mem", NvmeCtrl, params.ctratt.mem, false),
+ DEFINE_PROP_BOOL("atomic.dn", NvmeCtrl, params.atomic_dn, 0),
+ DEFINE_PROP_UINT16("atomic.awun", NvmeCtrl, params.atomic_awun, 0),
+ DEFINE_PROP_UINT16("atomic.awupf", NvmeCtrl, params.atomic_awupf, 0),
DEFINE_PROP_END_OF_LIST(),
};
@@ -8562,11 +8983,25 @@ static void nvme_pci_write_config(PCIDevice *dev, uint32_t address,
{
uint16_t old_num_vfs = pcie_sriov_num_vfs(dev);
+ if (pcie_find_capability(dev, PCI_EXT_CAP_ID_DOE)) {
+ pcie_doe_write_config(&dev->doe_spdm, address, val, len);
+ }
pci_default_write_config(dev, address, val, len);
pcie_cap_flr_write_config(dev, address, val, len);
nvme_sriov_post_write_config(dev, old_num_vfs);
}
+static uint32_t nvme_pci_read_config(PCIDevice *dev, uint32_t address, int len)
+{
+ uint32_t val;
+ if (dev->spdm_port && pcie_find_capability(dev, PCI_EXT_CAP_ID_DOE)) {
+ if (pcie_doe_read_config(&dev->doe_spdm, address, len, &val)) {
+ return val;
+ }
+ }
+ return pci_default_read_config(dev, address, len);
+}
+
static const VMStateDescription nvme_vmstate = {
.name = "nvme",
.unmigratable = 1,
@@ -8579,6 +9014,7 @@ static void nvme_class_init(ObjectClass *oc, void *data)
pc->realize = nvme_realize;
pc->config_write = nvme_pci_write_config;
+ pc->config_read = nvme_pci_read_config;
pc->exit = nvme_exit;
pc->class_id = PCI_CLASS_STORAGE_EXPRESS;
pc->revision = 2;
@@ -8587,7 +9023,7 @@ static void nvme_class_init(ObjectClass *oc, void *data)
dc->desc = "Non-Volatile Memory Express";
device_class_set_props(dc, nvme_props);
dc->vmsd = &nvme_vmstate;
- dc->reset = nvme_pci_reset;
+ device_class_set_legacy_reset(dc, nvme_pci_reset);
}
static void nvme_instance_init(Object *obj)
diff --git a/hw/nvme/nvme.h b/hw/nvme/nvme.h
index 7819857..7566b31 100644
--- a/hw/nvme/nvme.h
+++ b/hw/nvme/nvme.h
@@ -220,6 +220,11 @@ typedef struct NvmeNamespaceParams {
} fdp;
} NvmeNamespaceParams;
+typedef struct NvmeAtomic {
+ uint32_t atomic_max_write_size;
+ bool atomic_writes;
+} NvmeAtomic;
+
typedef struct NvmeNamespace {
DeviceState parent_obj;
BlockConf blkconf;
@@ -421,6 +426,7 @@ typedef struct NvmeRequest {
NvmeCmd cmd;
BlockAcctCookie acct;
NvmeSg sg;
+ bool atomic_write;
QTAILQ_ENTRY(NvmeRequest)entry;
} NvmeRequest;
@@ -538,6 +544,14 @@ typedef struct NvmeParams {
uint32_t sriov_max_vq_per_vf;
uint32_t sriov_max_vi_per_vf;
bool msix_exclusive_bar;
+
+ struct {
+ bool mem;
+ } ctratt;
+
+ uint16_t atomic_awun;
+ uint16_t atomic_awupf;
+ bool atomic_dn;
} NvmeParams;
typedef struct NvmeCtrl {
@@ -619,6 +633,8 @@ typedef struct NvmeCtrl {
uint16_t vqrfap;
uint16_t virfap;
} next_pri_ctrl_cap; /* These override pri_ctrl_cap after reset */
+ uint32_t dn; /* Disable Normal */
+ NvmeAtomic atomic;
} NvmeCtrl;
typedef enum NvmeResetType {
diff --git a/hw/nvram/eeprom_at24c.c b/hw/nvram/eeprom_at24c.c
index 3272068..ec748e5 100644
--- a/hw/nvram/eeprom_at24c.c
+++ b/hw/nvram/eeprom_at24c.c
@@ -254,7 +254,7 @@ void at24c_eeprom_class_init(ObjectClass *klass, void *data)
k->send = &at24c_eeprom_send;
device_class_set_props(dc, at24c_eeprom_props);
- dc->reset = at24c_eeprom_reset;
+ device_class_set_legacy_reset(dc, at24c_eeprom_reset);
}
static
diff --git a/hw/nvram/fw_cfg-acpi.c b/hw/nvram/fw_cfg-acpi.c
index 58cdcd3..2e6ef89 100644
--- a/hw/nvram/fw_cfg-acpi.c
+++ b/hw/nvram/fw_cfg-acpi.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Add fw_cfg device in DSDT
*
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index fc0263f..b644577 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -1171,11 +1171,6 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
return s;
}
-FWCfgState *fw_cfg_init_io(uint32_t iobase)
-{
- return fw_cfg_init_io_dma(iobase, 0, NULL);
-}
-
FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
hwaddr data_addr, uint32_t data_width,
hwaddr dma_addr, AddressSpace *dma_as)
@@ -1260,7 +1255,7 @@ static void fw_cfg_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = fw_cfg_reset;
+ device_class_set_legacy_reset(dc, fw_cfg_reset);
dc->vmsd = &vmstate_fw_cfg;
device_class_set_props(dc, fw_cfg_properties);
diff --git a/hw/nvram/mac_nvram.c b/hw/nvram/mac_nvram.c
index fe9df9f..e47e52a 100644
--- a/hw/nvram/mac_nvram.c
+++ b/hw/nvram/mac_nvram.c
@@ -35,7 +35,7 @@
#include "qemu/module.h"
#include "qemu/error-report.h"
#include "trace.h"
-#include <zlib.h>
+#include <zlib.h> /* for adler32 */
#define DEF_SYSTEM_SIZE 0xc10
@@ -147,7 +147,7 @@ static void macio_nvram_class_init(ObjectClass *oc, void *data)
dc->realize = macio_nvram_realizefn;
dc->unrealize = macio_nvram_unrealizefn;
- dc->reset = macio_nvram_reset;
+ device_class_set_legacy_reset(dc, macio_nvram_reset);
dc->vmsd = &vmstate_macio_nvram;
device_class_set_props(dc, macio_nvram_properties);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
diff --git a/hw/nvram/nrf51_nvm.c b/hw/nvram/nrf51_nvm.c
index 73564f7..b1f8175 100644
--- a/hw/nvram/nrf51_nvm.c
+++ b/hw/nvram/nrf51_nvm.c
@@ -378,7 +378,7 @@ static void nrf51_nvm_class_init(ObjectClass *klass, void *data)
device_class_set_props(dc, nrf51_nvm_properties);
dc->vmsd = &vmstate_nvm;
dc->realize = nrf51_nvm_realize;
- dc->reset = nrf51_nvm_reset;
+ device_class_set_legacy_reset(dc, nrf51_nvm_reset);
}
static const TypeInfo nrf51_nvm_info = {
diff --git a/hw/nvram/xlnx-bbram.c b/hw/nvram/xlnx-bbram.c
index 09575a7..1bc58e9 100644
--- a/hw/nvram/xlnx-bbram.c
+++ b/hw/nvram/xlnx-bbram.c
@@ -456,9 +456,8 @@ static void bbram_ctrl_init(Object *obj)
{
XlnxBBRam *s = XLNX_BBRAM(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- RegisterInfoArray *reg_array;
- reg_array =
+ s->reg_array =
register_init_block32(DEVICE(obj), bbram_ctrl_regs_info,
ARRAY_SIZE(bbram_ctrl_regs_info),
s->regs_info, s->regs,
@@ -466,10 +465,17 @@ static void bbram_ctrl_init(Object *obj)
XLNX_BBRAM_ERR_DEBUG,
R_MAX * 4);
- sysbus_init_mmio(sbd, &reg_array->mem);
+ sysbus_init_mmio(sbd, &s->reg_array->mem);
sysbus_init_irq(sbd, &s->irq_bbram);
}
+static void bbram_ctrl_finalize(Object *obj)
+{
+ XlnxBBRam *s = XLNX_BBRAM(obj);
+
+ register_finalize_block(s->reg_array);
+}
+
static void bbram_prop_set_drive(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
@@ -537,6 +543,7 @@ static const TypeInfo bbram_ctrl_info = {
.instance_size = sizeof(XlnxBBRam),
.class_init = bbram_ctrl_class_init,
.instance_init = bbram_ctrl_init,
+ .instance_finalize = bbram_ctrl_finalize,
};
static void bbram_ctrl_register_types(void)
diff --git a/hw/nvram/xlnx-versal-efuse-ctrl.c b/hw/nvram/xlnx-versal-efuse-ctrl.c
index def6fe33..8252a5c 100644
--- a/hw/nvram/xlnx-versal-efuse-ctrl.c
+++ b/hw/nvram/xlnx-versal-efuse-ctrl.c
@@ -712,9 +712,8 @@ static void efuse_ctrl_init(Object *obj)
{
XlnxVersalEFuseCtrl *s = XLNX_VERSAL_EFUSE_CTRL(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- RegisterInfoArray *reg_array;
- reg_array =
+ s->reg_array =
register_init_block32(DEVICE(obj), efuse_ctrl_regs_info,
ARRAY_SIZE(efuse_ctrl_regs_info),
s->regs_info, s->regs,
@@ -722,7 +721,7 @@ static void efuse_ctrl_init(Object *obj)
XLNX_VERSAL_EFUSE_CTRL_ERR_DEBUG,
R_MAX * 4);
- sysbus_init_mmio(sbd, &reg_array->mem);
+ sysbus_init_mmio(sbd, &s->reg_array->mem);
sysbus_init_irq(sbd, &s->irq_efuse_imr);
}
@@ -730,6 +729,7 @@ static void efuse_ctrl_finalize(Object *obj)
{
XlnxVersalEFuseCtrl *s = XLNX_VERSAL_EFUSE_CTRL(obj);
+ register_finalize_block(s->reg_array);
g_free(s->extra_pg0_lock_spec);
}
diff --git a/hw/nvram/xlnx-zynqmp-efuse.c b/hw/nvram/xlnx-zynqmp-efuse.c
index 2d465f0..4e2d1b9 100644
--- a/hw/nvram/xlnx-zynqmp-efuse.c
+++ b/hw/nvram/xlnx-zynqmp-efuse.c
@@ -803,9 +803,8 @@ static void zynqmp_efuse_init(Object *obj)
{
XlnxZynqMPEFuse *s = XLNX_ZYNQMP_EFUSE(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- RegisterInfoArray *reg_array;
- reg_array =
+ s->reg_array =
register_init_block32(DEVICE(obj), zynqmp_efuse_regs_info,
ARRAY_SIZE(zynqmp_efuse_regs_info),
s->regs_info, s->regs,
@@ -813,10 +812,17 @@ static void zynqmp_efuse_init(Object *obj)
ZYNQMP_EFUSE_ERR_DEBUG,
R_MAX * 4);
- sysbus_init_mmio(sbd, &reg_array->mem);
+ sysbus_init_mmio(sbd, &s->reg_array->mem);
sysbus_init_irq(sbd, &s->irq);
}
+static void zynqmp_efuse_finalize(Object *obj)
+{
+ XlnxZynqMPEFuse *s = XLNX_ZYNQMP_EFUSE(obj);
+
+ register_finalize_block(s->reg_array);
+}
+
static const VMStateDescription vmstate_efuse = {
.name = TYPE_XLNX_ZYNQMP_EFUSE,
.version_id = 1,
@@ -853,6 +859,7 @@ static const TypeInfo efuse_info = {
.instance_size = sizeof(XlnxZynqMPEFuse),
.class_init = zynqmp_efuse_class_init,
.instance_init = zynqmp_efuse_init,
+ .instance_finalize = zynqmp_efuse_finalize,
};
static void efuse_register_types(void)
diff --git a/hw/openrisc/Kconfig b/hw/openrisc/Kconfig
index 76b953c..0702f62 100644
--- a/hw/openrisc/Kconfig
+++ b/hw/openrisc/Kconfig
@@ -3,7 +3,7 @@ config OR1K_SIM
default y
depends on OPENRISC
select DEVICE_TREE
- select SERIAL
+ select SERIAL_MM
select OPENCORES_ETH
select OMPIC
select SPLIT_IRQ
@@ -19,6 +19,6 @@ config OR1K_VIRT
select PCI
select PCI_EXPRESS_GENERIC_BRIDGE
select GOLDFISH_RTC
- select SERIAL
+ select SERIAL_MM
select SIFIVE_TEST
select VIRTIO_MMIO
diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c
index bffd6f7..9fb6351 100644
--- a/hw/openrisc/openrisc_sim.c
+++ b/hw/openrisc/openrisc_sim.c
@@ -24,7 +24,7 @@
#include "cpu.h"
#include "hw/irq.h"
#include "hw/boards.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "net/net.h"
#include "hw/openrisc/boot.h"
#include "hw/qdev-properties.h"
diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c
index f8a68a6..47d2c9b 100644
--- a/hw/openrisc/virt.c
+++ b/hw/openrisc/virt.c
@@ -14,7 +14,7 @@
#include "exec/address-spaces.h"
#include "hw/irq.h"
#include "hw/boards.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/core/split-irq.h"
#include "hw/openrisc/boot.h"
#include "hw/misc/sifive_test.h"
diff --git a/hw/pci-bridge/Kconfig b/hw/pci-bridge/Kconfig
index 6707736..449ec98 100644
--- a/hw/pci-bridge/Kconfig
+++ b/hw/pci-bridge/Kconfig
@@ -1,3 +1,8 @@
+config PCI_BRIDGE
+ bool
+ default y if PCI_DEVICES
+ depends on PCI
+
config PCIE_PORT
bool
default y if PCI_DEVICES
diff --git a/hw/pci-bridge/cxl_downstream.c b/hw/pci-bridge/cxl_downstream.c
index 742da07..4b42984 100644
--- a/hw/pci-bridge/cxl_downstream.c
+++ b/hw/pci-bridge/cxl_downstream.c
@@ -236,7 +236,7 @@ static void cxl_dsp_class_init(ObjectClass *oc, void *data)
k->revision = 0;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->desc = "CXL Switch Downstream Port";
- dc->reset = cxl_dsp_reset;
+ device_class_set_legacy_reset(dc, cxl_dsp_reset);
}
static const TypeInfo cxl_dsp_info = {
diff --git a/hw/pci-bridge/cxl_upstream.c b/hw/pci-bridge/cxl_upstream.c
index e51221a..a5a39cc 100644
--- a/hw/pci-bridge/cxl_upstream.c
+++ b/hw/pci-bridge/cxl_upstream.c
@@ -234,7 +234,7 @@ static int build_cdat_table(CDATSubHeader ***cdat_table, void *priv)
.type = CDAT_TYPE_SSLBIS,
.length = sslbis_size,
},
- .data_type = HMATLB_DATA_TYPE_ACCESS_LATENCY,
+ .data_type = HMAT_LB_DATA_TYPE_ACCESS_LATENCY,
.entry_base_unit = 10000,
},
};
@@ -254,7 +254,7 @@ static int build_cdat_table(CDATSubHeader ***cdat_table, void *priv)
.type = CDAT_TYPE_SSLBIS,
.length = sslbis_size,
},
- .data_type = HMATLB_DATA_TYPE_ACCESS_BANDWIDTH,
+ .data_type = HMAT_LB_DATA_TYPE_ACCESS_BANDWIDTH,
.entry_base_unit = 1024,
},
};
@@ -380,7 +380,7 @@ static void cxl_upstream_class_init(ObjectClass *oc, void *data)
k->revision = 0;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->desc = "CXL Switch Upstream Port";
- dc->reset = cxl_usp_reset;
+ device_class_set_legacy_reset(dc, cxl_usp_reset);
device_class_set_props(dc, cxl_upstream_props);
}
diff --git a/hw/pci-bridge/i82801b11.c b/hw/pci-bridge/i82801b11.c
index c140919..00d2fbd 100644
--- a/hw/pci-bridge/i82801b11.c
+++ b/hw/pci-bridge/i82801b11.c
@@ -98,7 +98,7 @@ static void i82801b11_bridge_class_init(ObjectClass *klass, void *data)
k->realize = i82801b11_bridge_realize;
k->config_write = pci_bridge_write_config;
dc->vmsd = &i82801b11_bridge_dev_vmstate;
- dc->reset = pci_bridge_reset;
+ device_class_set_legacy_reset(dc, pci_bridge_reset);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
}
diff --git a/hw/pci-bridge/meson.build b/hw/pci-bridge/meson.build
index f2a6043..2e0eb0d 100644
--- a/hw/pci-bridge/meson.build
+++ b/hw/pci-bridge/meson.build
@@ -1,5 +1,5 @@
pci_ss = ss.source_set()
-pci_ss.add(files('pci_bridge_dev.c'))
+pci_ss.add(when: 'CONFIG_PCI_BRIDGE', if_true: files('pci_bridge_dev.c'))
pci_ss.add(when: 'CONFIG_I82801B11', if_true: files('i82801b11.c'))
pci_ss.add(when: 'CONFIG_IOH3420', if_true: files('ioh3420.c'))
pci_ss.add(when: 'CONFIG_PCIE_PORT', if_true: files('pcie_root_port.c', 'gen_pcie_root_port.c'))
diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c
index 089f91e..8e7f926 100644
--- a/hw/pci-bridge/pci_bridge_dev.c
+++ b/hw/pci-bridge/pci_bridge_dev.c
@@ -254,7 +254,7 @@ static void pci_bridge_dev_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE;
k->class_id = PCI_CLASS_BRIDGE_PCI;
dc->desc = "Standard PCI Bridge";
- dc->reset = qdev_pci_bridge_dev_reset;
+ device_class_set_legacy_reset(dc, qdev_pci_bridge_dev_reset);
device_class_set_props(dc, pci_bridge_dev_properties);
dc->vmsd = &pci_bridge_dev_vmstate;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
index 0411ad3..dfaea6c 100644
--- a/hw/pci-bridge/pci_expander_bridge.c
+++ b/hw/pci-bridge/pci_expander_bridge.c
@@ -515,7 +515,7 @@ static void pxb_cxl_dev_class_init(ObjectClass *klass, void *data)
/* Host bridges aren't hotpluggable. FIXME: spec reference */
dc->hotpluggable = false;
- dc->reset = pxb_cxl_dev_reset;
+ device_class_set_legacy_reset(dc, pxb_cxl_dev_reset);
}
static const TypeInfo pxb_cxl_dev_info = {
diff --git a/hw/pci-bridge/pcie_pci_bridge.c b/hw/pci-bridge/pcie_pci_bridge.c
index 7646ac2..6e8d7d9 100644
--- a/hw/pci-bridge/pcie_pci_bridge.c
+++ b/hw/pci-bridge/pcie_pci_bridge.c
@@ -152,7 +152,7 @@ static void pcie_pci_bridge_class_init(ObjectClass *klass, void *data)
k->config_write = pcie_pci_bridge_write_config;
dc->vmsd = &pcie_pci_bridge_dev_vmstate;
device_class_set_props(dc, pcie_pci_bridge_dev_properties);
- dc->reset = &pcie_pci_bridge_reset;
+ device_class_set_legacy_reset(dc, pcie_pci_bridge_reset);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
hc->plug = pci_bridge_dev_plug_cb;
hc->unplug = pci_bridge_dev_unplug_cb;
diff --git a/hw/pci-bridge/simba.c b/hw/pci-bridge/simba.c
index 17aa0d7..5fe090d 100644
--- a/hw/pci-bridge/simba.c
+++ b/hw/pci-bridge/simba.c
@@ -78,7 +78,7 @@ static void simba_pci_bridge_class_init(ObjectClass *klass, void *data)
k->revision = 0x11;
k->config_write = pci_bridge_write_config;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->reset = pci_bridge_reset;
+ device_class_set_legacy_reset(dc, pci_bridge_reset);
dc->vmsd = &vmstate_pci_device;
}
diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c
index 907d510..473e2dd 100644
--- a/hw/pci-bridge/xio3130_downstream.c
+++ b/hw/pci-bridge/xio3130_downstream.c
@@ -167,7 +167,7 @@ static void xio3130_downstream_class_init(ObjectClass *klass, void *data)
k->revision = XIO3130_REVISION;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->desc = "TI X3130 Downstream Port of PCI Express Switch";
- dc->reset = xio3130_downstream_reset;
+ device_class_set_legacy_reset(dc, xio3130_downstream_reset);
dc->vmsd = &vmstate_xio3130_downstream;
device_class_set_props(dc, xio3130_downstream_props);
}
diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c
index 2a6cff6..fb1547b 100644
--- a/hw/pci-bridge/xio3130_upstream.c
+++ b/hw/pci-bridge/xio3130_upstream.c
@@ -136,7 +136,7 @@ static void xio3130_upstream_class_init(ObjectClass *klass, void *data)
k->revision = XIO3130_REVISION;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->desc = "TI X3130 Upstream Port of PCI Express Switch";
- dc->reset = xio3130_upstream_reset;
+ device_class_set_legacy_reset(dc, xio3130_upstream_reset);
dc->vmsd = &vmstate_xio3130_upstream;
}
diff --git a/hw/pci-host/astro.c b/hw/pci-host/astro.c
index e3e589c..379095b 100644
--- a/hw/pci-host/astro.c
+++ b/hw/pci-host/astro.c
@@ -489,7 +489,7 @@ static void elroy_pcihost_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = elroy_reset;
+ device_class_set_legacy_reset(dc, elroy_reset);
device_class_set_props(dc, elroy_pcihost_properties);
dc->vmsd = &vmstate_elroy;
dc->user_creatable = false;
@@ -865,7 +865,7 @@ static void astro_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = astro_reset;
+ device_class_set_legacy_reset(dc, astro_reset);
dc->vmsd = &vmstate_astro;
dc->realize = astro_realize;
/*
diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c
index c25d50f..c3fc37b 100644
--- a/hw/pci-host/designware.c
+++ b/hw/pci-host/designware.c
@@ -395,6 +395,7 @@ static void designware_pcie_root_realize(PCIDevice *dev, Error **errp)
{
DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(dev);
DesignwarePCIEHost *host = designware_pcie_root_to_host(root);
+ MemoryRegion *host_mem = get_system_memory();
MemoryRegion *address_space = &host->pci.memory;
PCIBridge *br = PCI_BRIDGE(dev);
DesignwarePCIEViewport *viewport;
@@ -435,7 +436,7 @@ static void designware_pcie_root_realize(PCIDevice *dev, Error **errp)
viewport->cr[0] = DESIGNWARE_PCIE_ATU_TYPE_MEM;
source = &host->pci.address_space_root;
- destination = get_system_memory();
+ destination = host_mem;
direction = "Inbound";
/*
@@ -460,7 +461,7 @@ static void designware_pcie_root_realize(PCIDevice *dev, Error **errp)
destination = &host->pci.memory;
direction = "Outbound";
- source = get_system_memory();
+ source = host_mem;
/*
* Configure MemoryRegion implementing CPU -> PCI memory
@@ -607,7 +608,7 @@ static void designware_pcie_root_class_init(ObjectClass *klass, void *data)
k->config_read = designware_pcie_root_config_read;
k->config_write = designware_pcie_root_config_write;
- dc->reset = pci_bridge_reset;
+ device_class_set_legacy_reset(dc, pci_bridge_reset);
/*
* PCI-facing part of the host bridge, not usable without the
* host-facing part, which can't be device_add'ed, yet.
@@ -752,28 +753,23 @@ static void designware_pcie_host_init(Object *obj)
qdev_prop_set_bit(DEVICE(root), "multifunction", false);
}
-static const TypeInfo designware_pcie_root_info = {
- .name = TYPE_DESIGNWARE_PCIE_ROOT,
- .parent = TYPE_PCI_BRIDGE,
- .instance_size = sizeof(DesignwarePCIERoot),
- .class_init = designware_pcie_root_class_init,
- .interfaces = (InterfaceInfo[]) {
- { INTERFACE_PCIE_DEVICE },
- { }
+static const TypeInfo designware_pcie_types[] = {
+ {
+ .name = TYPE_DESIGNWARE_PCIE_HOST,
+ .parent = TYPE_PCI_HOST_BRIDGE,
+ .instance_size = sizeof(DesignwarePCIEHost),
+ .instance_init = designware_pcie_host_init,
+ .class_init = designware_pcie_host_class_init,
+ }, {
+ .name = TYPE_DESIGNWARE_PCIE_ROOT,
+ .parent = TYPE_PCI_BRIDGE,
+ .instance_size = sizeof(DesignwarePCIERoot),
+ .class_init = designware_pcie_root_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { INTERFACE_PCIE_DEVICE },
+ { }
+ },
},
};
-static const TypeInfo designware_pcie_host_info = {
- .name = TYPE_DESIGNWARE_PCIE_HOST,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(DesignwarePCIEHost),
- .instance_init = designware_pcie_host_init,
- .class_init = designware_pcie_host_class_init,
-};
-
-static void designware_pcie_register(void)
-{
- type_register_static(&designware_pcie_root_info);
- type_register_static(&designware_pcie_host_info);
-}
-type_init(designware_pcie_register)
+DEFINE_TYPES(designware_pcie_types)
diff --git a/hw/pci-host/dino.c b/hw/pci-host/dino.c
index d992c4b..283fc0d 100644
--- a/hw/pci-host/dino.c
+++ b/hw/pci-host/dino.c
@@ -502,7 +502,7 @@ static void dino_pcihost_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = dino_pcihost_reset;
+ device_class_set_legacy_reset(dc, dino_pcihost_reset);
dc->realize = dino_pcihost_realize;
dc->unrealize = dino_pcihost_unrealize;
device_class_set_props(dc, dino_pcihost_properties);
diff --git a/hw/pci-host/gpex-acpi.c b/hw/pci-host/gpex-acpi.c
index f69413e..391fabb 100644
--- a/hw/pci-host/gpex-acpi.c
+++ b/hw/pci-host/gpex-acpi.c
@@ -7,7 +7,8 @@
#include "hw/pci/pcie_host.h"
#include "hw/acpi/cxl.h"
-static void acpi_dsdt_add_pci_route_table(Aml *dev, uint32_t irq)
+static void acpi_dsdt_add_pci_route_table(Aml *dev, uint32_t irq,
+ Aml *scope, uint8_t bus_num)
{
Aml *method, *crs;
int i, slot_no;
@@ -20,7 +21,7 @@ static void acpi_dsdt_add_pci_route_table(Aml *dev, uint32_t irq)
Aml *pkg = aml_package(4);
aml_append(pkg, aml_int((slot_no << 16) | 0xFFFF));
aml_append(pkg, aml_int(i));
- aml_append(pkg, aml_name("GSI%d", gsi));
+ aml_append(pkg, aml_name("L%.02X%X", bus_num, gsi));
aml_append(pkg, aml_int(0));
aml_append(rt_pkg, pkg);
}
@@ -30,7 +31,7 @@ static void acpi_dsdt_add_pci_route_table(Aml *dev, uint32_t irq)
/* Create GSI link device */
for (i = 0; i < PCI_NUM_PINS; i++) {
uint32_t irqs = irq + i;
- Aml *dev_gsi = aml_device("GSI%d", i);
+ Aml *dev_gsi = aml_device("L%.02X%X", bus_num, i);
aml_append(dev_gsi, aml_name_decl("_HID", aml_string("PNP0C0F")));
aml_append(dev_gsi, aml_name_decl("_UID", aml_int(i)));
crs = aml_resource_template();
@@ -45,7 +46,7 @@ static void acpi_dsdt_add_pci_route_table(Aml *dev, uint32_t irq)
aml_append(dev_gsi, aml_name_decl("_CRS", crs));
method = aml_method("_SRS", 1, AML_NOTSERIALIZED);
aml_append(dev_gsi, method);
- aml_append(dev, dev_gsi);
+ aml_append(scope, dev_gsi);
}
}
@@ -174,7 +175,7 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg)
aml_append(dev, aml_name_decl("_PXM", aml_int(numa_node)));
}
- acpi_dsdt_add_pci_route_table(dev, cfg->irq);
+ acpi_dsdt_add_pci_route_table(dev, cfg->irq, scope, bus_num);
/*
* Resources defined for PXBs are composed of the following parts:
@@ -205,7 +206,7 @@ void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg)
aml_append(dev, aml_name_decl("_STR", aml_unicode("PCIe 0 Device")));
aml_append(dev, aml_name_decl("_CCA", aml_int(1)));
- acpi_dsdt_add_pci_route_table(dev, cfg->irq);
+ acpi_dsdt_add_pci_route_table(dev, cfg->irq, scope, 0);
method = aml_method("_CBA", 0, AML_NOTSERIALIZED);
aml_append(method, aml_return(aml_int(cfg->ecam.base)));
diff --git a/hw/pci-host/gt64120.c b/hw/pci-host/gt64120.c
index e02efc9..14fc803 100644
--- a/hw/pci-host/gt64120.c
+++ b/hw/pci-host/gt64120.c
@@ -1,6 +1,8 @@
/*
* QEMU GT64120 PCI host
*
+ * (Datasheet GT-64120 Rev 1.4 from Sep 14, 1999)
+ *
* Copyright (c) 2006,2007 Aurelien Jarno
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -687,7 +689,6 @@ static void gt64120_writel(void *opaque, hwaddr addr,
case GT_PCI0_CFGDATA:
/* Mapped via in gt64120_pci_mapping() */
g_assert_not_reached();
- break;
/* Interrupts */
case GT_INTRCAUSE:
@@ -931,7 +932,6 @@ static uint64_t gt64120_readl(void *opaque,
case GT_PCI0_CFGDATA:
/* Mapped via in gt64120_pci_mapping() */
g_assert_not_reached();
- break;
case GT_PCI0_CMD:
case GT_PCI0_TOR:
@@ -1213,17 +1213,34 @@ static void gt64120_realize(DeviceState *dev, Error **errp)
static void gt64120_pci_realize(PCIDevice *d, Error **errp)
{
- /* FIXME: Malta specific hw assumptions ahead */
+ /* Values from chapter 17.16 "PCI Configuration" */
+
+ pci_set_long(d->wmask + PCI_BASE_ADDRESS_0, 0xfffff008); /* SCS[1:0] */
+ pci_set_long(d->wmask + PCI_BASE_ADDRESS_1, 0xfffff008); /* SCS[3:2] */
+ pci_set_long(d->wmask + PCI_BASE_ADDRESS_2, 0xfffff008); /* CS[2:0] */
+ pci_set_long(d->wmask + PCI_BASE_ADDRESS_3, 0xfffff008); /* CS[3], BootCS */
+ pci_set_long(d->wmask + PCI_BASE_ADDRESS_4, 0xfffff000); /* ISD MMIO */
+ pci_set_long(d->wmask + PCI_BASE_ADDRESS_5, 0xfffff001); /* ISD I/O */
+}
+
+static void gt64120_pci_reset_hold(Object *obj, ResetType type)
+{
+ PCIDevice *d = PCI_DEVICE(obj);
+
+ /* Values from chapter 17.16 "PCI Configuration" */
+
pci_set_word(d->config + PCI_COMMAND, 0);
pci_set_word(d->config + PCI_STATUS,
PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
pci_config_set_prog_interface(d->config, 0);
+
pci_set_long(d->config + PCI_BASE_ADDRESS_0, 0x00000008);
pci_set_long(d->config + PCI_BASE_ADDRESS_1, 0x01000008);
pci_set_long(d->config + PCI_BASE_ADDRESS_2, 0x1c000000);
pci_set_long(d->config + PCI_BASE_ADDRESS_3, 0x1f000000);
pci_set_long(d->config + PCI_BASE_ADDRESS_4, 0x14000000);
pci_set_long(d->config + PCI_BASE_ADDRESS_5, 0x14000001);
+
pci_set_byte(d->config + 0x3d, 0x01);
}
@@ -1231,7 +1248,9 @@ static void gt64120_pci_class_init(ObjectClass *klass, void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+ rc->phases.hold = gt64120_pci_reset_hold;
k->realize = gt64120_pci_realize;
k->vendor_id = PCI_VENDOR_ID_MARVELL;
k->device_id = PCI_DEVICE_ID_MARVELL_GT6412X;
@@ -1268,7 +1287,7 @@ static void gt64120_class_init(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
device_class_set_props(dc, gt64120_properties);
dc->realize = gt64120_realize;
- dc->reset = gt64120_reset;
+ device_class_set_legacy_reset(dc, gt64120_reset);
dc->vmsd = &vmstate_gt64120;
}
diff --git a/hw/pci-host/mv64361.c b/hw/pci-host/mv64361.c
index 01bd8c8..1036d86 100644
--- a/hw/pci-host/mv64361.c
+++ b/hw/pci-host/mv64361.c
@@ -928,7 +928,7 @@ static void mv64361_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = mv64361_realize;
- dc->reset = mv64361_reset;
+ device_class_set_legacy_reset(dc, mv64361_reset);
}
static const TypeInfo mv64361_type_info = {
diff --git a/hw/pci-host/ppc440_pcix.c b/hw/pci-host/ppc440_pcix.c
index ef212d9..07924bc 100644
--- a/hw/pci-host/ppc440_pcix.c
+++ b/hw/pci-host/ppc440_pcix.c
@@ -524,7 +524,7 @@ static void ppc440_pcix_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = ppc440_pcix_realize;
- dc->reset = ppc440_pcix_reset;
+ device_class_set_legacy_reset(dc, ppc440_pcix_reset);
}
static const TypeInfo ppc440_pcix_info = {
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index 0b6cbae..f3e7133 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -662,16 +662,6 @@ static void mch_realize(PCIDevice *d, Error **errp)
OBJECT(&mch->smram));
}
-uint64_t mch_mcfg_base(void)
-{
- bool ambiguous;
- Object *o = object_resolve_path_type("", TYPE_MCH_PCI_DEVICE, &ambiguous);
- if (!o) {
- return 0;
- }
- return MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT;
-}
-
static Property mch_props[] = {
DEFINE_PROP_UINT16("extended-tseg-mbytes", MCHPCIState, ext_tseg_mbytes,
16),
@@ -686,7 +676,7 @@ static void mch_class_init(ObjectClass *klass, void *data)
k->realize = mch_realize;
k->config_write = mch_write_config;
- dc->reset = mch_reset;
+ device_class_set_legacy_reset(dc, mch_reset);
device_class_set_props(dc, mch_props);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->desc = "Host bridge";
diff --git a/hw/pci-host/sabre.c b/hw/pci-host/sabre.c
index d0851b4..1707feb 100644
--- a/hw/pci-host/sabre.c
+++ b/hw/pci-host/sabre.c
@@ -504,7 +504,7 @@ static void sabre_class_init(ObjectClass *klass, void *data)
SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
dc->realize = sabre_realize;
- dc->reset = sabre_reset;
+ device_class_set_legacy_reset(dc, sabre_reset);
device_class_set_props(dc, sabre_properties);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
dc->fw_name = "pci";
diff --git a/hw/pci-host/versatile.c b/hw/pci-host/versatile.c
index 0e65deb..d257ace 100644
--- a/hw/pci-host/versatile.c
+++ b/hw/pci-host/versatile.c
@@ -509,7 +509,7 @@ static void pci_vpb_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = pci_vpb_realize;
- dc->reset = pci_vpb_reset;
+ device_class_set_legacy_reset(dc, pci_vpb_reset);
dc->vmsd = &pci_vpb_vmstate;
device_class_set_props(dc, pci_vpb_properties);
}
diff --git a/hw/pci-host/xilinx-pcie.c b/hw/pci-host/xilinx-pcie.c
index c9ab705..24f691e 100644
--- a/hw/pci-host/xilinx-pcie.c
+++ b/hw/pci-host/xilinx-pcie.c
@@ -300,7 +300,7 @@ static void xilinx_pcie_root_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_BRIDGE_HOST;
k->realize = xilinx_pcie_root_realize;
k->exit = pci_bridge_exitfn;
- dc->reset = pci_bridge_reset;
+ device_class_set_legacy_reset(dc, pci_bridge_reset);
k->config_read = xilinx_pcie_root_config_read;
k->config_write = xilinx_pcie_root_config_write;
/*
diff --git a/hw/pci/pci-hmp-cmds.c b/hw/pci/pci-hmp-cmds.c
index b09fce9..fdfe444 100644
--- a/hw/pci/pci-hmp-cmds.c
+++ b/hw/pci/pci-hmp-cmds.c
@@ -83,15 +83,25 @@ static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev)
monitor_printf(mon, " BAR%" PRId64 ": ", region->value->bar);
if (!strcmp(region->value->type, "io")) {
- monitor_printf(mon, "I/O at 0x%04" PRIx64
- " [0x%04" PRIx64 "].\n",
- addr, addr + size - 1);
+ if (addr != PCI_BAR_UNMAPPED) {
+ monitor_printf(mon, "I/O at 0x%04" PRIx64
+ " [0x%04" PRIx64 "]\n",
+ addr, addr + size - 1);
+ } else {
+ monitor_printf(mon, "I/O (not mapped)\n");
+ }
} else {
- monitor_printf(mon, "%d bit%s memory at 0x%08" PRIx64
- " [0x%08" PRIx64 "].\n",
- region->value->mem_type_64 ? 64 : 32,
- region->value->prefetch ? " prefetchable" : "",
- addr, addr + size - 1);
+ if (addr != PCI_BAR_UNMAPPED) {
+ monitor_printf(mon, "%d bit%s memory at 0x%08" PRIx64
+ " [0x%08" PRIx64 "]\n",
+ region->value->mem_type_64 ? 64 : 32,
+ region->value->prefetch ? " prefetchable" : "",
+ addr, addr + size - 1);
+ } else {
+ monitor_printf(mon, "%d bit%s memory (not mapped)\n",
+ region->value->mem_type_64 ? 64 : 32,
+ region->value->prefetch ? " prefetchable" : "");
+ }
}
}
diff --git a/hw/pci/pci-stub.c b/hw/pci/pci-stub.c
index f050868..3397d0c 100644
--- a/hw/pci/pci-stub.c
+++ b/hw/pci/pci-stub.c
@@ -46,14 +46,12 @@ void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict)
/* kvm-all wants this */
MSIMessage pci_get_msi_message(PCIDevice *dev, int vector)
{
- g_assert(false);
- return (MSIMessage){};
+ g_assert_not_reached();
}
uint16_t pci_requester_id(PCIDevice *dev)
{
- g_assert(false);
- return 0;
+ g_assert_not_reached();
}
/* Required by ahci.c */
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 4c7be52..87da35c 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -85,6 +85,8 @@ static Property pci_props[] = {
QEMU_PCIE_ERR_UNC_MASK_BITNR, true),
DEFINE_PROP_BIT("x-pcie-ari-nextfn-1", PCIDevice, cap_present,
QEMU_PCIE_ARI_NEXTFN_1_BITNR, false),
+ DEFINE_PROP_SIZE32("x-max-bounce-buffer-size", PCIDevice,
+ max_bounce_buffer_size, DEFAULT_MAX_BOUNCE_BUFFER_SIZE),
DEFINE_PROP_END_OF_LIST()
};
@@ -733,17 +735,10 @@ static bool migrate_is_not_pcie(void *opaque, int version_id)
return !pci_is_express((PCIDevice *)opaque);
}
-static int pci_post_load(void *opaque, int version_id)
-{
- pcie_sriov_pf_post_load(opaque);
- return 0;
-}
-
const VMStateDescription vmstate_pci_device = {
.name = "PCIDevice",
.version_id = 2,
.minimum_version_id = 1,
- .post_load = pci_post_load,
.fields = (const VMStateField[]) {
VMSTATE_INT32_POSITIVE_LE(version_id, PCIDevice),
VMSTATE_BUFFER_UNSAFE_INFO_TEST(config, PCIDevice,
@@ -1186,14 +1181,15 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev,
PCI_SLOT(devfn), PCI_FUNC(devfn), name,
bus->devices[devfn]->name, bus->devices[devfn]->qdev.id);
return NULL;
- } /*
- * Populating function 0 triggers a scan from the guest that
- * exposes other non-zero functions. Hence we need to ensure that
- * function 0 wasn't added yet.
- */
- else if (dev->hotplugged &&
- !pci_is_vf(pci_dev) &&
- pci_get_function_0(pci_dev)) {
+ }
+
+ /*
+ * Populating function 0 triggers a scan from the guest that
+ * exposes other non-zero functions. Hence we need to ensure that
+ * function 0 wasn't added yet.
+ */
+ if (dev->hotplugged && !pci_is_vf(pci_dev) &&
+ pci_get_function_0(pci_dev)) {
error_setg(errp, "PCI: slot %d function 0 already occupied by %s,"
" new func %s cannot be exposed to guest.",
PCI_SLOT(pci_get_function_0(pci_dev)->devfn),
@@ -1211,6 +1207,8 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev,
"bus master container", UINT64_MAX);
address_space_init(&pci_dev->bus_master_as,
&pci_dev->bus_master_container_region, pci_dev->name);
+ pci_dev->bus_master_as.max_bounce_buffer_size =
+ pci_dev->max_bounce_buffer_size;
if (phase_check(PHASE_MACHINE_READY)) {
pci_init_bus_master(pci_dev);
@@ -1532,7 +1530,7 @@ static void pci_update_mappings(PCIDevice *d)
continue;
new_addr = pci_bar_address(d, i, r->type, r->size);
- if (!d->enabled) {
+ if (!d->has_power) {
new_addr = PCI_BAR_UNMAPPED;
}
@@ -1620,7 +1618,7 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val_in, int
pci_update_irq_disabled(d, was_irq_disabled);
memory_region_set_enabled(&d->bus_master_enable_region,
(pci_get_word(d->config + PCI_COMMAND)
- & PCI_COMMAND_MASTER) && d->enabled);
+ & PCI_COMMAND_MASTER) && d->has_power);
}
msi_write_config(d, addr, val_in, l);
@@ -2640,6 +2638,10 @@ static void pci_device_class_init(ObjectClass *klass, void *data)
k->unrealize = pci_qdev_unrealize;
k->bus_type = TYPE_PCI_BUS;
device_class_set_props(k, pci_props);
+ object_class_property_set_description(
+ klass, "x-max-bounce-buffer-size",
+ "Maximum buffer size allocated for bounce buffers used for mapped "
+ "access to indirect DMA memory");
}
static void pci_device_class_base_init(ObjectClass *klass, void *data)
@@ -2891,18 +2893,18 @@ MSIMessage pci_get_msi_message(PCIDevice *dev, int vector)
return msg;
}
-void pci_set_enabled(PCIDevice *d, bool state)
+void pci_set_power(PCIDevice *d, bool state)
{
- if (d->enabled == state) {
+ if (d->has_power == state) {
return;
}
- d->enabled = state;
+ d->has_power = state;
pci_update_mappings(d);
memory_region_set_enabled(&d->bus_master_enable_region,
(pci_get_word(d->config + PCI_COMMAND)
- & PCI_COMMAND_MASTER) && d->enabled);
- if (d->qdev.realized) {
+ & PCI_COMMAND_MASTER) && d->has_power);
+ if (!d->has_power) {
pci_device_reset(d);
}
}
diff --git a/hw/pci/pci_host.c b/hw/pci/pci_host.c
index 0d82727..dfe6fe6 100644
--- a/hw/pci/pci_host.c
+++ b/hw/pci/pci_host.c
@@ -86,7 +86,7 @@ void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
* allowing direct removal of unexposed functions.
*/
if ((pci_dev->qdev.hotplugged && !pci_get_function_0(pci_dev)) ||
- !pci_dev->enabled || is_pci_dev_ejected(pci_dev)) {
+ !pci_dev->has_power || is_pci_dev_ejected(pci_dev)) {
return;
}
@@ -111,7 +111,7 @@ uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
* allowing direct removal of unexposed functions.
*/
if ((pci_dev->qdev.hotplugged && !pci_get_function_0(pci_dev)) ||
- !pci_dev->enabled || is_pci_dev_ejected(pci_dev)) {
+ !pci_dev->has_power || is_pci_dev_ejected(pci_dev)) {
return ~0x0;
}
diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c
index 20ff2b3..9f978ba 100644
--- a/hw/pci/pcie_port.c
+++ b/hw/pci/pcie_port.c
@@ -92,16 +92,6 @@ static PCIESlot *pcie_chassis_find_slot_with_chassis(struct PCIEChassis *c,
return s;
}
-PCIESlot *pcie_chassis_find_slot(uint8_t chassis_number, uint16_t slot)
-{
- struct PCIEChassis *c;
- c = pcie_chassis_find(chassis_number);
- if (!c) {
- return NULL;
- }
- return pcie_chassis_find_slot_with_chassis(c, slot);
-}
-
int pcie_chassis_add_slot(struct PCIESlot *slot)
{
struct PCIEChassis *c;
diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c
index 56523ab..e9b2322 100644
--- a/hw/pci/pcie_sriov.c
+++ b/hw/pci/pcie_sriov.c
@@ -20,43 +20,23 @@
#include "qapi/error.h"
#include "trace.h"
-static void unparent_vfs(PCIDevice *dev, uint16_t total_vfs)
-{
- for (uint16_t i = 0; i < total_vfs; i++) {
- PCIDevice *vf = dev->exp.sriov_pf.vf[i];
- object_unparent(OBJECT(vf));
- object_unref(OBJECT(vf));
- }
- g_free(dev->exp.sriov_pf.vf);
- dev->exp.sriov_pf.vf = NULL;
-}
+static PCIDevice *register_vf(PCIDevice *pf, int devfn,
+ const char *name, uint16_t vf_num);
+static void unregister_vfs(PCIDevice *dev);
-bool pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset,
+void pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset,
const char *vfname, uint16_t vf_dev_id,
uint16_t init_vfs, uint16_t total_vfs,
- uint16_t vf_offset, uint16_t vf_stride,
- Error **errp)
+ uint16_t vf_offset, uint16_t vf_stride)
{
- BusState *bus = qdev_get_parent_bus(&dev->qdev);
- int32_t devfn = dev->devfn + vf_offset;
uint8_t *cfg = dev->config + offset;
uint8_t *wmask;
- if (total_vfs) {
- uint16_t ari_cap = pcie_find_capability(dev, PCI_EXT_CAP_ID_ARI);
- uint16_t first_vf_devfn = dev->devfn + vf_offset;
- uint16_t last_vf_devfn = first_vf_devfn + vf_stride * (total_vfs - 1);
-
- if ((!ari_cap && PCI_SLOT(dev->devfn) != PCI_SLOT(last_vf_devfn)) ||
- last_vf_devfn >= PCI_DEVFN_MAX) {
- error_setg(errp, "VF function number overflows");
- return false;
- }
- }
-
pcie_add_capability(dev, PCI_EXT_CAP_ID_SRIOV, 1,
offset, PCI_EXT_CAP_SRIOV_SIZEOF);
dev->exp.sriov_cap = offset;
+ dev->exp.sriov_pf.num_vfs = 0;
+ dev->exp.sriov_pf.vfname = g_strdup(vfname);
dev->exp.sriov_pf.vf = NULL;
pci_set_word(cfg + PCI_SRIOV_VF_OFFSET, vf_offset);
@@ -89,37 +69,13 @@ bool pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset,
pci_set_word(wmask + PCI_SRIOV_SYS_PGSIZE, 0x553);
qdev_prop_set_bit(&dev->qdev, "multifunction", true);
-
- dev->exp.sriov_pf.vf = g_new(PCIDevice *, total_vfs);
-
- for (uint16_t i = 0; i < total_vfs; i++) {
- PCIDevice *vf = pci_new(devfn, vfname);
- vf->exp.sriov_vf.pf = dev;
- vf->exp.sriov_vf.vf_number = i;
-
- if (!qdev_realize(&vf->qdev, bus, errp)) {
- object_unparent(OBJECT(vf));
- object_unref(vf);
- unparent_vfs(dev, i);
- return false;
- }
-
- /* set vid/did according to sr/iov spec - they are not used */
- pci_config_set_vendor_id(vf->config, 0xffff);
- pci_config_set_device_id(vf->config, 0xffff);
-
- dev->exp.sriov_pf.vf[i] = vf;
- devfn += vf_stride;
- }
-
- return true;
}
void pcie_sriov_pf_exit(PCIDevice *dev)
{
- uint8_t *cfg = dev->config + dev->exp.sriov_cap;
-
- unparent_vfs(dev, pci_get_word(cfg + PCI_SRIOV_TOTAL_VF));
+ unregister_vfs(dev);
+ g_free((char *)dev->exp.sriov_pf.vfname);
+ dev->exp.sriov_pf.vfname = NULL;
}
void pcie_sriov_pf_init_vf_bar(PCIDevice *dev, int region_num,
@@ -185,10 +141,26 @@ void pcie_sriov_vf_register_bar(PCIDevice *dev, int region_num,
}
}
-static void clear_ctrl_vfe(PCIDevice *dev)
+static PCIDevice *register_vf(PCIDevice *pf, int devfn, const char *name,
+ uint16_t vf_num)
{
- uint8_t *ctrl = dev->config + dev->exp.sriov_cap + PCI_SRIOV_CTRL;
- pci_set_word(ctrl, pci_get_word(ctrl) & ~PCI_SRIOV_CTRL_VFE);
+ PCIDevice *dev = pci_new(devfn, name);
+ dev->exp.sriov_vf.pf = pf;
+ dev->exp.sriov_vf.vf_number = vf_num;
+ PCIBus *bus = pci_get_bus(pf);
+ Error *local_err = NULL;
+
+ qdev_realize(&dev->qdev, &bus->qbus, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ return NULL;
+ }
+
+ /* set vid/did according to sr/iov spec - they are not used */
+ pci_config_set_vendor_id(dev->config, 0xffff);
+ pci_config_set_device_id(dev->config, 0xffff);
+
+ return dev;
}
static void register_vfs(PCIDevice *dev)
@@ -196,31 +168,53 @@ static void register_vfs(PCIDevice *dev)
uint16_t num_vfs;
uint16_t i;
uint16_t sriov_cap = dev->exp.sriov_cap;
+ uint16_t vf_offset =
+ pci_get_word(dev->config + sriov_cap + PCI_SRIOV_VF_OFFSET);
+ uint16_t vf_stride =
+ pci_get_word(dev->config + sriov_cap + PCI_SRIOV_VF_STRIDE);
+ int32_t devfn = dev->devfn + vf_offset;
assert(sriov_cap > 0);
num_vfs = pci_get_word(dev->config + sriov_cap + PCI_SRIOV_NUM_VF);
if (num_vfs > pci_get_word(dev->config + sriov_cap + PCI_SRIOV_TOTAL_VF)) {
- clear_ctrl_vfe(dev);
return;
}
+ dev->exp.sriov_pf.vf = g_new(PCIDevice *, num_vfs);
+
trace_sriov_register_vfs(dev->name, PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn), num_vfs);
for (i = 0; i < num_vfs; i++) {
- pci_set_enabled(dev->exp.sriov_pf.vf[i], true);
+ dev->exp.sriov_pf.vf[i] = register_vf(dev, devfn,
+ dev->exp.sriov_pf.vfname, i);
+ if (!dev->exp.sriov_pf.vf[i]) {
+ num_vfs = i;
+ break;
+ }
+ devfn += vf_stride;
}
+ dev->exp.sriov_pf.num_vfs = num_vfs;
}
static void unregister_vfs(PCIDevice *dev)
{
+ uint16_t num_vfs = dev->exp.sriov_pf.num_vfs;
uint16_t i;
- uint8_t *cfg = dev->config + dev->exp.sriov_cap;
trace_sriov_unregister_vfs(dev->name, PCI_SLOT(dev->devfn),
- PCI_FUNC(dev->devfn));
- for (i = 0; i < pci_get_word(cfg + PCI_SRIOV_TOTAL_VF); i++) {
- pci_set_enabled(dev->exp.sriov_pf.vf[i], false);
+ PCI_FUNC(dev->devfn), num_vfs);
+ for (i = 0; i < num_vfs; i++) {
+ Error *err = NULL;
+ PCIDevice *vf = dev->exp.sriov_pf.vf[i];
+ if (!object_property_set_bool(OBJECT(vf), "realized", false, &err)) {
+ error_reportf_err(err, "Failed to unplug: ");
+ }
+ object_unparent(OBJECT(vf));
+ object_unref(OBJECT(vf));
}
+ g_free(dev->exp.sriov_pf.vf);
+ dev->exp.sriov_pf.vf = NULL;
+ dev->exp.sriov_pf.num_vfs = 0;
}
void pcie_sriov_config_write(PCIDevice *dev, uint32_t address,
@@ -241,21 +235,15 @@ void pcie_sriov_config_write(PCIDevice *dev, uint32_t address,
PCI_FUNC(dev->devfn), off, val, len);
if (range_covers_byte(off, len, PCI_SRIOV_CTRL)) {
- if (val & PCI_SRIOV_CTRL_VFE) {
- register_vfs(dev);
+ if (dev->exp.sriov_pf.num_vfs) {
+ if (!(val & PCI_SRIOV_CTRL_VFE)) {
+ unregister_vfs(dev);
+ }
} else {
- unregister_vfs(dev);
+ if (val & PCI_SRIOV_CTRL_VFE) {
+ register_vfs(dev);
+ }
}
- } else if (range_covers_byte(off, len, PCI_SRIOV_NUM_VF)) {
- clear_ctrl_vfe(dev);
- unregister_vfs(dev);
- }
-}
-
-void pcie_sriov_pf_post_load(PCIDevice *dev)
-{
- if (dev->exp.sriov_cap) {
- register_vfs(dev);
}
}
@@ -318,7 +306,7 @@ PCIDevice *pcie_sriov_get_pf(PCIDevice *dev)
PCIDevice *pcie_sriov_get_vf_at_index(PCIDevice *dev, int n)
{
assert(!pci_is_vf(dev));
- if (n < pcie_sriov_num_vfs(dev)) {
+ if (n < dev->exp.sriov_pf.num_vfs) {
return dev->exp.sriov_pf.vf[n];
}
return NULL;
@@ -326,10 +314,5 @@ PCIDevice *pcie_sriov_get_vf_at_index(PCIDevice *dev, int n)
uint16_t pcie_sriov_num_vfs(PCIDevice *dev)
{
- uint16_t sriov_cap = dev->exp.sriov_cap;
- uint8_t *cfg = dev->config + sriov_cap;
-
- return sriov_cap &&
- (pci_get_word(cfg + PCI_SRIOV_CTRL) & PCI_SRIOV_CTRL_VFE) ?
- pci_get_word(cfg + PCI_SRIOV_NUM_VF) : 0;
+ return dev->exp.sriov_pf.num_vfs;
}
diff --git a/hw/pci/trace-events b/hw/pci/trace-events
index e98f575..19643aa 100644
--- a/hw/pci/trace-events
+++ b/hw/pci/trace-events
@@ -14,7 +14,7 @@ msix_write_config(char *name, bool enabled, bool masked) "dev %s enabled %d mask
# hw/pci/pcie_sriov.c
sriov_register_vfs(const char *name, int slot, int function, int num_vfs) "%s %02x:%x: creating %d vf devs"
-sriov_unregister_vfs(const char *name, int slot, int function) "%s %02x:%x: Unregistering vf devs"
+sriov_unregister_vfs(const char *name, int slot, int function, int num_vfs) "%s %02x:%x: Unregistering %d vf devs"
sriov_config_write(const char *name, int slot, int fun, uint32_t offset, uint32_t val, uint32_t len) "%s %02x:%x: sriov offset 0x%x val 0x%x len %d"
# pcie.c
diff --git a/hw/pcmcia/Kconfig b/hw/pcmcia/Kconfig
deleted file mode 100644
index 41f2df9..0000000
--- a/hw/pcmcia/Kconfig
+++ /dev/null
@@ -1,2 +0,0 @@
-config PCMCIA
- bool
diff --git a/hw/pcmcia/meson.build b/hw/pcmcia/meson.build
deleted file mode 100644
index 04e29c1..0000000
--- a/hw/pcmcia/meson.build
+++ /dev/null
@@ -1,2 +0,0 @@
-system_ss.add(when: 'CONFIG_PCMCIA', if_true: files('pcmcia.c'))
-system_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx.c'))
diff --git a/hw/pcmcia/pcmcia.c b/hw/pcmcia/pcmcia.c
deleted file mode 100644
index 03d13e7..0000000
--- a/hw/pcmcia/pcmcia.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * PCMCIA emulation
- *
- * Copyright 2013 SUSE LINUX Products GmbH
- */
-
-#include "qemu/osdep.h"
-#include "qemu/module.h"
-#include "hw/pcmcia.h"
-
-static const TypeInfo pcmcia_card_type_info = {
- .name = TYPE_PCMCIA_CARD,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(PCMCIACardState),
- .abstract = true,
- .class_size = sizeof(PCMCIACardClass),
-};
-
-static void pcmcia_register_types(void)
-{
- type_register_static(&pcmcia_card_type_info);
-}
-
-type_init(pcmcia_register_types)
diff --git a/hw/pcmcia/pxa2xx.c b/hw/pcmcia/pxa2xx.c
deleted file mode 100644
index e3111fd..0000000
--- a/hw/pcmcia/pxa2xx.c
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Intel XScale PXA255/270 PC Card and CompactFlash Interface.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPLv2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#include "qemu/osdep.h"
-#include "hw/irq.h"
-#include "hw/sysbus.h"
-#include "qapi/error.h"
-#include "qemu/module.h"
-#include "hw/pcmcia.h"
-#include "hw/arm/pxa.h"
-
-struct PXA2xxPCMCIAState {
- SysBusDevice parent_obj;
-
- PCMCIASocket slot;
- MemoryRegion container_mem;
- MemoryRegion common_iomem;
- MemoryRegion attr_iomem;
- MemoryRegion iomem;
-
- qemu_irq irq;
- qemu_irq cd_irq;
-
- PCMCIACardState *card;
-};
-
-static uint64_t pxa2xx_pcmcia_common_read(void *opaque,
- hwaddr offset, unsigned size)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (s->slot.attached) {
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
- return pcc->common_read(s->card, offset);
- }
-
- return 0;
-}
-
-static void pxa2xx_pcmcia_common_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (s->slot.attached) {
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
- pcc->common_write(s->card, offset, value);
- }
-}
-
-static uint64_t pxa2xx_pcmcia_attr_read(void *opaque,
- hwaddr offset, unsigned size)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (s->slot.attached) {
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
- return pcc->attr_read(s->card, offset);
- }
-
- return 0;
-}
-
-static void pxa2xx_pcmcia_attr_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (s->slot.attached) {
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
- pcc->attr_write(s->card, offset, value);
- }
-}
-
-static uint64_t pxa2xx_pcmcia_io_read(void *opaque,
- hwaddr offset, unsigned size)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (s->slot.attached) {
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
- return pcc->io_read(s->card, offset);
- }
-
- return 0;
-}
-
-static void pxa2xx_pcmcia_io_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (s->slot.attached) {
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
- pcc->io_write(s->card, offset, value);
- }
-}
-
-static const MemoryRegionOps pxa2xx_pcmcia_common_ops = {
- .read = pxa2xx_pcmcia_common_read,
- .write = pxa2xx_pcmcia_common_write,
- .endianness = DEVICE_NATIVE_ENDIAN
-};
-
-static const MemoryRegionOps pxa2xx_pcmcia_attr_ops = {
- .read = pxa2xx_pcmcia_attr_read,
- .write = pxa2xx_pcmcia_attr_write,
- .endianness = DEVICE_NATIVE_ENDIAN
-};
-
-static const MemoryRegionOps pxa2xx_pcmcia_io_ops = {
- .read = pxa2xx_pcmcia_io_read,
- .write = pxa2xx_pcmcia_io_write,
- .endianness = DEVICE_NATIVE_ENDIAN
-};
-
-static void pxa2xx_pcmcia_set_irq(void *opaque, int line, int level)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- if (!s->irq)
- return;
-
- qemu_set_irq(s->irq, level);
-}
-
-static void pxa2xx_pcmcia_initfn(Object *obj)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- PXA2xxPCMCIAState *s = PXA2XX_PCMCIA(obj);
-
- memory_region_init(&s->container_mem, obj, "container", 0x10000000);
- sysbus_init_mmio(sbd, &s->container_mem);
-
- /* Socket I/O Memory Space */
- memory_region_init_io(&s->iomem, obj, &pxa2xx_pcmcia_io_ops, s,
- "pxa2xx-pcmcia-io", 0x04000000);
- memory_region_add_subregion(&s->container_mem, 0x00000000,
- &s->iomem);
-
- /* Then next 64 MB is reserved */
-
- /* Socket Attribute Memory Space */
- memory_region_init_io(&s->attr_iomem, obj, &pxa2xx_pcmcia_attr_ops, s,
- "pxa2xx-pcmcia-attribute", 0x04000000);
- memory_region_add_subregion(&s->container_mem, 0x08000000,
- &s->attr_iomem);
-
- /* Socket Common Memory Space */
- memory_region_init_io(&s->common_iomem, obj, &pxa2xx_pcmcia_common_ops, s,
- "pxa2xx-pcmcia-common", 0x04000000);
- memory_region_add_subregion(&s->container_mem, 0x0c000000,
- &s->common_iomem);
-
- s->slot.irq = qemu_allocate_irq(pxa2xx_pcmcia_set_irq, s, 0);
-
- object_property_add_link(obj, "card", TYPE_PCMCIA_CARD,
- (Object **)&s->card,
- NULL, /* read-only property */
- 0);
-}
-
-/* Insert a new card into a slot */
-int pxa2xx_pcmcia_attach(void *opaque, PCMCIACardState *card)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (s->slot.attached) {
- return -EEXIST;
- }
-
- if (s->cd_irq) {
- qemu_irq_raise(s->cd_irq);
- }
-
- s->card = card;
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
-
- s->slot.attached = true;
- s->card->slot = &s->slot;
- pcc->attach(s->card);
-
- return 0;
-}
-
-/* Eject card from the slot */
-int pxa2xx_pcmcia_detach(void *opaque)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- PCMCIACardClass *pcc;
-
- if (!s->slot.attached) {
- return -ENOENT;
- }
-
- pcc = PCMCIA_CARD_GET_CLASS(s->card);
- pcc->detach(s->card);
- s->card->slot = NULL;
- s->card = NULL;
-
- s->slot.attached = false;
-
- if (s->irq) {
- qemu_irq_lower(s->irq);
- }
- if (s->cd_irq) {
- qemu_irq_lower(s->cd_irq);
- }
-
- return 0;
-}
-
-/* Who to notify on card events */
-void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq)
-{
- PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
- s->irq = irq;
- s->cd_irq = cd_irq;
-}
-
-static const TypeInfo pxa2xx_pcmcia_type_info = {
- .name = TYPE_PXA2XX_PCMCIA,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxPCMCIAState),
- .instance_init = pxa2xx_pcmcia_initfn,
-};
-
-static void pxa2xx_pcmcia_register_types(void)
-{
- type_register_static(&pxa2xx_pcmcia_type_info);
-}
-
-type_init(pxa2xx_pcmcia_register_types)
diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
index 347212f..b44d91b 100644
--- a/hw/ppc/Kconfig
+++ b/hw/ppc/Kconfig
@@ -39,6 +39,10 @@ config POWERNV
select PCI_POWERNV
select PCA9552
select PCA9554
+ select SERIAL_ISA
+ select SSI
+ select SSI_M25P80
+ select PNV_SPI
config PPC405
bool
@@ -47,7 +51,7 @@ config PPC405
select M48T59
select PFLASH_CFI02
select PPC4XX
- select SERIAL
+ select SERIAL_MM
config PPC440
bool
@@ -59,7 +63,7 @@ config PPC440
select PCI_EXPRESS
select PPC440_PCIX
select PPC4XX
- select SERIAL
+ select SERIAL_MM
select FDT_PPC
config PPC4XX
@@ -76,7 +80,7 @@ config SAM460EX
select IDE_SII3112
select M41T80
select PPC440
- select SERIAL
+ select SERIAL_MM
select SM501
select SMBUS_EEPROM
select USB_EHCI_SYSBUS
@@ -159,7 +163,7 @@ config E500
select PLATFORM_BUS
select PPCE500_PCI
select SDHCI
- select SERIAL
+ select SERIAL_MM
select MPC_I2C
select FDT_PPC
select DS1338
@@ -183,7 +187,7 @@ config VIRTEX
depends on PPC && FDT
select PPC4XX
select PFLASH_CFI01
- select SERIAL
+ select SERIAL_MM
select XILINX
select XILINX_ETHLITE
select FDT_PPC
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 3bd12b5..b760c6d 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -24,7 +24,7 @@
#include "net/net.h"
#include "qemu/config-file.h"
#include "hw/block/flash.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/pci/pci.h"
#include "sysemu/block-backend-io.h"
#include "sysemu/sysemu.h"
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index ff9e490..9d249a5 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -571,7 +571,7 @@ static void core99_machine_class_init(ObjectClass *oc, void *data)
MachineClass *mc = MACHINE_CLASS(oc);
FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
- mc->desc = "Mac99 based PowerMAC";
+ mc->desc = "Mac99 based PowerMac";
mc->init = ppc_core99_init;
mc->block_default_type = IF_IDE;
/* SMP is not supported currently */
diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c
index 1981d3d..eef3261 100644
--- a/hw/ppc/mac_oldworld.c
+++ b/hw/ppc/mac_oldworld.c
@@ -411,7 +411,7 @@ static void heathrow_class_init(ObjectClass *oc, void *data)
MachineClass *mc = MACHINE_CLASS(oc);
FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
- mc->desc = "Heathrow based PowerMAC";
+ mc->desc = "Heathrow based PowerMac";
mc->init = ppc_heathrow_init;
mc->block_default_type = IF_IDE;
/* SMP is not supported currently */
diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build
index 3ebbf32..7cd9189 100644
--- a/hw/ppc/meson.build
+++ b/hw/ppc/meson.build
@@ -42,6 +42,7 @@ endif
ppc_ss.add(when: 'CONFIG_POWERNV', if_true: files(
'pnv.c',
'pnv_xscom.c',
+ 'pnv_adu.c',
'pnv_core.c',
'pnv_i2c.c',
'pnv_lpc.c',
diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c
index 9b0a6b7..8ff4a00 100644
--- a/hw/ppc/pegasos2.c
+++ b/hw/ppc/pegasos2.c
@@ -291,14 +291,14 @@ static void pegasos2_superio_write(uint8_t addr, uint8_t val)
cpu_physical_memory_write(PCI1_IO_BASE + 0x3f1, &val, 1);
}
-static void pegasos2_machine_reset(MachineState *machine, ShutdownCause reason)
+static void pegasos2_machine_reset(MachineState *machine, ResetType type)
{
Pegasos2MachineState *pm = PEGASOS2_MACHINE(machine);
void *fdt;
uint64_t d[2];
int sz;
- qemu_devices_reset(reason);
+ qemu_devices_reset(type);
if (!pm->vof) {
return; /* Firmware should set up machine so nothing to do */
}
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 6b41d1d..795acc2 100644
--- a/hw/ppc/pnv.c
+++ b/hw/ppc/pnv.c
@@ -53,7 +53,7 @@
#include "hw/ppc/pnv_pnor.h"
#include "hw/isa/isa.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-isa.h"
#include "hw/rtc/mc146818rtc.h"
#include <libfdt.h>
@@ -141,9 +141,9 @@ static int pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
CPUPPCState *env = &cpu->env;
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
PnvChipClass *pnv_cc = PNV_CHIP_GET_CLASS(chip);
- g_autofree uint32_t *servers_prop = g_new(uint32_t, smt_threads);
+ uint32_t *servers_prop;
int i;
- uint32_t pir;
+ uint32_t pir, tir;
uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
0xffffffff, 0xffffffff};
uint32_t tbfreq = PNV_TIMEBASE_FREQ;
@@ -154,7 +154,10 @@ static int pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
char *nodename;
int cpus_offset = get_cpus_node(fdt);
- pir = pnv_cc->chip_pir(chip, pc->hwid, 0);
+ pnv_cc->get_pir_tir(chip, pc->hwid, 0, &pir, &tir);
+
+ /* Only one DT node per (big) core */
+ g_assert(tir == 0);
nodename = g_strdup_printf("%s@%x", dc->fw_name, pir);
offset = fdt_add_subnode(fdt, cpus_offset, nodename);
@@ -235,11 +238,28 @@ static int pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
}
/* Build interrupt servers properties */
- for (i = 0; i < smt_threads; i++) {
- servers_prop[i] = cpu_to_be32(pnv_cc->chip_pir(chip, pc->hwid, i));
+ if (pc->big_core) {
+ servers_prop = g_new(uint32_t, smt_threads * 2);
+ for (i = 0; i < smt_threads; i++) {
+ pnv_cc->get_pir_tir(chip, pc->hwid, i, &pir, NULL);
+ servers_prop[i * 2] = cpu_to_be32(pir);
+
+ pnv_cc->get_pir_tir(chip, pc->hwid + 1, i, &pir, NULL);
+ servers_prop[i * 2 + 1] = cpu_to_be32(pir);
+ }
+ _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
+ servers_prop, sizeof(*servers_prop) * smt_threads
+ * 2)));
+ } else {
+ servers_prop = g_new(uint32_t, smt_threads);
+ for (i = 0; i < smt_threads; i++) {
+ pnv_cc->get_pir_tir(chip, pc->hwid, i, &pir, NULL);
+ servers_prop[i] = cpu_to_be32(pir);
+ }
+ _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
+ servers_prop, sizeof(*servers_prop) * smt_threads)));
}
- _FDT((fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
- servers_prop, sizeof(*servers_prop) * smt_threads)));
+ g_free(servers_prop);
return offset;
}
@@ -248,14 +268,17 @@ static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t hwid,
uint32_t nr_threads)
{
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
- uint32_t pir = pcc->chip_pir(chip, hwid, 0);
- uint64_t addr = PNV_ICP_BASE(chip) | (pir << 12);
+ uint32_t pir;
+ uint64_t addr;
char *name;
const char compat[] = "IBM,power8-icp\0IBM,ppc-xicp";
uint32_t irange[2], i, rsize;
uint64_t *reg;
int offset;
+ pcc->get_pir_tir(chip, hwid, 0, &pir, NULL);
+ addr = PNV_ICP_BASE(chip) | (pir << 12);
+
irange[0] = cpu_to_be32(pir);
irange[1] = cpu_to_be32(nr_threads);
@@ -385,6 +408,10 @@ static void pnv_chip_power9_dt_populate(PnvChip *chip, void *fdt)
_FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
pa_features_300, sizeof(pa_features_300))));
+
+ if (pnv_core->big_core) {
+ i++; /* Big-core groups two QEMU cores */
+ }
}
if (chip->ram_size) {
@@ -446,6 +473,10 @@ static void pnv_chip_power10_dt_populate(PnvChip *chip, void *fdt)
_FDT((fdt_setprop(fdt, offset, "ibm,pa-features",
pa_features_31, sizeof(pa_features_31))));
+
+ if (pnv_core->big_core) {
+ i++; /* Big-core groups two QEMU cores */
+ }
}
if (chip->ram_size) {
@@ -678,13 +709,13 @@ static void pnv_powerdown_notify(Notifier *n, void *opaque)
}
}
-static void pnv_reset(MachineState *machine, ShutdownCause reason)
+static void pnv_reset(MachineState *machine, ResetType type)
{
PnvMachineState *pnv = PNV_MACHINE(machine);
IPMIBmc *bmc;
void *fdt;
- qemu_devices_reset(reason);
+ qemu_devices_reset(type);
/*
* The machine should provide by default an internal BMC simulator.
@@ -727,7 +758,8 @@ static ISABus *pnv_chip_power8_isa_create(PnvChip *chip, Error **errp)
Pnv8Chip *chip8 = PNV8_CHIP(chip);
qemu_irq irq = qdev_get_gpio_in(DEVICE(&chip8->psi), PSIHB_IRQ_EXTERNAL);
- qdev_connect_gpio_out(DEVICE(&chip8->lpc), 0, irq);
+ qdev_connect_gpio_out_named(DEVICE(&chip8->lpc), "LPCHC", 0, irq);
+
return pnv_lpc_isa_create(&chip8->lpc, true, errp);
}
@@ -736,25 +768,48 @@ static ISABus *pnv_chip_power8nvl_isa_create(PnvChip *chip, Error **errp)
Pnv8Chip *chip8 = PNV8_CHIP(chip);
qemu_irq irq = qdev_get_gpio_in(DEVICE(&chip8->psi), PSIHB_IRQ_LPC_I2C);
- qdev_connect_gpio_out(DEVICE(&chip8->lpc), 0, irq);
+ qdev_connect_gpio_out_named(DEVICE(&chip8->lpc), "LPCHC", 0, irq);
+
return pnv_lpc_isa_create(&chip8->lpc, false, errp);
}
static ISABus *pnv_chip_power9_isa_create(PnvChip *chip, Error **errp)
{
Pnv9Chip *chip9 = PNV9_CHIP(chip);
- qemu_irq irq = qdev_get_gpio_in(DEVICE(&chip9->psi), PSIHB9_IRQ_LPCHC);
+ qemu_irq irq;
+
+ irq = qdev_get_gpio_in(DEVICE(&chip9->psi), PSIHB9_IRQ_LPCHC);
+ qdev_connect_gpio_out_named(DEVICE(&chip9->lpc), "LPCHC", 0, irq);
+
+ irq = qdev_get_gpio_in(DEVICE(&chip9->psi), PSIHB9_IRQ_LPC_SIRQ0);
+ qdev_connect_gpio_out_named(DEVICE(&chip9->lpc), "SERIRQ", 0, irq);
+ irq = qdev_get_gpio_in(DEVICE(&chip9->psi), PSIHB9_IRQ_LPC_SIRQ1);
+ qdev_connect_gpio_out_named(DEVICE(&chip9->lpc), "SERIRQ", 1, irq);
+ irq = qdev_get_gpio_in(DEVICE(&chip9->psi), PSIHB9_IRQ_LPC_SIRQ2);
+ qdev_connect_gpio_out_named(DEVICE(&chip9->lpc), "SERIRQ", 2, irq);
+ irq = qdev_get_gpio_in(DEVICE(&chip9->psi), PSIHB9_IRQ_LPC_SIRQ3);
+ qdev_connect_gpio_out_named(DEVICE(&chip9->lpc), "SERIRQ", 3, irq);
- qdev_connect_gpio_out(DEVICE(&chip9->lpc), 0, irq);
return pnv_lpc_isa_create(&chip9->lpc, false, errp);
}
static ISABus *pnv_chip_power10_isa_create(PnvChip *chip, Error **errp)
{
Pnv10Chip *chip10 = PNV10_CHIP(chip);
- qemu_irq irq = qdev_get_gpio_in(DEVICE(&chip10->psi), PSIHB9_IRQ_LPCHC);
+ qemu_irq irq;
+
+ irq = qdev_get_gpio_in(DEVICE(&chip10->psi), PSIHB9_IRQ_LPCHC);
+ qdev_connect_gpio_out_named(DEVICE(&chip10->lpc), "LPCHC", 0, irq);
+
+ irq = qdev_get_gpio_in(DEVICE(&chip10->psi), PSIHB9_IRQ_LPC_SIRQ0);
+ qdev_connect_gpio_out_named(DEVICE(&chip10->lpc), "SERIRQ", 0, irq);
+ irq = qdev_get_gpio_in(DEVICE(&chip10->psi), PSIHB9_IRQ_LPC_SIRQ1);
+ qdev_connect_gpio_out_named(DEVICE(&chip10->lpc), "SERIRQ", 1, irq);
+ irq = qdev_get_gpio_in(DEVICE(&chip10->psi), PSIHB9_IRQ_LPC_SIRQ2);
+ qdev_connect_gpio_out_named(DEVICE(&chip10->lpc), "SERIRQ", 2, irq);
+ irq = qdev_get_gpio_in(DEVICE(&chip10->psi), PSIHB9_IRQ_LPC_SIRQ3);
+ qdev_connect_gpio_out_named(DEVICE(&chip10->lpc), "SERIRQ", 3, irq);
- qdev_connect_gpio_out(DEVICE(&chip10->lpc), 0, irq);
return pnv_lpc_isa_create(&chip10->lpc, false, errp);
}
@@ -875,6 +930,7 @@ static void pnv_init(MachineState *machine)
PnvMachineState *pnv = PNV_MACHINE(machine);
MachineClass *mc = MACHINE_GET_CLASS(machine);
PnvMachineClass *pmc = PNV_MACHINE_GET_CLASS(machine);
+ int max_smt_threads = pmc->max_smt_threads;
char *fw_filename;
long fw_size;
uint64_t chip_ram_start = 0;
@@ -970,20 +1026,52 @@ static void pnv_init(MachineState *machine)
exit(1);
}
+ /* Set lpar-per-core mode if lpar-per-thread is not supported */
+ if (!pmc->has_lpar_per_thread) {
+ pnv->lpar_per_core = true;
+ }
+
pnv->num_chips =
machine->smp.max_cpus / (machine->smp.cores * machine->smp.threads);
- if (machine->smp.threads > 8) {
- error_report("Cannot support more than 8 threads/core "
- "on a powernv machine");
+ if (pnv->big_core) {
+ if (machine->smp.threads % 2 == 1) {
+ error_report("Cannot support %d threads with big-core option "
+ "because it must be an even number",
+ machine->smp.threads);
+ exit(1);
+ }
+ max_smt_threads *= 2;
+ }
+
+ if (machine->smp.threads > max_smt_threads) {
+ error_report("Cannot support more than %d threads/core "
+ "on %s machine", max_smt_threads, mc->desc);
+ if (pmc->max_smt_threads == 4) {
+ error_report("(use big-core=on for 8 threads per core)");
+ }
exit(1);
}
+
+ if (pnv->big_core) {
+ /*
+ * powernv models PnvCore as a SMT4 core. Big-core requires 2xPnvCore
+ * per core, so adjust topology here. pnv_dt_core() processor
+ * device-tree and TCG SMT code make the 2 cores appear as one big core
+ * from software point of view. pnv pervasive models and xscoms tend to
+ * see the big core as 2 small core halves.
+ */
+ machine->smp.cores *= 2;
+ machine->smp.threads /= 2;
+ }
+
if (!is_power_of_2(machine->smp.threads)) {
- error_report("Cannot support %d threads/core on a powernv"
+ error_report("Cannot support %d threads/core on a powernv "
"machine because it must be a power of 2",
machine->smp.threads);
exit(1);
}
+
/*
* TODO: should we decide on how many chips we can create based
* on #cores and Venice vs. Murano vs. Naples chip type etc...,
@@ -1017,6 +1105,10 @@ static void pnv_init(MachineState *machine)
&error_fatal);
object_property_set_int(chip, "nr-threads", machine->smp.threads,
&error_fatal);
+ object_property_set_bool(chip, "big-core", pnv->big_core,
+ &error_fatal);
+ object_property_set_bool(chip, "lpar-per-core", pnv->lpar_per_core,
+ &error_fatal);
/*
* The POWER8 machine use the XICS interrupt interface.
* Propagate the XICS fabric to the chip and its controllers.
@@ -1079,10 +1171,16 @@ static void pnv_init(MachineState *machine)
* 25:28 Core number
* 29:31 Thread ID
*/
-static uint32_t pnv_chip_pir_p8(PnvChip *chip, uint32_t core_id,
- uint32_t thread_id)
+static void pnv_get_pir_tir_p8(PnvChip *chip,
+ uint32_t core_id, uint32_t thread_id,
+ uint32_t *pir, uint32_t *tir)
{
- return (chip->chip_id << 7) | (core_id << 3) | thread_id;
+ if (pir) {
+ *pir = (chip->chip_id << 7) | (core_id << 3) | thread_id;
+ }
+ if (tir) {
+ *tir = thread_id;
+ }
}
static void pnv_chip_power8_intc_create(PnvChip *chip, PowerPCCPU *cpu,
@@ -1134,14 +1232,26 @@ static void pnv_chip_power8_intc_print_info(PnvChip *chip, PowerPCCPU *cpu,
*
* We only care about the lower bits. uint32_t is fine for the moment.
*/
-static uint32_t pnv_chip_pir_p9(PnvChip *chip, uint32_t core_id,
- uint32_t thread_id)
-{
- if (chip->nr_threads == 8) {
- return (chip->chip_id << 8) | ((thread_id & 1) << 2) | (core_id << 3) |
- (thread_id >> 1);
+static void pnv_get_pir_tir_p9(PnvChip *chip,
+ uint32_t core_id, uint32_t thread_id,
+ uint32_t *pir, uint32_t *tir)
+{
+ if (chip->big_core) {
+ /* Big-core interleaves thread ID between small-cores */
+ thread_id <<= 1;
+ thread_id |= core_id & 1;
+ core_id >>= 1;
+
+ if (pir) {
+ *pir = (chip->chip_id << 8) | (core_id << 3) | thread_id;
+ }
} else {
- return (chip->chip_id << 8) | (core_id << 2) | thread_id;
+ if (pir) {
+ *pir = (chip->chip_id << 8) | (core_id << 2) | thread_id;
+ }
+ }
+ if (tir) {
+ *tir = thread_id;
}
}
@@ -1156,14 +1266,26 @@ static uint32_t pnv_chip_pir_p9(PnvChip *chip, uint32_t core_id,
*
* We only care about the lower bits. uint32_t is fine for the moment.
*/
-static uint32_t pnv_chip_pir_p10(PnvChip *chip, uint32_t core_id,
- uint32_t thread_id)
-{
- if (chip->nr_threads == 8) {
- return (chip->chip_id << 8) | ((core_id / 4) << 4) |
- ((core_id % 2) << 3) | thread_id;
+static void pnv_get_pir_tir_p10(PnvChip *chip,
+ uint32_t core_id, uint32_t thread_id,
+ uint32_t *pir, uint32_t *tir)
+{
+ if (chip->big_core) {
+ /* Big-core interleaves thread ID between small-cores */
+ thread_id <<= 1;
+ thread_id |= core_id & 1;
+ core_id >>= 1;
+
+ if (pir) {
+ *pir = (chip->chip_id << 8) | (core_id << 3) | thread_id;
+ }
} else {
- return (chip->chip_id << 8) | (core_id << 2) | thread_id;
+ if (pir) {
+ *pir = (chip->chip_id << 8) | (core_id << 2) | thread_id;
+ }
+ }
+ if (tir) {
+ *tir = thread_id;
}
}
@@ -1343,8 +1465,11 @@ static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp)
int core_hwid = CPU_CORE(pnv_core)->core_id;
for (j = 0; j < CPU_CORE(pnv_core)->nr_threads; j++) {
- uint32_t pir = pcc->chip_pir(chip, core_hwid, j);
- PnvICPState *icp = PNV_ICP(xics_icp_get(chip8->xics, pir));
+ uint32_t pir;
+ PnvICPState *icp;
+
+ pcc->get_pir_tir(chip, core_hwid, j, &pir, NULL);
+ icp = PNV_ICP(xics_icp_get(chip8->xics, pir));
memory_region_add_subregion(&chip8->icp_mmio, pir << 12,
&icp->mmio);
@@ -1456,7 +1581,7 @@ static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
k->chip_cfam_id = 0x221ef04980000000ull; /* P8 Murano DD2.1 */
k->cores_mask = POWER8E_CORE_MASK;
k->num_phbs = 3;
- k->chip_pir = pnv_chip_pir_p8;
+ k->get_pir_tir = pnv_get_pir_tir_p8;
k->intc_create = pnv_chip_power8_intc_create;
k->intc_reset = pnv_chip_power8_intc_reset;
k->intc_destroy = pnv_chip_power8_intc_destroy;
@@ -1480,7 +1605,7 @@ static void pnv_chip_power8_class_init(ObjectClass *klass, void *data)
k->chip_cfam_id = 0x220ea04980000000ull; /* P8 Venice DD2.0 */
k->cores_mask = POWER8_CORE_MASK;
k->num_phbs = 3;
- k->chip_pir = pnv_chip_pir_p8;
+ k->get_pir_tir = pnv_get_pir_tir_p8;
k->intc_create = pnv_chip_power8_intc_create;
k->intc_reset = pnv_chip_power8_intc_reset;
k->intc_destroy = pnv_chip_power8_intc_destroy;
@@ -1504,7 +1629,7 @@ static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data)
k->chip_cfam_id = 0x120d304980000000ull; /* P8 Naples DD1.0 */
k->cores_mask = POWER8_CORE_MASK;
k->num_phbs = 4;
- k->chip_pir = pnv_chip_pir_p8;
+ k->get_pir_tir = pnv_get_pir_tir_p8;
k->intc_create = pnv_chip_power8_intc_create;
k->intc_reset = pnv_chip_power8_intc_reset;
k->intc_destroy = pnv_chip_power8_intc_destroy;
@@ -1527,6 +1652,7 @@ static void pnv_chip_power9_instance_init(Object *obj)
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(obj);
int i;
+ object_initialize_child(obj, "adu", &chip9->adu, TYPE_PNV_ADU);
object_initialize_child(obj, "xive", &chip9->xive, TYPE_PNV_XIVE);
object_property_add_alias(obj, "xive-fabric", OBJECT(&chip9->xive),
"xive-fabric");
@@ -1637,6 +1763,15 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
return;
}
+ /* ADU */
+ object_property_set_link(OBJECT(&chip9->adu), "lpc", OBJECT(&chip9->lpc),
+ &error_abort);
+ if (!qdev_realize(DEVICE(&chip9->adu), NULL, errp)) {
+ return;
+ }
+ pnv_xscom_add_subregion(chip, PNV9_XSCOM_ADU_BASE,
+ &chip9->adu.xscom_regs);
+
pnv_chip_quad_realize(chip9, &local_err);
if (local_err) {
error_propagate(errp, local_err);
@@ -1777,7 +1912,7 @@ static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
k->chip_cfam_id = 0x220d104900008000ull; /* P9 Nimbus DD2.0 */
k->cores_mask = POWER9_CORE_MASK;
- k->chip_pir = pnv_chip_pir_p9;
+ k->get_pir_tir = pnv_get_pir_tir_p9;
k->intc_create = pnv_chip_power9_intc_create;
k->intc_reset = pnv_chip_power9_intc_reset;
k->intc_destroy = pnv_chip_power9_intc_destroy;
@@ -1803,6 +1938,7 @@ static void pnv_chip_power10_instance_init(Object *obj)
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(obj);
int i;
+ object_initialize_child(obj, "adu", &chip10->adu, TYPE_PNV_ADU);
object_initialize_child(obj, "xive", &chip10->xive, TYPE_PNV_XIVE2);
object_property_add_alias(obj, "xive-fabric", OBJECT(&chip10->xive),
"xive-fabric");
@@ -1826,6 +1962,11 @@ static void pnv_chip_power10_instance_init(Object *obj)
for (i = 0; i < pcc->i2c_num_engines; i++) {
object_initialize_child(obj, "i2c[*]", &chip10->i2c[i], TYPE_PNV_I2C);
}
+
+ for (i = 0; i < PNV10_CHIP_MAX_PIB_SPIC; i++) {
+ object_initialize_child(obj, "pib_spic[*]", &chip10->pib_spic[i],
+ TYPE_PNV_SPI);
+ }
}
static void pnv_chip_power10_quad_realize(Pnv10Chip *chip10, Error **errp)
@@ -1895,6 +2036,15 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
return;
}
+ /* ADU */
+ object_property_set_link(OBJECT(&chip10->adu), "lpc", OBJECT(&chip10->lpc),
+ &error_abort);
+ if (!qdev_realize(DEVICE(&chip10->adu), NULL, errp)) {
+ return;
+ }
+ pnv_xscom_add_subregion(chip, PNV10_XSCOM_ADU_BASE,
+ &chip10->adu.xscom_regs);
+
pnv_chip_power10_quad_realize(chip10, &local_err);
if (local_err) {
error_propagate(errp, local_err);
@@ -2040,7 +2190,21 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(DEVICE(&chip10->psi),
PSIHB9_IRQ_SBE_I2C));
}
-
+ /* PIB SPI Controller */
+ for (i = 0; i < PNV10_CHIP_MAX_PIB_SPIC; i++) {
+ object_property_set_int(OBJECT(&chip10->pib_spic[i]), "spic_num",
+ i, &error_fatal);
+ /* pib_spic[2] connected to 25csm04 which implements 1 byte transfer */
+ object_property_set_int(OBJECT(&chip10->pib_spic[i]), "transfer_len",
+ (i == 2) ? 1 : 4, &error_fatal);
+ if (!sysbus_realize(SYS_BUS_DEVICE(OBJECT
+ (&chip10->pib_spic[i])), errp)) {
+ return;
+ }
+ pnv_xscom_add_subregion(chip, PNV10_XSCOM_PIB_SPIC_BASE +
+ i * PNV10_XSCOM_PIB_SPIC_SIZE,
+ &chip10->pib_spic[i].xscom_spic_regs);
+ }
}
static void pnv_rainier_i2c_init(PnvMachineState *pnv)
@@ -2087,9 +2251,9 @@ static void pnv_chip_power10_class_init(ObjectClass *klass, void *data)
PnvChipClass *k = PNV_CHIP_CLASS(klass);
static const int i2c_ports_per_engine[PNV10_CHIP_MAX_I2C] = {14, 14, 2, 16};
- k->chip_cfam_id = 0x120da04900008000ull; /* P10 DD1.0 (with NX) */
+ k->chip_cfam_id = 0x220da04980000000ull; /* P10 DD2.0 (with NX) */
k->cores_mask = POWER10_CORE_MASK;
- k->chip_pir = pnv_chip_pir_p10;
+ k->get_pir_tir = pnv_get_pir_tir_p10;
k->intc_create = pnv_chip_power10_intc_create;
k->intc_reset = pnv_chip_power10_intc_reset;
k->intc_destroy = pnv_chip_power10_intc_destroy;
@@ -2108,7 +2272,8 @@ static void pnv_chip_power10_class_init(ObjectClass *klass, void *data)
&k->parent_realize);
}
-static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
+static void pnv_chip_core_sanitize(PnvMachineState *pnv, PnvChip *chip,
+ Error **errp)
{
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
int cores_max;
@@ -2129,6 +2294,17 @@ static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
}
chip->cores_mask &= pcc->cores_mask;
+ /* Ensure small-cores a paired up in big-core mode */
+ if (pnv->big_core) {
+ uint64_t even_cores = chip->cores_mask & 0x5555555555555555ULL;
+ uint64_t odd_cores = chip->cores_mask & 0xaaaaaaaaaaaaaaaaULL;
+
+ if (even_cores ^ (odd_cores >> 1)) {
+ error_setg(errp, "warning: unpaired cores in big-core mode !");
+ return;
+ }
+ }
+
/* now that we have a sane layout, let check the number of cores */
cores_max = ctpop64(chip->cores_mask);
if (chip->nr_cores > cores_max) {
@@ -2140,11 +2316,12 @@ static void pnv_chip_core_sanitize(PnvChip *chip, Error **errp)
static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
{
+ PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
+ PnvMachineClass *pmc = PNV_MACHINE_GET_CLASS(pnv);
Error *error = NULL;
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(chip);
const char *typename = pnv_chip_core_typename(chip);
int i, core_hwid;
- PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
if (!object_class_by_name(typename)) {
error_setg(errp, "Unable to find PowerNV CPU Core '%s'", typename);
@@ -2152,7 +2329,7 @@ static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
}
/* Cores */
- pnv_chip_core_sanitize(chip, &error);
+ pnv_chip_core_sanitize(pnv, chip, &error);
if (error) {
error_propagate(errp, error);
return;
@@ -2183,8 +2360,15 @@ static void pnv_chip_core_realize(PnvChip *chip, Error **errp)
&error_fatal);
object_property_set_int(OBJECT(pnv_core), "hrmor", pnv->fw_load_addr,
&error_fatal);
+ object_property_set_bool(OBJECT(pnv_core), "big-core", chip->big_core,
+ &error_fatal);
+ object_property_set_bool(OBJECT(pnv_core), "quirk-tb-big-core",
+ pmc->quirk_tb_big_core, &error_fatal);
+ object_property_set_bool(OBJECT(pnv_core), "lpar-per-core",
+ chip->lpar_per_core, &error_fatal);
object_property_set_link(OBJECT(pnv_core), "chip", OBJECT(chip),
&error_abort);
+
qdev_realize(DEVICE(pnv_core), NULL, &error_fatal);
/* Each core has an XSCOM MMIO region */
@@ -2216,6 +2400,8 @@ static Property pnv_chip_properties[] = {
DEFINE_PROP_UINT32("nr-cores", PnvChip, nr_cores, 1),
DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0),
DEFINE_PROP_UINT32("nr-threads", PnvChip, nr_threads, 1),
+ DEFINE_PROP_BOOL("big-core", PnvChip, big_core, false),
+ DEFINE_PROP_BOOL("lpar-per-core", PnvChip, lpar_per_core, false),
DEFINE_PROP_END_OF_LIST(),
};
@@ -2424,6 +2610,46 @@ static int pnv10_xive_match_nvt(XiveFabric *xfb, uint8_t format,
return total_count;
}
+static bool pnv_machine_get_big_core(Object *obj, Error **errp)
+{
+ PnvMachineState *pnv = PNV_MACHINE(obj);
+ return pnv->big_core;
+}
+
+static void pnv_machine_set_big_core(Object *obj, bool value, Error **errp)
+{
+ PnvMachineState *pnv = PNV_MACHINE(obj);
+ pnv->big_core = value;
+}
+
+static bool pnv_machine_get_lpar_per_core(Object *obj, Error **errp)
+{
+ PnvMachineState *pnv = PNV_MACHINE(obj);
+ return pnv->lpar_per_core;
+}
+
+static void pnv_machine_set_lpar_per_core(Object *obj, bool value, Error **errp)
+{
+ PnvMachineState *pnv = PNV_MACHINE(obj);
+ pnv->lpar_per_core = value;
+}
+
+static bool pnv_machine_get_hb(Object *obj, Error **errp)
+{
+ PnvMachineState *pnv = PNV_MACHINE(obj);
+
+ return !!pnv->fw_load_addr;
+}
+
+static void pnv_machine_set_hb(Object *obj, bool value, Error **errp)
+{
+ PnvMachineState *pnv = PNV_MACHINE(obj);
+
+ if (value) {
+ pnv->fw_load_addr = 0x8000000;
+ }
+}
+
static void pnv_machine_power8_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -2446,6 +2672,9 @@ static void pnv_machine_power8_class_init(ObjectClass *oc, void *data)
pmc->compat = compat;
pmc->compat_size = sizeof(compat);
+ pmc->max_smt_threads = 8;
+ /* POWER8 is always lpar-per-core mode */
+ pmc->has_lpar_per_thread = false;
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB);
}
@@ -2470,9 +2699,23 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data)
pmc->compat = compat;
pmc->compat_size = sizeof(compat);
+ pmc->max_smt_threads = 4;
+ pmc->has_lpar_per_thread = true;
pmc->dt_power_mgt = pnv_dt_power_mgt;
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB);
+
+ object_class_property_add_bool(oc, "big-core",
+ pnv_machine_get_big_core,
+ pnv_machine_set_big_core);
+ object_class_property_set_description(oc, "big-core",
+ "Use big-core (aka fused-core) mode");
+
+ object_class_property_add_bool(oc, "lpar-per-core",
+ pnv_machine_get_lpar_per_core,
+ pnv_machine_set_lpar_per_core);
+ object_class_property_set_description(oc, "lpar-per-core",
+ "Use 1 LPAR per core mode");
}
static void pnv_machine_p10_common_class_init(ObjectClass *oc, void *data)
@@ -2494,6 +2737,9 @@ static void pnv_machine_p10_common_class_init(ObjectClass *oc, void *data)
pmc->compat = compat;
pmc->compat_size = sizeof(compat);
+ pmc->max_smt_threads = 4;
+ pmc->has_lpar_per_thread = true;
+ pmc->quirk_tb_big_core = true;
pmc->dt_power_mgt = pnv_dt_power_mgt;
xfc->match_nvt = pnv10_xive_match_nvt;
@@ -2507,6 +2753,23 @@ static void pnv_machine_power10_class_init(ObjectClass *oc, void *data)
pnv_machine_p10_common_class_init(oc, data);
mc->desc = "IBM PowerNV (Non-Virtualized) POWER10";
+
+ /*
+ * This is the parent of POWER10 Rainier class, so properies go here
+ * rather than common init (which would add them to both parent and
+ * child which is invalid).
+ */
+ object_class_property_add_bool(oc, "big-core",
+ pnv_machine_get_big_core,
+ pnv_machine_set_big_core);
+ object_class_property_set_description(oc, "big-core",
+ "Use big-core (aka fused-core) mode");
+
+ object_class_property_add_bool(oc, "lpar-per-core",
+ pnv_machine_get_lpar_per_core,
+ pnv_machine_set_lpar_per_core);
+ object_class_property_set_description(oc, "lpar-per-core",
+ "Use 1 LPAR per core mode");
}
static void pnv_machine_p10_rainier_class_init(ObjectClass *oc, void *data)
@@ -2519,22 +2782,6 @@ static void pnv_machine_p10_rainier_class_init(ObjectClass *oc, void *data)
pmc->i2c_init = pnv_rainier_i2c_init;
}
-static bool pnv_machine_get_hb(Object *obj, Error **errp)
-{
- PnvMachineState *pnv = PNV_MACHINE(obj);
-
- return !!pnv->fw_load_addr;
-}
-
-static void pnv_machine_set_hb(Object *obj, bool value, Error **errp)
-{
- PnvMachineState *pnv = PNV_MACHINE(obj);
-
- if (value) {
- pnv->fw_load_addr = 0x8000000;
- }
-}
-
static void pnv_cpu_do_nmi_on_cpu(CPUState *cs, run_on_cpu_data arg)
{
CPUPPCState *env = cpu_env(cs);
@@ -2561,11 +2808,23 @@ static void pnv_cpu_do_nmi_on_cpu(CPUState *cs, run_on_cpu_data arg)
*/
env->spr[SPR_SRR1] |= SRR1_WAKESCOM;
}
+ if (arg.host_int == 1) {
+ cpu_resume(cs);
+ }
+}
+
+/*
+ * Send a SRESET (NMI) interrupt to the CPU, and resume execution if it was
+ * paused.
+ */
+void pnv_cpu_do_nmi_resume(CPUState *cs)
+{
+ async_run_on_cpu(cs, pnv_cpu_do_nmi_on_cpu, RUN_ON_CPU_HOST_INT(1));
}
static void pnv_cpu_do_nmi(PnvChip *chip, PowerPCCPU *cpu, void *opaque)
{
- async_run_on_cpu(CPU(cpu), pnv_cpu_do_nmi_on_cpu, RUN_ON_CPU_NULL);
+ async_run_on_cpu(CPU(cpu), pnv_cpu_do_nmi_on_cpu, RUN_ON_CPU_HOST_INT(0));
}
static void pnv_nmi(NMIState *n, int cpu_index, Error **errp)
diff --git a/hw/ppc/pnv_adu.c b/hw/ppc/pnv_adu.c
new file mode 100644
index 0000000..81b7d6e
--- /dev/null
+++ b/hw/ppc/pnv_adu.c
@@ -0,0 +1,206 @@
+/*
+ * QEMU PowerPC PowerNV ADU unit
+ *
+ * The ADU unit actually implements XSCOM, which is the bridge between MMIO
+ * and PIB. However it also includes control and status registers and other
+ * functions that are exposed as PIB (xscom) registers.
+ *
+ * To keep things simple, pnv_xscom.c remains the XSCOM bridge
+ * implementation, and pnv_adu.c implements the ADU registers and other
+ * functions.
+ *
+ * Copyright (c) 2024, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+
+#include "hw/qdev-properties.h"
+#include "hw/ppc/pnv.h"
+#include "hw/ppc/pnv_adu.h"
+#include "hw/ppc/pnv_chip.h"
+#include "hw/ppc/pnv_lpc.h"
+#include "hw/ppc/pnv_xscom.h"
+#include "trace.h"
+
+#define ADU_LPC_BASE_REG 0x40
+#define ADU_LPC_CMD_REG 0x41
+#define ADU_LPC_DATA_REG 0x42
+#define ADU_LPC_STATUS_REG 0x43
+
+static uint64_t pnv_adu_xscom_read(void *opaque, hwaddr addr, unsigned width)
+{
+ PnvADU *adu = PNV_ADU(opaque);
+ uint32_t offset = addr >> 3;
+ uint64_t val = 0;
+
+ switch (offset) {
+ case 0x18: /* Receive status reg */
+ case 0x12: /* log register */
+ case 0x13: /* error register */
+ break;
+ case ADU_LPC_BASE_REG:
+ /*
+ * LPC Address Map in Pervasive ADU Workbook
+ *
+ * return PNV10_LPCM_BASE(chip) & PPC_BITMASK(8, 31);
+ * XXX: implement as class property, or get from LPC?
+ */
+ qemu_log_mask(LOG_UNIMP, "ADU: LPC_BASE_REG is not implemented\n");
+ break;
+ case ADU_LPC_CMD_REG:
+ val = adu->lpc_cmd_reg;
+ break;
+ case ADU_LPC_DATA_REG:
+ val = adu->lpc_data_reg;
+ break;
+ case ADU_LPC_STATUS_REG:
+ val = PPC_BIT(0); /* ack / done */
+ break;
+
+ default:
+ qemu_log_mask(LOG_UNIMP, "ADU Unimplemented read register: Ox%08x\n",
+ offset);
+ }
+
+ trace_pnv_adu_xscom_read(addr, val);
+
+ return val;
+}
+
+static bool lpc_cmd_read(PnvADU *adu)
+{
+ return !!(adu->lpc_cmd_reg & PPC_BIT(0));
+}
+
+static bool lpc_cmd_write(PnvADU *adu)
+{
+ return !lpc_cmd_read(adu);
+}
+
+static uint32_t lpc_cmd_addr(PnvADU *adu)
+{
+ return (adu->lpc_cmd_reg & PPC_BITMASK(32, 63)) >> PPC_BIT_NR(63);
+}
+
+static uint32_t lpc_cmd_size(PnvADU *adu)
+{
+ return (adu->lpc_cmd_reg & PPC_BITMASK(5, 11)) >> PPC_BIT_NR(11);
+}
+
+static void pnv_adu_xscom_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned width)
+{
+ PnvADU *adu = PNV_ADU(opaque);
+ uint32_t offset = addr >> 3;
+
+ trace_pnv_adu_xscom_write(addr, val);
+
+ switch (offset) {
+ case 0x18: /* Receive status reg */
+ case 0x12: /* log register */
+ case 0x13: /* error register */
+ break;
+
+ case ADU_LPC_BASE_REG:
+ qemu_log_mask(LOG_UNIMP,
+ "ADU: Changing LPC_BASE_REG is not implemented\n");
+ break;
+
+ case ADU_LPC_CMD_REG:
+ adu->lpc_cmd_reg = val;
+ if (lpc_cmd_read(adu)) {
+ uint32_t lpc_addr = lpc_cmd_addr(adu);
+ uint32_t lpc_size = lpc_cmd_size(adu);
+ uint64_t data = 0;
+
+ pnv_lpc_opb_read(adu->lpc, lpc_addr, (void *)&data, lpc_size);
+
+ /*
+ * ADU access is performed within 8-byte aligned sectors. Smaller
+ * access sizes don't get formatted to the least significant byte,
+ * but rather appear in the data reg at the same offset as the
+ * address in memory. This shifts them into that position.
+ */
+ adu->lpc_data_reg = be64_to_cpu(data) >> ((lpc_addr & 7) * 8);
+ }
+ break;
+
+ case ADU_LPC_DATA_REG:
+ adu->lpc_data_reg = val;
+ if (lpc_cmd_write(adu)) {
+ uint32_t lpc_addr = lpc_cmd_addr(adu);
+ uint32_t lpc_size = lpc_cmd_size(adu);
+ uint64_t data;
+
+ data = cpu_to_be64(val) >> ((lpc_addr & 7) * 8); /* See above */
+ pnv_lpc_opb_write(adu->lpc, lpc_addr, (void *)&data, lpc_size);
+ }
+ break;
+
+ case ADU_LPC_STATUS_REG:
+ qemu_log_mask(LOG_UNIMP,
+ "ADU: Changing LPC_STATUS_REG is not implemented\n");
+ break;
+
+ default:
+ qemu_log_mask(LOG_UNIMP, "ADU Unimplemented write register: Ox%08x\n",
+ offset);
+ }
+}
+
+const MemoryRegionOps pnv_adu_xscom_ops = {
+ .read = pnv_adu_xscom_read,
+ .write = pnv_adu_xscom_write,
+ .valid.min_access_size = 8,
+ .valid.max_access_size = 8,
+ .impl.min_access_size = 8,
+ .impl.max_access_size = 8,
+ .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static void pnv_adu_realize(DeviceState *dev, Error **errp)
+{
+ PnvADU *adu = PNV_ADU(dev);
+
+ assert(adu->lpc);
+
+ /* XScom regions for ADU registers */
+ pnv_xscom_region_init(&adu->xscom_regs, OBJECT(dev),
+ &pnv_adu_xscom_ops, adu, "xscom-adu",
+ PNV9_XSCOM_ADU_SIZE);
+}
+
+static Property pnv_adu_properties[] = {
+ DEFINE_PROP_LINK("lpc", PnvADU, lpc, TYPE_PNV_LPC, PnvLpcController *),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pnv_adu_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = pnv_adu_realize;
+ dc->desc = "PowerNV ADU";
+ device_class_set_props(dc, pnv_adu_properties);
+ dc->user_creatable = false;
+}
+
+static const TypeInfo pnv_adu_type_info = {
+ .name = TYPE_PNV_ADU,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(PnvADU),
+ .class_init = pnv_adu_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_PNV_XSCOM_INTERFACE },
+ { } },
+};
+
+static void pnv_adu_register_types(void)
+{
+ type_register_static(&pnv_adu_type_info);
+}
+
+type_init(pnv_adu_register_types);
diff --git a/hw/ppc/pnv_chiptod.c b/hw/ppc/pnv_chiptod.c
index 3831a72..1e41fe5 100644
--- a/hw/ppc/pnv_chiptod.c
+++ b/hw/ppc/pnv_chiptod.c
@@ -364,8 +364,7 @@ static void pnv_chiptod_xscom_write(void *opaque, hwaddr addr,
qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: xscom write reg"
" TOD_MOVE_TOD_TO_TB_REG with no slave target\n");
} else {
- PowerPCCPU *cpu = chiptod->slave_pc_target->threads[0];
- CPUPPCState *env = &cpu->env;
+ PnvCore *pc = chiptod->slave_pc_target;
/*
* Moving TOD to TB will set the TB of all threads in a
@@ -377,8 +376,8 @@ static void pnv_chiptod_xscom_write(void *opaque, hwaddr addr,
* thread 0.
*/
- if (env->pnv_tod_tbst.tb_ready_for_tod) {
- env->pnv_tod_tbst.tod_sent_to_tb = 1;
+ if (pc->tod_state.tb_ready_for_tod) {
+ pc->tod_state.tod_sent_to_tb = 1;
} else {
qemu_log_mask(LOG_GUEST_ERROR, "pnv_chiptod: xscom write reg"
" TOD_MOVE_TOD_TO_TB_REG with TB not ready to"
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index f40ab72..a306939 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -58,6 +58,10 @@ static void pnv_core_cpu_reset(PnvCore *pc, PowerPCCPU *cpu)
env->nip = 0x10;
env->msr |= MSR_HVB; /* Hypervisor mode */
env->spr[SPR_HRMOR] = pc->hrmor;
+ if (pc->big_core) {
+ /* Clear "small core" bit on Power9/10 (this is set in default PVR) */
+ env->spr[SPR_PVR] &= ~PPC_BIT(51);
+ }
hreg_compute_hflags(env);
ppc_maybe_interrupt(env);
@@ -181,16 +185,43 @@ static const MemoryRegionOps pnv_core_power9_xscom_ops = {
*/
#define PNV10_XSCOM_EC_CORE_THREAD_STATE 0x412
+#define PNV10_XSCOM_EC_CORE_THREAD_INFO 0x413
+#define PNV10_XSCOM_EC_CORE_DIRECT_CONTROLS 0x449
+#define PNV10_XSCOM_EC_CORE_RAS_STATUS 0x454
static uint64_t pnv_core_power10_xscom_read(void *opaque, hwaddr addr,
unsigned int width)
{
+ PnvCore *pc = PNV_CORE(opaque);
+ int nr_threads = CPU_CORE(pc)->nr_threads;
+ int i;
uint32_t offset = addr >> 3;
uint64_t val = 0;
switch (offset) {
case PNV10_XSCOM_EC_CORE_THREAD_STATE:
- val = 0;
+ for (i = 0; i < nr_threads; i++) {
+ PowerPCCPU *cpu = pc->threads[i];
+ CPUState *cs = CPU(cpu);
+
+ if (cs->halted) {
+ val |= PPC_BIT(56 + i);
+ }
+ }
+ if (pc->lpar_per_core) {
+ val |= PPC_BIT(62);
+ }
+ break;
+ case PNV10_XSCOM_EC_CORE_THREAD_INFO:
+ break;
+ case PNV10_XSCOM_EC_CORE_RAS_STATUS:
+ for (i = 0; i < nr_threads; i++) {
+ PowerPCCPU *cpu = pc->threads[i];
+ CPUState *cs = CPU(cpu);
+ if (cs->stopped) {
+ val |= PPC_BIT(0 + 8 * i) | PPC_BIT(1 + 8 * i);
+ }
+ }
break;
default:
qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
@@ -203,9 +234,46 @@ static uint64_t pnv_core_power10_xscom_read(void *opaque, hwaddr addr,
static void pnv_core_power10_xscom_write(void *opaque, hwaddr addr,
uint64_t val, unsigned int width)
{
+ PnvCore *pc = PNV_CORE(opaque);
+ int nr_threads = CPU_CORE(pc)->nr_threads;
+ int i;
uint32_t offset = addr >> 3;
switch (offset) {
+ case PNV10_XSCOM_EC_CORE_DIRECT_CONTROLS:
+ for (i = 0; i < nr_threads; i++) {
+ PowerPCCPU *cpu = pc->threads[i];
+ CPUState *cs = CPU(cpu);
+
+ if (val & PPC_BIT(7 + 8 * i)) { /* stop */
+ val &= ~PPC_BIT(7 + 8 * i);
+ cpu_pause(cs);
+ }
+ if (val & PPC_BIT(6 + 8 * i)) { /* start */
+ val &= ~PPC_BIT(6 + 8 * i);
+ cpu_resume(cs);
+ }
+ if (val & PPC_BIT(4 + 8 * i)) { /* sreset */
+ val &= ~PPC_BIT(4 + 8 * i);
+ pnv_cpu_do_nmi_resume(cs);
+ }
+ if (val & PPC_BIT(3 + 8 * i)) { /* clear maint */
+ /*
+ * Hardware has very particular cases for where clear maint
+ * must be used and where start must be used to resume a
+ * thread. These are not modelled exactly, just treat
+ * this and start the same.
+ */
+ val &= ~PPC_BIT(3 + 8 * i);
+ cpu_resume(cs);
+ }
+ }
+ if (val) {
+ qemu_log_mask(LOG_UNIMP, "%s: unimp bits in DIRECT_CONTROLS "
+ "0x%016" PRIx64 "\n", __func__, val);
+ }
+ break;
+
default:
qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
offset);
@@ -227,8 +295,9 @@ static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp,
{
CPUPPCState *env = &cpu->env;
int core_hwid;
- ppc_spr_t *pir = &env->spr_cb[SPR_PIR];
- ppc_spr_t *tir = &env->spr_cb[SPR_TIR];
+ ppc_spr_t *pir_spr = &env->spr_cb[SPR_PIR];
+ ppc_spr_t *tir_spr = &env->spr_cb[SPR_TIR];
+ uint32_t pir, tir;
Error *local_err = NULL;
PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip);
@@ -244,8 +313,20 @@ static void pnv_core_cpu_realize(PnvCore *pc, PowerPCCPU *cpu, Error **errp,
core_hwid = object_property_get_uint(OBJECT(pc), "hwid", &error_abort);
- tir->default_value = thread_index;
- pir->default_value = pcc->chip_pir(pc->chip, core_hwid, thread_index);
+ pcc->get_pir_tir(pc->chip, core_hwid, thread_index, &pir, &tir);
+ pir_spr->default_value = pir;
+ tir_spr->default_value = tir;
+
+ if (pc->big_core) {
+ /* 2 "small cores" get the same core index for SMT operations */
+ env->core_index = core_hwid >> 1;
+ } else {
+ env->core_index = core_hwid;
+ }
+
+ if (pc->lpar_per_core) {
+ cpu_ppc_set_1lpar(cpu);
+ }
/* Set time-base frequency to 512 MHz */
cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ);
@@ -278,16 +359,22 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
pc->threads = g_new(PowerPCCPU *, cc->nr_threads);
for (i = 0; i < cc->nr_threads; i++) {
PowerPCCPU *cpu;
+ PnvCPUState *pnv_cpu;
obj = object_new(typename);
cpu = POWERPC_CPU(obj);
pc->threads[i] = POWERPC_CPU(obj);
+ if (cc->nr_threads > 1) {
+ cpu->env.has_smt_siblings = true;
+ }
snprintf(name, sizeof(name), "thread[%d]", i);
object_property_add_child(OBJECT(pc), name, obj);
cpu->machine_data = g_new0(PnvCPUState, 1);
+ pnv_cpu = pnv_cpu_state(cpu);
+ pnv_cpu->pnv_core = pc;
object_unref(obj);
}
@@ -344,6 +431,10 @@ static void pnv_core_unrealize(DeviceState *dev)
static Property pnv_core_properties[] = {
DEFINE_PROP_UINT32("hwid", PnvCore, hwid, 0),
DEFINE_PROP_UINT64("hrmor", PnvCore, hrmor, 0),
+ DEFINE_PROP_BOOL("big-core", PnvCore, big_core, false),
+ DEFINE_PROP_BOOL("quirk-tb-big-core", PnvCore, tod_state.big_core_quirk,
+ false),
+ DEFINE_PROP_BOOL("lpar-per-core", PnvCore, lpar_per_core, false),
DEFINE_PROP_LINK("chip", PnvCore, chip, TYPE_PNV_CHIP, PnvChip *),
DEFINE_PROP_END_OF_LIST(),
};
@@ -504,6 +595,7 @@ static const MemoryRegionOps pnv_quad_power10_xscom_ops = {
static uint64_t pnv_qme_power10_xscom_read(void *opaque, hwaddr addr,
unsigned int width)
{
+ PnvQuad *eq = PNV_QUAD(opaque);
uint32_t offset = addr >> 3;
uint64_t val = -1;
@@ -511,10 +603,14 @@ static uint64_t pnv_qme_power10_xscom_read(void *opaque, hwaddr addr,
* Forth nibble selects the core within a quad, mask it to process read
* for any core.
*/
- switch (offset & ~0xf000) {
- case P10_QME_SPWU_HYP:
+ switch (offset & ~PPC_BITMASK32(16, 19)) {
case P10_QME_SSH_HYP:
- return 0;
+ val = 0;
+ if (eq->special_wakeup_done) {
+ val |= PPC_BIT(1); /* SPWU DONE */
+ val |= PPC_BIT(4); /* SSH SPWU DONE */
+ }
+ break;
default:
qemu_log_mask(LOG_UNIMP, "%s: unimp read 0x%08x\n", __func__,
offset);
@@ -526,9 +622,22 @@ static uint64_t pnv_qme_power10_xscom_read(void *opaque, hwaddr addr,
static void pnv_qme_power10_xscom_write(void *opaque, hwaddr addr,
uint64_t val, unsigned int width)
{
+ PnvQuad *eq = PNV_QUAD(opaque);
uint32_t offset = addr >> 3;
+ bool set;
+ int i;
- switch (offset) {
+ switch (offset & ~PPC_BITMASK32(16, 19)) {
+ case P10_QME_SPWU_HYP:
+ set = !!(val & PPC_BIT(0));
+ eq->special_wakeup_done = set;
+ for (i = 0; i < 4; i++) {
+ /* These bits select cores in the quad */
+ if (offset & PPC_BIT32(16 + i)) {
+ eq->special_wakeup[i] = set;
+ }
+ }
+ break;
default:
qemu_log_mask(LOG_UNIMP, "%s: unimp write 0x%08x\n", __func__,
offset);
diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c
index d692858..f8aad95 100644
--- a/hw/ppc/pnv_lpc.c
+++ b/hw/ppc/pnv_lpc.c
@@ -64,6 +64,7 @@ enum {
#define LPC_HC_IRQSER_START_4CLK 0x00000000
#define LPC_HC_IRQSER_START_6CLK 0x01000000
#define LPC_HC_IRQSER_START_8CLK 0x02000000
+#define LPC_HC_IRQSER_AUTO_CLEAR 0x00800000
#define LPC_HC_IRQMASK 0x34 /* same bit defs as LPC_HC_IRQSTAT */
#define LPC_HC_IRQSTAT 0x38
#define LPC_HC_IRQ_SERIRQ0 0x80000000 /* all bits down to ... */
@@ -235,16 +236,16 @@ int pnv_dt_lpc(PnvChip *chip, void *fdt, int root_offset, uint64_t lpcm_addr,
* TODO: rework to use address_space_stq() and address_space_ldq()
* instead.
*/
-static bool opb_read(PnvLpcController *lpc, uint32_t addr, uint8_t *data,
- int sz)
+bool pnv_lpc_opb_read(PnvLpcController *lpc, uint32_t addr,
+ uint8_t *data, int sz)
{
/* XXX Handle access size limits and FW read caching here */
return !address_space_read(&lpc->opb_as, addr, MEMTXATTRS_UNSPECIFIED,
data, sz);
}
-static bool opb_write(PnvLpcController *lpc, uint32_t addr, uint8_t *data,
- int sz)
+bool pnv_lpc_opb_write(PnvLpcController *lpc, uint32_t addr,
+ uint8_t *data, int sz)
{
/* XXX Handle access size limits here */
return !address_space_write(&lpc->opb_as, addr, MEMTXATTRS_UNSPECIFIED,
@@ -276,7 +277,7 @@ static void pnv_lpc_do_eccb(PnvLpcController *lpc, uint64_t cmd)
}
if (cmd & ECCB_CTL_READ) {
- success = opb_read(lpc, opb_addr, data, sz);
+ success = pnv_lpc_opb_read(lpc, opb_addr, data, sz);
if (success) {
lpc->eccb_stat_reg = ECCB_STAT_OP_DONE |
(((uint64_t)data[0]) << 24 |
@@ -293,7 +294,7 @@ static void pnv_lpc_do_eccb(PnvLpcController *lpc, uint64_t cmd)
data[2] = lpc->eccb_data_reg >> 8;
data[3] = lpc->eccb_data_reg;
- success = opb_write(lpc, opb_addr, data, sz);
+ success = pnv_lpc_opb_write(lpc, opb_addr, data, sz);
lpc->eccb_stat_reg = ECCB_STAT_OP_DONE;
}
/* XXX Which error bit (if any) to signal OPB error ? */
@@ -420,32 +421,90 @@ static const MemoryRegionOps pnv_lpc_mmio_ops = {
.endianness = DEVICE_BIG_ENDIAN,
};
-static void pnv_lpc_eval_irqs(PnvLpcController *lpc)
+/* Program the POWER9 LPC irq to PSI serirq routing table */
+static void pnv_lpc_eval_serirq_routes(PnvLpcController *lpc)
{
- bool lpc_to_opb_irq = false;
+ int irq;
- /* Update LPC controller to OPB line */
- if (lpc->lpc_hc_irqser_ctrl & LPC_HC_IRQSER_EN) {
- uint32_t irqs;
+ if (!lpc->psi_has_serirq) {
+ if ((lpc->opb_irq_route0 & PPC_BITMASK(8, 13)) ||
+ (lpc->opb_irq_route1 & PPC_BITMASK(4, 31))) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "OPB: setting serirq routing on POWER8 system, ignoring.\n");
+ }
+ return;
+ }
- irqs = lpc->lpc_hc_irqstat & lpc->lpc_hc_irqmask;
- lpc_to_opb_irq = (irqs != 0);
+ for (irq = 0; irq <= 13; irq++) {
+ int serirq = (lpc->opb_irq_route1 >> (31 - 5 - (irq * 2))) & 0x3;
+ lpc->irq_to_serirq_route[irq] = serirq;
}
- /* We don't honor the polarity register, it's pointless and unused
- * anyway
- */
- if (lpc_to_opb_irq) {
- lpc->opb_irq_input |= OPB_MASTER_IRQ_LPC;
- } else {
- lpc->opb_irq_input &= ~OPB_MASTER_IRQ_LPC;
+ for (irq = 14; irq < ISA_NUM_IRQS; irq++) {
+ int serirq = (lpc->opb_irq_route0 >> (31 - 9 - (irq * 2))) & 0x3;
+ lpc->irq_to_serirq_route[irq] = serirq;
}
+}
- /* Update OPB internal latch */
- lpc->opb_irq_stat |= lpc->opb_irq_input & lpc->opb_irq_mask;
+static void pnv_lpc_eval_irqs(PnvLpcController *lpc)
+{
+ uint32_t active_irqs = 0;
+
+ if (lpc->lpc_hc_irqstat & PPC_BITMASK32(16, 31)) {
+ qemu_log_mask(LOG_UNIMP, "LPC HC Unimplemented irqs in IRQSTAT: "
+ "0x%08"PRIx32"\n", lpc->lpc_hc_irqstat);
+ }
+
+ if (lpc->lpc_hc_irqser_ctrl & LPC_HC_IRQSER_EN) {
+ active_irqs = lpc->lpc_hc_irqstat & lpc->lpc_hc_irqmask;
+ }
/* Reflect the interrupt */
- qemu_set_irq(lpc->psi_irq, lpc->opb_irq_stat != 0);
+ if (!lpc->psi_has_serirq) {
+ /*
+ * POWER8 ORs all irqs together (also with LPCHC internal interrupt
+ * sources) and outputs a single line that raises the PSI LPCHC irq
+ * which then latches an OPB IRQ status register that sends the irq
+ * to PSI.
+ *
+ * We don't honor the polarity register, it's pointless and unused
+ * anyway
+ */
+ if (active_irqs) {
+ lpc->opb_irq_input |= OPB_MASTER_IRQ_LPC;
+ } else {
+ lpc->opb_irq_input &= ~OPB_MASTER_IRQ_LPC;
+ }
+
+ /* Update OPB internal latch */
+ lpc->opb_irq_stat |= lpc->opb_irq_input & lpc->opb_irq_mask;
+
+ qemu_set_irq(lpc->psi_irq_lpchc, lpc->opb_irq_stat != 0);
+ } else {
+ /*
+ * POWER9 and POWER10 have routing fields in OPB master registers that
+ * send LPC irqs to 4 output lines that raise the PSI SERIRQ irqs.
+ * These don't appear to get latched into an OPB register like the
+ * LPCHC irqs.
+ *
+ * POWER9 LPC controller internal irqs still go via the OPB
+ * and LPCHC PSI irqs like P8, but we have no such internal sources
+ * modelled yet.
+ */
+ bool serirq_out[4] = { false, false, false, false };
+ int irq;
+
+ for (irq = 0; irq < ISA_NUM_IRQS; irq++) {
+ if (active_irqs & (LPC_HC_IRQ_SERIRQ0 >> irq)) {
+ serirq_out[lpc->irq_to_serirq_route[irq]] = true;
+ }
+ }
+
+ qemu_set_irq(lpc->psi_irq_serirq[0], serirq_out[0]);
+ qemu_set_irq(lpc->psi_irq_serirq[1], serirq_out[1]);
+ qemu_set_irq(lpc->psi_irq_serirq[2], serirq_out[2]);
+ qemu_set_irq(lpc->psi_irq_serirq[3], serirq_out[3]);
+ }
}
static uint64_t lpc_hc_read(void *opaque, hwaddr addr, unsigned size)
@@ -505,7 +564,14 @@ static void lpc_hc_write(void *opaque, hwaddr addr, uint64_t val,
pnv_lpc_eval_irqs(lpc);
break;
case LPC_HC_IRQSTAT:
- lpc->lpc_hc_irqstat &= ~val;
+ /*
+ * This register is write-to-clear for the IRQSER (LPC device IRQ)
+ * status. However if the device has not de-asserted its interrupt
+ * that will just raise this IRQ status bit again. Model this by
+ * keeping track of the inputs and only clearing if the inputs are
+ * deasserted.
+ */
+ lpc->lpc_hc_irqstat &= ~(val & ~lpc->lpc_hc_irq_inputs);
pnv_lpc_eval_irqs(lpc);
break;
case LPC_HC_ERROR_ADDRESS:
@@ -536,10 +602,10 @@ static uint64_t opb_master_read(void *opaque, hwaddr addr, unsigned size)
uint64_t val = 0xfffffffffffffffful;
switch (addr) {
- case OPB_MASTER_LS_ROUTE0: /* TODO */
+ case OPB_MASTER_LS_ROUTE0:
val = lpc->opb_irq_route0;
break;
- case OPB_MASTER_LS_ROUTE1: /* TODO */
+ case OPB_MASTER_LS_ROUTE1:
val = lpc->opb_irq_route1;
break;
case OPB_MASTER_LS_IRQ_STAT:
@@ -568,11 +634,15 @@ static void opb_master_write(void *opaque, hwaddr addr,
PnvLpcController *lpc = opaque;
switch (addr) {
- case OPB_MASTER_LS_ROUTE0: /* TODO */
+ case OPB_MASTER_LS_ROUTE0:
lpc->opb_irq_route0 = val;
+ pnv_lpc_eval_serirq_routes(lpc);
+ pnv_lpc_eval_irqs(lpc);
break;
- case OPB_MASTER_LS_ROUTE1: /* TODO */
+ case OPB_MASTER_LS_ROUTE1:
lpc->opb_irq_route1 = val;
+ pnv_lpc_eval_serirq_routes(lpc);
+ pnv_lpc_eval_irqs(lpc);
break;
case OPB_MASTER_LS_IRQ_STAT:
lpc->opb_irq_stat &= ~val;
@@ -657,6 +727,8 @@ static void pnv_lpc_power9_realize(DeviceState *dev, Error **errp)
PnvLpcClass *plc = PNV_LPC_GET_CLASS(dev);
Error *local_err = NULL;
+ object_property_set_bool(OBJECT(lpc), "psi-serirq", true, &error_abort);
+
plc->parent_realize(dev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
@@ -666,6 +738,9 @@ static void pnv_lpc_power9_realize(DeviceState *dev, Error **errp)
/* P9 uses a MMIO region */
memory_region_init_io(&lpc->xscom_regs, OBJECT(lpc), &pnv_lpc_mmio_ops,
lpc, "lpcm", PNV9_LPCM_SIZE);
+
+ /* P9 LPC routes ISA irqs to 4 PSI SERIRQ lines */
+ qdev_init_gpio_out_named(dev, lpc->psi_irq_serirq, "SERIRQ", 4);
}
static void pnv_lpc_power9_class_init(ObjectClass *klass, void *data)
@@ -744,13 +819,19 @@ static void pnv_lpc_realize(DeviceState *dev, Error **errp)
memory_region_add_subregion(&lpc->opb_mr, LPC_HC_REGS_OPB_ADDR,
&lpc->lpc_hc_regs);
- qdev_init_gpio_out(dev, &lpc->psi_irq, 1);
+ qdev_init_gpio_out_named(dev, &lpc->psi_irq_lpchc, "LPCHC", 1);
}
+static Property pnv_lpc_properties[] = {
+ DEFINE_PROP_BOOL("psi-serirq", PnvLpcController, psi_has_serirq, false),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void pnv_lpc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ device_class_set_props(dc, pnv_lpc_properties);
dc->realize = pnv_lpc_realize;
dc->desc = "PowerNV LPC Controller";
dc->user_creatable = false;
@@ -796,18 +877,34 @@ static void pnv_lpc_isa_irq_handler_cpld(void *opaque, int n, int level)
}
if (pnv->cpld_irqstate != old_state) {
- qemu_set_irq(lpc->psi_irq, pnv->cpld_irqstate != 0);
+ qemu_set_irq(lpc->psi_irq_lpchc, pnv->cpld_irqstate != 0);
}
}
static void pnv_lpc_isa_irq_handler(void *opaque, int n, int level)
{
PnvLpcController *lpc = PNV_LPC(opaque);
+ uint32_t irq_bit = LPC_HC_IRQ_SERIRQ0 >> n;
- /* The Naples HW latches the 1 levels, clearing is done by SW */
if (level) {
- lpc->lpc_hc_irqstat |= LPC_HC_IRQ_SERIRQ0 >> n;
+ lpc->lpc_hc_irq_inputs |= irq_bit;
+
+ /*
+ * The LPC HC in Naples and later latches LPC IRQ into a bit field in
+ * the IRQSTAT register, and that drives the PSI IRQ to the IC.
+ * Software clears this bit manually (see LPC_HC_IRQSTAT handler).
+ */
+ lpc->lpc_hc_irqstat |= irq_bit;
pnv_lpc_eval_irqs(lpc);
+ } else {
+ lpc->lpc_hc_irq_inputs &= ~irq_bit;
+
+ /* POWER9 adds an auto-clear mode that clears IRQSTAT bits on EOI */
+ if (lpc->psi_has_serirq &&
+ (lpc->lpc_hc_irqser_ctrl & LPC_HC_IRQSER_AUTO_CLEAR)) {
+ lpc->lpc_hc_irqstat &= ~irq_bit;
+ pnv_lpc_eval_irqs(lpc);
+ }
}
}
@@ -838,6 +935,7 @@ ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp)
handler = pnv_lpc_isa_irq_handler;
}
+ /* POWER has a 17th irq, QEMU only implements the 16 regular device irqs */
irqs = qemu_allocate_irqs(handler, lpc, ISA_NUM_IRQS);
isa_bus_register_input_irqs(isa_bus, irqs);
diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c
index 18cc76a..37c5688 100644
--- a/hw/ppc/pnv_psi.c
+++ b/hw/ppc/pnv_psi.c
@@ -897,7 +897,7 @@ static void pnv_psi_power9_class_init(ObjectClass *klass, void *data)
dc->desc = "PowerNV PSI Controller POWER9";
dc->realize = pnv_psi_power9_realize;
- dc->reset = pnv_psi_power9_reset;
+ device_class_set_legacy_reset(dc, pnv_psi_power9_reset);
ppc->xscom_pcba = PNV9_XSCOM_PSIHB_BASE;
ppc->xscom_size = PNV9_XSCOM_PSIHB_SIZE;
@@ -949,7 +949,7 @@ static void pnv_psi_class_init(ObjectClass *klass, void *data)
dc->desc = "PowerNV PSI Controller";
device_class_set_props(dc, pnv_psi_properties);
- dc->reset = pnv_psi_reset;
+ device_class_set_legacy_reset(dc, pnv_psi_reset);
dc->user_creatable = false;
}
diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c
index a17816d..d192bbe 100644
--- a/hw/ppc/pnv_xscom.c
+++ b/hw/ppc/pnv_xscom.c
@@ -75,11 +75,6 @@ static uint64_t xscom_read_default(PnvChip *chip, uint32_t pcba)
case PRD_P9_IPOLL_REG_MASK:
case PRD_P9_IPOLL_REG_STATUS:
- /* P9 xscom reset */
- case 0x0090018: /* Receive status reg */
- case 0x0090012: /* log register */
- case 0x0090013: /* error register */
-
/* P8 xscom reset */
case 0x2020007: /* ADU stuff, log register */
case 0x2020009: /* ADU stuff, error register */
@@ -119,10 +114,6 @@ static bool xscom_write_default(PnvChip *chip, uint32_t pcba, uint64_t val)
case 0x1010c03: /* PIBAM FIR MASK */
case 0x1010c04: /* PIBAM FIR MASK */
case 0x1010c05: /* PIBAM FIR MASK */
- /* P9 xscom reset */
- case 0x0090018: /* Receive status reg */
- case 0x0090012: /* log register */
- case 0x0090013: /* error register */
/* P8 xscom reset */
case 0x2020007: /* ADU stuff, log register */
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index e6fa558..fde4619 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -267,7 +267,6 @@ static void power9_set_irq(void *opaque, int pin, int level)
break;
default:
g_assert_not_reached();
- return;
}
}
diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c
index c44e7ed..347428e 100644
--- a/hw/ppc/ppc405_boards.c
+++ b/hw/ppc/ppc405_boards.c
@@ -457,7 +457,7 @@ static void ref405ep_fpga_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = ref405ep_fpga_realize;
- dc->reset = ref405ep_fpga_reset;
+ device_class_set_legacy_reset(dc, ref405ep_fpga_reset);
/* Reason: only works as part of a ppc405 board */
dc->user_creatable = false;
}
diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c
index 0cc6817..58cbd05 100644
--- a/hw/ppc/ppc405_uc.c
+++ b/hw/ppc/ppc405_uc.c
@@ -32,7 +32,7 @@
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "ppc405.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "qemu/timer.h"
#include "sysemu/reset.h"
#include "sysemu/sysemu.h"
@@ -119,7 +119,7 @@ static void ppc405_pob_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = ppc405_pob_realize;
- dc->reset = ppc405_pob_reset;
+ device_class_set_legacy_reset(dc, ppc405_pob_reset);
/* Reason: only works as function of a ppc4xx SoC */
dc->user_creatable = false;
}
@@ -196,7 +196,7 @@ static void ppc405_opba_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = ppc405_opba_realize;
- dc->reset = ppc405_opba_reset;
+ device_class_set_legacy_reset(dc, ppc405_opba_reset);
/* Reason: only works as function of a ppc4xx SoC */
dc->user_creatable = false;
}
@@ -302,7 +302,7 @@ static void ppc405_dma_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = ppc405_dma_realize;
- dc->reset = ppc405_dma_reset;
+ device_class_set_legacy_reset(dc, ppc405_dma_reset);
/* Reason: only works as function of a ppc4xx SoC */
dc->user_creatable = false;
}
@@ -492,7 +492,7 @@ static void ppc405_ocm_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = ppc405_ocm_realize;
- dc->reset = ppc405_ocm_reset;
+ device_class_set_legacy_reset(dc, ppc405_ocm_reset);
/* Reason: only works as function of a ppc4xx SoC */
dc->user_creatable = false;
}
@@ -726,7 +726,7 @@ static void ppc405_gpt_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = ppc405_gpt_realize;
- dc->reset = ppc405_gpt_reset;
+ device_class_set_legacy_reset(dc, ppc405_gpt_reset);
/* Reason: only works as function of a ppc4xx SoC */
dc->user_creatable = false;
}
@@ -975,7 +975,7 @@ static void ppc405_cpc_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = ppc405_cpc_realize;
- dc->reset = ppc405_cpc_reset;
+ device_class_set_legacy_reset(dc, ppc405_cpc_reset);
/* Reason: only works as function of a ppc4xx SoC */
dc->user_creatable = false;
device_class_set_props(dc, ppc405_cpc_properties);
diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c
index 73f80cf..96d9ce6 100644
--- a/hw/ppc/ppc440_bamboo.c
+++ b/hw/ppc/ppc440_bamboo.c
@@ -23,7 +23,7 @@
#include "sysemu/device_tree.h"
#include "hw/loader.h"
#include "elf.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/ppc/ppc.h"
#include "hw/pci-host/ppc4xx.h"
#include "sysemu/sysemu.h"
diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
index c1d1114..db8f6b9 100644
--- a/hw/ppc/ppc4xx_devs.c
+++ b/hw/ppc/ppc4xx_devs.c
@@ -242,7 +242,7 @@ static void ppc4xx_mal_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = ppc4xx_mal_realize;
- dc->reset = ppc4xx_mal_reset;
+ device_class_set_legacy_reset(dc, ppc4xx_mal_reset);
/* Reason: only works as function of a ppc4xx SoC */
dc->user_creatable = false;
device_class_set_props(dc, ppc4xx_mal_properties);
@@ -332,7 +332,7 @@ static void ppc405_plb_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = ppc405_plb_realize;
- dc->reset = ppc405_plb_reset;
+ device_class_set_legacy_reset(dc, ppc405_plb_reset);
/* Reason: only works as function of a ppc4xx SoC */
dc->user_creatable = false;
}
@@ -518,7 +518,7 @@ static void ppc405_ebc_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = ppc405_ebc_realize;
- dc->reset = ppc405_ebc_reset;
+ device_class_set_legacy_reset(dc, ppc405_ebc_reset);
/* Reason: only works as function of a ppc4xx SoC */
dc->user_creatable = false;
}
diff --git a/hw/ppc/ppc4xx_sdram.c b/hw/ppc/ppc4xx_sdram.c
index c0c87ff..2ee21f1 100644
--- a/hw/ppc/ppc4xx_sdram.c
+++ b/hw/ppc/ppc4xx_sdram.c
@@ -437,7 +437,7 @@ static void ppc4xx_sdram_ddr_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = ppc4xx_sdram_ddr_realize;
- dc->reset = ppc4xx_sdram_ddr_reset;
+ device_class_set_legacy_reset(dc, ppc4xx_sdram_ddr_reset);
/* Reason: only works as function of a ppc4xx SoC */
dc->user_creatable = false;
device_class_set_props(dc, ppc4xx_sdram_ddr_props);
@@ -722,7 +722,7 @@ static void ppc4xx_sdram_ddr2_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = ppc4xx_sdram_ddr2_realize;
- dc->reset = ppc4xx_sdram_ddr2_reset;
+ device_class_set_legacy_reset(dc, ppc4xx_sdram_ddr2_reset);
/* Reason: only works as function of a ppc4xx SoC */
dc->user_creatable = false;
device_class_set_props(dc, ppc4xx_sdram_ddr2_props);
diff --git a/hw/ppc/ppce500_spin.c b/hw/ppc/ppce500_spin.c
index dfbe759..e08739a 100644
--- a/hw/ppc/ppce500_spin.c
+++ b/hw/ppc/ppce500_spin.c
@@ -191,7 +191,7 @@ static void ppce500_spin_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = spin_reset;
+ device_class_set_legacy_reset(dc, spin_reset);
}
static const TypeInfo ppce500_spin_info = {
diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
index 4eb5477..fb58c31 100644
--- a/hw/ppc/prep.c
+++ b/hw/ppc/prep.c
@@ -25,7 +25,6 @@
#include "qemu/osdep.h"
#include "hw/rtc/m48t59.h"
-#include "hw/char/serial.h"
#include "hw/block/fdc.h"
#include "net/net.h"
#include "hw/isa/isa.h"
diff --git a/hw/ppc/rs6000_mc.c b/hw/ppc/rs6000_mc.c
index e6ec4b4..07b0b66 100644
--- a/hw/ppc/rs6000_mc.c
+++ b/hw/ppc/rs6000_mc.c
@@ -3,10 +3,12 @@
*
* Copyright (c) 2017 HervƩ Poussineau
*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
* 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) version 3 or any later version.
+ * (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
diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c
index 8dc75fb..1fce093 100644
--- a/hw/ppc/sam460ex.c
+++ b/hw/ppc/sam460ex.c
@@ -31,7 +31,7 @@
#include "sysemu/sysemu.h"
#include "sysemu/reset.h"
#include "hw/sysbus.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/i2c/ppc4xx_i2c.h"
#include "hw/i2c/smbus_eeprom.h"
#include "hw/ide/pci.h"
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 98fa3aa..2c10a70 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1725,7 +1725,7 @@ void spapr_check_mmu_mode(bool guest_radix)
}
}
-static void spapr_machine_reset(MachineState *machine, ShutdownCause reason)
+static void spapr_machine_reset(MachineState *machine, ResetType type)
{
SpaprMachineState *spapr = SPAPR_MACHINE(machine);
PowerPCCPU *first_ppc_cpu;
@@ -1733,7 +1733,7 @@ static void spapr_machine_reset(MachineState *machine, ShutdownCause reason)
void *fdt;
int rc;
- if (reason != SHUTDOWN_CAUSE_SNAPSHOT_LOAD) {
+ if (type != RESET_TYPE_SNAPSHOT_LOAD) {
/*
* Record-replay snapshot load must not consume random, this was
* already replayed from initial machine reset.
@@ -1762,7 +1762,7 @@ static void spapr_machine_reset(MachineState *machine, ShutdownCause reason)
spapr_setup_hpt(spapr);
}
- qemu_devices_reset(reason);
+ qemu_devices_reset(type);
spapr_ovec_cleanup(spapr->ov5_cas);
spapr->ov5_cas = spapr_ovec_new();
@@ -2195,6 +2195,7 @@ static const VMStateDescription vmstate_spapr = {
&vmstate_spapr_cap_fwnmi,
&vmstate_spapr_fwnmi,
&vmstate_spapr_cap_rpt_invalidate,
+ &vmstate_spapr_cap_ail_mode_3,
&vmstate_spapr_cap_nested_papr,
NULL
}
@@ -4837,14 +4838,25 @@ static void spapr_machine_latest_class_options(MachineClass *mc)
DEFINE_SPAPR_MACHINE_IMPL(false, major, minor, _, tag)
/*
+ * pseries-9.2
+ */
+static void spapr_machine_9_2_class_options(MachineClass *mc)
+{
+ /* Defaults for the latest behaviour inherited from the base class */
+}
+
+DEFINE_SPAPR_MACHINE_AS_LATEST(9, 2);
+
+/*
* pseries-9.1
*/
static void spapr_machine_9_1_class_options(MachineClass *mc)
{
- /* Defaults for the latest behaviour inherited from the base class */
+ spapr_machine_9_2_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_9_1, hw_compat_9_1_len);
}
-DEFINE_SPAPR_MACHINE_AS_LATEST(9, 1);
+DEFINE_SPAPR_MACHINE(9, 1);
/*
* pseries-9.0
diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
index 0a15415..2f74923 100644
--- a/hw/ppc/spapr_caps.c
+++ b/hw/ppc/spapr_caps.c
@@ -974,6 +974,7 @@ SPAPR_CAP_MIG_STATE(large_decr, SPAPR_CAP_LARGE_DECREMENTER);
SPAPR_CAP_MIG_STATE(ccf_assist, SPAPR_CAP_CCF_ASSIST);
SPAPR_CAP_MIG_STATE(fwnmi, SPAPR_CAP_FWNMI);
SPAPR_CAP_MIG_STATE(rpt_invalidate, SPAPR_CAP_RPT_INVALIDATE);
+SPAPR_CAP_MIG_STATE(ail_mode_3, SPAPR_CAP_AIL_MODE_3);
void spapr_caps_init(SpaprMachineState *spapr)
{
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index e7c9edd..4642245 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -300,11 +300,13 @@ static PowerPCCPU *spapr_create_vcpu(SpaprCpuCore *sc, int i, Error **errp)
g_autofree char *id = NULL;
CPUState *cs;
PowerPCCPU *cpu;
+ CPUPPCState *env;
obj = object_new(scc->cpu_type);
cs = CPU(obj);
cpu = POWERPC_CPU(obj);
+ env = &cpu->env;
/*
* All CPUs start halted. CPU0 is unhalted from the machine level reset code
* and the rest are explicitly started up by the guest using an RTAS call.
@@ -315,6 +317,8 @@ static PowerPCCPU *spapr_create_vcpu(SpaprCpuCore *sc, int i, Error **errp)
return NULL;
}
+ env->core_index = cc->core_id;
+
cpu->node_id = sc->node_id;
id = g_strdup_printf("thread[%d]", i);
@@ -345,9 +349,15 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
qemu_register_reset(spapr_cpu_core_reset_handler, sc);
sc->threads = g_new0(PowerPCCPU *, cc->nr_threads);
for (i = 0; i < cc->nr_threads; i++) {
- sc->threads[i] = spapr_create_vcpu(sc, i, errp);
- if (!sc->threads[i] ||
- !spapr_realize_vcpu(sc->threads[i], spapr, sc, i, errp)) {
+ PowerPCCPU *cpu;
+
+ cpu = spapr_create_vcpu(sc, i, errp);
+ sc->threads[i] = cpu;
+ if (cpu && cc->nr_threads > 1) {
+ cpu->env.has_smt_siblings = true;
+ }
+
+ if (!cpu || !spapr_realize_vcpu(cpu, spapr, sc, i, errp)) {
spapr_cpu_core_unrealize(dev);
return;
}
@@ -368,7 +378,7 @@ static void spapr_cpu_core_class_init(ObjectClass *oc, void *data)
dc->realize = spapr_cpu_core_realize;
dc->unrealize = spapr_cpu_core_unrealize;
- dc->reset = spapr_cpu_core_reset;
+ device_class_set_legacy_reset(dc, spapr_cpu_core_reset);
device_class_set_props(dc, spapr_cpu_core_properties);
scc->cpu_type = data;
}
diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c
index cb0eeee..4dbf8e2 100644
--- a/hw/ppc/spapr_events.c
+++ b/hw/ppc/spapr_events.c
@@ -645,8 +645,7 @@ static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action,
/* we shouldn't be signaling hotplug events for resources
* that don't support them
*/
- g_assert(false);
- return;
+ g_assert_not_reached();
}
if (hp_id == RTAS_LOG_V6_HP_ID_DRC_COUNT) {
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index e3c01ef..7836dc7 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -672,7 +672,7 @@ static void spapr_tce_table_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = spapr_tce_table_realize;
- dc->reset = spapr_tce_reset;
+ device_class_set_legacy_reset(dc, spapr_tce_reset);
dc->unrealize = spapr_tce_table_unrealize;
/* Reason: This is just an internal device for handling the hypercalls */
dc->user_creatable = false;
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index ed4454b..5c0024b 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -1296,10 +1296,6 @@ static void spapr_dt_pci_device_cb(PCIBus *bus, PCIDevice *pdev,
return;
}
- if (!pdev->enabled) {
- return;
- }
-
err = spapr_dt_pci_device(p->sphb, pdev, p->fdt, p->offset);
if (err < 0) {
p->err = err;
@@ -1573,9 +1569,7 @@ static void spapr_pci_pre_plug(HotplugHandler *plug_handler,
* hotplug, we do not allow functions to be hotplugged to a
* slot that already has function 0 present
*/
- if (plugged_dev->hotplugged &&
- !pci_is_vf(pdev) &&
- bus->devices[PCI_DEVFN(slotnr, 0)] &&
+ if (plugged_dev->hotplugged && bus->devices[PCI_DEVFN(slotnr, 0)] &&
PCI_FUNC(pdev->devfn) != 0) {
error_setg(errp, "PCI: slot %d function 0 already occupied by %s,"
" additional functions can no longer be exposed to guest.",
@@ -2254,7 +2248,7 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
dc->realize = spapr_phb_realize;
dc->unrealize = spapr_phb_unrealize;
device_class_set_props(dc, spapr_phb_properties);
- dc->reset = spapr_phb_reset;
+ device_class_set_legacy_reset(dc, spapr_phb_reset);
dc->vmsd = &vmstate_spapr_pci;
/* Supported by TYPE_SPAPR_MACHINE */
dc->user_creatable = true;
diff --git a/hw/ppc/spapr_vhyp_mmu.c b/hw/ppc/spapr_vhyp_mmu.c
index b3dd8b3..2d41d7f 100644
--- a/hw/ppc/spapr_vhyp_mmu.c
+++ b/hw/ppc/spapr_vhyp_mmu.c
@@ -15,19 +15,6 @@
#include "helper_regs.h"
#include "hw/ppc/spapr.h"
#include "mmu-hash64.h"
-#include "mmu-book3s-v3.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)
@@ -70,7 +57,7 @@ static target_ulong h_enter(PowerPCCPU *cpu, SpaprMachineState *spapr,
pteh &= ~0x60ULL;
- if (!valid_ptex(cpu, ptex)) {
+ if (!ppc_hash64_valid_ptex(cpu, ptex)) {
return H_PARAMETER;
}
@@ -119,7 +106,7 @@ static RemoveResult remove_hpte(PowerPCCPU *cpu
const ppc_hash_pte64_t *hptes;
target_ulong v, r;
- if (!valid_ptex(cpu, ptex)) {
+ if (!ppc_hash64_valid_ptex(cpu, ptex)) {
return REMOVE_PARM;
}
@@ -250,7 +237,7 @@ static target_ulong h_protect(PowerPCCPU *cpu, SpaprMachineState *spapr,
const ppc_hash_pte64_t *hptes;
target_ulong v, r;
- if (!valid_ptex(cpu, ptex)) {
+ if (!ppc_hash64_valid_ptex(cpu, ptex)) {
return H_PARAMETER;
}
@@ -287,7 +274,7 @@ static target_ulong h_read(PowerPCCPU *cpu, SpaprMachineState *spapr,
int i, ridx, n_entries = 1;
const ppc_hash_pte64_t *hptes;
- if (!valid_ptex(cpu, ptex)) {
+ if (!ppc_hash64_valid_ptex(cpu, ptex)) {
return H_PARAMETER;
}
diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c
index 3221874..6a5a7f5 100644
--- a/hw/ppc/spapr_vio.c
+++ b/hw/ppc/spapr_vio.c
@@ -635,7 +635,7 @@ static void vio_spapr_device_class_init(ObjectClass *klass, void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
k->realize = spapr_vio_busdev_realize;
- k->reset = spapr_vio_busdev_reset;
+ device_class_set_legacy_reset(k, spapr_vio_busdev_reset);
k->bus_type = TYPE_SPAPR_VIO_BUS;
}
diff --git a/hw/ppc/spapr_vof.c b/hw/ppc/spapr_vof.c
index 09f29be..c02eaac 100644
--- a/hw/ppc/spapr_vof.c
+++ b/hw/ppc/spapr_vof.c
@@ -28,7 +28,7 @@ target_ulong spapr_h_vof_client(PowerPCCPU *cpu, SpaprMachineState *spapr,
void spapr_vof_client_dt_finalize(SpaprMachineState *spapr, void *fdt)
{
- char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus);
+ g_autofree char *stdout_path = spapr_vio_stdout_path(spapr->vio_bus);
vof_build_dt(fdt, spapr->vof);
diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
index bf29bbf..1f125ce 100644
--- a/hw/ppc/trace-events
+++ b/hw/ppc/trace-events
@@ -95,6 +95,10 @@ vof_write(uint32_t ih, unsigned cb, const char *msg) "ih=0x%x [%u] \"%s\""
vof_avail(uint64_t start, uint64_t end, uint64_t size) "0x%"PRIx64"..0x%"PRIx64" size=0x%"PRIx64
vof_claimed(uint64_t start, uint64_t end, uint64_t size) "0x%"PRIx64"..0x%"PRIx64" size=0x%"PRIx64
+# pnv_adu.c
+pnv_adu_xscom_read(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " val 0x%" PRIx64
+pnv_adu_xscom_write(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " val 0x%" PRIx64
+
# pnv_chiptod.c
pnv_chiptod_xscom_read(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " val 0x%" PRIx64
pnv_chiptod_xscom_write(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " val 0x%" PRIx64
diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c
index c49da1f..235281e 100644
--- a/hw/ppc/virtex_ml507.c
+++ b/hw/ppc/virtex_ml507.c
@@ -28,7 +28,7 @@
#include "exec/page-protection.h"
#include "cpu.h"
#include "hw/sysbus.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/block/flash.h"
#include "sysemu/sysemu.h"
#include "sysemu/reset.h"
diff --git a/hw/ppc/vof.c b/hw/ppc/vof.c
index e3b430a..b5b6514 100644
--- a/hw/ppc/vof.c
+++ b/hw/ppc/vof.c
@@ -646,7 +646,7 @@ static void vof_dt_memory_available(void *fdt, GArray *claimed, uint64_t base)
mem0_reg = fdt_getprop(fdt, offset, "reg", &proplen);
g_assert(mem0_reg && proplen == sizeof(uint32_t) * (ac + sc));
if (sc == 2) {
- mem0_end = be64_to_cpu(*(uint64_t *)(mem0_reg + sizeof(uint32_t) * ac));
+ mem0_end = ldq_be_p(mem0_reg + sizeof(uint32_t) * ac);
} else {
mem0_end = be32_to_cpu(*(uint32_t *)(mem0_reg + sizeof(uint32_t) * ac));
}
diff --git a/hw/remote/iohub.c b/hw/remote/iohub.c
index 40dfee4..988d328 100644
--- a/hw/remote/iohub.c
+++ b/hw/remote/iohub.c
@@ -33,19 +33,6 @@ void remote_iohub_init(RemoteIOHubState *iohub)
}
}
-void remote_iohub_finalize(RemoteIOHubState *iohub)
-{
- int pirq;
-
- for (pirq = 0; pirq < REMOTE_IOHUB_NB_PIRQS; pirq++) {
- qemu_set_fd_handler(event_notifier_get_fd(&iohub->resamplefds[pirq]),
- NULL, NULL, NULL);
- event_notifier_cleanup(&iohub->irqfds[pirq]);
- event_notifier_cleanup(&iohub->resamplefds[pirq]);
- qemu_mutex_destroy(&iohub->irq_level_lock[pirq]);
- }
-}
-
int remote_iohub_map_irq(PCIDevice *pci_dev, int intx)
{
return pci_dev->devfn;
diff --git a/hw/remote/message.c b/hw/remote/message.c
index 50f6bf2..38ae6c7 100644
--- a/hw/remote/message.c
+++ b/hw/remote/message.c
@@ -215,13 +215,10 @@ fail:
static void process_device_reset_msg(QIOChannel *ioc, PCIDevice *dev,
Error **errp)
{
- DeviceClass *dc = DEVICE_GET_CLASS(dev);
DeviceState *s = DEVICE(dev);
MPQemuMsg ret = { 0 };
- if (dc->reset) {
- dc->reset(s);
- }
+ device_cold_reset(s);
ret.cmd = MPQEMU_CMD_RET;
diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c
index fbc85a8..302a0a4 100644
--- a/hw/remote/proxy.c
+++ b/hw/remote/proxy.c
@@ -206,7 +206,7 @@ static void pci_proxy_dev_class_init(ObjectClass *klass, void *data)
k->config_read = pci_proxy_read_config;
k->config_write = pci_proxy_write_config;
- dc->reset = proxy_device_reset;
+ device_class_set_legacy_reset(dc, proxy_device_reset);
device_class_set_props(dc, proxy_properties);
}
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index a2030e3..44695ff 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -44,7 +44,7 @@ config RISCV_VIRT
select PCI
select PCI_EXPRESS_GENERIC_BRIDGE
select PFLASH_CFI01
- select SERIAL
+ select SERIAL_MM
select RISCV_ACLINT
select RISCV_APLIC
select RISCV_IMSIC
diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c
index 47281ca..9115ecd 100644
--- a/hw/riscv/boot.c
+++ b/hw/riscv/boot.c
@@ -128,11 +128,11 @@ char *riscv_find_firmware(const char *firmware_filename,
target_ulong riscv_find_and_load_firmware(MachineState *machine,
const char *default_machine_firmware,
- hwaddr firmware_load_addr,
+ hwaddr *firmware_load_addr,
symbol_fn_t sym_cb)
{
char *firmware_filename;
- target_ulong firmware_end_addr = firmware_load_addr;
+ target_ulong firmware_end_addr = *firmware_load_addr;
firmware_filename = riscv_find_firmware(machine->firmware,
default_machine_firmware);
@@ -148,7 +148,7 @@ target_ulong riscv_find_and_load_firmware(MachineState *machine,
}
target_ulong riscv_load_firmware(const char *firmware_filename,
- hwaddr firmware_load_addr,
+ hwaddr *firmware_load_addr,
symbol_fn_t sym_cb)
{
uint64_t firmware_entry, firmware_end;
@@ -159,15 +159,16 @@ target_ulong riscv_load_firmware(const char *firmware_filename,
if (load_elf_ram_sym(firmware_filename, NULL, NULL, NULL,
&firmware_entry, NULL, &firmware_end, NULL,
0, EM_RISCV, 1, 0, NULL, true, sym_cb) > 0) {
+ *firmware_load_addr = firmware_entry;
return firmware_end;
}
firmware_size = load_image_targphys_as(firmware_filename,
- firmware_load_addr,
+ *firmware_load_addr,
current_machine->ram_size, NULL);
if (firmware_size > 0) {
- return firmware_load_addr + firmware_size;
+ return *firmware_load_addr + firmware_size;
}
error_report("could not load firmware '%s'", firmware_filename);
diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c
index 7725dfb..f9a3b43 100644
--- a/hw/riscv/microchip_pfsoc.c
+++ b/hw/riscv/microchip_pfsoc.c
@@ -613,7 +613,7 @@ static void microchip_icicle_kit_machine_init(MachineState *machine)
/* Load the firmware */
firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
- firmware_load_addr, NULL);
+ &firmware_load_addr, NULL);
if (kernel_as_payload) {
kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc.u_cpus,
diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c
index 436503f..e2830e9 100644
--- a/hw/riscv/opentitan.c
+++ b/hw/riscv/opentitan.c
@@ -98,7 +98,8 @@ static void opentitan_machine_init(MachineState *machine)
memmap[IBEX_DEV_RAM].base, machine->ram);
if (machine->firmware) {
- riscv_load_firmware(machine->firmware, memmap[IBEX_DEV_RAM].base, NULL);
+ hwaddr firmware_load_addr = memmap[IBEX_DEV_RAM].base;
+ riscv_load_firmware(machine->firmware, &firmware_load_addr, NULL);
}
if (machine->kernel_filename) {
diff --git a/hw/riscv/shakti_c.c b/hw/riscv/shakti_c.c
index 3888034..2dccc1e 100644
--- a/hw/riscv/shakti_c.c
+++ b/hw/riscv/shakti_c.c
@@ -45,6 +45,7 @@ static void shakti_c_machine_state_init(MachineState *mstate)
{
ShaktiCMachineState *sms = RISCV_SHAKTI_MACHINE(mstate);
MemoryRegion *system_memory = get_system_memory();
+ hwaddr firmware_load_addr = shakti_c_memmap[SHAKTI_C_RAM].base;
/* Initialize SoC */
object_initialize_child(OBJECT(mstate), "soc", &sms->soc,
@@ -56,16 +57,14 @@ static void shakti_c_machine_state_init(MachineState *mstate)
shakti_c_memmap[SHAKTI_C_RAM].base,
mstate->ram);
+ if (mstate->firmware) {
+ riscv_load_firmware(mstate->firmware, &firmware_load_addr, NULL);
+ }
+
/* ROM reset vector */
- riscv_setup_rom_reset_vec(mstate, &sms->soc.cpus,
- shakti_c_memmap[SHAKTI_C_RAM].base,
+ riscv_setup_rom_reset_vec(mstate, &sms->soc.cpus, firmware_load_addr,
shakti_c_memmap[SHAKTI_C_ROM].base,
shakti_c_memmap[SHAKTI_C_ROM].size, 0, 0);
- 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)
diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c
index 87d9602..5a1959f 100644
--- a/hw/riscv/sifive_e.c
+++ b/hw/riscv/sifive_e.c
@@ -35,7 +35,6 @@
#include "hw/boards.h"
#include "hw/loader.h"
#include "hw/sysbus.h"
-#include "hw/char/serial.h"
#include "hw/misc/unimp.h"
#include "target/riscv/cpu.h"
#include "hw/riscv/riscv_hart.h"
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index af5f923..9b3dcf3 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -43,7 +43,6 @@
#include "hw/irq.h"
#include "hw/loader.h"
#include "hw/sysbus.h"
-#include "hw/char/serial.h"
#include "hw/cpu/cluster.h"
#include "hw/misc/unimp.h"
#include "hw/sd/sd.h"
@@ -515,7 +514,7 @@ static void sifive_u_machine_init(MachineState *machine)
SiFiveUState *s = RISCV_U_MACHINE(machine);
MemoryRegion *system_memory = get_system_memory();
MemoryRegion *flash0 = g_new(MemoryRegion, 1);
- target_ulong start_addr = memmap[SIFIVE_U_DEV_DRAM].base;
+ hwaddr start_addr = memmap[SIFIVE_U_DEV_DRAM].base;
target_ulong firmware_end_addr, kernel_start_addr;
const char *firmware_name;
uint32_t start_addr_hi32 = 0x00000000;
@@ -589,7 +588,7 @@ static void sifive_u_machine_init(MachineState *machine)
firmware_name = riscv_default_firmware_name(&s->soc.u_cpus);
firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
- start_addr, NULL);
+ &start_addr, NULL);
if (machine->kernel_filename) {
kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc.u_cpus,
diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
index 6407439..fceb91d 100644
--- a/hw/riscv/spike.c
+++ b/hw/riscv/spike.c
@@ -198,6 +198,7 @@ static void spike_board_init(MachineState *machine)
MemoryRegion *system_memory = get_system_memory();
MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
target_ulong firmware_end_addr = memmap[SPIKE_DRAM].base;
+ hwaddr firmware_load_addr = memmap[SPIKE_DRAM].base;
target_ulong kernel_start_addr;
char *firmware_name;
uint32_t fdt_load_addr;
@@ -290,7 +291,7 @@ static void spike_board_init(MachineState *machine)
/* Load firmware */
if (firmware_name) {
firmware_end_addr = riscv_load_firmware(firmware_name,
- memmap[SPIKE_DRAM].base,
+ &firmware_load_addr,
htif_symbol_callback);
g_free(firmware_name);
}
@@ -320,7 +321,7 @@ static void spike_board_init(MachineState *machine)
riscv_load_fdt(fdt_load_addr, machine->fdt);
/* load the reset vector */
- riscv_setup_rom_reset_vec(machine, &s->soc[0], memmap[SPIKE_DRAM].base,
+ riscv_setup_rom_reset_vec(machine, &s->soc[0], firmware_load_addr,
memmap[SPIKE_MROM].base,
memmap[SPIKE_MROM].size, kernel_entry,
fdt_load_addr);
diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c
index 0925528..36d6a3a 100644
--- a/hw/riscv/virt-acpi-build.c
+++ b/hw/riscv/virt-acpi-build.c
@@ -141,12 +141,36 @@ static void acpi_dsdt_add_cpus(Aml *scope, RISCVVirtState *s)
}
}
+static void acpi_dsdt_add_plic_aplic(Aml *scope, uint8_t socket_count,
+ uint64_t mmio_base, uint64_t mmio_size,
+ const char *hid)
+{
+ uint64_t plic_aplic_addr;
+ uint32_t gsi_base;
+ uint8_t socket;
+
+ for (socket = 0; socket < socket_count; socket++) {
+ plic_aplic_addr = mmio_base + mmio_size * socket;
+ gsi_base = VIRT_IRQCHIP_NUM_SOURCES * socket;
+ Aml *dev = aml_device("IC%.02X", socket);
+ aml_append(dev, aml_name_decl("_HID", aml_string("%s", hid)));
+ aml_append(dev, aml_name_decl("_UID", aml_int(socket)));
+ aml_append(dev, aml_name_decl("_GSB", aml_int(gsi_base)));
+
+ Aml *crs = aml_resource_template();
+ aml_append(crs, aml_memory32_fixed(plic_aplic_addr, mmio_size,
+ AML_READ_WRITE));
+ aml_append(dev, aml_name_decl("_CRS", crs));
+ aml_append(scope, dev);
+ }
+}
+
static void
acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap,
uint32_t uart_irq)
{
Aml *dev = aml_device("COM0");
- aml_append(dev, aml_name_decl("_HID", aml_string("PNP0501")));
+ aml_append(dev, aml_name_decl("_HID", aml_string("RSCV0003")));
aml_append(dev, aml_name_decl("_UID", aml_int(0)));
Aml *crs = aml_resource_template();
@@ -411,6 +435,14 @@ static void build_dsdt(GArray *table_data,
socket_count = riscv_socket_count(ms);
+ if (s->aia_type == VIRT_AIA_TYPE_NONE) {
+ acpi_dsdt_add_plic_aplic(scope, socket_count, memmap[VIRT_PLIC].base,
+ memmap[VIRT_PLIC].size, "RSCV0001");
+ } else {
+ acpi_dsdt_add_plic_aplic(scope, socket_count, memmap[VIRT_APLIC_S].base,
+ memmap[VIRT_APLIC_S].size, "RSCV0002");
+ }
+
acpi_dsdt_add_uart(scope, &memmap[VIRT_UART0], UART0_IRQ);
if (socket_count == 1) {
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index bc0893e..ee3129f 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -27,7 +27,7 @@
#include "hw/loader.h"
#include "hw/sysbus.h"
#include "hw/qdev-properties.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "target/riscv/cpu.h"
#include "hw/core/sysbus-fdt.h"
#include "target/riscv/pmu.h"
@@ -552,7 +552,6 @@ static void create_fdt_one_imsic(RISCVVirtState *s, hwaddr base_addr,
FDT_IMSIC_INT_CELLS);
qemu_fdt_setprop(ms->fdt, imsic_name, "interrupt-controller", NULL, 0);
qemu_fdt_setprop(ms->fdt, imsic_name, "msi-controller", NULL, 0);
- qemu_fdt_setprop_cell(ms->fdt, imsic_name, "#msi-cells", 0);
qemu_fdt_setprop(ms->fdt, imsic_name, "interrupts-extended",
imsic_cells, ms->smp.cpus * sizeof(uint32_t) * 2);
qemu_fdt_setprop(ms->fdt, imsic_name, "reg", imsic_regs,
@@ -651,6 +650,15 @@ static void create_fdt_one_aplic(RISCVVirtState *s, int socket,
qemu_fdt_setprop_cells(ms->fdt, aplic_name, "riscv,delegation",
aplic_child_phandle, 0x1,
VIRT_IRQCHIP_NUM_SOURCES);
+ /*
+ * DEPRECATED_9.1: Compat property kept temporarily
+ * to allow old firmwares to work with AIA. Do *not*
+ * use 'riscv,delegate' in new code: use
+ * 'riscv,delegation' instead.
+ */
+ qemu_fdt_setprop_cells(ms->fdt, aplic_name, "riscv,delegate",
+ aplic_child_phandle, 0x1,
+ VIRT_IRQCHIP_NUM_SOURCES);
}
riscv_socket_fdt_write_id(ms, aplic_name, socket);
@@ -1327,7 +1335,7 @@ static void virt_machine_done(Notifier *notifier, void *data)
machine_done);
const MemMapEntry *memmap = virt_memmap;
MachineState *machine = MACHINE(s);
- target_ulong start_addr = memmap[VIRT_DRAM].base;
+ hwaddr start_addr = memmap[VIRT_DRAM].base;
target_ulong firmware_end_addr, kernel_start_addr;
const char *firmware_name = riscv_default_firmware_name(&s->soc[0]);
uint64_t fdt_load_addr;
@@ -1359,7 +1367,7 @@ static void virt_machine_done(Notifier *notifier, void *data)
}
firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
- start_addr, NULL);
+ &start_addr, NULL);
pflash_blk0 = pflash_cfi01_get_blk(s->flash[0]);
if (pflash_blk0) {
diff --git a/hw/rtc/Kconfig b/hw/rtc/Kconfig
index d0d8dda..2fe04ec 100644
--- a/hw/rtc/Kconfig
+++ b/hw/rtc/Kconfig
@@ -14,10 +14,6 @@ config M48T59
config PL031
bool
-config TWL92230
- bool
- depends on I2C
-
config MC146818RTC
depends on ISA_BUS
bool
diff --git a/hw/rtc/allwinner-rtc.c b/hw/rtc/allwinner-rtc.c
index 2ac50b3..1057d6a 100644
--- a/hw/rtc/allwinner-rtc.c
+++ b/hw/rtc/allwinner-rtc.c
@@ -320,7 +320,7 @@ static void allwinner_rtc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = allwinner_rtc_reset;
+ device_class_set_legacy_reset(dc, allwinner_rtc_reset);
dc->vmsd = &allwinner_rtc_vmstate;
device_class_set_props(dc, allwinner_rtc_properties);
}
diff --git a/hw/rtc/aspeed_rtc.c b/hw/rtc/aspeed_rtc.c
index 589d9a5..3cddf43 100644
--- a/hw/rtc/aspeed_rtc.c
+++ b/hw/rtc/aspeed_rtc.c
@@ -162,7 +162,7 @@ static void aspeed_rtc_class_init(ObjectClass *klass, void *data)
dc->realize = aspeed_rtc_realize;
dc->vmsd = &vmstate_aspeed_rtc;
- dc->reset = aspeed_rtc_reset;
+ device_class_set_legacy_reset(dc, aspeed_rtc_reset);
}
static const TypeInfo aspeed_rtc_info = {
diff --git a/hw/rtc/ds1338.c b/hw/rtc/ds1338.c
index e479661..a5fe221 100644
--- a/hw/rtc/ds1338.c
+++ b/hw/rtc/ds1338.c
@@ -223,7 +223,7 @@ static void ds1338_class_init(ObjectClass *klass, void *data)
k->event = ds1338_event;
k->recv = ds1338_recv;
k->send = ds1338_send;
- dc->reset = ds1338_reset;
+ device_class_set_legacy_reset(dc, ds1338_reset);
dc->vmsd = &vmstate_ds1338;
}
diff --git a/hw/rtc/exynos4210_rtc.c b/hw/rtc/exynos4210_rtc.c
index 319371f..ca28a45 100644
--- a/hw/rtc/exynos4210_rtc.c
+++ b/hw/rtc/exynos4210_rtc.c
@@ -596,7 +596,7 @@ static void exynos4210_rtc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = exynos4210_rtc_reset;
+ device_class_set_legacy_reset(dc, exynos4210_rtc_reset);
dc->vmsd = &vmstate_exynos4210_rtc_state;
}
diff --git a/hw/rtc/goldfish_rtc.c b/hw/rtc/goldfish_rtc.c
index 01acf30..a6dfbf8 100644
--- a/hw/rtc/goldfish_rtc.c
+++ b/hw/rtc/goldfish_rtc.c
@@ -298,7 +298,7 @@ static void goldfish_rtc_class_init(ObjectClass *klass, void *data)
device_class_set_props(dc, goldfish_rtc_properties);
dc->realize = goldfish_rtc_realize;
- dc->reset = goldfish_rtc_reset;
+ device_class_set_legacy_reset(dc, goldfish_rtc_reset);
dc->vmsd = &goldfish_rtc_vmstate;
}
diff --git a/hw/rtc/ls7a_rtc.c b/hw/rtc/ls7a_rtc.c
index 052201c..c9c3cd8 100644
--- a/hw/rtc/ls7a_rtc.c
+++ b/hw/rtc/ls7a_rtc.c
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
- * Loongarch LS7A Real Time Clock emulation
+ * LoongArch LS7A Real Time Clock emulation
*
* Copyright (C) 2021 Loongson Technology Corporation Limited
*/
@@ -469,7 +469,7 @@ static void ls7a_rtc_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_ls7a_rtc;
dc->realize = ls7a_rtc_realize;
- dc->reset = ls7a_rtc_reset;
+ device_class_set_legacy_reset(dc, ls7a_rtc_reset);
dc->desc = "ls7a rtc";
}
diff --git a/hw/rtc/m48t59-isa.c b/hw/rtc/m48t59-isa.c
index 5bb46f2..6e9723f 100644
--- a/hw/rtc/m48t59-isa.c
+++ b/hw/rtc/m48t59-isa.c
@@ -120,7 +120,7 @@ static void m48txx_isa_class_init(ObjectClass *klass, void *data)
NvramClass *nc = NVRAM_CLASS(klass);
dc->realize = m48t59_isa_realize;
- dc->reset = m48t59_reset_isa;
+ device_class_set_legacy_reset(dc, m48t59_reset_isa);
device_class_set_props(dc, m48t59_isa_properties);
nc->read = m48txx_isa_read;
nc->write = m48txx_isa_write;
diff --git a/hw/rtc/m48t59.c b/hw/rtc/m48t59.c
index 1585a2d..48846d8 100644
--- a/hw/rtc/m48t59.c
+++ b/hw/rtc/m48t59.c
@@ -629,7 +629,7 @@ static void m48txx_sysbus_class_init(ObjectClass *klass, void *data)
NvramClass *nc = NVRAM_CLASS(klass);
dc->realize = m48t59_realize;
- dc->reset = m48t59_reset_sysbus;
+ device_class_set_legacy_reset(dc, m48t59_reset_sysbus);
device_class_set_props(dc, m48t59_sysbus_properties);
dc->vmsd = &vmstate_m48t59;
nc->read = m48txx_sysbus_read;
diff --git a/hw/rtc/meson.build b/hw/rtc/meson.build
index 3ea2aff..8ecc2d7 100644
--- a/hw/rtc/meson.build
+++ b/hw/rtc/meson.build
@@ -3,7 +3,6 @@ system_ss.add(when: 'CONFIG_DS1338', if_true: files('ds1338.c'))
system_ss.add(when: 'CONFIG_M41T80', if_true: files('m41t80.c'))
system_ss.add(when: 'CONFIG_M48T59', if_true: files('m48t59.c'))
system_ss.add(when: 'CONFIG_PL031', if_true: files('pl031.c'))
-system_ss.add(when: 'CONFIG_TWL92230', if_true: files('twl92230.c'))
system_ss.add(when: ['CONFIG_ISA_BUS', 'CONFIG_M48T59'], if_true: files('m48t59-isa.c'))
system_ss.add(when: 'CONFIG_XLNX_ZYNQMP', if_true: files('xlnx-zynqmp-rtc.c'))
diff --git a/hw/rtc/twl92230.c b/hw/rtc/twl92230.c
deleted file mode 100644
index efd19a7..0000000
--- a/hw/rtc/twl92230.c
+++ /dev/null
@@ -1,882 +0,0 @@
-/*
- * TI TWL92230C energy-management companion device for the OMAP24xx.
- * Aka. Menelaus (N4200 MENELAUS1_V2.2)
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/timer.h"
-#include "hw/i2c/i2c.h"
-#include "hw/irq.h"
-#include "migration/qemu-file-types.h"
-#include "migration/vmstate.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/rtc.h"
-#include "qemu/bcd.h"
-#include "qemu/module.h"
-#include "qom/object.h"
-
-#define VERBOSE 1
-
-#define TYPE_TWL92230 "twl92230"
-OBJECT_DECLARE_SIMPLE_TYPE(MenelausState, TWL92230)
-
-struct MenelausState {
- I2CSlave parent_obj;
-
- int firstbyte;
- uint8_t reg;
-
- uint8_t vcore[5];
- uint8_t dcdc[3];
- uint8_t ldo[8];
- uint8_t sleep[2];
- uint8_t osc;
- uint8_t detect;
- uint16_t mask;
- uint16_t status;
- uint8_t dir;
- uint8_t inputs;
- uint8_t outputs;
- uint8_t bbsms;
- uint8_t pull[4];
- uint8_t mmc_ctrl[3];
- uint8_t mmc_debounce;
- struct {
- uint8_t ctrl;
- uint16_t comp;
- QEMUTimer *hz_tm;
- int64_t next;
- struct tm tm;
- struct tm new;
- struct tm alm;
- int64_t sec_offset;
- int64_t alm_sec;
- int next_comp;
- } rtc;
- uint16_t rtc_next_vmstate;
- qemu_irq out[4];
- uint8_t pwrbtn_state;
-};
-
-static inline void menelaus_update(MenelausState *s)
-{
- qemu_set_irq(s->out[3], s->status & ~s->mask);
-}
-
-static inline void menelaus_rtc_start(MenelausState *s)
-{
- s->rtc.next += qemu_clock_get_ms(rtc_clock);
- timer_mod(s->rtc.hz_tm, s->rtc.next);
-}
-
-static inline void menelaus_rtc_stop(MenelausState *s)
-{
- timer_del(s->rtc.hz_tm);
- s->rtc.next -= qemu_clock_get_ms(rtc_clock);
- if (s->rtc.next < 1)
- s->rtc.next = 1;
-}
-
-static void menelaus_rtc_update(MenelausState *s)
-{
- qemu_get_timedate(&s->rtc.tm, s->rtc.sec_offset);
-}
-
-static void menelaus_alm_update(MenelausState *s)
-{
- if ((s->rtc.ctrl & 3) == 3)
- s->rtc.alm_sec = qemu_timedate_diff(&s->rtc.alm) - s->rtc.sec_offset;
-}
-
-static void menelaus_rtc_hz(void *opaque)
-{
- MenelausState *s = (MenelausState *) opaque;
-
- s->rtc.next_comp --;
- s->rtc.alm_sec --;
- s->rtc.next += 1000;
- timer_mod(s->rtc.hz_tm, s->rtc.next);
- if ((s->rtc.ctrl >> 3) & 3) { /* EVERY */
- menelaus_rtc_update(s);
- if (((s->rtc.ctrl >> 3) & 3) == 1 && !s->rtc.tm.tm_sec)
- s->status |= 1 << 8; /* RTCTMR */
- else if (((s->rtc.ctrl >> 3) & 3) == 2 && !s->rtc.tm.tm_min)
- s->status |= 1 << 8; /* RTCTMR */
- else if (!s->rtc.tm.tm_hour)
- s->status |= 1 << 8; /* RTCTMR */
- } else
- s->status |= 1 << 8; /* RTCTMR */
- if ((s->rtc.ctrl >> 1) & 1) { /* RTC_AL_EN */
- if (s->rtc.alm_sec == 0)
- s->status |= 1 << 9; /* RTCALM */
- /* TODO: wake-up */
- }
- if (s->rtc.next_comp <= 0) {
- s->rtc.next -= muldiv64((int16_t) s->rtc.comp, 1000, 0x8000);
- s->rtc.next_comp = 3600;
- }
- menelaus_update(s);
-}
-
-static void menelaus_reset(I2CSlave *i2c)
-{
- MenelausState *s = TWL92230(i2c);
-
- s->reg = 0x00;
-
- s->vcore[0] = 0x0c; /* XXX: X-loader needs 0x8c? check! */
- s->vcore[1] = 0x05;
- s->vcore[2] = 0x02;
- s->vcore[3] = 0x0c;
- s->vcore[4] = 0x03;
- s->dcdc[0] = 0x33; /* Depends on wiring */
- s->dcdc[1] = 0x03;
- s->dcdc[2] = 0x00;
- s->ldo[0] = 0x95;
- s->ldo[1] = 0x7e;
- s->ldo[2] = 0x00;
- s->ldo[3] = 0x00; /* Depends on wiring */
- s->ldo[4] = 0x03; /* Depends on wiring */
- s->ldo[5] = 0x00;
- s->ldo[6] = 0x00;
- s->ldo[7] = 0x00;
- s->sleep[0] = 0x00;
- s->sleep[1] = 0x00;
- s->osc = 0x01;
- s->detect = 0x09;
- s->mask = 0x0fff;
- s->status = 0;
- s->dir = 0x07;
- s->outputs = 0x00;
- s->bbsms = 0x00;
- s->pull[0] = 0x00;
- s->pull[1] = 0x00;
- s->pull[2] = 0x00;
- s->pull[3] = 0x00;
- s->mmc_ctrl[0] = 0x03;
- s->mmc_ctrl[1] = 0xc0;
- s->mmc_ctrl[2] = 0x00;
- s->mmc_debounce = 0x05;
-
- if (s->rtc.ctrl & 1)
- menelaus_rtc_stop(s);
- s->rtc.ctrl = 0x00;
- s->rtc.comp = 0x0000;
- s->rtc.next = 1000;
- s->rtc.sec_offset = 0;
- s->rtc.next_comp = 1800;
- s->rtc.alm_sec = 1800;
- s->rtc.alm.tm_sec = 0x00;
- s->rtc.alm.tm_min = 0x00;
- s->rtc.alm.tm_hour = 0x00;
- s->rtc.alm.tm_mday = 0x01;
- s->rtc.alm.tm_mon = 0x00;
- s->rtc.alm.tm_year = 2004;
- menelaus_update(s);
-}
-
-static void menelaus_gpio_set(void *opaque, int line, int level)
-{
- MenelausState *s = (MenelausState *) opaque;
-
- if (line < 3) {
- /* No interrupt generated */
- s->inputs &= ~(1 << line);
- s->inputs |= level << line;
- return;
- }
-
- if (!s->pwrbtn_state && level) {
- s->status |= 1 << 11; /* PSHBTN */
- menelaus_update(s);
- }
- s->pwrbtn_state = level;
-}
-
-#define MENELAUS_REV 0x01
-#define MENELAUS_VCORE_CTRL1 0x02
-#define MENELAUS_VCORE_CTRL2 0x03
-#define MENELAUS_VCORE_CTRL3 0x04
-#define MENELAUS_VCORE_CTRL4 0x05
-#define MENELAUS_VCORE_CTRL5 0x06
-#define MENELAUS_DCDC_CTRL1 0x07
-#define MENELAUS_DCDC_CTRL2 0x08
-#define MENELAUS_DCDC_CTRL3 0x09
-#define MENELAUS_LDO_CTRL1 0x0a
-#define MENELAUS_LDO_CTRL2 0x0b
-#define MENELAUS_LDO_CTRL3 0x0c
-#define MENELAUS_LDO_CTRL4 0x0d
-#define MENELAUS_LDO_CTRL5 0x0e
-#define MENELAUS_LDO_CTRL6 0x0f
-#define MENELAUS_LDO_CTRL7 0x10
-#define MENELAUS_LDO_CTRL8 0x11
-#define MENELAUS_SLEEP_CTRL1 0x12
-#define MENELAUS_SLEEP_CTRL2 0x13
-#define MENELAUS_DEVICE_OFF 0x14
-#define MENELAUS_OSC_CTRL 0x15
-#define MENELAUS_DETECT_CTRL 0x16
-#define MENELAUS_INT_MASK1 0x17
-#define MENELAUS_INT_MASK2 0x18
-#define MENELAUS_INT_STATUS1 0x19
-#define MENELAUS_INT_STATUS2 0x1a
-#define MENELAUS_INT_ACK1 0x1b
-#define MENELAUS_INT_ACK2 0x1c
-#define MENELAUS_GPIO_CTRL 0x1d
-#define MENELAUS_GPIO_IN 0x1e
-#define MENELAUS_GPIO_OUT 0x1f
-#define MENELAUS_BBSMS 0x20
-#define MENELAUS_RTC_CTRL 0x21
-#define MENELAUS_RTC_UPDATE 0x22
-#define MENELAUS_RTC_SEC 0x23
-#define MENELAUS_RTC_MIN 0x24
-#define MENELAUS_RTC_HR 0x25
-#define MENELAUS_RTC_DAY 0x26
-#define MENELAUS_RTC_MON 0x27
-#define MENELAUS_RTC_YR 0x28
-#define MENELAUS_RTC_WKDAY 0x29
-#define MENELAUS_RTC_AL_SEC 0x2a
-#define MENELAUS_RTC_AL_MIN 0x2b
-#define MENELAUS_RTC_AL_HR 0x2c
-#define MENELAUS_RTC_AL_DAY 0x2d
-#define MENELAUS_RTC_AL_MON 0x2e
-#define MENELAUS_RTC_AL_YR 0x2f
-#define MENELAUS_RTC_COMP_MSB 0x30
-#define MENELAUS_RTC_COMP_LSB 0x31
-#define MENELAUS_S1_PULL_EN 0x32
-#define MENELAUS_S1_PULL_DIR 0x33
-#define MENELAUS_S2_PULL_EN 0x34
-#define MENELAUS_S2_PULL_DIR 0x35
-#define MENELAUS_MCT_CTRL1 0x36
-#define MENELAUS_MCT_CTRL2 0x37
-#define MENELAUS_MCT_CTRL3 0x38
-#define MENELAUS_MCT_PIN_ST 0x39
-#define MENELAUS_DEBOUNCE1 0x3a
-
-static uint8_t menelaus_read(void *opaque, uint8_t addr)
-{
- MenelausState *s = (MenelausState *) opaque;
-
- switch (addr) {
- case MENELAUS_REV:
- return 0x22;
-
- case MENELAUS_VCORE_CTRL1 ... MENELAUS_VCORE_CTRL5:
- return s->vcore[addr - MENELAUS_VCORE_CTRL1];
-
- case MENELAUS_DCDC_CTRL1 ... MENELAUS_DCDC_CTRL3:
- return s->dcdc[addr - MENELAUS_DCDC_CTRL1];
-
- case MENELAUS_LDO_CTRL1 ... MENELAUS_LDO_CTRL8:
- return s->ldo[addr - MENELAUS_LDO_CTRL1];
-
- case MENELAUS_SLEEP_CTRL1:
- case MENELAUS_SLEEP_CTRL2:
- return s->sleep[addr - MENELAUS_SLEEP_CTRL1];
-
- case MENELAUS_DEVICE_OFF:
- return 0;
-
- case MENELAUS_OSC_CTRL:
- return s->osc | (1 << 7); /* CLK32K_GOOD */
-
- case MENELAUS_DETECT_CTRL:
- return s->detect;
-
- case MENELAUS_INT_MASK1:
- return (s->mask >> 0) & 0xff;
- case MENELAUS_INT_MASK2:
- return (s->mask >> 8) & 0xff;
-
- case MENELAUS_INT_STATUS1:
- return (s->status >> 0) & 0xff;
- case MENELAUS_INT_STATUS2:
- return (s->status >> 8) & 0xff;
-
- case MENELAUS_INT_ACK1:
- case MENELAUS_INT_ACK2:
- return 0;
-
- case MENELAUS_GPIO_CTRL:
- return s->dir;
- case MENELAUS_GPIO_IN:
- return s->inputs | (~s->dir & s->outputs);
- case MENELAUS_GPIO_OUT:
- return s->outputs;
-
- case MENELAUS_BBSMS:
- return s->bbsms;
-
- case MENELAUS_RTC_CTRL:
- return s->rtc.ctrl;
- case MENELAUS_RTC_UPDATE:
- return 0x00;
- case MENELAUS_RTC_SEC:
- menelaus_rtc_update(s);
- return to_bcd(s->rtc.tm.tm_sec);
- case MENELAUS_RTC_MIN:
- menelaus_rtc_update(s);
- return to_bcd(s->rtc.tm.tm_min);
- case MENELAUS_RTC_HR:
- menelaus_rtc_update(s);
- if ((s->rtc.ctrl >> 2) & 1) /* MODE12_n24 */
- return to_bcd((s->rtc.tm.tm_hour % 12) + 1) |
- (!!(s->rtc.tm.tm_hour >= 12) << 7); /* PM_nAM */
- else
- return to_bcd(s->rtc.tm.tm_hour);
- case MENELAUS_RTC_DAY:
- menelaus_rtc_update(s);
- return to_bcd(s->rtc.tm.tm_mday);
- case MENELAUS_RTC_MON:
- menelaus_rtc_update(s);
- return to_bcd(s->rtc.tm.tm_mon + 1);
- case MENELAUS_RTC_YR:
- menelaus_rtc_update(s);
- return to_bcd(s->rtc.tm.tm_year - 2000);
- case MENELAUS_RTC_WKDAY:
- menelaus_rtc_update(s);
- return to_bcd(s->rtc.tm.tm_wday);
- case MENELAUS_RTC_AL_SEC:
- return to_bcd(s->rtc.alm.tm_sec);
- case MENELAUS_RTC_AL_MIN:
- return to_bcd(s->rtc.alm.tm_min);
- case MENELAUS_RTC_AL_HR:
- if ((s->rtc.ctrl >> 2) & 1) /* MODE12_n24 */
- return to_bcd((s->rtc.alm.tm_hour % 12) + 1) |
- (!!(s->rtc.alm.tm_hour >= 12) << 7);/* AL_PM_nAM */
- else
- return to_bcd(s->rtc.alm.tm_hour);
- case MENELAUS_RTC_AL_DAY:
- return to_bcd(s->rtc.alm.tm_mday);
- case MENELAUS_RTC_AL_MON:
- return to_bcd(s->rtc.alm.tm_mon + 1);
- case MENELAUS_RTC_AL_YR:
- return to_bcd(s->rtc.alm.tm_year - 2000);
- case MENELAUS_RTC_COMP_MSB:
- return (s->rtc.comp >> 8) & 0xff;
- case MENELAUS_RTC_COMP_LSB:
- return (s->rtc.comp >> 0) & 0xff;
-
- case MENELAUS_S1_PULL_EN:
- return s->pull[0];
- case MENELAUS_S1_PULL_DIR:
- return s->pull[1];
- case MENELAUS_S2_PULL_EN:
- return s->pull[2];
- case MENELAUS_S2_PULL_DIR:
- return s->pull[3];
-
- case MENELAUS_MCT_CTRL1 ... MENELAUS_MCT_CTRL3:
- return s->mmc_ctrl[addr - MENELAUS_MCT_CTRL1];
- case MENELAUS_MCT_PIN_ST:
- /* TODO: return the real Card Detect */
- return 0;
- case MENELAUS_DEBOUNCE1:
- return s->mmc_debounce;
-
- default:
-#ifdef VERBOSE
- printf("%s: unknown register %02x\n", __func__, addr);
-#endif
- break;
- }
- return 0;
-}
-
-static void menelaus_write(void *opaque, uint8_t addr, uint8_t value)
-{
- MenelausState *s = (MenelausState *) opaque;
- int line;
- struct tm tm;
-
- switch (addr) {
- case MENELAUS_VCORE_CTRL1:
- s->vcore[0] = (value & 0xe) | MIN(value & 0x1f, 0x12);
- break;
- case MENELAUS_VCORE_CTRL2:
- s->vcore[1] = value;
- break;
- case MENELAUS_VCORE_CTRL3:
- s->vcore[2] = MIN(value & 0x1f, 0x12);
- break;
- case MENELAUS_VCORE_CTRL4:
- s->vcore[3] = MIN(value & 0x1f, 0x12);
- break;
- case MENELAUS_VCORE_CTRL5:
- s->vcore[4] = value & 3;
- /* XXX
- * auto set to 3 on M_Active, nRESWARM
- * auto set to 0 on M_WaitOn, M_Backup
- */
- break;
-
- case MENELAUS_DCDC_CTRL1:
- s->dcdc[0] = value & 0x3f;
- break;
- case MENELAUS_DCDC_CTRL2:
- s->dcdc[1] = value & 0x07;
- /* XXX
- * auto set to 3 on M_Active, nRESWARM
- * auto set to 0 on M_WaitOn, M_Backup
- */
- break;
- case MENELAUS_DCDC_CTRL3:
- s->dcdc[2] = value & 0x07;
- break;
-
- case MENELAUS_LDO_CTRL1:
- s->ldo[0] = value;
- break;
- case MENELAUS_LDO_CTRL2:
- s->ldo[1] = value & 0x7f;
- /* XXX
- * auto set to 0x7e on M_WaitOn, M_Backup
- */
- break;
- case MENELAUS_LDO_CTRL3:
- s->ldo[2] = value & 3;
- /* XXX
- * auto set to 3 on M_Active, nRESWARM
- * auto set to 0 on M_WaitOn, M_Backup
- */
- break;
- case MENELAUS_LDO_CTRL4:
- s->ldo[3] = value & 3;
- /* XXX
- * auto set to 3 on M_Active, nRESWARM
- * auto set to 0 on M_WaitOn, M_Backup
- */
- break;
- case MENELAUS_LDO_CTRL5:
- s->ldo[4] = value & 3;
- /* XXX
- * auto set to 3 on M_Active, nRESWARM
- * auto set to 0 on M_WaitOn, M_Backup
- */
- break;
- case MENELAUS_LDO_CTRL6:
- s->ldo[5] = value & 3;
- break;
- case MENELAUS_LDO_CTRL7:
- s->ldo[6] = value & 3;
- break;
- case MENELAUS_LDO_CTRL8:
- s->ldo[7] = value & 3;
- break;
-
- case MENELAUS_SLEEP_CTRL1:
- case MENELAUS_SLEEP_CTRL2:
- s->sleep[addr - MENELAUS_SLEEP_CTRL1] = value;
- break;
-
- case MENELAUS_DEVICE_OFF:
- if (value & 1) {
- menelaus_reset(I2C_SLAVE(s));
- }
- break;
-
- case MENELAUS_OSC_CTRL:
- s->osc = value & 7;
- break;
-
- case MENELAUS_DETECT_CTRL:
- s->detect = value & 0x7f;
- break;
-
- case MENELAUS_INT_MASK1:
- s->mask &= 0xf00;
- s->mask |= value << 0;
- menelaus_update(s);
- break;
- case MENELAUS_INT_MASK2:
- s->mask &= 0x0ff;
- s->mask |= value << 8;
- menelaus_update(s);
- break;
-
- case MENELAUS_INT_ACK1:
- s->status &= ~(((uint16_t) value) << 0);
- menelaus_update(s);
- break;
- case MENELAUS_INT_ACK2:
- s->status &= ~(((uint16_t) value) << 8);
- menelaus_update(s);
- break;
-
- case MENELAUS_GPIO_CTRL:
- for (line = 0; line < 3; line ++) {
- if (((s->dir ^ value) >> line) & 1) {
- qemu_set_irq(s->out[line],
- ((s->outputs & ~s->dir) >> line) & 1);
- }
- }
- s->dir = value & 0x67;
- break;
- case MENELAUS_GPIO_OUT:
- for (line = 0; line < 3; line ++) {
- if ((((s->outputs ^ value) & ~s->dir) >> line) & 1) {
- qemu_set_irq(s->out[line], (s->outputs >> line) & 1);
- }
- }
- s->outputs = value & 0x07;
- break;
-
- case MENELAUS_BBSMS:
- s->bbsms = 0x0d;
- break;
-
- case MENELAUS_RTC_CTRL:
- if ((s->rtc.ctrl ^ value) & 1) { /* RTC_EN */
- if (value & 1)
- menelaus_rtc_start(s);
- else
- menelaus_rtc_stop(s);
- }
- s->rtc.ctrl = value & 0x1f;
- menelaus_alm_update(s);
- break;
- case MENELAUS_RTC_UPDATE:
- menelaus_rtc_update(s);
- memcpy(&tm, &s->rtc.tm, sizeof(tm));
- switch (value & 0xf) {
- case 0:
- break;
- case 1:
- tm.tm_sec = s->rtc.new.tm_sec;
- break;
- case 2:
- tm.tm_min = s->rtc.new.tm_min;
- break;
- case 3:
- if (s->rtc.new.tm_hour > 23)
- goto rtc_badness;
- tm.tm_hour = s->rtc.new.tm_hour;
- break;
- case 4:
- if (s->rtc.new.tm_mday < 1)
- goto rtc_badness;
- /* TODO check range */
- tm.tm_mday = s->rtc.new.tm_mday;
- break;
- case 5:
- if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11)
- goto rtc_badness;
- tm.tm_mon = s->rtc.new.tm_mon;
- break;
- case 6:
- tm.tm_year = s->rtc.new.tm_year;
- break;
- case 7:
- /* TODO set .tm_mday instead */
- tm.tm_wday = s->rtc.new.tm_wday;
- break;
- case 8:
- if (s->rtc.new.tm_hour > 23)
- goto rtc_badness;
- if (s->rtc.new.tm_mday < 1)
- goto rtc_badness;
- if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11)
- goto rtc_badness;
- tm.tm_sec = s->rtc.new.tm_sec;
- tm.tm_min = s->rtc.new.tm_min;
- tm.tm_hour = s->rtc.new.tm_hour;
- tm.tm_mday = s->rtc.new.tm_mday;
- tm.tm_mon = s->rtc.new.tm_mon;
- tm.tm_year = s->rtc.new.tm_year;
- break;
- rtc_badness:
- default:
- fprintf(stderr, "%s: bad RTC_UPDATE value %02x\n",
- __func__, value);
- s->status |= 1 << 10; /* RTCERR */
- menelaus_update(s);
- }
- s->rtc.sec_offset = qemu_timedate_diff(&tm);
- break;
- case MENELAUS_RTC_SEC:
- s->rtc.tm.tm_sec = from_bcd(value & 0x7f);
- break;
- case MENELAUS_RTC_MIN:
- s->rtc.tm.tm_min = from_bcd(value & 0x7f);
- break;
- case MENELAUS_RTC_HR:
- s->rtc.tm.tm_hour = (s->rtc.ctrl & (1 << 2)) ? /* MODE12_n24 */
- MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) :
- from_bcd(value & 0x3f);
- break;
- case MENELAUS_RTC_DAY:
- s->rtc.tm.tm_mday = from_bcd(value);
- break;
- case MENELAUS_RTC_MON:
- s->rtc.tm.tm_mon = MAX(1, from_bcd(value)) - 1;
- break;
- case MENELAUS_RTC_YR:
- s->rtc.tm.tm_year = 2000 + from_bcd(value);
- break;
- case MENELAUS_RTC_WKDAY:
- s->rtc.tm.tm_mday = from_bcd(value);
- break;
- case MENELAUS_RTC_AL_SEC:
- s->rtc.alm.tm_sec = from_bcd(value & 0x7f);
- menelaus_alm_update(s);
- break;
- case MENELAUS_RTC_AL_MIN:
- s->rtc.alm.tm_min = from_bcd(value & 0x7f);
- menelaus_alm_update(s);
- break;
- case MENELAUS_RTC_AL_HR:
- s->rtc.alm.tm_hour = (s->rtc.ctrl & (1 << 2)) ? /* MODE12_n24 */
- MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) :
- from_bcd(value & 0x3f);
- menelaus_alm_update(s);
- break;
- case MENELAUS_RTC_AL_DAY:
- s->rtc.alm.tm_mday = from_bcd(value);
- menelaus_alm_update(s);
- break;
- case MENELAUS_RTC_AL_MON:
- s->rtc.alm.tm_mon = MAX(1, from_bcd(value)) - 1;
- menelaus_alm_update(s);
- break;
- case MENELAUS_RTC_AL_YR:
- s->rtc.alm.tm_year = 2000 + from_bcd(value);
- menelaus_alm_update(s);
- break;
- case MENELAUS_RTC_COMP_MSB:
- s->rtc.comp &= 0xff;
- s->rtc.comp |= value << 8;
- break;
- case MENELAUS_RTC_COMP_LSB:
- s->rtc.comp &= 0xff << 8;
- s->rtc.comp |= value;
- break;
-
- case MENELAUS_S1_PULL_EN:
- s->pull[0] = value;
- break;
- case MENELAUS_S1_PULL_DIR:
- s->pull[1] = value & 0x1f;
- break;
- case MENELAUS_S2_PULL_EN:
- s->pull[2] = value;
- break;
- case MENELAUS_S2_PULL_DIR:
- s->pull[3] = value & 0x1f;
- break;
-
- case MENELAUS_MCT_CTRL1:
- s->mmc_ctrl[0] = value & 0x7f;
- break;
- case MENELAUS_MCT_CTRL2:
- s->mmc_ctrl[1] = value;
- /* TODO update Card Detect interrupts */
- break;
- case MENELAUS_MCT_CTRL3:
- s->mmc_ctrl[2] = value & 0xf;
- break;
- case MENELAUS_DEBOUNCE1:
- s->mmc_debounce = value & 0x3f;
- break;
-
- default:
-#ifdef VERBOSE
- printf("%s: unknown register %02x\n", __func__, addr);
-#endif
- break;
- }
-}
-
-static int menelaus_event(I2CSlave *i2c, enum i2c_event event)
-{
- MenelausState *s = TWL92230(i2c);
-
- if (event == I2C_START_SEND)
- s->firstbyte = 1;
-
- return 0;
-}
-
-static int menelaus_tx(I2CSlave *i2c, uint8_t data)
-{
- MenelausState *s = TWL92230(i2c);
-
- /* Interpret register address byte */
- if (s->firstbyte) {
- s->reg = data;
- s->firstbyte = 0;
- } else
- menelaus_write(s, s->reg ++, data);
-
- return 0;
-}
-
-static uint8_t menelaus_rx(I2CSlave *i2c)
-{
- MenelausState *s = TWL92230(i2c);
-
- return menelaus_read(s, s->reg ++);
-}
-
-/* Save restore 32 bit int as uint16_t
- This is a Big hack, but it is how the old state did it.
- Or we broke compatibility in the state, or we can't use struct tm
- */
-
-static int get_int32_as_uint16(QEMUFile *f, void *pv, size_t size,
- const VMStateField *field)
-{
- int *v = pv;
- *v = qemu_get_be16(f);
- return 0;
-}
-
-static int put_int32_as_uint16(QEMUFile *f, void *pv, size_t size,
- const VMStateField *field, JSONWriter *vmdesc)
-{
- int *v = pv;
- qemu_put_be16(f, *v);
-
- return 0;
-}
-
-static const VMStateInfo vmstate_hack_int32_as_uint16 = {
- .name = "int32_as_uint16",
- .get = get_int32_as_uint16,
- .put = put_int32_as_uint16,
-};
-
-#define VMSTATE_UINT16_HACK(_f, _s) \
- VMSTATE_SINGLE(_f, _s, 0, vmstate_hack_int32_as_uint16, int32_t)
-
-
-static const VMStateDescription vmstate_menelaus_tm = {
- .name = "menelaus_tm",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT16_HACK(tm_sec, struct tm),
- VMSTATE_UINT16_HACK(tm_min, struct tm),
- VMSTATE_UINT16_HACK(tm_hour, struct tm),
- VMSTATE_UINT16_HACK(tm_mday, struct tm),
- VMSTATE_UINT16_HACK(tm_min, struct tm),
- VMSTATE_UINT16_HACK(tm_year, struct tm),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int menelaus_pre_save(void *opaque)
-{
- MenelausState *s = opaque;
- /* Should be <= 1000 */
- s->rtc_next_vmstate = s->rtc.next - qemu_clock_get_ms(rtc_clock);
-
- return 0;
-}
-
-static int menelaus_post_load(void *opaque, int version_id)
-{
- MenelausState *s = opaque;
-
- if (s->rtc.ctrl & 1) /* RTC_EN */
- menelaus_rtc_stop(s);
-
- s->rtc.next = s->rtc_next_vmstate;
-
- menelaus_alm_update(s);
- menelaus_update(s);
- if (s->rtc.ctrl & 1) /* RTC_EN */
- menelaus_rtc_start(s);
- return 0;
-}
-
-static const VMStateDescription vmstate_menelaus = {
- .name = "menelaus",
- .version_id = 0,
- .minimum_version_id = 0,
- .pre_save = menelaus_pre_save,
- .post_load = menelaus_post_load,
- .fields = (const VMStateField[]) {
- VMSTATE_INT32(firstbyte, MenelausState),
- VMSTATE_UINT8(reg, MenelausState),
- VMSTATE_UINT8_ARRAY(vcore, MenelausState, 5),
- VMSTATE_UINT8_ARRAY(dcdc, MenelausState, 3),
- VMSTATE_UINT8_ARRAY(ldo, MenelausState, 8),
- VMSTATE_UINT8_ARRAY(sleep, MenelausState, 2),
- VMSTATE_UINT8(osc, MenelausState),
- VMSTATE_UINT8(detect, MenelausState),
- VMSTATE_UINT16(mask, MenelausState),
- VMSTATE_UINT16(status, MenelausState),
- VMSTATE_UINT8(dir, MenelausState),
- VMSTATE_UINT8(inputs, MenelausState),
- VMSTATE_UINT8(outputs, MenelausState),
- VMSTATE_UINT8(bbsms, MenelausState),
- VMSTATE_UINT8_ARRAY(pull, MenelausState, 4),
- VMSTATE_UINT8_ARRAY(mmc_ctrl, MenelausState, 3),
- VMSTATE_UINT8(mmc_debounce, MenelausState),
- VMSTATE_UINT8(rtc.ctrl, MenelausState),
- VMSTATE_UINT16(rtc.comp, MenelausState),
- VMSTATE_UINT16(rtc_next_vmstate, MenelausState),
- VMSTATE_STRUCT(rtc.new, MenelausState, 0, vmstate_menelaus_tm,
- struct tm),
- VMSTATE_STRUCT(rtc.alm, MenelausState, 0, vmstate_menelaus_tm,
- struct tm),
- VMSTATE_UINT8(pwrbtn_state, MenelausState),
- VMSTATE_I2C_SLAVE(parent_obj, MenelausState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void twl92230_realize(DeviceState *dev, Error **errp)
-{
- MenelausState *s = TWL92230(dev);
-
- s->rtc.hz_tm = timer_new_ms(rtc_clock, menelaus_rtc_hz, s);
- /* Three output pins plus one interrupt pin. */
- qdev_init_gpio_out(dev, s->out, 4);
-
- /* Three input pins plus one power-button pin. */
- qdev_init_gpio_in(dev, menelaus_gpio_set, 4);
-
- menelaus_reset(I2C_SLAVE(dev));
-}
-
-static void twl92230_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
-
- dc->realize = twl92230_realize;
- sc->event = menelaus_event;
- sc->recv = menelaus_rx;
- sc->send = menelaus_tx;
- dc->vmsd = &vmstate_menelaus;
-}
-
-static const TypeInfo twl92230_info = {
- .name = TYPE_TWL92230,
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(MenelausState),
- .class_init = twl92230_class_init,
-};
-
-static void twl92230_register_types(void)
-{
- type_register_static(&twl92230_info);
-}
-
-type_init(twl92230_register_types)
diff --git a/hw/rtc/xlnx-zynqmp-rtc.c b/hw/rtc/xlnx-zynqmp-rtc.c
index 613c640..f37df09 100644
--- a/hw/rtc/xlnx-zynqmp-rtc.c
+++ b/hw/rtc/xlnx-zynqmp-rtc.c
@@ -255,7 +255,7 @@ static void rtc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = rtc_reset;
+ device_class_set_legacy_reset(dc, rtc_reset);
dc->vmsd = &vmstate_rtc;
}
diff --git a/hw/s390x/ccw-device.c b/hw/s390x/ccw-device.c
index a7d682e..230cc09 100644
--- a/hw/s390x/ccw-device.c
+++ b/hw/s390x/ccw-device.c
@@ -13,6 +13,10 @@
#include "ccw-device.h"
#include "hw/qdev-properties.h"
#include "qemu/module.h"
+#include "ipl.h"
+#include "qapi/visitor.h"
+#include "qemu/ctype.h"
+#include "qapi/error.h"
static void ccw_device_refill_ids(CcwDevice *dev)
{
@@ -37,16 +41,58 @@ static bool ccw_device_realize(CcwDevice *dev, Error **errp)
return true;
}
+static void ccw_device_get_loadparm(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ CcwDevice *dev = CCW_DEVICE(obj);
+ char *str = g_strndup((char *) dev->loadparm, sizeof(dev->loadparm));
+
+ visit_type_str(v, name, &str, errp);
+ g_free(str);
+}
+
+static void ccw_device_set_loadparm(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ CcwDevice *dev = CCW_DEVICE(obj);
+ char *val;
+ int index;
+
+ index = object_property_get_int(obj, "bootindex", NULL);
+
+ if (index < 0) {
+ error_setg(errp, "LOADPARM is only valid for boot devices!");
+ }
+
+ if (!visit_type_str(v, name, &val, errp)) {
+ return;
+ }
+
+ s390_ipl_fmt_loadparm(dev->loadparm, val, errp);
+}
+
+static const PropertyInfo ccw_loadparm = {
+ .name = "ccw_loadparm",
+ .description = "Up to 8 chars in set of [A-Za-z0-9. ] to pass"
+ " to the guest loader/kernel",
+ .get = ccw_device_get_loadparm,
+ .set = ccw_device_set_loadparm,
+};
+
static Property ccw_device_properties[] = {
DEFINE_PROP_CSS_DEV_ID("devno", CcwDevice, devno),
DEFINE_PROP_CSS_DEV_ID_RO("dev_id", CcwDevice, dev_id),
DEFINE_PROP_CSS_DEV_ID_RO("subch_id", CcwDevice, subch_id),
+ DEFINE_PROP("loadparm", CcwDevice, loadparm, ccw_loadparm,
+ typeof(uint8_t[8])),
DEFINE_PROP_END_OF_LIST(),
};
-static void ccw_device_reset(DeviceState *d)
+static void ccw_device_reset_hold(Object *obj, ResetType type)
{
- CcwDevice *ccw_dev = CCW_DEVICE(d);
+ CcwDevice *ccw_dev = CCW_DEVICE(obj);
css_reset_sch(ccw_dev->sch);
}
@@ -55,11 +101,12 @@ static void ccw_device_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
CCWDeviceClass *k = CCW_DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
k->realize = ccw_device_realize;
k->refill_ids = ccw_device_refill_ids;
device_class_set_props(dc, ccw_device_properties);
- dc->reset = ccw_device_reset;
+ rc->phases.hold = ccw_device_reset_hold;
dc->bus_type = TYPE_VIRTUAL_CSS_BUS;
}
diff --git a/hw/s390x/ccw-device.h b/hw/s390x/ccw-device.h
index 5feeb0e..1e1737c 100644
--- a/hw/s390x/ccw-device.h
+++ b/hw/s390x/ccw-device.h
@@ -26,6 +26,8 @@ struct CcwDevice {
CssDevId dev_id;
/* The actual busid of the virtual subchannel. */
CssDevId subch_id;
+ /* If set, use this loadparm value when device is boot target */
+ uint8_t loadparm[8];
};
typedef struct CcwDevice CcwDevice;
diff --git a/hw/s390x/cpu-topology.c b/hw/s390x/cpu-topology.c
index f16bdf6..7d4e1f5 100644
--- a/hw/s390x/cpu-topology.c
+++ b/hw/s390x/cpu-topology.c
@@ -105,7 +105,7 @@ static void s390_topology_init(MachineState *ms)
*/
void s390_handle_ptf(S390CPU *cpu, uint8_t r1, uintptr_t ra)
{
- CpuS390Polarization polarization;
+ S390CpuPolarization polarization;
CPUS390XState *env = &cpu->env;
uint64_t reg = env->regs[r1];
int fc = reg & S390_TOPO_FC_MASK;
@@ -357,7 +357,7 @@ static void s390_change_topology(uint16_t core_id,
bool has_book_id, uint16_t book_id,
bool has_drawer_id, uint16_t drawer_id,
bool has_entitlement,
- CpuS390Entitlement entitlement,
+ S390CpuEntitlement entitlement,
bool has_dedicated, bool dedicated,
Error **errp)
{
@@ -446,7 +446,7 @@ void qmp_set_cpu_topology(uint16_t core,
bool has_socket, uint16_t socket,
bool has_book, uint16_t book,
bool has_drawer, uint16_t drawer,
- bool has_entitlement, CpuS390Entitlement entitlement,
+ bool has_entitlement, S390CpuEntitlement entitlement,
bool has_dedicated, bool dedicated,
Error **errp)
{
diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c
index 06c1da0..2b0332c 100644
--- a/hw/s390x/event-facility.c
+++ b/hw/s390x/event-facility.c
@@ -467,7 +467,7 @@ static void init_event_facility_class(ObjectClass *klass, void *data)
SCLPEventFacilityClass *k = EVENT_FACILITY_CLASS(dc);
dc->realize = realize_event_facility;
- dc->reset = reset_event_facility;
+ device_class_set_legacy_reset(dc, reset_event_facility);
dc->vmsd = &vmstate_event_facility;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
k->command_handler = command_handler;
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index e934bf8..dc02b0f 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -34,6 +34,7 @@
#include "qemu/config-file.h"
#include "qemu/cutils.h"
#include "qemu/option.h"
+#include "qemu/ctype.h"
#include "standard-headers/linux/virtio_ids.h"
#define KERN_IMAGE_START 0x010000UL
@@ -45,6 +46,7 @@
#define INITRD_PARM_START 0x010408UL
#define PARMFILE_START 0x001000UL
#define ZIPL_IMAGE_START 0x009000UL
+#define BIOS_MAX_SIZE 0x300000UL
#define IPL_PSW_MASK (PSW_MASK_32 | PSW_MASK_64)
static bool iplb_extended_needed(void *opaque)
@@ -54,6 +56,13 @@ static bool iplb_extended_needed(void *opaque)
return ipl->iplbext_migration;
}
+/* Place the IPLB chain immediately before the BIOS in memory */
+static uint64_t find_iplb_chain_addr(uint64_t bios_addr, uint16_t count)
+{
+ return (bios_addr & TARGET_PAGE_MASK)
+ - (count * sizeof(IplParameterBlock));
+}
+
static const VMStateDescription vmstate_iplb_extended = {
.name = "ipl/iplb_extended",
.version_id = 0,
@@ -144,7 +153,14 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
* even if an external kernel has been defined.
*/
if (!ipl->kernel || ipl->enforce_bios) {
- uint64_t fwbase = (MIN(ms->ram_size, 0x80000000U) - 0x200000) & ~0xffffUL;
+ uint64_t fwbase;
+
+ if (ms->ram_size < BIOS_MAX_SIZE) {
+ error_setg(errp, "not enough RAM to load the BIOS file");
+ return;
+ }
+
+ fwbase = (MIN(ms->ram_size, 0x80000000U) - BIOS_MAX_SIZE) & ~0xffffUL;
bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, ipl->firmware);
if (bios_filename == NULL) {
@@ -252,8 +268,8 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
*/
romptr = rom_ptr(INITRD_PARM_START, 16);
if (romptr) {
- stq_p(romptr, initrd_offset);
- stq_p(romptr + 1, initrd_size);
+ stq_be_p(romptr, initrd_offset);
+ stq_be_p(romptr + 1, initrd_size);
}
}
}
@@ -280,7 +296,6 @@ static Property s390_ipl_properties[] = {
DEFINE_PROP_STRING("initrd", S390IPLState, initrd),
DEFINE_PROP_STRING("cmdline", S390IPLState, cmdline),
DEFINE_PROP_STRING("firmware", S390IPLState, firmware),
- DEFINE_PROP_STRING("netboot_fw", S390IPLState, netboot_fw),
DEFINE_PROP_BOOL("enforce_bios", S390IPLState, enforce_bios, false),
DEFINE_PROP_BOOL("iplbext_migration", S390IPLState, iplbext_migration,
true),
@@ -390,174 +405,169 @@ static CcwDevice *s390_get_ccw_device(DeviceState *dev_st, int *devtype)
return ccw_dev;
}
-static bool s390_gen_initial_iplb(S390IPLState *ipl)
+static uint64_t s390_ipl_map_iplb_chain(IplParameterBlock *iplb_chain)
+{
+ S390IPLState *ipl = get_ipl_device();
+ uint16_t count = be16_to_cpu(ipl->qipl.chain_len);
+ uint64_t len = sizeof(IplParameterBlock) * count;
+ uint64_t chain_addr = find_iplb_chain_addr(ipl->bios_start_addr, count);
+
+ cpu_physical_memory_write(chain_addr, iplb_chain, len);
+ return chain_addr;
+}
+
+void s390_ipl_fmt_loadparm(uint8_t *loadparm, char *str, Error **errp)
+{
+ int i;
+
+ /* Initialize the loadparm with spaces */
+ memset(loadparm, ' ', LOADPARM_LEN);
+ for (i = 0; i < LOADPARM_LEN && str[i]; i++) {
+ uint8_t c = qemu_toupper(str[i]); /* mimic HMC */
+
+ if (qemu_isalnum(c) || c == '.' || c == ' ') {
+ loadparm[i] = c;
+ } else {
+ error_setg(errp, "LOADPARM: invalid character '%c' (ASCII 0x%02x)",
+ c, c);
+ return;
+ }
+ }
+}
+
+void s390_ipl_convert_loadparm(char *ascii_lp, uint8_t *ebcdic_lp)
+{
+ int i;
+
+ /* Initialize the loadparm with EBCDIC spaces (0x40) */
+ memset(ebcdic_lp, '@', LOADPARM_LEN);
+ for (i = 0; i < LOADPARM_LEN && ascii_lp[i]; i++) {
+ ebcdic_lp[i] = ascii2ebcdic[(uint8_t) ascii_lp[i]];
+ }
+}
+
+static bool s390_build_iplb(DeviceState *dev_st, IplParameterBlock *iplb)
{
- DeviceState *dev_st;
CcwDevice *ccw_dev = NULL;
SCSIDevice *sd;
int devtype;
-
- dev_st = get_boot_device(0);
- if (dev_st) {
- ccw_dev = s390_get_ccw_device(dev_st, &devtype);
- }
+ uint8_t *lp;
/*
* Currently allow IPL only from CCW devices.
*/
+ ccw_dev = s390_get_ccw_device(dev_st, &devtype);
if (ccw_dev) {
+ lp = ccw_dev->loadparm;
+
switch (devtype) {
case CCW_DEVTYPE_SCSI:
sd = SCSI_DEVICE(dev_st);
- ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN);
- ipl->iplb.blk0_len =
+ iplb->len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN);
+ iplb->blk0_len =
cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN - S390_IPLB_HEADER_LEN);
- ipl->iplb.pbt = S390_IPL_TYPE_QEMU_SCSI;
- ipl->iplb.scsi.lun = cpu_to_be32(sd->lun);
- ipl->iplb.scsi.target = cpu_to_be16(sd->id);
- ipl->iplb.scsi.channel = cpu_to_be16(sd->channel);
- ipl->iplb.scsi.devno = cpu_to_be16(ccw_dev->sch->devno);
- ipl->iplb.scsi.ssid = ccw_dev->sch->ssid & 3;
+ iplb->pbt = S390_IPL_TYPE_QEMU_SCSI;
+ iplb->scsi.lun = cpu_to_be32(sd->lun);
+ iplb->scsi.target = cpu_to_be16(sd->id);
+ iplb->scsi.channel = cpu_to_be16(sd->channel);
+ iplb->scsi.devno = cpu_to_be16(ccw_dev->sch->devno);
+ iplb->scsi.ssid = ccw_dev->sch->ssid & 3;
break;
case CCW_DEVTYPE_VFIO:
- ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
- ipl->iplb.pbt = S390_IPL_TYPE_CCW;
- ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
- ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
+ iplb->len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
+ iplb->pbt = S390_IPL_TYPE_CCW;
+ iplb->ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
+ iplb->ccw.ssid = ccw_dev->sch->ssid & 3;
break;
case CCW_DEVTYPE_VIRTIO_NET:
- ipl->netboot = true;
- /* Fall through to CCW_DEVTYPE_VIRTIO case */
case CCW_DEVTYPE_VIRTIO:
- ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
- ipl->iplb.blk0_len =
+ iplb->len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
+ iplb->blk0_len =
cpu_to_be32(S390_IPLB_MIN_CCW_LEN - S390_IPLB_HEADER_LEN);
- ipl->iplb.pbt = S390_IPL_TYPE_CCW;
- ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
- ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
+ iplb->pbt = S390_IPL_TYPE_CCW;
+ iplb->ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
+ iplb->ccw.ssid = ccw_dev->sch->ssid & 3;
break;
}
- if (!s390_ipl_set_loadparm(ipl->iplb.loadparm)) {
- ipl->iplb.flags |= DIAG308_FLAGS_LP_VALID;
+ /* If the device loadparm is empty use the global machine loadparm */
+ if (memcmp(lp, NO_LOADPARM, 8) == 0) {
+ lp = S390_CCW_MACHINE(qdev_get_machine())->loadparm;
}
+ s390_ipl_convert_loadparm((char *)lp, iplb->loadparm);
+ iplb->flags |= DIAG308_FLAGS_LP_VALID;
+
return true;
}
return false;
}
-int s390_ipl_set_loadparm(uint8_t *loadparm)
+void s390_rebuild_iplb(uint16_t dev_index, IplParameterBlock *iplb)
{
- MachineState *machine = MACHINE(qdev_get_machine());
- char *lp = object_property_get_str(OBJECT(machine), "loadparm", NULL);
-
- if (lp) {
- int i;
-
- /* lp is an uppercase string without leading/embedded spaces */
- for (i = 0; i < 8 && lp[i]; i++) {
- loadparm[i] = ascii2ebcdic[(uint8_t) lp[i]];
- }
-
- if (i < 8) {
- memset(loadparm + i, 0x40, 8 - i); /* fill with EBCDIC spaces */
- }
-
- g_free(lp);
- return 0;
- }
+ S390IPLState *ipl = get_ipl_device();
+ uint16_t index;
+ index = ipl->rebuilt_iplb ? ipl->iplb_index : dev_index;
- return -1;
+ ipl->rebuilt_iplb = s390_build_iplb(get_boot_device(index), iplb);
+ ipl->iplb_index = index;
}
-static int load_netboot_image(Error **errp)
+static bool s390_init_all_iplbs(S390IPLState *ipl)
{
- MachineState *ms = MACHINE(qdev_get_machine());
- S390IPLState *ipl = get_ipl_device();
- char *netboot_filename;
- MemoryRegion *sysmem = get_system_memory();
- MemoryRegion *mr = NULL;
- void *ram_ptr = NULL;
- int img_size = -1;
-
- mr = memory_region_find(sysmem, 0, 1).mr;
- if (!mr) {
- error_setg(errp, "Failed to find memory region at address 0");
- return -1;
- }
+ int iplb_num = 0;
+ IplParameterBlock iplb_chain[7];
+ DeviceState *dev_st = get_boot_device(0);
+ Object *machine = qdev_get_machine();
- ram_ptr = memory_region_get_ram_ptr(mr);
- if (!ram_ptr) {
- error_setg(errp, "No RAM found");
- goto unref_mr;
+ /*
+ * Parse the boot devices. Generate an IPLB for only the first boot device
+ * which will later be set with DIAG308.
+ */
+ if (!dev_st) {
+ ipl->qipl.chain_len = 0;
+ return false;
}
- netboot_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, ipl->netboot_fw);
- if (netboot_filename == NULL) {
- error_setg(errp, "Could not find network bootloader '%s'",
- ipl->netboot_fw);
- goto unref_mr;
+ /* If no machine loadparm was defined fill it with spaces */
+ if (memcmp(S390_CCW_MACHINE(machine)->loadparm, NO_LOADPARM, 8) == 0) {
+ object_property_set_str(machine, "loadparm", " ", NULL);
}
- img_size = load_elf_ram(netboot_filename, NULL, NULL, NULL,
- &ipl->start_addr,
- NULL, NULL, NULL, 1, EM_S390, 0, 0, NULL,
- false);
+ iplb_num = 1;
+ s390_build_iplb(dev_st, &ipl->iplb);
- if (img_size < 0) {
- img_size = load_image_size(netboot_filename, ram_ptr, ms->ram_size);
- ipl->start_addr = KERN_IMAGE_START;
+ /* Index any fallback boot devices */
+ while (get_boot_device(iplb_num)) {
+ iplb_num++;
}
- if (img_size < 0) {
- error_setg(errp, "Failed to load network bootloader");
- }
+ if (iplb_num > MAX_BOOT_DEVS) {
+ warn_report("Excess boot devices defined! %d boot devices found, "
+ "but only the first %d will be considered.",
+ iplb_num, MAX_BOOT_DEVS);
- g_free(netboot_filename);
-
-unref_mr:
- memory_region_unref(mr);
- return img_size;
-}
-
-static bool is_virtio_ccw_device_of_type(IplParameterBlock *iplb,
- int virtio_id)
-{
- uint8_t cssid;
- uint8_t ssid;
- uint16_t devno;
- uint16_t schid;
- SubchDev *sch = NULL;
-
- if (iplb->pbt != S390_IPL_TYPE_CCW) {
- return false;
+ iplb_num = MAX_BOOT_DEVS;
}
- devno = be16_to_cpu(iplb->ccw.devno);
- ssid = iplb->ccw.ssid & 3;
-
- for (schid = 0; schid < MAX_SCHID; schid++) {
- for (cssid = 0; cssid < MAX_CSSID; cssid++) {
- sch = css_find_subch(1, cssid, ssid, schid);
+ ipl->qipl.chain_len = cpu_to_be16(iplb_num - 1);
- if (sch && sch->devno == devno) {
- return sch->id.cu_model == virtio_id;
- }
+ /*
+ * Build fallback IPLBs for any boot devices above index 0, up to a
+ * maximum amount as defined in ipl.h
+ */
+ if (iplb_num > 1) {
+ /* Start at 1 because the IPLB for boot index 0 is not chained */
+ for (int i = 1; i < iplb_num; i++) {
+ dev_st = get_boot_device(i);
+ s390_build_iplb(dev_st, &iplb_chain[i - 1]);
}
- }
- return false;
-}
-static bool is_virtio_net_device(IplParameterBlock *iplb)
-{
- return is_virtio_ccw_device_of_type(iplb, VIRTIO_ID_NET);
-}
+ ipl->qipl.next_iplb = cpu_to_be64(s390_ipl_map_iplb_chain(iplb_chain));
+ }
-static bool is_virtio_scsi_device(IplParameterBlock *iplb)
-{
- return is_virtio_ccw_device_of_type(iplb, VIRTIO_ID_SCSI);
+ return iplb_num;
}
static void update_machine_ipl_properties(IplParameterBlock *iplb)
@@ -577,7 +587,7 @@ static void update_machine_ipl_properties(IplParameterBlock *iplb)
ascii_loadparm[i] = 0;
object_property_set_str(machine, "loadparm", ascii_loadparm, &err);
} else {
- object_property_set_str(machine, "loadparm", "", &err);
+ object_property_set_str(machine, "loadparm", " ", &err);
}
if (err) {
warn_report_err(err);
@@ -599,7 +609,7 @@ void s390_ipl_update_diag308(IplParameterBlock *iplb)
ipl->iplb = *iplb;
ipl->iplb_valid = true;
}
- ipl->netboot = is_virtio_net_device(iplb);
+
update_machine_ipl_properties(iplb);
}
@@ -626,32 +636,14 @@ IplParameterBlock *s390_ipl_get_iplb(void)
void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type)
{
S390IPLState *ipl = get_ipl_device();
-
if (reset_type == S390_RESET_EXTERNAL || reset_type == S390_RESET_REIPL) {
/* use CPU 0 for full resets */
ipl->reset_cpu_index = 0;
} else {
ipl->reset_cpu_index = cs->cpu_index;
}
- ipl->reset_type = reset_type;
-
- if (reset_type == S390_RESET_REIPL &&
- ipl->iplb_valid &&
- !ipl->netboot &&
- ipl->iplb.pbt == S390_IPL_TYPE_CCW &&
- is_virtio_scsi_device(&ipl->iplb)) {
- CcwDevice *ccw_dev = s390_get_ccw_device(get_boot_device(0), NULL);
- if (ccw_dev &&
- cpu_to_be16(ccw_dev->sch->devno) == ipl->iplb.ccw.devno &&
- (ccw_dev->sch->ssid & 3) == ipl->iplb.ccw.ssid) {
- /*
- * this is the original boot device's SCSI
- * so restore IPL parameter info from it
- */
- ipl->iplb_valid = s390_gen_initial_iplb(ipl);
- }
- }
+ ipl->reset_type = reset_type;
if (reset_type == S390_RESET_MODIFIED_CLEAR ||
reset_type == S390_RESET_LOAD_NORMAL ||
reset_type == S390_RESET_PV) {
@@ -743,13 +735,11 @@ void s390_ipl_prepare_cpu(S390CPU *cpu)
if (!ipl->kernel || ipl->iplb_valid) {
cpu->env.psw.addr = ipl->bios_start_addr;
if (!ipl->iplb_valid) {
- ipl->iplb_valid = s390_gen_initial_iplb(ipl);
+ ipl->iplb_valid = s390_init_all_iplbs(ipl);
+ } else {
+ ipl->qipl.chain_len = 0;
}
}
- if (ipl->netboot) {
- load_netboot_image(&error_fatal);
- ipl->qipl.netboot_start_addr = cpu_to_be64(ipl->start_addr);
- }
s390_ipl_set_boot_menu(ipl);
s390_ipl_prepare_qipl(cpu);
}
@@ -770,7 +760,7 @@ static void s390_ipl_class_init(ObjectClass *klass, void *data)
dc->realize = s390_ipl_realize;
device_class_set_props(dc, s390_ipl_properties);
- dc->reset = s390_ipl_reset;
+ device_class_set_legacy_reset(dc, s390_ipl_reset);
dc->vmsd = &vmstate_ipl;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
/* Reason: Loads the ROMs and thus can only be used one time - internally */
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 57cd125..d7d0b7b 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -16,96 +16,15 @@
#include "cpu.h"
#include "exec/address-spaces.h"
#include "hw/qdev-core.h"
+#include "hw/s390x/ipl/qipl.h"
#include "qom/object.h"
-struct IPLBlockPVComp {
- uint64_t tweak_pref;
- uint64_t addr;
- uint64_t size;
-} QEMU_PACKED;
-typedef struct IPLBlockPVComp IPLBlockPVComp;
-
-struct IPLBlockPV {
- uint8_t reserved18[87]; /* 0x18 */
- uint8_t version; /* 0x6f */
- uint32_t reserved70; /* 0x70 */
- uint32_t num_comp; /* 0x74 */
- uint64_t pv_header_addr; /* 0x78 */
- uint64_t pv_header_len; /* 0x80 */
- struct IPLBlockPVComp components[0];
-} QEMU_PACKED;
-typedef struct IPLBlockPV IPLBlockPV;
-
-struct IplBlockCcw {
- uint8_t reserved0[85];
- uint8_t ssid;
- uint16_t devno;
- uint8_t vm_flags;
- uint8_t reserved3[3];
- uint32_t vm_parm_len;
- uint8_t nss_name[8];
- uint8_t vm_parm[64];
- uint8_t reserved4[8];
-} QEMU_PACKED;
-typedef struct IplBlockCcw IplBlockCcw;
-
-struct IplBlockFcp {
- uint8_t reserved1[305 - 1];
- uint8_t opt;
- uint8_t reserved2[3];
- uint16_t reserved3;
- uint16_t devno;
- uint8_t reserved4[4];
- uint64_t wwpn;
- uint64_t lun;
- uint32_t bootprog;
- uint8_t reserved5[12];
- uint64_t br_lba;
- uint32_t scp_data_len;
- uint8_t reserved6[260];
- uint8_t scp_data[0];
-} QEMU_PACKED;
-typedef struct IplBlockFcp IplBlockFcp;
-
-struct IplBlockQemuScsi {
- uint32_t lun;
- uint16_t target;
- uint16_t channel;
- uint8_t reserved0[77];
- uint8_t ssid;
- uint16_t devno;
-} QEMU_PACKED;
-typedef struct IplBlockQemuScsi IplBlockQemuScsi;
-
#define DIAG308_FLAGS_LP_VALID 0x80
+#define MAX_BOOT_DEVS 8 /* Max number of devices that may have a bootindex */
-union IplParameterBlock {
- struct {
- uint32_t len;
- uint8_t reserved0[3];
- uint8_t version;
- uint32_t blk0_len;
- uint8_t pbt;
- uint8_t flags;
- uint16_t reserved01;
- uint8_t loadparm[8];
- union {
- IplBlockCcw ccw;
- IplBlockFcp fcp;
- IPLBlockPV pv;
- IplBlockQemuScsi scsi;
- };
- } QEMU_PACKED;
- struct {
- uint8_t reserved1[110];
- uint16_t devno;
- uint8_t reserved2[88];
- uint8_t reserved_ext[4096 - 200];
- } QEMU_PACKED;
-} QEMU_PACKED;
-typedef union IplParameterBlock IplParameterBlock;
-
-int s390_ipl_set_loadparm(uint8_t *loadparm);
+void s390_ipl_convert_loadparm(char *ascii_lp, uint8_t *ebcdic_lp);
+void s390_ipl_fmt_loadparm(uint8_t *loadparm, char *str, Error **errp);
+void s390_rebuild_iplb(uint16_t index, IplParameterBlock *iplb);
void s390_ipl_update_diag308(IplParameterBlock *iplb);
int s390_ipl_prepare_pv_header(Error **errp);
int s390_ipl_pv_unpack(void);
@@ -131,27 +50,6 @@ void s390_ipl_clear_reset_request(void);
#define QIPL_FLAG_BM_OPTS_CMD 0x80
#define QIPL_FLAG_BM_OPTS_ZIPL 0x40
-/*
- * The QEMU IPL Parameters will be stored at absolute address
- * 204 (0xcc) which means it is 32-bit word aligned but not
- * double-word aligned.
- * Placement of data fields in this area must account for
- * their alignment needs. E.g., netboot_start_address must
- * have an offset of 4 + n * 8 bytes within the struct in order
- * to keep it double-word aligned.
- * The total size of the struct must never exceed 28 bytes.
- * This definition must be kept in sync with the definition
- * in pc-bios/s390-ccw/iplb.h.
- */
-struct QemuIplParameters {
- uint8_t qipl_flags;
- uint8_t reserved1[3];
- uint64_t netboot_start_addr;
- uint32_t boot_menu_timeout;
- uint8_t reserved2[12];
-} QEMU_PACKED;
-typedef struct QemuIplParameters QemuIplParameters;
-
#define TYPE_S390_IPL "s390-ipl"
OBJECT_DECLARE_SIMPLE_TYPE(S390IPLState, S390_IPL)
@@ -168,7 +66,8 @@ struct S390IPLState {
bool enforce_bios;
bool iplb_valid;
bool iplb_valid_pv;
- bool netboot;
+ bool rebuilt_iplb;
+ uint16_t iplb_index;
/* reset related properties don't have to be migrated or reset */
enum s390_reset reset_type;
int reset_cpu_index;
@@ -178,7 +77,6 @@ struct S390IPLState {
char *initrd;
char *cmdline;
char *firmware;
- char *netboot_fw;
uint8_t cssid;
uint8_t ssid;
uint16_t devno;
@@ -276,11 +174,14 @@ static inline bool iplb_valid_pv(IplParameterBlock *iplb)
static inline bool iplb_valid(IplParameterBlock *iplb)
{
+ uint32_t len = be32_to_cpu(iplb->len);
+
switch (iplb->pbt) {
case S390_IPL_TYPE_FCP:
- return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_FCP_LEN;
+ return len >= S390_IPLB_MIN_FCP_LEN;
case S390_IPL_TYPE_CCW:
- return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_CCW_LEN;
+ return len >= S390_IPLB_MIN_CCW_LEN;
+ case S390_IPL_TYPE_QEMU_SCSI:
default:
return false;
}
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index 3e57d5f..40b2567 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -1323,7 +1323,7 @@ static void s390_pcihost_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
- dc->reset = s390_pcihost_reset;
+ device_class_set_legacy_reset(dc, s390_pcihost_reset);
dc->realize = s390_pcihost_realize;
dc->unrealize = s390_pcihost_unrealize;
hc->pre_plug = s390_pcihost_pre_plug;
@@ -1506,7 +1506,7 @@ static void s390_pci_device_class_init(ObjectClass *klass, void *data)
dc->desc = "zpci device";
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->reset = s390_pci_device_reset;
+ device_class_set_legacy_reset(dc, s390_pci_device_reset);
dc->bus_type = TYPE_S390_PCI_BUS;
dc->realize = s390_pci_device_realize;
device_class_set_props(dc, s390_pci_device_properties);
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index 3014954..4165508 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -55,26 +55,26 @@ static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc)
uint64_t resume_token;
rc = 0;
- if (lduw_p(&rrb->request.hdr.len) != 32) {
+ if (lduw_be_p(&rrb->request.hdr.len) != 32) {
res_code = CLP_RC_LEN;
rc = -EINVAL;
goto out;
}
- if ((ldl_p(&rrb->request.fmt) & CLP_MASK_FMT) != 0) {
+ if ((ldl_be_p(&rrb->request.fmt) & CLP_MASK_FMT) != 0) {
res_code = CLP_RC_FMT;
rc = -EINVAL;
goto out;
}
- if ((ldl_p(&rrb->request.fmt) & ~CLP_MASK_FMT) != 0 ||
- ldq_p(&rrb->request.reserved1) != 0) {
+ if ((ldl_be_p(&rrb->request.fmt) & ~CLP_MASK_FMT) != 0 ||
+ ldq_be_p(&rrb->request.reserved1) != 0) {
res_code = CLP_RC_RESNOT0;
rc = -EINVAL;
goto out;
}
- resume_token = ldq_p(&rrb->request.resume_token);
+ resume_token = ldq_be_p(&rrb->request.resume_token);
if (resume_token) {
pbdev = s390_pci_find_dev_by_idx(s, resume_token);
@@ -87,13 +87,13 @@ static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc)
pbdev = s390_pci_find_next_avail_dev(s, NULL);
}
- if (lduw_p(&rrb->response.hdr.len) < 48) {
+ if (lduw_be_p(&rrb->response.hdr.len) < 48) {
res_code = CLP_RC_8K;
rc = -EINVAL;
goto out;
}
- initial_l2 = lduw_p(&rrb->response.hdr.len);
+ initial_l2 = lduw_be_p(&rrb->response.hdr.len);
if ((initial_l2 - LIST_PCI_HDR_LEN) % sizeof(ClpFhListEntry)
!= 0) {
res_code = CLP_RC_LEN;
@@ -102,33 +102,33 @@ static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc)
goto out;
}
- stl_p(&rrb->response.fmt, 0);
- stq_p(&rrb->response.reserved1, 0);
- stl_p(&rrb->response.mdd, FH_MASK_SHM);
- stw_p(&rrb->response.max_fn, PCI_MAX_FUNCTIONS);
+ stl_be_p(&rrb->response.fmt, 0);
+ stq_be_p(&rrb->response.reserved1, 0);
+ stl_be_p(&rrb->response.mdd, FH_MASK_SHM);
+ stw_be_p(&rrb->response.max_fn, PCI_MAX_FUNCTIONS);
rrb->response.flags = UID_CHECKING_ENABLED;
rrb->response.entry_size = sizeof(ClpFhListEntry);
i = 0;
g_l2 = LIST_PCI_HDR_LEN;
while (g_l2 < initial_l2 && pbdev) {
- stw_p(&rrb->response.fh_list[i].device_id,
+ stw_be_p(&rrb->response.fh_list[i].device_id,
pci_get_word(pbdev->pdev->config + PCI_DEVICE_ID));
- stw_p(&rrb->response.fh_list[i].vendor_id,
+ stw_be_p(&rrb->response.fh_list[i].vendor_id,
pci_get_word(pbdev->pdev->config + PCI_VENDOR_ID));
/* Ignore RESERVED devices. */
- stl_p(&rrb->response.fh_list[i].config,
+ stl_be_p(&rrb->response.fh_list[i].config,
pbdev->state == ZPCI_FS_STANDBY ? 0 : 1 << 31);
- stl_p(&rrb->response.fh_list[i].fid, pbdev->fid);
- stl_p(&rrb->response.fh_list[i].fh, pbdev->fh);
+ stl_be_p(&rrb->response.fh_list[i].fid, pbdev->fid);
+ stl_be_p(&rrb->response.fh_list[i].fh, pbdev->fh);
g_l2 += sizeof(ClpFhListEntry);
/* Add endian check for DPRINTF? */
trace_s390_pci_list_entry(g_l2,
- lduw_p(&rrb->response.fh_list[i].vendor_id),
- lduw_p(&rrb->response.fh_list[i].device_id),
- ldl_p(&rrb->response.fh_list[i].fid),
- ldl_p(&rrb->response.fh_list[i].fh));
+ lduw_be_p(&rrb->response.fh_list[i].vendor_id),
+ lduw_be_p(&rrb->response.fh_list[i].device_id),
+ ldl_be_p(&rrb->response.fh_list[i].fid),
+ ldl_be_p(&rrb->response.fh_list[i].fh));
pbdev = s390_pci_find_next_avail_dev(s, pbdev);
i++;
}
@@ -138,13 +138,13 @@ static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc)
} else {
resume_token = pbdev->fh & FH_MASK_INDEX;
}
- stq_p(&rrb->response.resume_token, resume_token);
- stw_p(&rrb->response.hdr.len, g_l2);
- stw_p(&rrb->response.hdr.rsp, CLP_RC_OK);
+ stq_be_p(&rrb->response.resume_token, resume_token);
+ stw_be_p(&rrb->response.hdr.len, g_l2);
+ stw_be_p(&rrb->response.hdr.rsp, CLP_RC_OK);
out:
if (rc) {
trace_s390_pci_list(rc);
- stw_p(&rrb->response.hdr.rsp, res_code);
+ stw_be_p(&rrb->response.hdr.rsp, res_code);
}
return rc;
}
@@ -172,7 +172,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
return 0;
}
reqh = (ClpReqHdr *)buffer;
- req_len = lduw_p(&reqh->len);
+ req_len = lduw_be_p(&reqh->len);
if (req_len < 16 || req_len > 8184 || (req_len % 8 != 0)) {
s390_program_interrupt(env, PGM_OPERAND, ra);
return 0;
@@ -184,7 +184,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
return 0;
}
resh = (ClpRspHdr *)(buffer + req_len);
- res_len = lduw_p(&resh->len);
+ res_len = lduw_be_p(&resh->len);
if (res_len < 8 || res_len > 8176 || (res_len % 8 != 0)) {
s390_program_interrupt(env, PGM_OPERAND, ra);
return 0;
@@ -201,11 +201,11 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
}
if (req_len != 32) {
- stw_p(&resh->rsp, CLP_RC_LEN);
+ stw_be_p(&resh->rsp, CLP_RC_LEN);
goto out;
}
- switch (lduw_p(&reqh->cmd)) {
+ switch (lduw_be_p(&reqh->cmd)) {
case CLP_LIST_PCI: {
ClpReqRspListPci *rrb = (ClpReqRspListPci *)buffer;
list_pci(rrb, &cc);
@@ -215,9 +215,9 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
ClpReqSetPci *reqsetpci = (ClpReqSetPci *)reqh;
ClpRspSetPci *ressetpci = (ClpRspSetPci *)resh;
- pbdev = s390_pci_find_dev_by_fh(s, ldl_p(&reqsetpci->fh));
+ pbdev = s390_pci_find_dev_by_fh(s, ldl_be_p(&reqsetpci->fh));
if (!pbdev) {
- stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FH);
+ stw_be_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FH);
goto out;
}
@@ -225,17 +225,17 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
case CLP_SET_ENABLE_PCI_FN:
switch (reqsetpci->ndas) {
case 0:
- stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_DMAAS);
+ stw_be_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_DMAAS);
goto out;
case 1:
break;
default:
- stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_RES);
+ stw_be_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_RES);
goto out;
}
if (pbdev->fh & FH_MASK_ENABLE) {
- stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP);
+ stw_be_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP);
goto out;
}
@@ -249,29 +249,29 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
/* Take this opportunity to make sure we are sync'd with host */
if (!s390_pci_get_host_fh(pbdev, &pbdev->fh) ||
!(pbdev->fh & FH_MASK_ENABLE)) {
- stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FH);
+ stw_be_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FH);
goto out;
}
}
pbdev->fh |= FH_MASK_ENABLE;
pbdev->state = ZPCI_FS_ENABLED;
- stl_p(&ressetpci->fh, pbdev->fh);
- stw_p(&ressetpci->hdr.rsp, CLP_RC_OK);
+ stl_be_p(&ressetpci->fh, pbdev->fh);
+ stw_be_p(&ressetpci->hdr.rsp, CLP_RC_OK);
break;
case CLP_SET_DISABLE_PCI_FN:
if (!(pbdev->fh & FH_MASK_ENABLE)) {
- stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP);
+ stw_be_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP);
goto out;
}
device_cold_reset(DEVICE(pbdev));
pbdev->fh &= ~FH_MASK_ENABLE;
pbdev->state = ZPCI_FS_DISABLED;
- stl_p(&ressetpci->fh, pbdev->fh);
- stw_p(&ressetpci->hdr.rsp, CLP_RC_OK);
+ stl_be_p(&ressetpci->fh, pbdev->fh);
+ stw_be_p(&ressetpci->hdr.rsp, CLP_RC_OK);
break;
default:
trace_s390_pci_unknown("set-pci", reqsetpci->oc);
- stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP);
+ stw_be_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP);
break;
}
break;
@@ -280,23 +280,23 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
ClpReqQueryPci *reqquery = (ClpReqQueryPci *)reqh;
ClpRspQueryPci *resquery = (ClpRspQueryPci *)resh;
- pbdev = s390_pci_find_dev_by_fh(s, ldl_p(&reqquery->fh));
+ pbdev = s390_pci_find_dev_by_fh(s, ldl_be_p(&reqquery->fh));
if (!pbdev) {
- trace_s390_pci_nodev("query", ldl_p(&reqquery->fh));
- stw_p(&resquery->hdr.rsp, CLP_RC_SETPCIFN_FH);
+ trace_s390_pci_nodev("query", ldl_be_p(&reqquery->fh));
+ stw_be_p(&resquery->hdr.rsp, CLP_RC_SETPCIFN_FH);
goto out;
}
- stq_p(&resquery->sdma, pbdev->zpci_fn.sdma);
- stq_p(&resquery->edma, pbdev->zpci_fn.edma);
- stw_p(&resquery->pchid, pbdev->zpci_fn.pchid);
- stw_p(&resquery->vfn, pbdev->zpci_fn.vfn);
+ stq_be_p(&resquery->sdma, pbdev->zpci_fn.sdma);
+ stq_be_p(&resquery->edma, pbdev->zpci_fn.edma);
+ stw_be_p(&resquery->pchid, pbdev->zpci_fn.pchid);
+ stw_be_p(&resquery->vfn, pbdev->zpci_fn.vfn);
resquery->flags = pbdev->zpci_fn.flags;
resquery->pfgid = pbdev->zpci_fn.pfgid;
resquery->pft = pbdev->zpci_fn.pft;
resquery->fmbl = pbdev->zpci_fn.fmbl;
- stl_p(&resquery->fid, pbdev->zpci_fn.fid);
- stl_p(&resquery->uid, pbdev->zpci_fn.uid);
+ stl_be_p(&resquery->fid, pbdev->zpci_fn.fid);
+ stl_be_p(&resquery->uid, pbdev->zpci_fn.uid);
memcpy(resquery->pfip, pbdev->zpci_fn.pfip, CLP_PFIP_NR_SEGMENTS);
memcpy(resquery->util_str, pbdev->zpci_fn.util_str, CLP_UTIL_STR_LEN);
@@ -304,16 +304,16 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
uint32_t data = pci_get_long(pbdev->pdev->config +
PCI_BASE_ADDRESS_0 + (i * 4));
- stl_p(&resquery->bar[i], data);
+ stl_be_p(&resquery->bar[i], data);
resquery->bar_size[i] = pbdev->pdev->io_regions[i].size ?
ctz64(pbdev->pdev->io_regions[i].size) : 0;
trace_s390_pci_bar(i,
- ldl_p(&resquery->bar[i]),
+ ldl_be_p(&resquery->bar[i]),
pbdev->pdev->io_regions[i].size,
resquery->bar_size[i]);
}
- stw_p(&resquery->hdr.rsp, CLP_RC_OK);
+ stw_be_p(&resquery->hdr.rsp, CLP_RC_OK);
break;
}
case CLP_QUERY_PCI_FNGRP: {
@@ -326,23 +326,23 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
if (!group) {
/* We do not allow access to unknown groups */
/* The group must have been obtained with a vfio device */
- stw_p(&resgrp->hdr.rsp, CLP_RC_QUERYPCIFG_PFGID);
+ stw_be_p(&resgrp->hdr.rsp, CLP_RC_QUERYPCIFG_PFGID);
goto out;
}
resgrp->fr = group->zpci_group.fr;
- stq_p(&resgrp->dasm, group->zpci_group.dasm);
- stq_p(&resgrp->msia, group->zpci_group.msia);
- stw_p(&resgrp->mui, group->zpci_group.mui);
- stw_p(&resgrp->i, group->zpci_group.i);
- stw_p(&resgrp->maxstbl, group->zpci_group.maxstbl);
+ stq_be_p(&resgrp->dasm, group->zpci_group.dasm);
+ stq_be_p(&resgrp->msia, group->zpci_group.msia);
+ stw_be_p(&resgrp->mui, group->zpci_group.mui);
+ stw_be_p(&resgrp->i, group->zpci_group.i);
+ stw_be_p(&resgrp->maxstbl, group->zpci_group.maxstbl);
resgrp->version = group->zpci_group.version;
resgrp->dtsm = group->zpci_group.dtsm;
- stw_p(&resgrp->hdr.rsp, CLP_RC_OK);
+ stw_be_p(&resgrp->hdr.rsp, CLP_RC_OK);
break;
}
default:
- trace_s390_pci_unknown("clp", lduw_p(&reqh->cmd));
- stw_p(&resh->rsp, CLP_RC_CMD);
+ trace_s390_pci_unknown("clp", lduw_be_p(&reqh->cmd));
+ stw_be_p(&resh->rsp, CLP_RC_CMD);
break;
}
@@ -914,7 +914,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
for (i = 0; i < len / 8; i++) {
result = memory_region_dispatch_write(mr, offset + i * 8,
- ldq_p(buffer + i * 8),
+ ldq_be_p(buffer + i * 8),
MO_64, MEMTXATTRS_UNSPECIFIED);
if (result != MEMTX_OK) {
s390_program_interrupt(env, PGM_OPERAND, ra);
@@ -935,13 +935,13 @@ specification_error:
static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
{
int ret, len;
- uint8_t isc = FIB_DATA_ISC(ldl_p(&fib.data));
+ uint8_t isc = FIB_DATA_ISC(ldl_be_p(&fib.data));
pbdev->routes.adapter.adapter_id = css_get_adapter_id(
CSS_IO_ADAPTER_PCI, isc);
- pbdev->summary_ind = get_indicator(ldq_p(&fib.aisb), sizeof(uint64_t));
- len = BITS_TO_LONGS(FIB_DATA_NOI(ldl_p(&fib.data))) * sizeof(unsigned long);
- pbdev->indicator = get_indicator(ldq_p(&fib.aibv), len);
+ pbdev->summary_ind = get_indicator(ldq_be_p(&fib.aisb), sizeof(uint64_t));
+ len = BITS_TO_LONGS(FIB_DATA_NOI(ldl_be_p(&fib.data))) * sizeof(unsigned long);
+ pbdev->indicator = get_indicator(ldq_be_p(&fib.aibv), len);
ret = map_indicator(&pbdev->routes.adapter, pbdev->summary_ind);
if (ret) {
@@ -953,13 +953,13 @@ static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
goto out;
}
- pbdev->routes.adapter.summary_addr = ldq_p(&fib.aisb);
- pbdev->routes.adapter.summary_offset = FIB_DATA_AISBO(ldl_p(&fib.data));
- pbdev->routes.adapter.ind_addr = ldq_p(&fib.aibv);
- pbdev->routes.adapter.ind_offset = FIB_DATA_AIBVO(ldl_p(&fib.data));
+ pbdev->routes.adapter.summary_addr = ldq_be_p(&fib.aisb);
+ pbdev->routes.adapter.summary_offset = FIB_DATA_AISBO(ldl_be_p(&fib.data));
+ pbdev->routes.adapter.ind_addr = ldq_be_p(&fib.aibv);
+ pbdev->routes.adapter.ind_offset = FIB_DATA_AIBVO(ldl_be_p(&fib.data));
pbdev->isc = isc;
- pbdev->noi = FIB_DATA_NOI(ldl_p(&fib.data));
- pbdev->sum = FIB_DATA_SUM(ldl_p(&fib.data));
+ pbdev->noi = FIB_DATA_NOI(ldl_be_p(&fib.data));
+ pbdev->sum = FIB_DATA_SUM(ldl_be_p(&fib.data));
trace_s390_pci_irqs("register", pbdev->routes.adapter.adapter_id);
return 0;
@@ -994,9 +994,9 @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib,
uintptr_t ra)
{
S390PCIIOMMU *iommu = pbdev->iommu;
- uint64_t pba = ldq_p(&fib.pba);
- uint64_t pal = ldq_p(&fib.pal);
- uint64_t g_iota = ldq_p(&fib.iota);
+ uint64_t pba = ldq_be_p(&fib.pba);
+ uint64_t pal = ldq_be_p(&fib.pal);
+ uint64_t g_iota = ldq_be_p(&fib.iota);
uint8_t dt = (g_iota >> 2) & 0x7;
uint8_t t = (g_iota >> 11) & 0x1;
@@ -1289,7 +1289,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
}
break;
case ZPCI_MOD_FC_SET_MEASURE: {
- uint64_t fmb_addr = ldq_p(&fib.fmb_addr);
+ uint64_t fmb_addr = ldq_be_p(&fib.fmb_addr);
if (fmb_addr & FMBK_MASK) {
cc = ZPCI_PCI_LS_ERR;
@@ -1399,17 +1399,17 @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
return 0;
}
- stq_p(&fib.pba, pbdev->iommu->pba);
- stq_p(&fib.pal, pbdev->iommu->pal);
- stq_p(&fib.iota, pbdev->iommu->g_iota);
- stq_p(&fib.aibv, pbdev->routes.adapter.ind_addr);
- stq_p(&fib.aisb, pbdev->routes.adapter.summary_addr);
- stq_p(&fib.fmb_addr, pbdev->fmb_addr);
+ stq_be_p(&fib.pba, pbdev->iommu->pba);
+ stq_be_p(&fib.pal, pbdev->iommu->pal);
+ stq_be_p(&fib.iota, pbdev->iommu->g_iota);
+ stq_be_p(&fib.aibv, pbdev->routes.adapter.ind_addr);
+ stq_be_p(&fib.aisb, pbdev->routes.adapter.summary_addr);
+ stq_be_p(&fib.fmb_addr, pbdev->fmb_addr);
data = ((uint32_t)pbdev->isc << 28) | ((uint32_t)pbdev->noi << 16) |
((uint32_t)pbdev->routes.adapter.ind_offset << 8) |
((uint32_t)pbdev->sum << 7) | pbdev->routes.adapter.summary_offset;
- stl_p(&fib.data, data);
+ stl_be_p(&fib.data, data);
out:
if (s390_cpu_virt_mem_write(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) {
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index c483ff8..fe03f71 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -197,11 +197,10 @@ static void s390_memory_init(MemoryRegion *ram)
static void s390_init_ipl_dev(const char *kernel_filename,
const char *kernel_cmdline,
const char *initrd_filename, const char *firmware,
- const char *netboot_fw, bool enforce_bios)
+ bool enforce_bios)
{
Object *new = object_new(TYPE_S390_IPL);
DeviceState *dev = DEVICE(new);
- char *netboot_fw_prop;
if (kernel_filename) {
qdev_prop_set_string(dev, "kernel", kernel_filename);
@@ -212,11 +211,6 @@ static void s390_init_ipl_dev(const char *kernel_filename,
qdev_prop_set_string(dev, "cmdline", kernel_cmdline);
qdev_prop_set_string(dev, "firmware", firmware);
qdev_prop_set_bit(dev, "enforce_bios", enforce_bios);
- netboot_fw_prop = object_property_get_str(new, "netboot_fw", &error_abort);
- if (!strlen(netboot_fw_prop)) {
- qdev_prop_set_string(dev, "netboot_fw", netboot_fw);
- }
- g_free(netboot_fw_prop);
object_property_add_child(qdev_get_machine(), TYPE_S390_IPL,
new);
object_unref(new);
@@ -284,7 +278,7 @@ static void ccw_init(MachineState *machine)
s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline,
machine->initrd_filename,
machine->firmware ?: "s390-ccw.img",
- "s390-netboot.img", true);
+ true);
dev = qdev_new(TYPE_S390_PCI_HOST_BRIDGE);
object_property_add_child(qdev_get_machine(), TYPE_S390_PCI_HOST_BRIDGE,
@@ -440,7 +434,7 @@ static void s390_pv_prepare_reset(S390CcwMachineState *ms)
s390_pv_prep_reset();
}
-static void s390_machine_reset(MachineState *machine, ShutdownCause reason)
+static void s390_machine_reset(MachineState *machine, ResetType type)
{
S390CcwMachineState *ms = S390_CCW_MACHINE(machine);
enum s390_reset reset_type;
@@ -472,7 +466,7 @@ static void s390_machine_reset(MachineState *machine, ShutdownCause reason)
* Device reset includes CPU clear resets so this has to be
* done AFTER the unprotect call above.
*/
- qemu_devices_reset(reason);
+ qemu_devices_reset(type);
s390_crypto_reset();
/* configure and start the ipl CPU only */
@@ -728,28 +722,12 @@ static void machine_set_loadparm(Object *obj, Visitor *v,
{
S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
char *val;
- int i;
if (!visit_type_str(v, name, &val, errp)) {
return;
}
- for (i = 0; i < sizeof(ms->loadparm) && val[i]; i++) {
- uint8_t c = qemu_toupper(val[i]); /* mimic HMC */
-
- if (('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || (c == '.') ||
- (c == ' ')) {
- ms->loadparm[i] = c;
- } else {
- error_setg(errp, "LOADPARM: invalid character '%c' (ASCII 0x%02x)",
- c, c);
- return;
- }
- }
-
- for (; i < sizeof(ms->loadparm); i++) {
- ms->loadparm[i] = ' '; /* pad right with spaces */
- }
+ s390_ipl_fmt_loadparm(ms->loadparm, val, errp);
}
static void ccw_machine_class_init(ObjectClass *oc, void *data)
@@ -871,14 +849,26 @@ static const TypeInfo ccw_machine_info = {
DEFINE_CCW_MACHINE_IMPL(false, major, minor)
+static void ccw_machine_9_2_instance_options(MachineState *machine)
+{
+}
+
+static void ccw_machine_9_2_class_options(MachineClass *mc)
+{
+}
+DEFINE_CCW_MACHINE_AS_LATEST(9, 2);
+
static void ccw_machine_9_1_instance_options(MachineState *machine)
{
+ ccw_machine_9_2_instance_options(machine);
}
static void ccw_machine_9_1_class_options(MachineClass *mc)
{
+ ccw_machine_9_2_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_9_1, hw_compat_9_1_len);
}
-DEFINE_CCW_MACHINE_AS_LATEST(9, 1);
+DEFINE_CCW_MACHINE(9, 1);
static void ccw_machine_9_0_instance_options(MachineState *machine)
{
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
index e725dcd..8757626 100644
--- a/hw/s390x/sclp.c
+++ b/hw/s390x/sclp.c
@@ -110,7 +110,6 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
MachineState *machine = MACHINE(qdev_get_machine());
int cpu_count;
int rnsize, rnmax;
- IplParameterBlock *ipib = s390_ipl_get_iplb();
int required_len = SCCB_REQ_LEN(ReadInfo, machine->possible_cpus->len);
int offset_cpu = s390_has_feat(S390_FEAT_EXTENDED_LENGTH_SCCB) ?
offsetof(ReadInfo, entries) :
@@ -171,12 +170,8 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
read_info->rnmax2 = cpu_to_be64(rnmax);
}
- if (ipib && ipib->flags & DIAG308_FLAGS_LP_VALID) {
- memcpy(&read_info->loadparm, &ipib->loadparm,
- sizeof(read_info->loadparm));
- } else {
- s390_ipl_set_loadparm(read_info->loadparm);
- }
+ s390_ipl_convert_loadparm((char *)S390_CCW_MACHINE(machine)->loadparm,
+ read_info->loadparm);
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
}
diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c
index 14936aa..a32d6a9 100644
--- a/hw/s390x/sclpquiesce.c
+++ b/hw/s390x/sclpquiesce.c
@@ -117,7 +117,7 @@ static void quiesce_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
SCLPEventClass *k = SCLP_EVENT_CLASS(klass);
- dc->reset = quiesce_reset;
+ device_class_set_legacy_reset(dc, quiesce_reset);
dc->vmsd = &vmstate_sclpquiesce;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
/*
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index b467690..9674731 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -913,14 +913,15 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
}
}
-static void virtio_ccw_reset(DeviceState *d)
+static void virtio_ccw_reset_hold(Object *obj, ResetType type)
{
- VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
+ VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(obj);
VirtIOCCWDeviceClass *vdc = VIRTIO_CCW_DEVICE_GET_CLASS(dev);
virtio_ccw_reset_virtio(dev);
- if (vdc->parent_reset) {
- vdc->parent_reset(d);
+
+ if (vdc->parent_phases.hold) {
+ vdc->parent_phases.hold(obj, type);
}
}
@@ -1233,11 +1234,13 @@ static void virtio_ccw_device_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
CCWDeviceClass *k = CCW_DEVICE_CLASS(dc);
VirtIOCCWDeviceClass *vdc = VIRTIO_CCW_DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
k->unplug = virtio_ccw_busdev_unplug;
dc->realize = virtio_ccw_busdev_realize;
dc->unrealize = virtio_ccw_busdev_unrealize;
- device_class_set_parent_reset(dc, virtio_ccw_reset, &vdc->parent_reset);
+ resettable_class_set_parent_phases(rc, NULL, virtio_ccw_reset_hold, NULL,
+ &vdc->parent_phases);
}
static const TypeInfo virtio_ccw_device_info = {
diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h
index fac186c..c7a830a 100644
--- a/hw/s390x/virtio-ccw.h
+++ b/hw/s390x/virtio-ccw.h
@@ -57,7 +57,7 @@ struct VirtIOCCWDeviceClass {
CCWDeviceClass parent_class;
void (*realize)(VirtioCcwDevice *dev, Error **errp);
void (*unrealize)(VirtioCcwDevice *dev);
- void (*parent_reset)(DeviceState *dev);
+ ResettablePhases parent_phases;
};
/* Performance improves when virtqueue kick processing is decoupled from the
diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c
index 42d9d2e..fe4e045 100644
--- a/hw/scsi/esp-pci.c
+++ b/hw/scsi/esp-pci.c
@@ -440,7 +440,7 @@ static void esp_pci_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_STORAGE_SCSI;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
dc->desc = "AMD Am53c974 PCscsi-PCI SCSI adapter";
- dc->reset = esp_pci_hard_reset;
+ device_class_set_legacy_reset(dc, esp_pci_hard_reset);
dc->vmsd = &vmstate_esp_pci_scsi;
}
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 8504dd3..ac841dc 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -197,39 +197,9 @@ static uint8_t esp_fifo_pop(ESPState *s)
return val;
}
-static uint32_t esp_fifo8_pop_buf(Fifo8 *fifo, uint8_t *dest, int maxlen)
-{
- const uint8_t *buf;
- uint32_t n, n2;
- int len;
-
- if (maxlen == 0) {
- return 0;
- }
-
- len = maxlen;
- buf = fifo8_pop_buf(fifo, len, &n);
- if (dest) {
- memcpy(dest, buf, n);
- }
-
- /* Add FIFO wraparound if needed */
- len -= n;
- len = MIN(len, fifo8_num_used(fifo));
- if (len) {
- buf = fifo8_pop_buf(fifo, len, &n2);
- if (dest) {
- memcpy(&dest[n], buf, n2);
- }
- n += n2;
- }
-
- return n;
-}
-
static uint32_t esp_fifo_pop_buf(ESPState *s, uint8_t *dest, int maxlen)
{
- uint32_t len = esp_fifo8_pop_buf(&s->fifo, dest, maxlen);
+ uint32_t len = fifo8_pop_buf(&s->fifo, dest, maxlen);
esp_update_drq(s);
return len;
@@ -335,7 +305,7 @@ static void do_command_phase(ESPState *s)
if (!cmdlen || !s->current_dev) {
return;
}
- esp_fifo8_pop_buf(&s->cmdfifo, buf, cmdlen);
+ fifo8_pop_buf(&s->cmdfifo, buf, cmdlen);
current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, s->lun);
if (!current_lun) {
@@ -381,7 +351,7 @@ static void do_message_phase(ESPState *s)
/* Ignore extended messages for now */
if (s->cmdfifo_cdb_offset) {
int len = MIN(s->cmdfifo_cdb_offset, fifo8_num_used(&s->cmdfifo));
- esp_fifo8_pop_buf(&s->cmdfifo, NULL, len);
+ fifo8_drop(&s->cmdfifo, len);
s->cmdfifo_cdb_offset = 0;
}
}
@@ -486,7 +456,7 @@ static bool esp_cdb_ready(ESPState *s)
return false;
}
- pbuf = fifo8_peek_buf(&s->cmdfifo, len, &n);
+ pbuf = fifo8_peek_bufptr(&s->cmdfifo, len, &n);
if (n < len) {
/*
* In normal use the cmdfifo should never wrap, but include this check
@@ -1606,7 +1576,7 @@ static void sysbus_esp_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = sysbus_esp_realize;
- dc->reset = sysbus_esp_hard_reset;
+ device_class_set_legacy_reset(dc, sysbus_esp_hard_reset);
dc->vmsd = &vmstate_sysbus_esp_scsi;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
}
diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c
index f1935e5..1f72841 100644
--- a/hw/scsi/lsi53c895a.c
+++ b/hw/scsi/lsi53c895a.c
@@ -2386,7 +2386,7 @@ static void lsi_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_LSI_53C895A;
k->class_id = PCI_CLASS_STORAGE_SCSI;
k->subsystem_id = 0x1000;
- dc->reset = lsi_scsi_reset;
+ device_class_set_legacy_reset(dc, lsi_scsi_reset);
dc->vmsd = &vmstate_lsi_scsi;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
}
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index 2d0c607..221b06d 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -2557,7 +2557,7 @@ static void megasas_class_init(ObjectClass *oc, void *data)
e->product_name = info->product_name;
e->product_version = info->product_version;
device_class_set_props(dc, info->props);
- dc->reset = megasas_scsi_reset;
+ device_class_set_legacy_reset(dc, megasas_scsi_reset);
dc->vmsd = info->vmsd;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
dc->desc = info->desc;
diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c
index c5d3138..361b75e 100644
--- a/hw/scsi/mptsas.c
+++ b/hw/scsi/mptsas.c
@@ -1431,7 +1431,7 @@ static void mptsas1068_class_init(ObjectClass *oc, void *data)
pc->subsystem_id = 0x8000;
pc->class_id = PCI_CLASS_STORAGE_SCSI;
device_class_set_props(dc, mptsas_properties);
- dc->reset = mptsas_reset;
+ device_class_set_legacy_reset(dc, mptsas_reset);
dc->vmsd = &vmstate_mptsas;
dc->desc = "LSI SAS 1068";
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index a67092d..cb222da 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -65,6 +65,13 @@ OBJECT_DECLARE_TYPE(SCSIDiskState, SCSIDiskClass, SCSI_DISK_BASE)
struct SCSIDiskClass {
SCSIDeviceClass parent_class;
+ /*
+ * Callbacks receive ret == 0 for success. Errors are represented either as
+ * negative errno values, or as positive SAM status codes.
+ *
+ * Beware: For errors returned in host_status, the function may directly
+ * complete the request and never call the callback.
+ */
DMAIOFunc *dma_readv;
DMAIOFunc *dma_writev;
bool (*need_fua_emulation)(SCSICommand *cmd);
@@ -217,7 +224,7 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int ret, bool acct_failed)
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s));
SCSISense sense = SENSE_CODE(NO_SENSE);
- int error = 0;
+ int error;
bool req_has_sense = false;
BlockErrorAction action;
int status;
@@ -228,11 +235,35 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int ret, bool acct_failed)
} else {
/* A passthrough command has completed with nonzero status. */
status = ret;
- if (status == CHECK_CONDITION) {
+ switch (status) {
+ case CHECK_CONDITION:
req_has_sense = true;
error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense));
- } else {
+ break;
+ case RESERVATION_CONFLICT:
+ /*
+ * Don't apply the error policy, always report to the guest.
+ *
+ * This is a passthrough code path, so it's not a backend error, but
+ * a response to an invalid guest request.
+ *
+ * Windows Failover Cluster validation intentionally sends invalid
+ * requests to verify that reservations work as intended. It is
+ * crucial that it sees the resulting errors.
+ *
+ * Treating a reservation conflict as a guest-side error is obvious
+ * when a pr-manager is in use. Without one, the situation is less
+ * clear, but there might be nothing that can be fixed on the host
+ * (like in the above example), and we don't want to be stuck in a
+ * loop where resuming the VM and retrying the request immediately
+ * stops it again. So always reporting is still the safer option in
+ * this case, too.
+ */
+ error = 0;
+ break;
+ default:
error = EINVAL;
+ break;
}
}
@@ -242,8 +273,9 @@ static bool scsi_handle_rw_error(SCSIDiskReq *r, int ret, bool acct_failed)
* are usually retried immediately, so do not post them to QMP and
* do not account them as failed I/O.
*/
- if (req_has_sense &&
- scsi_sense_buf_is_guest_recoverable(r->req.sense, sizeof(r->req.sense))) {
+ if (!error || (req_has_sense &&
+ scsi_sense_buf_is_guest_recoverable(r->req.sense,
+ sizeof(r->req.sense)))) {
action = BLOCK_ERROR_ACTION_REPORT;
acct_failed = false;
} else {
@@ -283,7 +315,7 @@ static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed)
return true;
}
- if (ret < 0) {
+ if (ret != 0) {
return scsi_handle_rw_error(r, ret, acct_failed);
}
@@ -360,7 +392,7 @@ static void scsi_write_do_fua(SCSIDiskReq *r)
static void scsi_dma_complete_noio(SCSIDiskReq *r, int ret)
{
assert(r->req.aiocb == NULL);
- if (scsi_disk_req_check_error(r, ret, false)) {
+ if (scsi_disk_req_check_error(r, ret, ret > 0)) {
goto done;
}
@@ -377,6 +409,7 @@ done:
scsi_req_unref(&r->req);
}
+/* May not be called in all error cases, don't rely on cleanup here */
static void scsi_dma_complete(void *opaque, int ret)
{
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
@@ -385,9 +418,10 @@ static void scsi_dma_complete(void *opaque, int ret)
assert(r->req.aiocb != NULL);
r->req.aiocb = NULL;
+ /* ret > 0 is accounted for in scsi_disk_req_check_error() */
if (ret < 0) {
block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
- } else {
+ } else if (ret == 0) {
block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
}
scsi_dma_complete_noio(r, ret);
@@ -403,7 +437,7 @@ static void scsi_read_complete_noio(SCSIDiskReq *r, int ret)
qemu_get_current_aio_context());
assert(r->req.aiocb == NULL);
- if (scsi_disk_req_check_error(r, ret, false)) {
+ if (scsi_disk_req_check_error(r, ret, ret > 0)) {
goto done;
}
@@ -416,6 +450,7 @@ done:
scsi_req_unref(&r->req);
}
+/* May not be called in all error cases, don't rely on cleanup here */
static void scsi_read_complete(void *opaque, int ret)
{
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
@@ -424,9 +459,10 @@ static void scsi_read_complete(void *opaque, int ret)
assert(r->req.aiocb != NULL);
r->req.aiocb = NULL;
+ /* ret > 0 is accounted for in scsi_disk_req_check_error() */
if (ret < 0) {
block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
- } else {
+ } else if (ret == 0) {
block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
trace_scsi_disk_read_complete(r->req.tag, r->qiov.size);
}
@@ -534,7 +570,7 @@ static void scsi_write_complete_noio(SCSIDiskReq *r, int ret)
qemu_get_current_aio_context());
assert (r->req.aiocb == NULL);
- if (scsi_disk_req_check_error(r, ret, false)) {
+ if (scsi_disk_req_check_error(r, ret, ret > 0)) {
goto done;
}
@@ -554,6 +590,7 @@ done:
scsi_req_unref(&r->req);
}
+/* May not be called in all error cases, don't rely on cleanup here */
static void scsi_write_complete(void * opaque, int ret)
{
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
@@ -562,9 +599,10 @@ static void scsi_write_complete(void * opaque, int ret)
assert (r->req.aiocb != NULL);
r->req.aiocb = NULL;
+ /* ret > 0 is accounted for in scsi_disk_req_check_error() */
if (ret < 0) {
block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
- } else {
+ } else if (ret == 0) {
block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
}
scsi_write_complete_noio(r, ret);
@@ -2814,6 +2852,7 @@ static void scsi_block_sgio_complete(void *opaque, int ret)
sg_io_hdr_t *io_hdr = &req->io_header;
if (ret == 0) {
+ /* FIXME This skips calling req->cb() and any cleanup in it */
if (io_hdr->host_status != SCSI_HOST_OK) {
scsi_req_complete_failed(&r->req, io_hdr->host_status);
scsi_req_unref(&r->req);
@@ -2825,16 +2864,6 @@ static void scsi_block_sgio_complete(void *opaque, int ret)
} else {
ret = io_hdr->status;
}
-
- if (ret > 0) {
- if (scsi_handle_rw_error(r, ret, true)) {
- scsi_req_unref(&r->req);
- return;
- }
-
- /* Ignore error. */
- ret = 0;
- }
}
req->cb(req->cb_opaque, ret);
@@ -3112,7 +3141,7 @@ static void scsi_disk_base_class_initfn(ObjectClass *klass, void *data)
SCSIDiskClass *sdc = SCSI_DISK_BASE_CLASS(klass);
dc->fw_name = "disk";
- dc->reset = scsi_disk_reset;
+ device_class_set_legacy_reset(dc, scsi_disk_reset);
sdc->dma_readv = scsi_dma_readv;
sdc->dma_writev = scsi_dma_writev;
sdc->need_fua_emulation = scsi_is_cmd_fua;
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index ee945f8..76f04a5 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -797,7 +797,7 @@ static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
sc->parse_cdb = scsi_generic_parse_cdb;
dc->fw_name = "disk";
dc->desc = "pass through generic scsi device (/dev/sg*)";
- dc->reset = scsi_generic_reset;
+ device_class_set_legacy_reset(dc, scsi_generic_reset);
device_class_set_props(dc, scsi_generic_properties);
dc->vmsd = &vmstate_scsi_device;
}
diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c
index 3d5fe09..22d16dc 100644
--- a/hw/scsi/vhost-scsi.c
+++ b/hw/scsi/vhost-scsi.c
@@ -38,6 +38,7 @@ static const int kernel_feature_bits[] = {
VIRTIO_RING_F_EVENT_IDX,
VIRTIO_SCSI_F_HOTPLUG,
VIRTIO_F_RING_RESET,
+ VIRTIO_F_IN_ORDER,
VIRTIO_F_NOTIFICATION_DATA,
VHOST_INVALID_FEATURE_BIT
};
@@ -171,7 +172,7 @@ static int vhost_scsi_set_workers(VHostSCSICommon *vsc, bool per_virtqueue)
struct vhost_dev *dev = &vsc->dev;
struct vhost_vring_worker vq_worker;
struct vhost_worker_state worker;
- int i, ret;
+ int i, ret = 0;
/* Use default worker */
if (!per_virtqueue || dev->nvqs == VHOST_SCSI_VQ_NUM_FIXED + 1) {
diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c
index cc91ade..55e4be5 100644
--- a/hw/scsi/vhost-user-scsi.c
+++ b/hw/scsi/vhost-user-scsi.c
@@ -36,6 +36,7 @@ static const int user_feature_bits[] = {
VIRTIO_RING_F_EVENT_IDX,
VIRTIO_SCSI_F_HOTPLUG,
VIRTIO_F_RING_RESET,
+ VIRTIO_F_IN_ORDER,
VIRTIO_F_NOTIFICATION_DATA,
VHOST_INVALID_FEATURE_BIT
};
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 9f02cee..6637cfe 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -357,7 +357,6 @@ static void virtio_scsi_do_one_tmf_bh(VirtIOSCSIReq *req)
default:
g_assert_not_reached();
- break;
}
out:
diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c
index cd7bf6a..57761b5 100644
--- a/hw/scsi/vmw_pvscsi.c
+++ b/hw/scsi/vmw_pvscsi.c
@@ -1333,7 +1333,7 @@ static void pvscsi_class_init(ObjectClass *klass, void *data)
k->subsystem_id = 0x1000;
device_class_set_parent_realize(dc, pvscsi_realize,
&pvs_k->parent_dc_realize);
- dc->reset = pvscsi_reset;
+ device_class_set_legacy_reset(dc, pvscsi_reset);
dc->vmsd = &vmstate_pvscsi;
device_class_set_props(dc, pvscsi_properties);
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
diff --git a/hw/sd/allwinner-sdhost.c b/hw/sd/allwinner-sdhost.c
index a1b7230..bcfb4c1 100644
--- a/hw/sd/allwinner-sdhost.c
+++ b/hw/sd/allwinner-sdhost.c
@@ -900,7 +900,7 @@ static void allwinner_sdhost_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = allwinner_sdhost_reset;
+ device_class_set_legacy_reset(dc, allwinner_sdhost_reset);
dc->vmsd = &vmstate_allwinner_sdhost;
dc->realize = allwinner_sdhost_realize;
device_class_set_props(dc, allwinner_sdhost_properties);
diff --git a/hw/sd/aspeed_sdhci.c b/hw/sd/aspeed_sdhci.c
index 3b63926..427e533 100644
--- a/hw/sd/aspeed_sdhci.c
+++ b/hw/sd/aspeed_sdhci.c
@@ -193,7 +193,7 @@ static void aspeed_sdhci_class_init(ObjectClass *classp, void *data)
DeviceClass *dc = DEVICE_CLASS(classp);
dc->realize = aspeed_sdhci_realize;
- dc->reset = aspeed_sdhci_reset;
+ device_class_set_legacy_reset(dc, aspeed_sdhci_reset);
dc->vmsd = &vmstate_aspeed_sdhci;
device_class_set_props(dc, aspeed_sdhci_properties);
}
diff --git a/hw/sd/bcm2835_sdhost.c b/hw/sd/bcm2835_sdhost.c
index 11c54dd..4e411ff 100644
--- a/hw/sd/bcm2835_sdhost.c
+++ b/hw/sd/bcm2835_sdhost.c
@@ -432,7 +432,7 @@ static void bcm2835_sdhost_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = bcm2835_sdhost_reset;
+ device_class_set_legacy_reset(dc, bcm2835_sdhost_reset);
dc->vmsd = &vmstate_bcm2835_sdhost;
}
diff --git a/hw/sd/cadence_sdhci.c b/hw/sd/cadence_sdhci.c
index 7c8bc54..ad9daa2 100644
--- a/hw/sd/cadence_sdhci.c
+++ b/hw/sd/cadence_sdhci.c
@@ -171,7 +171,7 @@ static void cadence_sdhci_class_init(ObjectClass *classp, void *data)
dc->desc = "Cadence SD/SDIO/eMMC Host Controller (SD4HC)";
dc->realize = cadence_sdhci_realize;
- dc->reset = cadence_sdhci_reset;
+ device_class_set_legacy_reset(dc, cadence_sdhci_reset);
dc->vmsd = &vmstate_cadence_sdhci;
}
diff --git a/hw/sd/meson.build b/hw/sd/meson.build
index bbb75af..b43d45b 100644
--- a/hw/sd/meson.build
+++ b/hw/sd/meson.build
@@ -5,7 +5,6 @@ system_ss.add(when: 'CONFIG_SDHCI_PCI', if_true: files('sdhci-pci.c'))
system_ss.add(when: 'CONFIG_SSI_SD', if_true: files('ssi-sd.c'))
system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_mmc.c'))
-system_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_mmci.c'))
system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_sdhost.c'))
system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_sdhci.c'))
system_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-sdhost.c'))
diff --git a/hw/sd/npcm7xx_sdhci.c b/hw/sd/npcm7xx_sdhci.c
index fb51821..99028c1 100644
--- a/hw/sd/npcm7xx_sdhci.c
+++ b/hw/sd/npcm7xx_sdhci.c
@@ -155,7 +155,7 @@ static void npcm7xx_sdhci_class_init(ObjectClass *classp, void *data)
dc->desc = "NPCM7xx SD/eMMC Host Controller";
dc->realize = npcm7xx_sdhci_realize;
- dc->reset = npcm7xx_sdhci_reset;
+ device_class_set_legacy_reset(dc, npcm7xx_sdhci_reset);
dc->vmsd = &vmstate_npcm7xx_sdhci;
}
diff --git a/hw/sd/omap_mmc.c b/hw/sd/omap_mmc.c
index edd3cf2..91e9a3f 100644
--- a/hw/sd/omap_mmc.c
+++ b/hw/sd/omap_mmc.c
@@ -573,24 +573,6 @@ static const MemoryRegionOps omap_mmc_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static void omap_mmc_cover_cb(void *opaque, int line, int level)
-{
- struct omap_mmc_s *host = opaque;
-
- if (!host->cdet_state && level) {
- host->status |= 0x0002;
- omap_mmc_interrupts_update(host);
- if (host->cdet_wakeup) {
- /* TODO: Assert wake-up */
- }
- }
-
- if (host->cdet_state != level) {
- qemu_set_irq(host->coverswitch, level);
- host->cdet_state = level;
- }
-}
-
struct omap_mmc_s *omap_mmc_init(hwaddr base,
MemoryRegion *sysmem,
BlockBackend *blk,
@@ -617,48 +599,3 @@ struct omap_mmc_s *omap_mmc_init(hwaddr base,
return s;
}
-
-struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
- BlockBackend *blk, qemu_irq irq, qemu_irq dma[],
- omap_clk fclk, omap_clk iclk)
-{
- struct omap_mmc_s *s = g_new0(struct omap_mmc_s, 1);
-
- s->irq = irq;
- s->dma = dma;
- s->clk = fclk;
- s->lines = 4;
- s->rev = 2;
-
- memory_region_init_io(&s->iomem, NULL, &omap_mmc_ops, s, "omap.mmc",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &s->iomem);
-
- /* Instantiate the storage */
- s->card = sd_init(blk, false);
- if (s->card == NULL) {
- exit(1);
- }
-
- s->cdet = qemu_allocate_irq(omap_mmc_cover_cb, s, 0);
- sd_set_cb(s->card, NULL, s->cdet);
-
- omap_mmc_reset(s);
-
- return s;
-}
-
-void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover)
-{
- if (s->cdet) {
- sd_set_cb(s->card, ro, s->cdet);
- s->coverswitch = cover;
- qemu_set_irq(cover, s->cdet_state);
- } else
- sd_set_cb(s->card, ro, cover);
-}
-
-void omap_mmc_enable(struct omap_mmc_s *s, int enable)
-{
- sd_enable(s->card, enable);
-}
diff --git a/hw/sd/pl181.c b/hw/sd/pl181.c
index e3633c2..51b10ca 100644
--- a/hw/sd/pl181.c
+++ b/hw/sd/pl181.c
@@ -514,7 +514,7 @@ static void pl181_class_init(ObjectClass *klass, void *data)
DeviceClass *k = DEVICE_CLASS(klass);
k->vmsd = &vmstate_pl181;
- k->reset = pl181_reset;
+ device_class_set_legacy_reset(k, pl181_reset);
/* Reason: output IRQs should be wired up */
k->user_creatable = false;
}
diff --git a/hw/sd/pxa2xx_mmci.c b/hw/sd/pxa2xx_mmci.c
deleted file mode 100644
index 8252970..0000000
--- a/hw/sd/pxa2xx_mmci.c
+++ /dev/null
@@ -1,594 +0,0 @@
-/*
- * Intel XScale PXA255/270 MultiMediaCard/SD/SDIO Controller emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPLv2.
- *
- * 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 "qapi/error.h"
-#include "hw/irq.h"
-#include "hw/sysbus.h"
-#include "migration/vmstate.h"
-#include "hw/arm/pxa.h"
-#include "hw/sd/sd.h"
-#include "hw/qdev-properties.h"
-#include "qemu/log.h"
-#include "qemu/module.h"
-#include "trace.h"
-#include "qom/object.h"
-
-#define TYPE_PXA2XX_MMCI_BUS "pxa2xx-mmci-bus"
-/* This is reusing the SDBus typedef from SD_BUS */
-DECLARE_INSTANCE_CHECKER(SDBus, PXA2XX_MMCI_BUS,
- TYPE_PXA2XX_MMCI_BUS)
-
-struct PXA2xxMMCIState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- qemu_irq irq;
- qemu_irq rx_dma;
- qemu_irq tx_dma;
- qemu_irq inserted;
- qemu_irq readonly;
-
- BlockBackend *blk;
- SDBus sdbus;
-
- uint32_t status;
- uint32_t clkrt;
- uint32_t spi;
- uint32_t cmdat;
- uint32_t resp_tout;
- uint32_t read_tout;
- int32_t blklen;
- int32_t numblk;
- uint32_t intmask;
- uint32_t intreq;
- int32_t cmd;
- uint32_t arg;
-
- int32_t active;
- int32_t bytesleft;
- uint8_t tx_fifo[64];
- uint32_t tx_start;
- uint32_t tx_len;
- uint8_t rx_fifo[32];
- uint32_t rx_start;
- uint32_t rx_len;
- uint16_t resp_fifo[9];
- uint32_t resp_len;
-
- int32_t cmdreq;
-};
-
-static bool pxa2xx_mmci_vmstate_validate(void *opaque, int version_id)
-{
- PXA2xxMMCIState *s = opaque;
-
- return s->tx_start < ARRAY_SIZE(s->tx_fifo)
- && s->rx_start < ARRAY_SIZE(s->rx_fifo)
- && s->tx_len <= ARRAY_SIZE(s->tx_fifo)
- && s->rx_len <= ARRAY_SIZE(s->rx_fifo)
- && s->resp_len <= ARRAY_SIZE(s->resp_fifo);
-}
-
-
-static const VMStateDescription vmstate_pxa2xx_mmci = {
- .name = "pxa2xx-mmci",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32(status, PXA2xxMMCIState),
- VMSTATE_UINT32(clkrt, PXA2xxMMCIState),
- VMSTATE_UINT32(spi, PXA2xxMMCIState),
- VMSTATE_UINT32(cmdat, PXA2xxMMCIState),
- VMSTATE_UINT32(resp_tout, PXA2xxMMCIState),
- VMSTATE_UINT32(read_tout, PXA2xxMMCIState),
- VMSTATE_INT32(blklen, PXA2xxMMCIState),
- VMSTATE_INT32(numblk, PXA2xxMMCIState),
- VMSTATE_UINT32(intmask, PXA2xxMMCIState),
- VMSTATE_UINT32(intreq, PXA2xxMMCIState),
- VMSTATE_INT32(cmd, PXA2xxMMCIState),
- VMSTATE_UINT32(arg, PXA2xxMMCIState),
- VMSTATE_INT32(cmdreq, PXA2xxMMCIState),
- VMSTATE_INT32(active, PXA2xxMMCIState),
- VMSTATE_INT32(bytesleft, PXA2xxMMCIState),
- VMSTATE_UINT32(tx_start, PXA2xxMMCIState),
- VMSTATE_UINT32(tx_len, PXA2xxMMCIState),
- VMSTATE_UINT32(rx_start, PXA2xxMMCIState),
- VMSTATE_UINT32(rx_len, PXA2xxMMCIState),
- VMSTATE_UINT32(resp_len, PXA2xxMMCIState),
- VMSTATE_VALIDATE("fifo size incorrect", pxa2xx_mmci_vmstate_validate),
- VMSTATE_UINT8_ARRAY(tx_fifo, PXA2xxMMCIState, 64),
- VMSTATE_UINT8_ARRAY(rx_fifo, PXA2xxMMCIState, 32),
- VMSTATE_UINT16_ARRAY(resp_fifo, PXA2xxMMCIState, 9),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#define MMC_STRPCL 0x00 /* MMC Clock Start/Stop register */
-#define MMC_STAT 0x04 /* MMC Status register */
-#define MMC_CLKRT 0x08 /* MMC Clock Rate register */
-#define MMC_SPI 0x0c /* MMC SPI Mode register */
-#define MMC_CMDAT 0x10 /* MMC Command/Data register */
-#define MMC_RESTO 0x14 /* MMC Response Time-Out register */
-#define MMC_RDTO 0x18 /* MMC Read Time-Out register */
-#define MMC_BLKLEN 0x1c /* MMC Block Length register */
-#define MMC_NUMBLK 0x20 /* MMC Number of Blocks register */
-#define MMC_PRTBUF 0x24 /* MMC Buffer Partly Full register */
-#define MMC_I_MASK 0x28 /* MMC Interrupt Mask register */
-#define MMC_I_REG 0x2c /* MMC Interrupt Request register */
-#define MMC_CMD 0x30 /* MMC Command register */
-#define MMC_ARGH 0x34 /* MMC Argument High register */
-#define MMC_ARGL 0x38 /* MMC Argument Low register */
-#define MMC_RES 0x3c /* MMC Response FIFO */
-#define MMC_RXFIFO 0x40 /* MMC Receive FIFO */
-#define MMC_TXFIFO 0x44 /* MMC Transmit FIFO */
-#define MMC_RDWAIT 0x48 /* MMC RD_WAIT register */
-#define MMC_BLKS_REM 0x4c /* MMC Blocks Remaining register */
-
-/* Bitfield masks */
-#define STRPCL_STOP_CLK (1 << 0)
-#define STRPCL_STRT_CLK (1 << 1)
-#define STAT_TOUT_RES (1 << 1)
-#define STAT_CLK_EN (1 << 8)
-#define STAT_DATA_DONE (1 << 11)
-#define STAT_PRG_DONE (1 << 12)
-#define STAT_END_CMDRES (1 << 13)
-#define SPI_SPI_MODE (1 << 0)
-#define CMDAT_RES_TYPE (3 << 0)
-#define CMDAT_DATA_EN (1 << 2)
-#define CMDAT_WR_RD (1 << 3)
-#define CMDAT_DMA_EN (1 << 7)
-#define CMDAT_STOP_TRAN (1 << 10)
-#define INT_DATA_DONE (1 << 0)
-#define INT_PRG_DONE (1 << 1)
-#define INT_END_CMD (1 << 2)
-#define INT_STOP_CMD (1 << 3)
-#define INT_CLK_OFF (1 << 4)
-#define INT_RXFIFO_REQ (1 << 5)
-#define INT_TXFIFO_REQ (1 << 6)
-#define INT_TINT (1 << 7)
-#define INT_DAT_ERR (1 << 8)
-#define INT_RES_ERR (1 << 9)
-#define INT_RD_STALLED (1 << 10)
-#define INT_SDIO_INT (1 << 11)
-#define INT_SDIO_SACK (1 << 12)
-#define PRTBUF_PRT_BUF (1 << 0)
-
-/* Route internal interrupt lines to the global IC and DMA */
-static void pxa2xx_mmci_int_update(PXA2xxMMCIState *s)
-{
- uint32_t mask = s->intmask;
- if (s->cmdat & CMDAT_DMA_EN) {
- mask |= INT_RXFIFO_REQ | INT_TXFIFO_REQ;
-
- qemu_set_irq(s->rx_dma, !!(s->intreq & INT_RXFIFO_REQ));
- qemu_set_irq(s->tx_dma, !!(s->intreq & INT_TXFIFO_REQ));
- }
-
- qemu_set_irq(s->irq, !!(s->intreq & ~mask));
-}
-
-static void pxa2xx_mmci_fifo_update(PXA2xxMMCIState *s)
-{
- if (!s->active)
- return;
-
- if (s->cmdat & CMDAT_WR_RD) {
- while (s->bytesleft && s->tx_len) {
- sdbus_write_byte(&s->sdbus, s->tx_fifo[s->tx_start++]);
- s->tx_start &= 0x1f;
- s->tx_len --;
- s->bytesleft --;
- }
- if (s->bytesleft)
- s->intreq |= INT_TXFIFO_REQ;
- } else
- while (s->bytesleft && s->rx_len < 32) {
- s->rx_fifo[(s->rx_start + (s->rx_len ++)) & 0x1f] =
- sdbus_read_byte(&s->sdbus);
- s->bytesleft --;
- s->intreq |= INT_RXFIFO_REQ;
- }
-
- if (!s->bytesleft) {
- s->active = 0;
- s->intreq |= INT_DATA_DONE;
- s->status |= STAT_DATA_DONE;
-
- if (s->cmdat & CMDAT_WR_RD) {
- s->intreq |= INT_PRG_DONE;
- s->status |= STAT_PRG_DONE;
- }
- }
-
- pxa2xx_mmci_int_update(s);
-}
-
-static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s)
-{
- int rsplen, i;
- SDRequest request;
- uint8_t response[16];
-
- s->active = 1;
- s->rx_len = 0;
- s->tx_len = 0;
- s->cmdreq = 0;
-
- request.cmd = s->cmd;
- request.arg = s->arg;
- request.crc = 0; /* FIXME */
-
- rsplen = sdbus_do_command(&s->sdbus, &request, response);
- s->intreq |= INT_END_CMD;
-
- memset(s->resp_fifo, 0, sizeof(s->resp_fifo));
- switch (s->cmdat & CMDAT_RES_TYPE) {
-#define PXAMMCI_RESP(wd, value0, value1) \
- s->resp_fifo[(wd) + 0] |= (value0); \
- s->resp_fifo[(wd) + 1] |= (value1) << 8;
- case 0: /* No response */
- goto complete;
-
- case 1: /* R1, R4, R5 or R6 */
- if (rsplen < 4)
- goto timeout;
- goto complete;
-
- case 2: /* R2 */
- if (rsplen < 16)
- goto timeout;
- goto complete;
-
- case 3: /* R3 */
- if (rsplen < 4)
- goto timeout;
- goto complete;
-
- complete:
- for (i = 0; rsplen > 0; i ++, rsplen -= 2) {
- PXAMMCI_RESP(i, response[i * 2], response[i * 2 + 1]);
- }
- s->status |= STAT_END_CMDRES;
-
- if (!(s->cmdat & CMDAT_DATA_EN))
- s->active = 0;
- else
- s->bytesleft = s->numblk * s->blklen;
-
- s->resp_len = 0;
- break;
-
- timeout:
- s->active = 0;
- s->status |= STAT_TOUT_RES;
- break;
- }
-
- pxa2xx_mmci_fifo_update(s);
-}
-
-static uint64_t pxa2xx_mmci_read(void *opaque, hwaddr offset, unsigned size)
-{
- PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
- uint32_t ret = 0;
-
- switch (offset) {
- case MMC_STRPCL:
- break;
- case MMC_STAT:
- ret = s->status;
- break;
- case MMC_CLKRT:
- ret = s->clkrt;
- break;
- case MMC_SPI:
- ret = s->spi;
- break;
- case MMC_CMDAT:
- ret = s->cmdat;
- break;
- case MMC_RESTO:
- ret = s->resp_tout;
- break;
- case MMC_RDTO:
- ret = s->read_tout;
- break;
- case MMC_BLKLEN:
- ret = s->blklen;
- break;
- case MMC_NUMBLK:
- ret = s->numblk;
- break;
- case MMC_PRTBUF:
- break;
- case MMC_I_MASK:
- ret = s->intmask;
- break;
- case MMC_I_REG:
- ret = s->intreq;
- break;
- case MMC_CMD:
- ret = s->cmd | 0x40;
- break;
- case MMC_ARGH:
- ret = s->arg >> 16;
- break;
- case MMC_ARGL:
- ret = s->arg & 0xffff;
- break;
- case MMC_RES:
- ret = (s->resp_len < 9) ? s->resp_fifo[s->resp_len++] : 0;
- break;
- case MMC_RXFIFO:
- while (size-- && s->rx_len) {
- ret |= s->rx_fifo[s->rx_start++] << (size << 3);
- s->rx_start &= 0x1f;
- s->rx_len --;
- }
- s->intreq &= ~INT_RXFIFO_REQ;
- pxa2xx_mmci_fifo_update(s);
- break;
- case MMC_RDWAIT:
- break;
- case MMC_BLKS_REM:
- ret = s->numblk;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: incorrect register 0x%02" HWADDR_PRIx "\n",
- __func__, offset);
- }
- trace_pxa2xx_mmci_read(size, offset, ret);
-
- return ret;
-}
-
-static void pxa2xx_mmci_write(void *opaque,
- hwaddr offset, uint64_t value, unsigned size)
-{
- PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
-
- trace_pxa2xx_mmci_write(size, offset, value);
- switch (offset) {
- case MMC_STRPCL:
- if (value & STRPCL_STRT_CLK) {
- s->status |= STAT_CLK_EN;
- s->intreq &= ~INT_CLK_OFF;
-
- if (s->cmdreq && !(s->cmdat & CMDAT_STOP_TRAN)) {
- s->status &= STAT_CLK_EN;
- pxa2xx_mmci_wakequeues(s);
- }
- }
-
- if (value & STRPCL_STOP_CLK) {
- s->status &= ~STAT_CLK_EN;
- s->intreq |= INT_CLK_OFF;
- s->active = 0;
- }
-
- pxa2xx_mmci_int_update(s);
- break;
-
- case MMC_CLKRT:
- s->clkrt = value & 7;
- break;
-
- case MMC_SPI:
- s->spi = value & 0xf;
- if (value & SPI_SPI_MODE) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: attempted to use card in SPI mode\n", __func__);
- }
- break;
-
- case MMC_CMDAT:
- s->cmdat = value & 0x3dff;
- s->active = 0;
- s->cmdreq = 1;
- if (!(value & CMDAT_STOP_TRAN)) {
- s->status &= STAT_CLK_EN;
-
- if (s->status & STAT_CLK_EN)
- pxa2xx_mmci_wakequeues(s);
- }
-
- pxa2xx_mmci_int_update(s);
- break;
-
- case MMC_RESTO:
- s->resp_tout = value & 0x7f;
- break;
-
- case MMC_RDTO:
- s->read_tout = value & 0xffff;
- break;
-
- case MMC_BLKLEN:
- s->blklen = value & 0xfff;
- break;
-
- case MMC_NUMBLK:
- s->numblk = value & 0xffff;
- break;
-
- case MMC_PRTBUF:
- if (value & PRTBUF_PRT_BUF) {
- s->tx_start ^= 32;
- s->tx_len = 0;
- }
- pxa2xx_mmci_fifo_update(s);
- break;
-
- case MMC_I_MASK:
- s->intmask = value & 0x1fff;
- pxa2xx_mmci_int_update(s);
- break;
-
- case MMC_CMD:
- s->cmd = value & 0x3f;
- break;
-
- case MMC_ARGH:
- s->arg &= 0x0000ffff;
- s->arg |= value << 16;
- break;
-
- case MMC_ARGL:
- s->arg &= 0xffff0000;
- s->arg |= value & 0x0000ffff;
- break;
-
- case MMC_TXFIFO:
- while (size-- && s->tx_len < 0x20)
- s->tx_fifo[(s->tx_start + (s->tx_len ++)) & 0x1f] =
- (value >> (size << 3)) & 0xff;
- s->intreq &= ~INT_TXFIFO_REQ;
- pxa2xx_mmci_fifo_update(s);
- break;
-
- case MMC_RDWAIT:
- case MMC_BLKS_REM:
- break;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: incorrect reg 0x%02" HWADDR_PRIx " "
- "(value 0x%08" PRIx64 ")\n", __func__, offset, value);
- }
-}
-
-static const MemoryRegionOps pxa2xx_mmci_ops = {
- .read = pxa2xx_mmci_read,
- .write = pxa2xx_mmci_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem,
- hwaddr base,
- qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma)
-{
- DeviceState *dev;
-
- dev = sysbus_create_simple(TYPE_PXA2XX_MMCI, base, irq);
- qdev_connect_gpio_out_named(dev, "rx-dma", 0, rx_dma);
- qdev_connect_gpio_out_named(dev, "tx-dma", 0, tx_dma);
-
- return PXA2XX_MMCI(dev);
-}
-
-static void pxa2xx_mmci_set_inserted(DeviceState *dev, bool inserted)
-{
- PXA2xxMMCIState *s = PXA2XX_MMCI(dev);
-
- qemu_set_irq(s->inserted, inserted);
-}
-
-static void pxa2xx_mmci_set_readonly(DeviceState *dev, bool readonly)
-{
- PXA2xxMMCIState *s = PXA2XX_MMCI(dev);
-
- qemu_set_irq(s->readonly, readonly);
-}
-
-void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly,
- qemu_irq coverswitch)
-{
- DeviceState *dev = DEVICE(s);
-
- s->readonly = readonly;
- s->inserted = coverswitch;
-
- pxa2xx_mmci_set_inserted(dev, sdbus_get_inserted(&s->sdbus));
- pxa2xx_mmci_set_readonly(dev, sdbus_get_readonly(&s->sdbus));
-}
-
-static void pxa2xx_mmci_reset(DeviceState *d)
-{
- PXA2xxMMCIState *s = PXA2XX_MMCI(d);
-
- s->status = 0;
- s->clkrt = 0;
- s->spi = 0;
- s->cmdat = 0;
- s->resp_tout = 0;
- s->read_tout = 0;
- s->blklen = 0;
- s->numblk = 0;
- s->intmask = 0;
- s->intreq = 0;
- s->cmd = 0;
- s->arg = 0;
- s->active = 0;
- s->bytesleft = 0;
- s->tx_start = 0;
- s->tx_len = 0;
- s->rx_start = 0;
- s->rx_len = 0;
- s->resp_len = 0;
- s->cmdreq = 0;
- memset(s->tx_fifo, 0, sizeof(s->tx_fifo));
- memset(s->rx_fifo, 0, sizeof(s->rx_fifo));
- memset(s->resp_fifo, 0, sizeof(s->resp_fifo));
-}
-
-static void pxa2xx_mmci_instance_init(Object *obj)
-{
- PXA2xxMMCIState *s = PXA2XX_MMCI(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- DeviceState *dev = DEVICE(obj);
-
- memory_region_init_io(&s->iomem, obj, &pxa2xx_mmci_ops, s,
- "pxa2xx-mmci", 0x00100000);
- sysbus_init_mmio(sbd, &s->iomem);
- sysbus_init_irq(sbd, &s->irq);
- qdev_init_gpio_out_named(dev, &s->rx_dma, "rx-dma", 1);
- qdev_init_gpio_out_named(dev, &s->tx_dma, "tx-dma", 1);
-
- qbus_init(&s->sdbus, sizeof(s->sdbus),
- TYPE_PXA2XX_MMCI_BUS, DEVICE(obj), "sd-bus");
-}
-
-static void pxa2xx_mmci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_pxa2xx_mmci;
- dc->reset = pxa2xx_mmci_reset;
-}
-
-static void pxa2xx_mmci_bus_class_init(ObjectClass *klass, void *data)
-{
- SDBusClass *sbc = SD_BUS_CLASS(klass);
-
- sbc->set_inserted = pxa2xx_mmci_set_inserted;
- sbc->set_readonly = pxa2xx_mmci_set_readonly;
-}
-
-static const TypeInfo pxa2xx_mmci_types[] = {
- {
- .name = TYPE_PXA2XX_MMCI,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(PXA2xxMMCIState),
- .instance_init = pxa2xx_mmci_instance_init,
- .class_init = pxa2xx_mmci_class_init,
- },
- {
- .name = TYPE_PXA2XX_MMCI_BUS,
- .parent = TYPE_SD_BUS,
- .instance_size = sizeof(SDBus),
- .class_init = pxa2xx_mmci_bus_class_init,
- },
-};
-
-DEFINE_TYPES(pxa2xx_mmci_types)
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
index 07cb97d..a5d2d92 100644
--- a/hw/sd/sd.c
+++ b/hw/sd/sd.c
@@ -774,19 +774,12 @@ static uint32_t sd_blk_len(SDState *sd)
*/
static uint32_t sd_bootpart_offset(SDState *sd)
{
- bool partitions_enabled;
unsigned partition_access;
if (!sd->boot_part_size || !sd_is_emmc(sd)) {
return 0;
}
- partitions_enabled = sd->ext_csd[EXT_CSD_PART_CONFIG]
- & EXT_CSD_PART_CONFIG_EN_MASK;
- if (!partitions_enabled) {
- return 0;
- }
-
partition_access = sd->ext_csd[EXT_CSD_PART_CONFIG]
& EXT_CSD_PART_CONFIG_ACC_MASK;
switch (partition_access) {
@@ -2478,20 +2471,22 @@ void sd_write_byte(SDState *sd, uint8_t value)
uint8_t sd_read_byte(SDState *sd)
{
/* TODO: Append CRCs */
+ const uint8_t dummy_byte = 0x00;
uint8_t ret;
uint32_t io_len;
if (!sd->blk || !blk_is_inserted(sd->blk) || !sd->enable)
- return 0x00;
+ return dummy_byte;
if (sd->state != sd_sendingdata_state) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: not in Sending-Data state\n", __func__);
- return 0x00;
+ return dummy_byte;
}
- if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION))
- return 0x00;
+ if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION)) {
+ return dummy_byte;
+ }
io_len = sd_blk_len(sd);
@@ -2517,7 +2512,7 @@ uint8_t sd_read_byte(SDState *sd)
if (sd->data_offset == 0) {
if (!address_in_range(sd, "READ_MULTIPLE_BLOCK",
sd->data_start, io_len)) {
- return 0x00;
+ return dummy_byte;
}
sd_blk_read(sd, sd->data_start, io_len);
}
@@ -2538,7 +2533,9 @@ uint8_t sd_read_byte(SDState *sd)
break;
default:
- g_assert_not_reached();
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: DAT read illegal for command %s\n",
+ __func__, sd->last_cmd_name);
+ return dummy_byte;
}
return ret;
@@ -2815,7 +2812,7 @@ static void sdmmc_common_class_init(ObjectClass *klass, void *data)
device_class_set_props(dc, sdmmc_common_properties);
dc->vmsd = &sd_vmstate;
- dc->reset = sd_reset;
+ device_class_set_legacy_reset(dc, sd_reset);
dc->bus_type = TYPE_SD_BUS;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index d02c3e3..ed01499 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -747,7 +747,7 @@ static void sdhci_do_adma(SDHCIState *s)
const uint16_t block_size = s->blksize & BLOCK_SIZE_MASK;
const MemTxAttrs attrs = { .memory = true };
ADMADescr dscr = {};
- MemTxResult res;
+ MemTxResult res = MEMTX_ERROR;
int i;
if (s->trnmod & SDHC_TRNS_BLK_CNT_EN && !s->blkcnt) {
@@ -846,6 +846,7 @@ static void sdhci_do_adma(SDHCIState *s)
}
}
if (res != MEMTX_OK) {
+ s->data_count = 0;
if (s->errintstsen & SDHC_EISEN_ADMAERR) {
trace_sdhci_error("Set ADMA error flag");
s->errintsts |= SDHC_EIS_ADMAERR;
@@ -1519,7 +1520,7 @@ void sdhci_common_class_init(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
dc->vmsd = &sdhci_vmstate;
- dc->reset = sdhci_poweron_reset;
+ device_class_set_legacy_reset(dc, sdhci_poweron_reset);
}
/* --- qdev SysBus --- */
diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c
index 2dd070f..1594051 100644
--- a/hw/sd/ssi-sd.c
+++ b/hw/sd/ssi-sd.c
@@ -398,7 +398,7 @@ static void ssi_sd_class_init(ObjectClass *klass, void *data)
k->transfer = ssi_sd_transfer;
k->cs_polarity = SSI_CS_LOW;
dc->vmsd = &vmstate_ssi_sd;
- dc->reset = ssi_sd_reset;
+ device_class_set_legacy_reset(dc, ssi_sd_reset);
/* Reason: GPIO chip-select line should be wired up */
dc->user_creatable = false;
}
diff --git a/hw/sd/trace-events b/hw/sd/trace-events
index 43671dc..db06442 100644
--- a/hw/sd/trace-events
+++ b/hw/sd/trace-events
@@ -60,10 +60,6 @@ sdcard_set_voltage(uint16_t millivolts) "%u mV"
sdcard_ext_csd_update(unsigned index, uint8_t oval, uint8_t nval) "index %u: 0x%02x -> 0x%02x"
sdcard_switch(unsigned access, unsigned index, unsigned value, unsigned set) "SWITCH acc:%u idx:%u val:%u set:%u"
-# 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"
-
# pl181.c
pl181_command_send(uint8_t cmd, uint32_t arg) "sending CMD%02d arg 0x%08" PRIx32
pl181_command_sent(void) "command sent"
diff --git a/hw/sensor/dps310.c b/hw/sensor/dps310.c
index 01c776d..6966a53 100644
--- a/hw/sensor/dps310.c
+++ b/hw/sensor/dps310.c
@@ -205,7 +205,7 @@ static void dps310_class_init(ObjectClass *klass, void *data)
k->event = dps310_event;
k->recv = dps310_rx;
k->send = dps310_tx;
- dc->reset = dps310_reset;
+ device_class_set_legacy_reset(dc, dps310_reset);
dc->vmsd = &vmstate_dps310;
}
diff --git a/hw/sensor/emc141x.c b/hw/sensor/emc141x.c
index 9507955..aeccd2a 100644
--- a/hw/sensor/emc141x.c
+++ b/hw/sensor/emc141x.c
@@ -270,7 +270,7 @@ static void emc141x_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
- dc->reset = emc141x_reset;
+ device_class_set_legacy_reset(dc, emc141x_reset);
k->event = emc141x_event;
k->recv = emc141x_rx;
k->send = emc141x_tx;
diff --git a/hw/sensor/lsm303dlhc_mag.c b/hw/sensor/lsm303dlhc_mag.c
index 343ff98..0447153 100644
--- a/hw/sensor/lsm303dlhc_mag.c
+++ b/hw/sensor/lsm303dlhc_mag.c
@@ -535,7 +535,7 @@ static void lsm303dlhc_mag_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
- dc->reset = lsm303dlhc_mag_reset;
+ device_class_set_legacy_reset(dc, lsm303dlhc_mag_reset);
dc->vmsd = &vmstate_lsm303dlhc_mag;
k->event = lsm303dlhc_mag_event;
k->recv = lsm303dlhc_mag_recv;
diff --git a/hw/sensor/tmp105.c b/hw/sensor/tmp105.c
index a8730d0..9d7b911 100644
--- a/hw/sensor/tmp105.c
+++ b/hw/sensor/tmp105.c
@@ -26,22 +26,27 @@
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "qemu/module.h"
+#include "hw/registerfields.h"
+
+FIELD(CONFIG, SHUTDOWN_MODE, 0, 1)
+FIELD(CONFIG, THERMOSTAT_MODE, 1, 1)
+FIELD(CONFIG, POLARITY, 2, 1)
+FIELD(CONFIG, FAULT_QUEUE, 3, 2)
+FIELD(CONFIG, CONVERTER_RESOLUTION, 5, 2)
+FIELD(CONFIG, ONE_SHOT, 7, 1)
static void tmp105_interrupt_update(TMP105State *s)
{
- qemu_set_irq(s->pin, s->alarm ^ ((~s->config >> 2) & 1)); /* POL */
+ qemu_set_irq(s->pin, s->alarm ^ FIELD_EX8(~s->config, CONFIG, POLARITY));
}
-static void tmp105_alarm_update(TMP105State *s)
+static void tmp105_alarm_update(TMP105State *s, bool one_shot)
{
- if ((s->config >> 0) & 1) { /* SD */
- if ((s->config >> 7) & 1) /* OS */
- s->config &= ~(1 << 7); /* OS */
- else
- return;
+ if (FIELD_EX8(s->config, CONFIG, SHUTDOWN_MODE) && !one_shot) {
+ return;
}
- if (s->config >> 1 & 1) {
+ if (FIELD_EX8(s->config, CONFIG, THERMOSTAT_MODE)) {
/*
* TM == 1 : Interrupt mode. We signal Alert when the
* temperature rises above T_high, and expect the guest to clear
@@ -89,7 +94,8 @@ static void tmp105_get_temperature(Object *obj, Visitor *v, const char *name,
visit_type_int(v, name, &value, errp);
}
-/* Units are 0.001 centigrades relative to 0 C. s->temperature is 8.8
+/*
+ * Units are 0.001 centigrades relative to 0 C. s->temperature is 8.8
* fixed point, so units are 1/256 centigrades. A simple ratio will do.
*/
static void tmp105_set_temperature(Object *obj, Visitor *v, const char *name,
@@ -109,7 +115,7 @@ static void tmp105_set_temperature(Object *obj, Visitor *v, const char *name,
s->temperature = (int16_t) (temp * 256 / 1000);
- tmp105_alarm_update(s);
+ tmp105_alarm_update(s, false);
}
static const int tmp105_faultq[4] = { 1, 2, 4, 6 };
@@ -118,30 +124,30 @@ static void tmp105_read(TMP105State *s)
{
s->len = 0;
- if ((s->config >> 1) & 1) { /* TM */
+ if (FIELD_EX8(s->config, CONFIG, THERMOSTAT_MODE)) {
s->alarm = 0;
tmp105_interrupt_update(s);
}
switch (s->pointer & 3) {
case TMP105_REG_TEMPERATURE:
- s->buf[s->len ++] = (((uint16_t) s->temperature) >> 8);
- s->buf[s->len ++] = (((uint16_t) s->temperature) >> 0) &
- (0xf0 << ((~s->config >> 5) & 3)); /* R */
+ s->buf[s->len++] = (((uint16_t) s->temperature) >> 8);
+ s->buf[s->len++] = (((uint16_t) s->temperature) >> 0) &
+ (0xf0 << (FIELD_EX8(~s->config, CONFIG, CONVERTER_RESOLUTION)));
break;
case TMP105_REG_CONFIG:
- s->buf[s->len ++] = s->config;
+ s->buf[s->len++] = s->config;
break;
case TMP105_REG_T_LOW:
- s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 8;
- s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 0;
+ s->buf[s->len++] = ((uint16_t) s->limit[0]) >> 8;
+ s->buf[s->len++] = ((uint16_t) s->limit[0]) >> 0;
break;
case TMP105_REG_T_HIGH:
- s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 8;
- s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 0;
+ s->buf[s->len++] = ((uint16_t) s->limit[1]) >> 8;
+ s->buf[s->len++] = ((uint16_t) s->limit[1]) >> 0;
break;
}
}
@@ -153,19 +159,21 @@ static void tmp105_write(TMP105State *s)
break;
case TMP105_REG_CONFIG:
- if (s->buf[0] & ~s->config & (1 << 0)) /* SD */
+ if (FIELD_EX8(s->buf[0] & ~s->config, CONFIG, SHUTDOWN_MODE)) {
printf("%s: TMP105 shutdown\n", __func__);
- s->config = s->buf[0];
- s->faults = tmp105_faultq[(s->config >> 3) & 3]; /* F */
- tmp105_alarm_update(s);
+ }
+ s->config = FIELD_DP8(s->buf[0], CONFIG, ONE_SHOT, 0);
+ s->faults = tmp105_faultq[FIELD_EX8(s->config, CONFIG, FAULT_QUEUE)];
+ tmp105_alarm_update(s, FIELD_EX8(s->buf[0], CONFIG, ONE_SHOT));
break;
case TMP105_REG_T_LOW:
case TMP105_REG_T_HIGH:
- if (s->len >= 3)
+ if (s->len >= 3) {
s->limit[s->pointer & 1] = (int16_t)
- ((((uint16_t) s->buf[0]) << 8) | s->buf[1]);
- tmp105_alarm_update(s);
+ ((((uint16_t) s->buf[0]) << 8) | (s->buf[1] & 0xf0));
+ }
+ tmp105_alarm_update(s, false);
break;
}
}
@@ -175,7 +183,7 @@ static uint8_t tmp105_rx(I2CSlave *i2c)
TMP105State *s = TMP105(i2c);
if (s->len < 2) {
- return s->buf[s->len ++];
+ return s->buf[s->len++];
} else {
return 0xff;
}
@@ -215,7 +223,7 @@ static int tmp105_post_load(void *opaque, int version_id)
{
TMP105State *s = opaque;
- s->faults = tmp105_faultq[(s->config >> 3) & 3]; /* F */
+ s->faults = tmp105_faultq[FIELD_EX8(s->config, CONFIG, FAULT_QUEUE)];
tmp105_interrupt_update(s);
return 0;
@@ -273,7 +281,7 @@ static void tmp105_reset(I2CSlave *i2c)
s->temperature = 0;
s->pointer = 0;
s->config = 0;
- s->faults = tmp105_faultq[(s->config >> 3) & 3];
+ s->faults = tmp105_faultq[FIELD_EX8(s->config, CONFIG, FAULT_QUEUE)];
s->alarm = 0;
s->detect_falling = false;
diff --git a/hw/sh4/Kconfig b/hw/sh4/Kconfig
index 99a76a9..1660d29 100644
--- a/hw/sh4/Kconfig
+++ b/hw/sh4/Kconfig
@@ -13,13 +13,6 @@ config R2D
select SH7750
select SH_PCI
-config SHIX
- bool
- default y
- depends on SH4
- select SH7750
- select TC58128
-
config SH7750
bool
select SH_INTC
diff --git a/hw/sh4/meson.build b/hw/sh4/meson.build
index 70e814c..7d27839 100644
--- a/hw/sh4/meson.build
+++ b/hw/sh4/meson.build
@@ -4,6 +4,5 @@ sh4_ss.add(when: 'CONFIG_SH7750', if_true: files(
'sh7750_regnames.c',
))
sh4_ss.add(when: 'CONFIG_R2D', if_true: files('r2d.c'))
-sh4_ss.add(when: 'CONFIG_SHIX', if_true: files('shix.c'))
hw_arch += {'sh4': sh4_ss}
diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c
index e5ac675..7eecd79 100644
--- a/hw/sh4/r2d.c
+++ b/hw/sh4/r2d.c
@@ -286,9 +286,9 @@ static void r2d_init(MachineState *machine)
dinfo = drive_get(IF_IDE, 0, 0);
dev = qdev_new("mmio-ide");
busdev = SYS_BUS_DEVICE(dev);
+ sysbus_connect_irq(busdev, 0, irq[CF_IDE]);
qdev_prop_set_uint32(dev, "shift", 1);
sysbus_realize_and_unref(busdev, &error_fatal);
- sysbus_connect_irq(busdev, 0, irq[CF_IDE]);
sysbus_mmio_map(busdev, 0, 0x14001000);
sysbus_mmio_map(busdev, 1, 0x1400080c);
mmio_ide_init_drives(dev, dinfo, NULL);
diff --git a/hw/sh4/sh7750.c b/hw/sh4/sh7750.c
index ebe0fd9..8041b3b 100644
--- a/hw/sh4/sh7750.c
+++ b/hw/sh4/sh7750.c
@@ -38,8 +38,6 @@
#include "exec/exec-all.h"
#include "trace.h"
-#define NB_DEVICES 4
-
typedef struct SH7750State {
MemoryRegion iomem;
MemoryRegion iomem_1f0;
@@ -75,7 +73,6 @@ typedef struct SH7750State {
uint16_t periph_portdira; /* Direction seen from the peripherals */
uint16_t periph_pdtrb; /* Imposed by the peripherals */
uint16_t periph_portdirb; /* Direction seen from the peripherals */
- sh7750_io_device *devices[NB_DEVICES]; /* External peripherals */
/* Cache */
uint32_t ccr;
@@ -92,19 +89,6 @@ static inline int has_bcr3_and_bcr4(SH7750State *s)
* I/O ports
*/
-int sh7750_register_io_device(SH7750State *s, sh7750_io_device *device)
-{
- int i;
-
- for (i = 0; i < NB_DEVICES; i++) {
- if (s->devices[i] == NULL) {
- s->devices[i] = device;
- return 0;
- }
- }
- return -1;
-}
-
static uint16_t portdir(uint32_t v)
{
#define EVENPORTMASK(n) ((v & (1 << ((n) << 1))) >> (n))
@@ -142,63 +126,26 @@ static uint16_t portb_lines(SH7750State *s)
(~(s->portdirb | s->periph_portdirb) & s->portpullupb); /* Pullups */
}
-static void gen_port_interrupts(SH7750State *s)
-{
- /* XXXXX interrupts not generated */
-}
-
static void porta_changed(SH7750State *s, uint16_t prev)
{
- uint16_t currenta, changes;
- int i, r = 0;
+ uint16_t currenta;
currenta = porta_lines(s);
if (currenta == prev) {
return;
}
trace_sh7750_porta(prev, currenta, s->pdtra, s->pctra);
- changes = currenta ^ prev;
-
- for (i = 0; i < NB_DEVICES; i++) {
- if (s->devices[i] && (s->devices[i]->portamask_trigger & changes)) {
- r |= s->devices[i]->port_change_cb(currenta, portb_lines(s),
- &s->periph_pdtra,
- &s->periph_portdira,
- &s->periph_pdtrb,
- &s->periph_portdirb);
- }
- }
-
- if (r) {
- gen_port_interrupts(s);
- }
}
static void portb_changed(SH7750State *s, uint16_t prev)
{
- uint16_t currentb, changes;
- int i, r = 0;
+ uint16_t currentb;
currentb = portb_lines(s);
if (currentb == prev) {
return;
}
trace_sh7750_portb(prev, currentb, s->pdtrb, s->pctrb);
- changes = currentb ^ prev;
-
- for (i = 0; i < NB_DEVICES; i++) {
- if (s->devices[i] && (s->devices[i]->portbmask_trigger & changes)) {
- r |= s->devices[i]->port_change_cb(portb_lines(s), currentb,
- &s->periph_pdtra,
- &s->periph_portdira,
- &s->periph_pdtrb,
- &s->periph_portdirb);
- }
- }
-
- if (r) {
- gen_port_interrupts(s);
- }
}
/*
diff --git a/hw/sh4/shix.c b/hw/sh4/shix.c
deleted file mode 100644
index eb3150b..0000000
--- a/hw/sh4/shix.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * SHIX 2.0 board description
- *
- * Copyright (c) 2005 Samuel Tardieu
- *
- * 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.
- */
-/*
- * Shix 2.0 board by Alexis Polti, described at
- * https://web.archive.org/web/20070917001736/perso.enst.fr/~polti/realisations/shix20
- *
- * More information in target/sh4/README.sh4
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "cpu.h"
-#include "hw/sh4/sh.h"
-#include "sysemu/qtest.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "qemu/error-report.h"
-
-#define BIOS_FILENAME "shix_bios.bin"
-#define BIOS_ADDRESS 0xA0000000
-
-static void shix_init(MachineState *machine)
-{
- int ret;
- SuperHCPU *cpu;
- struct SH7750State *s;
- MemoryRegion *sysmem = get_system_memory();
- MemoryRegion *rom = g_new(MemoryRegion, 1);
- MemoryRegion *sdram = g_new(MemoryRegion, 2);
- const char *bios_name = machine->firmware ?: BIOS_FILENAME;
-
- cpu = SUPERH_CPU(cpu_create(machine->cpu_type));
-
- /* Allocate memory space */
- memory_region_init_rom(rom, NULL, "shix.rom", 0x4000, &error_fatal);
- memory_region_add_subregion(sysmem, 0x00000000, rom);
- memory_region_init_ram(&sdram[0], NULL, "shix.sdram1", 0x01000000,
- &error_fatal);
- memory_region_add_subregion(sysmem, 0x08000000, &sdram[0]);
- memory_region_init_ram(&sdram[1], NULL, "shix.sdram2", 0x01000000,
- &error_fatal);
- memory_region_add_subregion(sysmem, 0x0c000000, &sdram[1]);
-
- /* Load BIOS in 0 (and access it through P2, 0xA0000000) */
- ret = load_image_targphys(bios_name, 0, 0x4000);
- if (ret < 0 && !qtest_enabled()) {
- error_report("Could not load SHIX bios '%s'", bios_name);
- exit(1);
- }
-
- /* Register peripherals */
- s = sh7750_init(cpu, sysmem);
- /* XXXXX Check success */
- tc58128_init(s, "shix_linux_nand.bin", NULL);
-}
-
-static void shix_machine_init(MachineClass *mc)
-{
- mc->desc = "shix card";
- mc->init = shix_init;
- mc->is_default = true;
- mc->default_cpu_type = TYPE_SH7750R_CPU;
- mc->deprecation_reason = "old and unmaintained";
-}
-
-DEFINE_MACHINE("shix", shix_machine_init)
diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
index 3b77034..a394514 100644
--- a/hw/smbios/smbios.c
+++ b/hw/smbios/smbios.c
@@ -1093,6 +1093,7 @@ static bool smbios_get_tables_ep(MachineState *ms,
Error **errp)
{
unsigned i, dimm_cnt, offset;
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
ERRP_GUARD();
assert(ep_type == SMBIOS_ENTRY_POINT_TYPE_32 ||
@@ -1123,12 +1124,12 @@ static bool smbios_get_tables_ep(MachineState *ms,
smbios_build_type_9_table(errp);
smbios_build_type_11_table();
-#define MAX_DIMM_SZ (16 * GiB)
-#define GET_DIMM_SZ ((i < dimm_cnt - 1) ? MAX_DIMM_SZ \
- : ((current_machine->ram_size - 1) % MAX_DIMM_SZ) + 1)
+#define GET_DIMM_SZ ((i < dimm_cnt - 1) ? mc->smbios_memory_device_size \
+ : ((current_machine->ram_size - 1) % mc->smbios_memory_device_size) + 1)
- dimm_cnt = QEMU_ALIGN_UP(current_machine->ram_size, MAX_DIMM_SZ) /
- MAX_DIMM_SZ;
+ dimm_cnt = QEMU_ALIGN_UP(current_machine->ram_size,
+ mc->smbios_memory_device_size) /
+ mc->smbios_memory_device_size;
/*
* The offset determines if we need to keep additional space between
diff --git a/hw/sparc/sun4m_iommu.c b/hw/sparc/sun4m_iommu.c
index 06703b1..6f765e9 100644
--- a/hw/sparc/sun4m_iommu.c
+++ b/hw/sparc/sun4m_iommu.c
@@ -377,7 +377,7 @@ static void iommu_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = iommu_reset;
+ device_class_set_legacy_reset(dc, iommu_reset);
dc->vmsd = &vmstate_iommu;
device_class_set_props(dc, iommu_properties);
}
diff --git a/hw/sparc64/Kconfig b/hw/sparc64/Kconfig
index 3b948a2..f764c8a 100644
--- a/hw/sparc64/Kconfig
+++ b/hw/sparc64/Kconfig
@@ -10,6 +10,7 @@ config SUN4U
select ISA_BUS
select FDC_ISA
select SERIAL_ISA
+ select SERIAL_MM
select PCI_SABRE
select IDE_CMD646
select PCKBD
diff --git a/hw/sparc64/niagara.c b/hw/sparc64/niagara.c
index ab3c4ec..67ec403 100644
--- a/hw/sparc64/niagara.c
+++ b/hw/sparc64/niagara.c
@@ -27,7 +27,7 @@
#include "qemu/units.h"
#include "cpu.h"
#include "hw/boards.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/misc/unimp.h"
#include "hw/loader.h"
#include "hw/sparc/sparc64.h"
diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
index 4ece1ac..541c7f7 100644
--- a/hw/sparc64/sun4u.c
+++ b/hw/sparc64/sun4u.c
@@ -34,7 +34,8 @@
#include "hw/pci/pci_host.h"
#include "hw/qdev-properties.h"
#include "hw/pci-host/sabre.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-isa.h"
+#include "hw/char/serial-mm.h"
#include "hw/char/parallel-isa.h"
#include "hw/rtc/m48t59.h"
#include "migration/vmstate.h"
diff --git a/hw/sparc64/sun4u_iommu.c b/hw/sparc64/sun4u_iommu.c
index 1c1dca7..eba811a 100644
--- a/hw/sparc64/sun4u_iommu.c
+++ b/hw/sparc64/sun4u_iommu.c
@@ -309,7 +309,7 @@ static void iommu_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = iommu_reset;
+ device_class_set_legacy_reset(dc, iommu_reset);
}
static const TypeInfo iommu_info = {
diff --git a/hw/ssi/Kconfig b/hw/ssi/Kconfig
index 83ee53c..1bd5646 100644
--- a/hw/ssi/Kconfig
+++ b/hw/ssi/Kconfig
@@ -24,3 +24,11 @@ config STM32F2XX_SPI
config BCM2835_SPI
bool
select SSI
+
+config PNV_SPI
+ bool
+ select SSI
+
+config ALLWINNER_A10_SPI
+ bool
+ select SSI
diff --git a/hw/ssi/allwinner-a10-spi.c b/hw/ssi/allwinner-a10-spi.c
new file mode 100644
index 0000000..3eb50b4
--- /dev/null
+++ b/hw/ssi/allwinner-a10-spi.c
@@ -0,0 +1,561 @@
+/*
+ * Allwinner SPI Bus Serial Interface Emulation
+ *
+ * Copyright (C) 2024 Strahinja Jankovic <strahinja.p.jankovic@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 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/>.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/irq.h"
+#include "hw/ssi/allwinner-a10-spi.h"
+#include "migration/vmstate.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "trace.h"
+
+/* Allwinner SPI memory map */
+#define SPI_RXDATA_REG 0x00 /* receive data register */
+#define SPI_TXDATA_REG 0x04 /* transmit data register */
+#define SPI_CTL_REG 0x08 /* control register */
+#define SPI_INTCTL_REG 0x0c /* interrupt control register */
+#define SPI_INT_STA_REG 0x10 /* interrupt status register */
+#define SPI_DMACTL_REG 0x14 /* DMA control register */
+#define SPI_WAIT_REG 0x18 /* wait clock counter register */
+#define SPI_CCTL_REG 0x1c /* clock rate control register */
+#define SPI_BC_REG 0x20 /* burst control register */
+#define SPI_TC_REG 0x24 /* transmit counter register */
+#define SPI_FIFO_STA_REG 0x28 /* FIFO status register */
+
+/* Data register */
+#define SPI_DATA_RESET 0
+
+/* Control register */
+#define SPI_CTL_SDC (1 << 19)
+#define SPI_CTL_TP_EN (1 << 18)
+#define SPI_CTL_SS_LEVEL (1 << 17)
+#define SPI_CTL_SS_CTRL (1 << 16)
+#define SPI_CTL_DHB (1 << 15)
+#define SPI_CTL_DDB (1 << 14)
+#define SPI_CTL_SS (3 << 12)
+#define SPI_CTL_SS_SHIFT 12
+#define SPI_CTL_RPSM (1 << 11)
+#define SPI_CTL_XCH (1 << 10)
+#define SPI_CTL_RF_RST (1 << 9)
+#define SPI_CTL_TF_RST (1 << 8)
+#define SPI_CTL_SSCTL (1 << 7)
+#define SPI_CTL_LMTF (1 << 6)
+#define SPI_CTL_DMAMC (1 << 5)
+#define SPI_CTL_SSPOL (1 << 4)
+#define SPI_CTL_POL (1 << 3)
+#define SPI_CTL_PHA (1 << 2)
+#define SPI_CTL_MODE (1 << 1)
+#define SPI_CTL_EN (1 << 0)
+#define SPI_CTL_MASK 0xFFFFFu
+#define SPI_CTL_RESET 0x0002001Cu
+
+/* Interrupt control register */
+#define SPI_INTCTL_SS_INT_EN (1 << 17)
+#define SPI_INTCTL_TX_INT_EN (1 << 16)
+#define SPI_INTCTL_TF_UR_INT_EN (1 << 14)
+#define SPI_INTCTL_TF_OF_INT_EN (1 << 13)
+#define SPI_INTCTL_TF_E34_INT_EN (1 << 12)
+#define SPI_INTCTL_TF_E14_INT_EN (1 << 11)
+#define SPI_INTCTL_TF_FL_INT_EN (1 << 10)
+#define SPI_INTCTL_TF_HALF_EMP_INT_EN (1 << 9)
+#define SPI_INTCTL_TF_EMP_INT_EN (1 << 8)
+#define SPI_INTCTL_RF_UR_INT_EN (1 << 6)
+#define SPI_INTCTL_RF_OF_INT_EN (1 << 5)
+#define SPI_INTCTL_RF_E34_INT_EN (1 << 4)
+#define SPI_INTCTL_RF_E14_INT_EN (1 << 3)
+#define SPI_INTCTL_RF_FU_INT_EN (1 << 2)
+#define SPI_INTCTL_RF_HALF_FU_INT_EN (1 << 1)
+#define SPI_INTCTL_RF_RDY_INT_EN (1 << 0)
+#define SPI_INTCTL_MASK 0x37F7Fu
+#define SPI_INTCTL_RESET 0
+
+/* Interrupt status register */
+#define SPI_INT_STA_INT_CBF (1 << 31)
+#define SPI_INT_STA_SSI (1 << 17)
+#define SPI_INT_STA_TC (1 << 16)
+#define SPI_INT_STA_TU (1 << 14)
+#define SPI_INT_STA_TO (1 << 13)
+#define SPI_INT_STA_TE34 (1 << 12)
+#define SPI_INT_STA_TE14 (1 << 11)
+#define SPI_INT_STA_TF (1 << 10)
+#define SPI_INT_STA_THE (1 << 9)
+#define SPI_INT_STA_TE (1 << 8)
+#define SPI_INT_STA_RU (1 << 6)
+#define SPI_INT_STA_RO (1 << 5)
+#define SPI_INT_STA_RF34 (1 << 4)
+#define SPI_INT_STA_RF14 (1 << 3)
+#define SPI_INT_STA_RF (1 << 2)
+#define SPI_INT_STA_RHF (1 << 1)
+#define SPI_INT_STA_RR (1 << 0)
+#define SPI_INT_STA_MASK 0x80037F7Fu
+#define SPI_INT_STA_RESET 0x00001B00u
+
+/* DMA control register - not implemented */
+#define SPI_DMACTL_RESET 0
+
+/* Wait clock register */
+#define SPI_WAIT_REG_WCC_MASK 0xFFFFu
+#define SPI_WAIT_RESET 0
+
+/* Clock control register - not implemented */
+#define SPI_CCTL_RESET 2
+
+/* Burst count register */
+#define SPI_BC_BC_MASK 0xFFFFFFu
+#define SPI_BC_RESET 0
+
+/* Transmi counter register */
+#define SPI_TC_WTC_MASK 0xFFFFFFu
+#define SPI_TC_RESET 0
+
+/* FIFO status register */
+#define SPI_FIFO_STA_CNT_MASK 0x7F
+#define SPI_FIFO_STA_TF_CNT_SHIFT 16
+#define SPI_FIFO_STA_RF_CNT_SHIFT 0
+#define SPI_FIFO_STA_RESET 0
+
+#define REG_INDEX(offset) (offset / sizeof(uint32_t))
+
+
+static const char *allwinner_a10_spi_get_regname(unsigned offset)
+{
+ switch (offset) {
+ case SPI_RXDATA_REG:
+ return "RXDATA";
+ case SPI_TXDATA_REG:
+ return "TXDATA";
+ case SPI_CTL_REG:
+ return "CTL";
+ case SPI_INTCTL_REG:
+ return "INTCTL";
+ case SPI_INT_STA_REG:
+ return "INT_STA";
+ case SPI_DMACTL_REG:
+ return "DMACTL";
+ case SPI_WAIT_REG:
+ return "WAIT";
+ case SPI_CCTL_REG:
+ return "CCTL";
+ case SPI_BC_REG:
+ return "BC";
+ case SPI_TC_REG:
+ return "TC";
+ case SPI_FIFO_STA_REG:
+ return "FIFO_STA";
+ default:
+ return "[?]";
+ }
+}
+
+static bool allwinner_a10_spi_is_enabled(AWA10SPIState *s)
+{
+ return s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_EN;
+}
+
+static void allwinner_a10_spi_txfifo_reset(AWA10SPIState *s)
+{
+ fifo8_reset(&s->tx_fifo);
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= (SPI_INT_STA_TE | SPI_INT_STA_TE14 |
+ SPI_INT_STA_THE | SPI_INT_STA_TE34);
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~(SPI_INT_STA_TU | SPI_INT_STA_TO);
+}
+
+static void allwinner_a10_spi_rxfifo_reset(AWA10SPIState *s)
+{
+ fifo8_reset(&s->rx_fifo);
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &=
+ ~(SPI_INT_STA_RU | SPI_INT_STA_RO | SPI_INT_STA_RF | SPI_INT_STA_RR |
+ SPI_INT_STA_RHF | SPI_INT_STA_RF14 | SPI_INT_STA_RF34);
+}
+
+static uint8_t allwinner_a10_spi_selected_channel(AWA10SPIState *s)
+{
+ return (s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_SS) >> SPI_CTL_SS_SHIFT;
+}
+
+static void allwinner_a10_spi_reset_hold(Object *obj, ResetType type)
+{
+ AWA10SPIState *s = AW_A10_SPI(obj);
+
+ s->regs[REG_INDEX(SPI_RXDATA_REG)] = SPI_DATA_RESET;
+ s->regs[REG_INDEX(SPI_TXDATA_REG)] = SPI_DATA_RESET;
+ s->regs[REG_INDEX(SPI_CTL_REG)] = SPI_CTL_RESET;
+ s->regs[REG_INDEX(SPI_INTCTL_REG)] = SPI_INTCTL_RESET;
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] = SPI_INT_STA_RESET;
+ s->regs[REG_INDEX(SPI_DMACTL_REG)] = SPI_DMACTL_RESET;
+ s->regs[REG_INDEX(SPI_WAIT_REG)] = SPI_WAIT_RESET;
+ s->regs[REG_INDEX(SPI_CCTL_REG)] = SPI_CCTL_RESET;
+ s->regs[REG_INDEX(SPI_BC_REG)] = SPI_BC_RESET;
+ s->regs[REG_INDEX(SPI_TC_REG)] = SPI_TC_RESET;
+ s->regs[REG_INDEX(SPI_FIFO_STA_REG)] = SPI_FIFO_STA_RESET;
+
+ allwinner_a10_spi_txfifo_reset(s);
+ allwinner_a10_spi_rxfifo_reset(s);
+}
+
+static void allwinner_a10_spi_update_irq(AWA10SPIState *s)
+{
+ bool level;
+
+ if (fifo8_is_empty(&s->rx_fifo)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_RR;
+ } else {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_RR;
+ }
+
+ if (fifo8_num_used(&s->rx_fifo) >= (AW_A10_SPI_FIFO_SIZE >> 2)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_RF14;
+ } else {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_RF14;
+ }
+
+ if (fifo8_num_used(&s->rx_fifo) >= (AW_A10_SPI_FIFO_SIZE >> 1)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_RHF;
+ } else {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_RHF;
+ }
+
+ if (fifo8_num_free(&s->rx_fifo) <= (AW_A10_SPI_FIFO_SIZE >> 2)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_RF34;
+ } else {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_RF34;
+ }
+
+ if (fifo8_is_full(&s->rx_fifo)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_RF;
+ } else {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_RF;
+ }
+
+ if (fifo8_is_empty(&s->tx_fifo)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_TE;
+ } else {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_TE;
+ }
+
+ if (fifo8_num_free(&s->tx_fifo) >= (AW_A10_SPI_FIFO_SIZE >> 2)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_TE14;
+ } else {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_TE14;
+ }
+
+ if (fifo8_num_free(&s->tx_fifo) >= (AW_A10_SPI_FIFO_SIZE >> 1)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_THE;
+ } else {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_THE;
+ }
+
+ if (fifo8_num_used(&s->tx_fifo) <= (AW_A10_SPI_FIFO_SIZE >> 2)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_TE34;
+ } else {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_TE34;
+ }
+
+ if (fifo8_is_full(&s->rx_fifo)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_TF;
+ } else {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_TF;
+ }
+
+ level = (s->regs[REG_INDEX(SPI_INT_STA_REG)] &
+ s->regs[REG_INDEX(SPI_INTCTL_REG)]) != 0;
+
+ qemu_set_irq(s->irq, level);
+
+ trace_allwinner_a10_spi_update_irq(level);
+}
+
+static void allwinner_a10_spi_flush_txfifo(AWA10SPIState *s)
+{
+ uint32_t burst_count = s->regs[REG_INDEX(SPI_BC_REG)];
+ uint32_t tx_burst = s->regs[REG_INDEX(SPI_TC_REG)];
+ trace_allwinner_a10_spi_burst_length(tx_burst);
+
+ trace_allwinner_a10_spi_flush_txfifo_begin(fifo8_num_used(&s->tx_fifo),
+ fifo8_num_used(&s->rx_fifo));
+
+ while (!fifo8_is_empty(&s->tx_fifo)) {
+ uint8_t tx = fifo8_pop(&s->tx_fifo);
+ uint8_t rx = 0;
+ bool fill_rx = true;
+
+ trace_allwinner_a10_spi_tx(tx);
+
+ /* Write one byte at a time */
+ rx = ssi_transfer(s->bus, tx);
+
+ trace_allwinner_a10_spi_rx(rx);
+
+ /* Check DHB here to determine if RX bytes should be stored */
+ if (s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_DHB) {
+ /* Store rx bytes only after WTC transfers */
+ if (tx_burst > 0u) {
+ fill_rx = false;
+ tx_burst--;
+ }
+ }
+
+ if (fill_rx) {
+ if (fifo8_is_full(&s->rx_fifo)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_RF;
+ } else {
+ fifo8_push(&s->rx_fifo, rx);
+ }
+ }
+
+ allwinner_a10_spi_update_irq(s);
+
+ burst_count--;
+
+ if (burst_count == 0) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_TC;
+ s->regs[REG_INDEX(SPI_CTL_REG)] &= ~SPI_CTL_XCH;
+ break;
+ }
+ }
+
+ if (fifo8_is_empty(&s->tx_fifo)) {
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_TC;
+ s->regs[REG_INDEX(SPI_CTL_REG)] &= ~SPI_CTL_XCH;
+ }
+
+ trace_allwinner_a10_spi_flush_txfifo_end(fifo8_num_used(&s->tx_fifo),
+ fifo8_num_used(&s->rx_fifo));
+}
+
+static uint64_t allwinner_a10_spi_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ uint32_t value = 0;
+ AWA10SPIState *s = opaque;
+ uint32_t index = offset >> 2;
+
+ if (offset > SPI_FIFO_STA_REG) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "[%s]%s: Bad register at offset 0x%" HWADDR_PRIx "\n",
+ TYPE_AW_A10_SPI, __func__, offset);
+ return 0;
+ }
+
+ value = s->regs[index];
+
+ if (allwinner_a10_spi_is_enabled(s)) {
+ switch (offset) {
+ case SPI_RXDATA_REG:
+ if (fifo8_is_empty(&s->rx_fifo)) {
+ /* value is undefined */
+ value = 0xdeadbeef;
+ } else {
+ /* read from the RX FIFO */
+ value = fifo8_pop(&s->rx_fifo);
+ }
+ break;
+ case SPI_TXDATA_REG:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "[%s]%s: Trying to read from TX FIFO\n",
+ TYPE_AW_A10_SPI, __func__);
+
+ /* Reading from TXDATA gives 0 */
+ break;
+ case SPI_FIFO_STA_REG:
+ /* Read current tx/rx fifo data count */
+ value = fifo8_num_used(&s->tx_fifo) << SPI_FIFO_STA_TF_CNT_SHIFT |
+ fifo8_num_used(&s->rx_fifo) << SPI_FIFO_STA_RF_CNT_SHIFT;
+ break;
+ case SPI_CTL_REG:
+ case SPI_INTCTL_REG:
+ case SPI_INT_STA_REG:
+ case SPI_DMACTL_REG:
+ case SPI_WAIT_REG:
+ case SPI_CCTL_REG:
+ case SPI_BC_REG:
+ case SPI_TC_REG:
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad offset 0x%x\n", __func__,
+ (uint32_t)offset);
+ break;
+ }
+
+ allwinner_a10_spi_update_irq(s);
+ }
+ trace_allwinner_a10_spi_read(allwinner_a10_spi_get_regname(offset), value);
+
+ return value;
+}
+
+static bool allwinner_a10_spi_update_cs_level(AWA10SPIState *s, int cs_line_nr)
+{
+ if (cs_line_nr == allwinner_a10_spi_selected_channel(s)) {
+ return (s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_SS_LEVEL) != 0;
+ } else {
+ return (s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_SSPOL) != 0;
+ }
+}
+
+static void allwinner_a10_spi_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ AWA10SPIState *s = opaque;
+ uint32_t index = offset >> 2;
+ int i = 0;
+
+ if (offset > SPI_FIFO_STA_REG) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "[%s]%s: Bad register at offset 0x%" HWADDR_PRIx "\n",
+ TYPE_AW_A10_SPI, __func__, offset);
+ return;
+ }
+
+ trace_allwinner_a10_spi_write(allwinner_a10_spi_get_regname(offset),
+ (uint32_t)value);
+
+ if (!allwinner_a10_spi_is_enabled(s)) {
+ /* Block is disabled */
+ if (offset != SPI_CTL_REG) {
+ /* Ignore access */
+ return;
+ }
+ }
+
+ switch (offset) {
+ case SPI_RXDATA_REG:
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to write to RX FIFO\n",
+ TYPE_AW_A10_SPI, __func__);
+ break;
+ case SPI_TXDATA_REG:
+ if (fifo8_is_full(&s->tx_fifo)) {
+ /* Ignore writes if queue is full */
+ break;
+ }
+
+ fifo8_push(&s->tx_fifo, (uint8_t)value);
+
+ break;
+ case SPI_INT_STA_REG:
+ /* Handle W1C bits - everything except SPI_INT_STA_INT_CBF. */
+ value &= ~SPI_INT_STA_INT_CBF;
+ s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~(value & SPI_INT_STA_MASK);
+ break;
+ case SPI_CTL_REG:
+ s->regs[REG_INDEX(SPI_CTL_REG)] = value;
+
+ for (i = 0; i < AW_A10_SPI_CS_LINES_NR; i++) {
+ qemu_set_irq(
+ s->cs_lines[i],
+ allwinner_a10_spi_update_cs_level(s, i));
+ }
+
+ if (s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_XCH) {
+ /* Request to start emitting */
+ allwinner_a10_spi_flush_txfifo(s);
+ }
+ if (s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_TF_RST) {
+ allwinner_a10_spi_txfifo_reset(s);
+ s->regs[REG_INDEX(SPI_CTL_REG)] &= ~SPI_CTL_TF_RST;
+ }
+ if (s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_RF_RST) {
+ allwinner_a10_spi_rxfifo_reset(s);
+ s->regs[REG_INDEX(SPI_CTL_REG)] &= ~SPI_CTL_RF_RST;
+ }
+ break;
+ case SPI_INTCTL_REG:
+ case SPI_DMACTL_REG:
+ case SPI_WAIT_REG:
+ case SPI_CCTL_REG:
+ case SPI_BC_REG:
+ case SPI_TC_REG:
+ case SPI_FIFO_STA_REG:
+ s->regs[index] = value;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad offset 0x%x\n", __func__,
+ (uint32_t)offset);
+ break;
+ }
+
+ allwinner_a10_spi_update_irq(s);
+}
+
+static const MemoryRegionOps allwinner_a10_spi_ops = {
+ .read = allwinner_a10_spi_read,
+ .write = allwinner_a10_spi_write,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription allwinner_a10_spi_vmstate = {
+ .name = TYPE_AW_A10_SPI,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_FIFO8(tx_fifo, AWA10SPIState),
+ VMSTATE_FIFO8(rx_fifo, AWA10SPIState),
+ VMSTATE_UINT32_ARRAY(regs, AWA10SPIState, AW_A10_SPI_REGS_NUM),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void allwinner_a10_spi_realize(DeviceState *dev, Error **errp)
+{
+ AWA10SPIState *s = AW_A10_SPI(dev);
+ int i = 0;
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_a10_spi_ops, s,
+ TYPE_AW_A10_SPI, AW_A10_SPI_IOSIZE);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
+
+ s->bus = ssi_create_bus(dev, "spi");
+ for (i = 0; i < AW_A10_SPI_CS_LINES_NR; i++) {
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->cs_lines[i]);
+ }
+ fifo8_create(&s->tx_fifo, AW_A10_SPI_FIFO_SIZE);
+ fifo8_create(&s->rx_fifo, AW_A10_SPI_FIFO_SIZE);
+}
+
+static void allwinner_a10_spi_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ rc->phases.hold = allwinner_a10_spi_reset_hold;
+ dc->vmsd = &allwinner_a10_spi_vmstate;
+ dc->realize = allwinner_a10_spi_realize;
+ dc->desc = "Allwinner A10 SPI Controller";
+}
+
+static const TypeInfo allwinner_a10_spi_type_info = {
+ .name = TYPE_AW_A10_SPI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(AWA10SPIState),
+ .class_init = allwinner_a10_spi_class_init,
+};
+
+static void allwinner_a10_spi_register_types(void)
+{
+ type_register_static(&allwinner_a10_spi_type_info);
+}
+
+type_init(allwinner_a10_spi_register_types)
diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index 49205ab..033cbbb 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -417,7 +417,7 @@ static void aspeed_smc_flash_do_select(AspeedSMCFlash *fl, bool unselect)
AspeedSMCState *s = fl->controller;
trace_aspeed_smc_flash_select(fl->cs, unselect ? "un" : "");
-
+ s->unselect = unselect;
qemu_set_irq(s->cs_lines[fl->cs], unselect);
}
@@ -677,22 +677,35 @@ static const MemoryRegionOps aspeed_smc_flash_ops = {
static void aspeed_smc_flash_update_ctrl(AspeedSMCFlash *fl, uint32_t value)
{
AspeedSMCState *s = fl->controller;
- bool unselect;
+ bool unselect = false;
+ uint32_t old_mode;
+ uint32_t new_mode;
+
+ old_mode = s->regs[s->r_ctrl0 + fl->cs] & CTRL_CMD_MODE_MASK;
+ new_mode = value & CTRL_CMD_MODE_MASK;
- /* User mode selects the CS, other modes unselect */
- unselect = (value & CTRL_CMD_MODE_MASK) != CTRL_USERMODE;
+ if (old_mode == CTRL_USERMODE) {
+ if (new_mode != CTRL_USERMODE) {
+ unselect = true;
+ }
- /* A change of CTRL_CE_STOP_ACTIVE from 0 to 1, unselects the CS */
- if (!(s->regs[s->r_ctrl0 + fl->cs] & CTRL_CE_STOP_ACTIVE) &&
- value & CTRL_CE_STOP_ACTIVE) {
- unselect = true;
+ /* A change of CTRL_CE_STOP_ACTIVE from 0 to 1, unselects the CS */
+ if (!(s->regs[s->r_ctrl0 + fl->cs] & CTRL_CE_STOP_ACTIVE) &&
+ value & CTRL_CE_STOP_ACTIVE) {
+ unselect = true;
+ }
+ } else {
+ if (new_mode != CTRL_USERMODE) {
+ unselect = true;
+ }
}
s->regs[s->r_ctrl0 + fl->cs] = value;
- s->snoop_index = unselect ? SNOOP_OFF : SNOOP_START;
-
- aspeed_smc_flash_do_select(fl, unselect);
+ if (unselect != s->unselect) {
+ s->snoop_index = unselect ? SNOOP_OFF : SNOOP_START;
+ aspeed_smc_flash_do_select(fl, unselect);
+ }
}
static void aspeed_smc_reset(DeviceState *d)
@@ -729,6 +742,8 @@ static void aspeed_smc_reset(DeviceState *d)
qemu_set_irq(s->cs_lines[i], true);
}
+ s->unselect = true;
+
/* setup the default segment register values and regions for all */
for (i = 0; i < asc->cs_num_max; ++i) {
aspeed_smc_flash_set_segment_region(s, i,
@@ -789,8 +804,7 @@ static uint8_t aspeed_smc_hclk_divisor(uint8_t hclk_mask)
}
}
- aspeed_smc_error("invalid HCLK mask %x", hclk_mask);
- return 0;
+ g_assert_not_reached();
}
/*
@@ -1262,12 +1276,13 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp)
static const VMStateDescription vmstate_aspeed_smc = {
.name = "aspeed.smc",
- .version_id = 2,
+ .version_id = 3,
.minimum_version_id = 2,
.fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, AspeedSMCState, ASPEED_SMC_R_MAX),
VMSTATE_UINT8(snoop_index, AspeedSMCState),
VMSTATE_UINT8(snoop_dummies, AspeedSMCState),
+ VMSTATE_BOOL_V(unselect, AspeedSMCState, 3),
VMSTATE_END_OF_LIST()
}
};
@@ -1285,7 +1300,7 @@ static void aspeed_smc_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_smc_realize;
- dc->reset = aspeed_smc_reset;
+ device_class_set_legacy_reset(dc, aspeed_smc_reset);
device_class_set_props(dc, aspeed_smc_properties);
dc->vmsd = &vmstate_aspeed_smc;
}
diff --git a/hw/ssi/bcm2835_spi.c b/hw/ssi/bcm2835_spi.c
index 6ecb42d..ebd8809 100644
--- a/hw/ssi/bcm2835_spi.c
+++ b/hw/ssi/bcm2835_spi.c
@@ -268,7 +268,7 @@ static void bcm2835_spi_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = bcm2835_spi_reset;
+ device_class_set_legacy_reset(dc, bcm2835_spi_reset);
dc->realize = bcm2835_spi_realize;
dc->vmsd = &vmstate_bcm2835_spi;
}
diff --git a/hw/ssi/ibex_spi_host.c b/hw/ssi/ibex_spi_host.c
index 863b5fd..9e07432 100644
--- a/hw/ssi/ibex_spi_host.c
+++ b/hw/ssi/ibex_spi_host.c
@@ -628,7 +628,7 @@ static void ibex_spi_host_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = ibex_spi_host_realize;
- dc->reset = ibex_spi_host_reset;
+ device_class_set_legacy_reset(dc, ibex_spi_host_reset);
dc->vmsd = &vmstate_ibex;
device_class_set_props(dc, ibex_spi_properties);
}
diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c
index 12d897d..2e31787 100644
--- a/hw/ssi/imx_spi.c
+++ b/hw/ssi/imx_spi.c
@@ -481,7 +481,7 @@ static void imx_spi_class_init(ObjectClass *klass, void *data)
dc->realize = imx_spi_realize;
dc->vmsd = &vmstate_imx_spi;
- dc->reset = imx_spi_reset;
+ device_class_set_legacy_reset(dc, imx_spi_reset);
dc->desc = "i.MX SPI Controller";
}
diff --git a/hw/ssi/meson.build b/hw/ssi/meson.build
index b999aeb..6afb1ea 100644
--- a/hw/ssi/meson.build
+++ b/hw/ssi/meson.build
@@ -1,3 +1,4 @@
+system_ss.add(when: 'CONFIG_ALLWINNER_A10_SPI', if_true: files('allwinner-a10-spi.c'))
system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_smc.c'))
system_ss.add(when: 'CONFIG_MSF2', if_true: files('mss-spi.c'))
system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_fiu.c', 'npcm_pspi.c'))
@@ -9,6 +10,6 @@ system_ss.add(when: 'CONFIG_XILINX_SPI', if_true: files('xilinx_spi.c'))
system_ss.add(when: 'CONFIG_XILINX_SPIPS', if_true: files('xilinx_spips.c'))
system_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-ospi.c'))
system_ss.add(when: 'CONFIG_IMX', if_true: files('imx_spi.c'))
-system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_spi.c'))
system_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_spi_host.c'))
system_ss.add(when: 'CONFIG_BCM2835_SPI', if_true: files('bcm2835_spi.c'))
+system_ss.add(when: 'CONFIG_PNV_SPI', if_true: files('pnv_spi.c'))
diff --git a/hw/ssi/mss-spi.c b/hw/ssi/mss-spi.c
index 1d25ba2..340adcd 100644
--- a/hw/ssi/mss-spi.c
+++ b/hw/ssi/mss-spi.c
@@ -403,7 +403,7 @@ static void mss_spi_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = mss_spi_realize;
- dc->reset = mss_spi_reset;
+ device_class_set_legacy_reset(dc, mss_spi_reset);
dc->vmsd = &vmstate_mss_spi;
}
diff --git a/hw/ssi/omap_spi.c b/hw/ssi/omap_spi.c
deleted file mode 100644
index 8f85c3e..0000000
--- a/hw/ssi/omap_spi.c
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * TI OMAP processor's Multichannel SPI emulation.
- *
- * Copyright (C) 2007-2009 Nokia Corporation
- *
- * Original code for OMAP2 by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/log.h"
-#include "hw/hw.h"
-#include "hw/irq.h"
-#include "hw/arm/omap.h"
-
-/* Multichannel SPI */
-struct omap_mcspi_s {
- MemoryRegion iomem;
- qemu_irq irq;
- int chnum;
-
- uint32_t sysconfig;
- uint32_t systest;
- uint32_t irqst;
- uint32_t irqen;
- uint32_t wken;
- uint32_t control;
-
- struct omap_mcspi_ch_s {
- qemu_irq txdrq;
- qemu_irq rxdrq;
- uint32_t (*txrx)(void *opaque, uint32_t, int);
- void *opaque;
-
- uint32_t tx;
- uint32_t rx;
-
- uint32_t config;
- uint32_t status;
- uint32_t control;
- } ch[4];
-};
-
-static inline void omap_mcspi_interrupt_update(struct omap_mcspi_s *s)
-{
- qemu_set_irq(s->irq, s->irqst & s->irqen);
-}
-
-static inline void omap_mcspi_dmarequest_update(struct omap_mcspi_ch_s *ch)
-{
- qemu_set_irq(ch->txdrq,
- (ch->control & 1) && /* EN */
- (ch->config & (1 << 14)) && /* DMAW */
- (ch->status & (1 << 1)) && /* TXS */
- ((ch->config >> 12) & 3) != 1); /* TRM */
- qemu_set_irq(ch->rxdrq,
- (ch->control & 1) && /* EN */
- (ch->config & (1 << 15)) && /* DMAW */
- (ch->status & (1 << 0)) && /* RXS */
- ((ch->config >> 12) & 3) != 2); /* TRM */
-}
-
-static void omap_mcspi_transfer_run(struct omap_mcspi_s *s, int chnum)
-{
- struct omap_mcspi_ch_s *ch = s->ch + chnum;
-
- if (!(ch->control & 1)) /* EN */
- return;
- if ((ch->status & (1 << 0)) && /* RXS */
- ((ch->config >> 12) & 3) != 2 && /* TRM */
- !(ch->config & (1 << 19))) /* TURBO */
- goto intr_update;
- if ((ch->status & (1 << 1)) && /* TXS */
- ((ch->config >> 12) & 3) != 1) /* TRM */
- goto intr_update;
-
- if (!(s->control & 1) || /* SINGLE */
- (ch->config & (1 << 20))) { /* FORCE */
- if (ch->txrx)
- ch->rx = ch->txrx(ch->opaque, ch->tx, /* WL */
- 1 + (0x1f & (ch->config >> 7)));
- }
-
- ch->tx = 0;
- ch->status |= 1 << 2; /* EOT */
- ch->status |= 1 << 1; /* TXS */
- if (((ch->config >> 12) & 3) != 2) /* TRM */
- ch->status |= 1 << 0; /* RXS */
-
-intr_update:
- if ((ch->status & (1 << 0)) && /* RXS */
- ((ch->config >> 12) & 3) != 2 && /* TRM */
- !(ch->config & (1 << 19))) /* TURBO */
- s->irqst |= 1 << (2 + 4 * chnum); /* RX_FULL */
- if ((ch->status & (1 << 1)) && /* TXS */
- ((ch->config >> 12) & 3) != 1) /* TRM */
- s->irqst |= 1 << (0 + 4 * chnum); /* TX_EMPTY */
- omap_mcspi_interrupt_update(s);
- omap_mcspi_dmarequest_update(ch);
-}
-
-void omap_mcspi_reset(struct omap_mcspi_s *s)
-{
- int ch;
-
- s->sysconfig = 0;
- s->systest = 0;
- s->irqst = 0;
- s->irqen = 0;
- s->wken = 0;
- s->control = 4;
-
- for (ch = 0; ch < 4; ch ++) {
- s->ch[ch].config = 0x060000;
- s->ch[ch].status = 2; /* TXS */
- s->ch[ch].control = 0;
-
- omap_mcspi_dmarequest_update(s->ch + ch);
- }
-
- omap_mcspi_interrupt_update(s);
-}
-
-static uint64_t omap_mcspi_read(void *opaque, hwaddr addr, unsigned size)
-{
- struct omap_mcspi_s *s = opaque;
- int ch = 0;
- uint32_t ret;
-
- if (size != 4) {
- return omap_badwidth_read32(opaque, addr);
- }
-
- switch (addr) {
- case 0x00: /* MCSPI_REVISION */
- return 0x91;
-
- case 0x10: /* MCSPI_SYSCONFIG */
- return s->sysconfig;
-
- case 0x14: /* MCSPI_SYSSTATUS */
- return 1; /* RESETDONE */
-
- case 0x18: /* MCSPI_IRQSTATUS */
- return s->irqst;
-
- case 0x1c: /* MCSPI_IRQENABLE */
- return s->irqen;
-
- case 0x20: /* MCSPI_WAKEUPENABLE */
- return s->wken;
-
- case 0x24: /* MCSPI_SYST */
- return s->systest;
-
- case 0x28: /* MCSPI_MODULCTRL */
- return s->control;
-
- case 0x68: ch ++;
- /* fall through */
- case 0x54: ch ++;
- /* fall through */
- case 0x40: ch ++;
- /* fall through */
- case 0x2c: /* MCSPI_CHCONF */
- return s->ch[ch].config;
-
- case 0x6c: ch ++;
- /* fall through */
- case 0x58: ch ++;
- /* fall through */
- case 0x44: ch ++;
- /* fall through */
- case 0x30: /* MCSPI_CHSTAT */
- return s->ch[ch].status;
-
- case 0x70: ch ++;
- /* fall through */
- case 0x5c: ch ++;
- /* fall through */
- case 0x48: ch ++;
- /* fall through */
- case 0x34: /* MCSPI_CHCTRL */
- return s->ch[ch].control;
-
- case 0x74: ch ++;
- /* fall through */
- case 0x60: ch ++;
- /* fall through */
- case 0x4c: ch ++;
- /* fall through */
- case 0x38: /* MCSPI_TX */
- return s->ch[ch].tx;
-
- case 0x78: ch ++;
- /* fall through */
- case 0x64: ch ++;
- /* fall through */
- case 0x50: ch ++;
- /* fall through */
- case 0x3c: /* MCSPI_RX */
- s->ch[ch].status &= ~(1 << 0); /* RXS */
- ret = s->ch[ch].rx;
- omap_mcspi_transfer_run(s, ch);
- return ret;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_mcspi_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_mcspi_s *s = opaque;
- int ch = 0;
-
- if (size != 4) {
- omap_badwidth_write32(opaque, addr, value);
- return;
- }
-
- switch (addr) {
- case 0x00: /* MCSPI_REVISION */
- case 0x14: /* MCSPI_SYSSTATUS */
- case 0x30: /* MCSPI_CHSTAT0 */
- case 0x3c: /* MCSPI_RX0 */
- case 0x44: /* MCSPI_CHSTAT1 */
- case 0x50: /* MCSPI_RX1 */
- case 0x58: /* MCSPI_CHSTAT2 */
- case 0x64: /* MCSPI_RX2 */
- case 0x6c: /* MCSPI_CHSTAT3 */
- case 0x78: /* MCSPI_RX3 */
- OMAP_RO_REG(addr);
- return;
-
- case 0x10: /* MCSPI_SYSCONFIG */
- if (value & (1 << 1)) /* SOFTRESET */
- omap_mcspi_reset(s);
- s->sysconfig = value & 0x31d;
- break;
-
- case 0x18: /* MCSPI_IRQSTATUS */
- if (!((s->control & (1 << 3)) && (s->systest & (1 << 11)))) {
- s->irqst &= ~value;
- omap_mcspi_interrupt_update(s);
- }
- break;
-
- case 0x1c: /* MCSPI_IRQENABLE */
- s->irqen = value & 0x1777f;
- omap_mcspi_interrupt_update(s);
- break;
-
- case 0x20: /* MCSPI_WAKEUPENABLE */
- s->wken = value & 1;
- break;
-
- case 0x24: /* MCSPI_SYST */
- if (s->control & (1 << 3)) /* SYSTEM_TEST */
- if (value & (1 << 11)) { /* SSB */
- s->irqst |= 0x1777f;
- omap_mcspi_interrupt_update(s);
- }
- s->systest = value & 0xfff;
- break;
-
- case 0x28: /* MCSPI_MODULCTRL */
- if (value & (1 << 3)) /* SYSTEM_TEST */
- if (s->systest & (1 << 11)) { /* SSB */
- s->irqst |= 0x1777f;
- omap_mcspi_interrupt_update(s);
- }
- s->control = value & 0xf;
- break;
-
- case 0x68: ch ++;
- /* fall through */
- case 0x54: ch ++;
- /* fall through */
- case 0x40: ch ++;
- /* fall through */
- case 0x2c: /* MCSPI_CHCONF */
- if ((value ^ s->ch[ch].config) & (3 << 14)) /* DMAR | DMAW */
- omap_mcspi_dmarequest_update(s->ch + ch);
- if (((value >> 12) & 3) == 3) { /* TRM */
- qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid TRM value (3)\n",
- __func__);
- }
- if (((value >> 7) & 0x1f) < 3) { /* WL */
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: invalid WL value (%" PRIx64 ")\n",
- __func__, (value >> 7) & 0x1f);
- }
- s->ch[ch].config = value & 0x7fffff;
- break;
-
- case 0x70: ch ++;
- /* fall through */
- case 0x5c: ch ++;
- /* fall through */
- case 0x48: ch ++;
- /* fall through */
- case 0x34: /* MCSPI_CHCTRL */
- if (value & ~s->ch[ch].control & 1) { /* EN */
- s->ch[ch].control |= 1;
- omap_mcspi_transfer_run(s, ch);
- } else
- s->ch[ch].control = value & 1;
- break;
-
- case 0x74: ch ++;
- /* fall through */
- case 0x60: ch ++;
- /* fall through */
- case 0x4c: ch ++;
- /* fall through */
- case 0x38: /* MCSPI_TX */
- s->ch[ch].tx = value;
- s->ch[ch].status &= ~(1 << 1); /* TXS */
- omap_mcspi_transfer_run(s, ch);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- return;
- }
-}
-
-static const MemoryRegionOps omap_mcspi_ops = {
- .read = omap_mcspi_read,
- .write = omap_mcspi_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
- qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk)
-{
- struct omap_mcspi_s *s = g_new0(struct omap_mcspi_s, 1);
- struct omap_mcspi_ch_s *ch = s->ch;
-
- s->irq = irq;
- s->chnum = chnum;
- while (chnum --) {
- ch->txdrq = *drq ++;
- ch->rxdrq = *drq ++;
- ch ++;
- }
- omap_mcspi_reset(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_mcspi_ops, s, "omap.mcspi",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &s->iomem);
-
- return s;
-}
-
-void omap_mcspi_attach(struct omap_mcspi_s *s,
- uint32_t (*txrx)(void *opaque, uint32_t, int), void *opaque,
- int chipselect)
-{
- if (chipselect < 0 || chipselect >= s->chnum)
- hw_error("%s: Bad chipselect %i\n", __func__, chipselect);
-
- s->ch[chipselect].txrx = txrx;
- s->ch[chipselect].opaque = opaque;
-}
diff --git a/hw/ssi/pl022.c b/hw/ssi/pl022.c
index b8be8dd..53c9c22 100644
--- a/hw/ssi/pl022.c
+++ b/hw/ssi/pl022.c
@@ -296,7 +296,7 @@ static void pl022_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = pl022_reset;
+ device_class_set_legacy_reset(dc, pl022_reset);
dc->vmsd = &vmstate_pl022;
dc->realize = pl022_realize;
}
diff --git a/hw/ssi/pnv_spi.c b/hw/ssi/pnv_spi.c
new file mode 100644
index 0000000..9e7207b
--- /dev/null
+++ b/hw/ssi/pnv_spi.c
@@ -0,0 +1,1268 @@
+/*
+ * QEMU PowerPC SPI model
+ *
+ * Copyright (c) 2024, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "hw/qdev-properties.h"
+#include "hw/ppc/pnv_xscom.h"
+#include "hw/ssi/pnv_spi.h"
+#include "hw/ssi/pnv_spi_regs.h"
+#include "hw/ssi/ssi.h"
+#include <libfdt.h>
+#include "hw/irq.h"
+#include "trace.h"
+
+#define PNV_SPI_OPCODE_LO_NIBBLE(x) (x & 0x0F)
+#define PNV_SPI_MASKED_OPCODE(x) (x & 0xF0)
+
+/*
+ * Macro from include/hw/ppc/fdt.h
+ * fdt.h cannot be included here as it contain ppc target specific dependency.
+ */
+#define _FDT(exp) \
+ do { \
+ int _ret = (exp); \
+ if (_ret < 0) { \
+ qemu_log_mask(LOG_GUEST_ERROR, \
+ "error creating device tree: %s: %s", \
+ #exp, fdt_strerror(_ret)); \
+ exit(1); \
+ } \
+ } while (0)
+
+/* PnvXferBuffer */
+typedef struct PnvXferBuffer {
+
+ uint32_t len;
+ uint8_t *data;
+
+} PnvXferBuffer;
+
+/* pnv_spi_xfer_buffer_methods */
+static PnvXferBuffer *pnv_spi_xfer_buffer_new(void)
+{
+ PnvXferBuffer *payload = g_malloc0(sizeof(*payload));
+
+ return payload;
+}
+
+static void pnv_spi_xfer_buffer_free(PnvXferBuffer *payload)
+{
+ free(payload->data);
+ free(payload);
+}
+
+static uint8_t *pnv_spi_xfer_buffer_write_ptr(PnvXferBuffer *payload,
+ uint32_t offset, uint32_t length)
+{
+ if (payload->len < (offset + length)) {
+ payload->len = offset + length;
+ payload->data = g_realloc(payload->data, payload->len);
+ }
+ return &payload->data[offset];
+}
+
+static bool does_rdr_match(PnvSpi *s)
+{
+ /*
+ * According to spec, the mask bits that are 0 are compared and the
+ * bits that are 1 are ignored.
+ */
+ uint16_t rdr_match_mask = GETFIELD(SPI_MM_RDR_MATCH_MASK,
+ s->regs[SPI_MM_REG]);
+ uint16_t rdr_match_val = GETFIELD(SPI_MM_RDR_MATCH_VAL,
+ s->regs[SPI_MM_REG]);
+
+ if ((~rdr_match_mask & rdr_match_val) == ((~rdr_match_mask) &
+ GETFIELD(PPC_BITMASK(48, 63), s->regs[SPI_RCV_DATA_REG]))) {
+ return true;
+ }
+ return false;
+}
+
+static uint8_t get_from_offset(PnvSpi *s, uint8_t offset)
+{
+ uint8_t byte;
+
+ /*
+ * Offset is an index between 0 and PNV_SPI_REG_SIZE - 1
+ * Check the offset before using it.
+ */
+ if (offset < PNV_SPI_REG_SIZE) {
+ byte = (s->regs[SPI_XMIT_DATA_REG] >> (56 - offset * 8)) & 0xFF;
+ } else {
+ /*
+ * Log an error and return a 0xFF since we have to assign something
+ * to byte before returning.
+ */
+ qemu_log_mask(LOG_GUEST_ERROR, "Invalid offset = %d used to get byte "
+ "from TDR\n", offset);
+ byte = 0xff;
+ }
+ return byte;
+}
+
+static uint8_t read_from_frame(PnvSpi *s, uint8_t *read_buf, uint8_t nr_bytes,
+ uint8_t ecc_count, uint8_t shift_in_count)
+{
+ uint8_t byte;
+ int count = 0;
+
+ while (count < nr_bytes) {
+ shift_in_count++;
+ if ((ecc_count != 0) &&
+ (shift_in_count == (PNV_SPI_REG_SIZE + ecc_count))) {
+ shift_in_count = 0;
+ } else {
+ byte = read_buf[count];
+ trace_pnv_spi_shift_rx(byte, count);
+ s->regs[SPI_RCV_DATA_REG] = (s->regs[SPI_RCV_DATA_REG] << 8) | byte;
+ }
+ count++;
+ } /* end of while */
+ return shift_in_count;
+}
+
+static void spi_response(PnvSpi *s, int bits, PnvXferBuffer *rsp_payload)
+{
+ uint8_t ecc_count;
+ uint8_t shift_in_count;
+
+ /*
+ * Processing here must handle:
+ * - Which bytes in the payload we should move to the RDR
+ * - Explicit mode counter configuration settings
+ * - RDR full and RDR overrun status
+ */
+
+ /*
+ * First check that the response payload is the exact same
+ * number of bytes as the request payload was
+ */
+ if (rsp_payload->len != (s->N1_bytes + s->N2_bytes)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "Invalid response payload size in "
+ "bytes, expected %d, got %d\n",
+ (s->N1_bytes + s->N2_bytes), rsp_payload->len);
+ } else {
+ uint8_t ecc_control;
+ trace_pnv_spi_rx_received(rsp_payload->len);
+ trace_pnv_spi_log_Ncounts(s->N1_bits, s->N1_bytes, s->N1_tx,
+ s->N1_rx, s->N2_bits, s->N2_bytes, s->N2_tx, s->N2_rx);
+ /*
+ * Adding an ECC count let's us know when we have found a payload byte
+ * that was shifted in but cannot be loaded into RDR. Bits 29-30 of
+ * clock_config_reset_control register equal to either 0b00 or 0b10
+ * indicate that we are taking in data with ECC and either applying
+ * the ECC or discarding it.
+ */
+ ecc_count = 0;
+ ecc_control = GETFIELD(SPI_CLK_CFG_ECC_CTRL, s->regs[SPI_CLK_CFG_REG]);
+ if (ecc_control == 0 || ecc_control == 2) {
+ ecc_count = 1;
+ }
+ /*
+ * Use the N1_rx and N2_rx counts to control shifting data from the
+ * payload into the RDR. Keep an overall count of the number of bytes
+ * shifted into RDR so we can discard every 9th byte when ECC is
+ * enabled.
+ */
+ shift_in_count = 0;
+ /* Handle the N1 portion of the frame first */
+ if (s->N1_rx != 0) {
+ trace_pnv_spi_rx_read_N1frame();
+ shift_in_count = read_from_frame(s, &rsp_payload->data[0],
+ s->N1_bytes, ecc_count, shift_in_count);
+ }
+ /* Handle the N2 portion of the frame */
+ if (s->N2_rx != 0) {
+ trace_pnv_spi_rx_read_N2frame();
+ shift_in_count = read_from_frame(s,
+ &rsp_payload->data[s->N1_bytes], s->N2_bytes,
+ ecc_count, shift_in_count);
+ }
+ if ((s->N1_rx + s->N2_rx) > 0) {
+ /*
+ * Data was received so handle RDR status.
+ * It is easier to handle RDR_full and RDR_overrun status here
+ * since the RDR register's shift_byte_in method is called
+ * multiple times in a row. Controlling RDR status is done here
+ * instead of in the RDR scoped methods for that reason.
+ */
+ if (GETFIELD(SPI_STS_RDR_FULL, s->status) == 1) {
+ /*
+ * Data was shifted into the RDR before having been read
+ * causing previous data to have been overrun.
+ */
+ s->status = SETFIELD(SPI_STS_RDR_OVERRUN, s->status, 1);
+ } else {
+ /*
+ * Set status to indicate that the received data register is
+ * full. This flag is only cleared once the RDR is unloaded.
+ */
+ s->status = SETFIELD(SPI_STS_RDR_FULL, s->status, 1);
+ }
+ }
+ } /* end of else */
+} /* end of spi_response() */
+
+static void transfer(PnvSpi *s, PnvXferBuffer *payload)
+{
+ uint32_t tx;
+ uint32_t rx;
+ PnvXferBuffer *rsp_payload = NULL;
+
+ rsp_payload = pnv_spi_xfer_buffer_new();
+ for (int offset = 0; offset < payload->len; offset += s->transfer_len) {
+ tx = 0;
+ for (int i = 0; i < s->transfer_len; i++) {
+ if ((offset + i) >= payload->len) {
+ tx <<= 8;
+ } else {
+ tx = (tx << 8) | payload->data[offset + i];
+ }
+ }
+ rx = ssi_transfer(s->ssi_bus, tx);
+ for (int i = 0; i < s->transfer_len; i++) {
+ if ((offset + i) >= payload->len) {
+ break;
+ }
+ *(pnv_spi_xfer_buffer_write_ptr(rsp_payload, rsp_payload->len, 1)) =
+ (rx >> (8 * (s->transfer_len - 1) - i * 8)) & 0xFF;
+ }
+ }
+ if (rsp_payload != NULL) {
+ spi_response(s, s->N1_bits, rsp_payload);
+ }
+}
+
+static inline uint8_t get_seq_index(PnvSpi *s)
+{
+ return GETFIELD(SPI_STS_SEQ_INDEX, s->status);
+}
+
+static inline void next_sequencer_fsm(PnvSpi *s)
+{
+ uint8_t seq_index = get_seq_index(s);
+ s->status = SETFIELD(SPI_STS_SEQ_INDEX, s->status, (seq_index + 1));
+ s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_INDEX_INCREMENT);
+}
+
+/*
+ * Calculate the N1 counters based on passed in opcode and
+ * internal register values.
+ * The method assumes that the opcode is a Shift_N1 opcode
+ * and doesn't test it.
+ * The counters returned are:
+ * N1 bits: Number of bits in the payload data that are significant
+ * to the responder.
+ * N1_bytes: Total count of payload bytes for the N1 (portion of the) frame.
+ * N1_tx: Total number of bytes taken from TDR for N1
+ * N1_rx: Total number of bytes taken from the payload for N1
+ */
+static void calculate_N1(PnvSpi *s, uint8_t opcode)
+{
+ /*
+ * Shift_N1 opcode form: 0x3M
+ * Implicit mode:
+ * If M != 0 the shift count is M bytes and M is the number of tx bytes.
+ * Forced Implicit mode:
+ * M is the shift count but tx and rx is determined by the count control
+ * register fields. Note that we only check for forced Implicit mode when
+ * M != 0 since the mode doesn't make sense when M = 0.
+ * Explicit mode:
+ * If M == 0 then shift count is number of bits defined in the
+ * Counter Configuration Register's shift_count_N1 field.
+ */
+ if (PNV_SPI_OPCODE_LO_NIBBLE(opcode) == 0) {
+ /* Explicit mode */
+ s->N1_bits = GETFIELD(SPI_CTR_CFG_N1, s->regs[SPI_CTR_CFG_REG]);
+ s->N1_bytes = (s->N1_bits + 7) / 8;
+ s->N1_tx = 0;
+ s->N1_rx = 0;
+ /* If tx count control for N1 is set, load the tx value */
+ if (GETFIELD(SPI_CTR_CFG_N1_CTRL_B2, s->regs[SPI_CTR_CFG_REG]) == 1) {
+ s->N1_tx = s->N1_bytes;
+ }
+ /* If rx count control for N1 is set, load the rx value */
+ if (GETFIELD(SPI_CTR_CFG_N1_CTRL_B3, s->regs[SPI_CTR_CFG_REG]) == 1) {
+ s->N1_rx = s->N1_bytes;
+ }
+ } else {
+ /* Implicit mode/Forced Implicit mode, use M field from opcode */
+ s->N1_bytes = PNV_SPI_OPCODE_LO_NIBBLE(opcode);
+ s->N1_bits = s->N1_bytes * 8;
+ /*
+ * Assume that we are going to transmit the count
+ * (pure Implicit only)
+ */
+ s->N1_tx = s->N1_bytes;
+ s->N1_rx = 0;
+ /* Let Forced Implicit mode have an effect on the counts */
+ if (GETFIELD(SPI_CTR_CFG_N1_CTRL_B1, s->regs[SPI_CTR_CFG_REG]) == 1) {
+ /*
+ * If Forced Implicit mode and count control doesn't
+ * indicate transmit then reset the tx count to 0
+ */
+ if (GETFIELD(SPI_CTR_CFG_N1_CTRL_B2,
+ s->regs[SPI_CTR_CFG_REG]) == 0) {
+ s->N1_tx = 0;
+ }
+ /* If rx count control for N1 is set, load the rx value */
+ if (GETFIELD(SPI_CTR_CFG_N1_CTRL_B3,
+ s->regs[SPI_CTR_CFG_REG]) == 1) {
+ s->N1_rx = s->N1_bytes;
+ }
+ }
+ }
+ /*
+ * Enforce an upper limit on the size of N1 that is equal to the known size
+ * of the shift register, 64 bits or 72 bits if ECC is enabled.
+ * If the size exceeds 72 bits it is a user error so log an error,
+ * cap the size at a max of 64 bits or 72 bits and set the sequencer FSM
+ * error bit.
+ */
+ uint8_t ecc_control = GETFIELD(SPI_CLK_CFG_ECC_CTRL,
+ s->regs[SPI_CLK_CFG_REG]);
+ if (ecc_control == 0 || ecc_control == 2) {
+ if (s->N1_bytes > (PNV_SPI_REG_SIZE + 1)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "Unsupported N1 shift size when "
+ "ECC enabled, bytes = 0x%x, bits = 0x%x\n",
+ s->N1_bytes, s->N1_bits);
+ s->N1_bytes = PNV_SPI_REG_SIZE + 1;
+ s->N1_bits = s->N1_bytes * 8;
+ }
+ } else if (s->N1_bytes > PNV_SPI_REG_SIZE) {
+ qemu_log_mask(LOG_GUEST_ERROR, "Unsupported N1 shift size, "
+ "bytes = 0x%x, bits = 0x%x\n",
+ s->N1_bytes, s->N1_bits);
+ s->N1_bytes = PNV_SPI_REG_SIZE;
+ s->N1_bits = s->N1_bytes * 8;
+ }
+} /* end of calculate_N1 */
+
+/*
+ * Shift_N1 operation handler method
+ */
+static bool operation_shiftn1(PnvSpi *s, uint8_t opcode,
+ PnvXferBuffer **payload, bool send_n1_alone)
+{
+ uint8_t n1_count;
+ bool stop = false;
+
+ /*
+ * If there isn't a current payload left over from a stopped sequence
+ * create a new one.
+ */
+ if (*payload == NULL) {
+ *payload = pnv_spi_xfer_buffer_new();
+ }
+ /*
+ * Use a combination of N1 counters to build the N1 portion of the
+ * transmit payload.
+ * We only care about transmit at this time since the request payload
+ * only represents data going out on the controller output line.
+ * Leave mode specific considerations in the calculate function since
+ * all we really care about are counters that tell use exactly how
+ * many bytes are in the payload and how many of those bytes to
+ * include from the TDR into the payload.
+ */
+ calculate_N1(s, opcode);
+ trace_pnv_spi_log_Ncounts(s->N1_bits, s->N1_bytes, s->N1_tx,
+ s->N1_rx, s->N2_bits, s->N2_bytes, s->N2_tx, s->N2_rx);
+ /*
+ * Zero out the N2 counters here in case there is no N2 operation following
+ * the N1 operation in the sequencer. This keeps leftover N2 information
+ * from interfering with spi_response logic.
+ */
+ s->N2_bits = 0;
+ s->N2_bytes = 0;
+ s->N2_tx = 0;
+ s->N2_rx = 0;
+ /*
+ * N1_bytes is the overall size of the N1 portion of the frame regardless of
+ * whether N1 is used for tx, rx or both. Loop over the size to build a
+ * payload that is N1_bytes long.
+ * N1_tx is the count of bytes to take from the TDR and "shift" into the
+ * frame which means append those bytes to the payload for the N1 portion
+ * of the frame.
+ * If N1_tx is 0 or if the count exceeds the size of the TDR append 0xFF to
+ * the frame until the overall N1 count is reached.
+ */
+ n1_count = 0;
+ while (n1_count < s->N1_bytes) {
+ /*
+ * Assuming that if N1_tx is not equal to 0 then it is the same as
+ * N1_bytes.
+ */
+ if ((s->N1_tx != 0) && (n1_count < PNV_SPI_REG_SIZE)) {
+
+ if (GETFIELD(SPI_STS_TDR_FULL, s->status) == 1) {
+ /*
+ * Note that we are only appending to the payload IF the TDR
+ * is full otherwise we don't touch the payload because we are
+ * going to NOT send the payload and instead tell the sequencer
+ * that called us to stop and wait for a TDR write so we have
+ * data to load into the payload.
+ */
+ uint8_t n1_byte = 0x00;
+ n1_byte = get_from_offset(s, n1_count);
+ trace_pnv_spi_tx_append("n1_byte", n1_byte, n1_count);
+ *(pnv_spi_xfer_buffer_write_ptr(*payload, (*payload)->len, 1)) =
+ n1_byte;
+ } else {
+ /*
+ * We hit a shift_n1 opcode TX but the TDR is empty, tell the
+ * sequencer to stop and break this loop.
+ */
+ trace_pnv_spi_sequencer_stop_requested("Shift N1"
+ "set for transmit but TDR is empty");
+ stop = true;
+ break;
+ }
+ } else {
+ /*
+ * Cases here:
+ * - we are receiving during the N1 frame segment and the RDR
+ * is full so we need to stop until the RDR is read
+ * - we are transmitting and we don't care about RDR status
+ * since we won't be loading RDR during the frame segment.
+ * - we are receiving and the RDR is empty so we allow the operation
+ * to proceed.
+ */
+ if ((s->N1_rx != 0) && (GETFIELD(SPI_STS_RDR_FULL,
+ s->status) == 1)) {
+ trace_pnv_spi_sequencer_stop_requested("shift N1"
+ "set for receive but RDR is full");
+ stop = true;
+ break;
+ } else {
+ trace_pnv_spi_tx_append_FF("n1_byte");
+ *(pnv_spi_xfer_buffer_write_ptr(*payload, (*payload)->len, 1))
+ = 0xff;
+ }
+ }
+ n1_count++;
+ } /* end of while */
+ /*
+ * If we are not stopping due to an empty TDR and we are doing an N1 TX
+ * and the TDR is full we need to clear the TDR_full status.
+ * Do this here instead of up in the loop above so we don't log the message
+ * in every loop iteration.
+ * Ignore the send_n1_alone flag, all that does is defer the TX until the N2
+ * operation, which was found immediately after the current opcode. The TDR
+ * was unloaded and will be shifted so we have to clear the TDR_full status.
+ */
+ if (!stop && (s->N1_tx != 0) &&
+ (GETFIELD(SPI_STS_TDR_FULL, s->status) == 1)) {
+ s->status = SETFIELD(SPI_STS_TDR_FULL, s->status, 0);
+ }
+ /*
+ * There are other reasons why the shifter would stop, such as a TDR empty
+ * or RDR full condition with N1 set to receive. If we haven't stopped due
+ * to either one of those conditions then check if the send_n1_alone flag is
+ * equal to False, indicating the next opcode is an N2 operation, AND if
+ * the N2 counter reload switch (bit 0 of the N2 count control field) is
+ * set. This condition requires a pacing write to "kick" off the N2
+ * shift which includes the N1 shift as well when send_n1_alone is False.
+ */
+ if (!stop && !send_n1_alone &&
+ (GETFIELD(SPI_CTR_CFG_N2_CTRL_B0, s->regs[SPI_CTR_CFG_REG]) == 1)) {
+ trace_pnv_spi_sequencer_stop_requested("N2 counter reload "
+ "active, stop N1 shift, TDR_underrun set to 1");
+ stop = true;
+ s->status = SETFIELD(SPI_STS_TDR_UNDERRUN, s->status, 1);
+ }
+ /*
+ * If send_n1_alone is set AND we have a full TDR then this is the first and
+ * last payload to send and we don't have an N2 frame segment to add to the
+ * payload.
+ */
+ if (send_n1_alone && !stop) {
+ /* We have a TX and a full TDR or an RX and an empty RDR */
+ trace_pnv_spi_tx_request("Shifting N1 frame", (*payload)->len);
+ transfer(s, *payload);
+ /* The N1 frame shift is complete so reset the N1 counters */
+ s->N2_bits = 0;
+ s->N2_bytes = 0;
+ s->N2_tx = 0;
+ s->N2_rx = 0;
+ pnv_spi_xfer_buffer_free(*payload);
+ *payload = NULL;
+ }
+ return stop;
+} /* end of operation_shiftn1() */
+
+/*
+ * Calculate the N2 counters based on passed in opcode and
+ * internal register values.
+ * The method assumes that the opcode is a Shift_N2 opcode
+ * and doesn't test it.
+ * The counters returned are:
+ * N2 bits: Number of bits in the payload data that are significant
+ * to the responder.
+ * N2_bytes: Total count of payload bytes for the N2 frame.
+ * N2_tx: Total number of bytes taken from TDR for N2
+ * N2_rx: Total number of bytes taken from the payload for N2
+ */
+static void calculate_N2(PnvSpi *s, uint8_t opcode)
+{
+ /*
+ * Shift_N2 opcode form: 0x4M
+ * Implicit mode:
+ * If M!=0 the shift count is M bytes and M is the number of rx bytes.
+ * Forced Implicit mode:
+ * M is the shift count but tx and rx is determined by the count control
+ * register fields. Note that we only check for Forced Implicit mode when
+ * M != 0 since the mode doesn't make sense when M = 0.
+ * Explicit mode:
+ * If M==0 then shift count is number of bits defined in the
+ * Counter Configuration Register's shift_count_N1 field.
+ */
+ if (PNV_SPI_OPCODE_LO_NIBBLE(opcode) == 0) {
+ /* Explicit mode */
+ s->N2_bits = GETFIELD(SPI_CTR_CFG_N2, s->regs[SPI_CTR_CFG_REG]);
+ s->N2_bytes = (s->N2_bits + 7) / 8;
+ s->N2_tx = 0;
+ s->N2_rx = 0;
+ /* If tx count control for N2 is set, load the tx value */
+ if (GETFIELD(SPI_CTR_CFG_N2_CTRL_B2, s->regs[SPI_CTR_CFG_REG]) == 1) {
+ s->N2_tx = s->N2_bytes;
+ }
+ /* If rx count control for N2 is set, load the rx value */
+ if (GETFIELD(SPI_CTR_CFG_N2_CTRL_B3, s->regs[SPI_CTR_CFG_REG]) == 1) {
+ s->N2_rx = s->N2_bytes;
+ }
+ } else {
+ /* Implicit mode/Forced Implicit mode, use M field from opcode */
+ s->N2_bytes = PNV_SPI_OPCODE_LO_NIBBLE(opcode);
+ s->N2_bits = s->N2_bytes * 8;
+ /* Assume that we are going to receive the count */
+ s->N2_rx = s->N2_bytes;
+ s->N2_tx = 0;
+ /* Let Forced Implicit mode have an effect on the counts */
+ if (GETFIELD(SPI_CTR_CFG_N2_CTRL_B1, s->regs[SPI_CTR_CFG_REG]) == 1) {
+ /*
+ * If Forced Implicit mode and count control doesn't
+ * indicate a receive then reset the rx count to 0
+ */
+ if (GETFIELD(SPI_CTR_CFG_N2_CTRL_B3,
+ s->regs[SPI_CTR_CFG_REG]) == 0) {
+ s->N2_rx = 0;
+ }
+ /* If tx count control for N2 is set, load the tx value */
+ if (GETFIELD(SPI_CTR_CFG_N2_CTRL_B2,
+ s->regs[SPI_CTR_CFG_REG]) == 1) {
+ s->N2_tx = s->N2_bytes;
+ }
+ }
+ }
+ /*
+ * Enforce an upper limit on the size of N1 that is equal to the
+ * known size of the shift register, 64 bits or 72 bits if ECC
+ * is enabled.
+ * If the size exceeds 72 bits it is a user error so log an error,
+ * cap the size at a max of 64 bits or 72 bits and set the sequencer FSM
+ * error bit.
+ */
+ uint8_t ecc_control = GETFIELD(SPI_CLK_CFG_ECC_CTRL,
+ s->regs[SPI_CLK_CFG_REG]);
+ if (ecc_control == 0 || ecc_control == 2) {
+ if (s->N2_bytes > (PNV_SPI_REG_SIZE + 1)) {
+ /* Unsupported N2 shift size when ECC enabled */
+ s->N2_bytes = PNV_SPI_REG_SIZE + 1;
+ s->N2_bits = s->N2_bytes * 8;
+ }
+ } else if (s->N2_bytes > PNV_SPI_REG_SIZE) {
+ /* Unsupported N2 shift size */
+ s->N2_bytes = PNV_SPI_REG_SIZE;
+ s->N2_bits = s->N2_bytes * 8;
+ }
+} /* end of calculate_N2 */
+
+/*
+ * Shift_N2 operation handler method
+ */
+
+static bool operation_shiftn2(PnvSpi *s, uint8_t opcode,
+ PnvXferBuffer **payload)
+{
+ uint8_t n2_count;
+ bool stop = false;
+
+ /*
+ * If there isn't a current payload left over from a stopped sequence
+ * create a new one.
+ */
+ if (*payload == NULL) {
+ *payload = pnv_spi_xfer_buffer_new();
+ }
+ /*
+ * Use a combination of N2 counters to build the N2 portion of the
+ * transmit payload.
+ */
+ calculate_N2(s, opcode);
+ trace_pnv_spi_log_Ncounts(s->N1_bits, s->N1_bytes, s->N1_tx,
+ s->N1_rx, s->N2_bits, s->N2_bytes, s->N2_tx, s->N2_rx);
+ /*
+ * The only difference between this code and the code for shift N1 is
+ * that this code has to account for the possible presence of N1 transmit
+ * bytes already taken from the TDR.
+ * If there are bytes to be transmitted for the N2 portion of the frame
+ * and there are still bytes in TDR that have not been copied into the
+ * TX data of the payload, this code will handle transmitting those
+ * remaining bytes.
+ * If for some reason the transmit count(s) add up to more than the size
+ * of the TDR we will just append 0xFF to the transmit payload data until
+ * the payload is N1 + N2 bytes long.
+ */
+ n2_count = 0;
+ while (n2_count < s->N2_bytes) {
+ /*
+ * If the RDR is full and we need to RX just bail out, letting the
+ * code continue will end up building the payload twice in the same
+ * buffer since RDR full causes a sequence stop and restart.
+ */
+ if ((s->N2_rx != 0) &&
+ (GETFIELD(SPI_STS_RDR_FULL, s->status) == 1)) {
+ trace_pnv_spi_sequencer_stop_requested("shift N2 set"
+ "for receive but RDR is full");
+ stop = true;
+ break;
+ }
+ if ((s->N2_tx != 0) && ((s->N1_tx + n2_count) <
+ PNV_SPI_REG_SIZE)) {
+ /* Always append data for the N2 segment if it is set for TX */
+ uint8_t n2_byte = 0x00;
+ n2_byte = get_from_offset(s, (s->N1_tx + n2_count));
+ trace_pnv_spi_tx_append("n2_byte", n2_byte, (s->N1_tx + n2_count));
+ *(pnv_spi_xfer_buffer_write_ptr(*payload, (*payload)->len, 1))
+ = n2_byte;
+ } else {
+ /*
+ * Regardless of whether or not N2 is set for TX or RX, we need
+ * the number of bytes in the payload to match the overall length
+ * of the operation.
+ */
+ trace_pnv_spi_tx_append_FF("n2_byte");
+ *(pnv_spi_xfer_buffer_write_ptr(*payload, (*payload)->len, 1))
+ = 0xff;
+ }
+ n2_count++;
+ } /* end of while */
+ if (!stop) {
+ /* We have a TX and a full TDR or an RX and an empty RDR */
+ trace_pnv_spi_tx_request("Shifting N2 frame", (*payload)->len);
+ transfer(s, *payload);
+ /*
+ * If we are doing an N2 TX and the TDR is full we need to clear the
+ * TDR_full status. Do this here instead of up in the loop above so we
+ * don't log the message in every loop iteration.
+ */
+ if ((s->N2_tx != 0) &&
+ (GETFIELD(SPI_STS_TDR_FULL, s->status) == 1)) {
+ s->status = SETFIELD(SPI_STS_TDR_FULL, s->status, 0);
+ }
+ /*
+ * The N2 frame shift is complete so reset the N2 counters.
+ * Reset the N1 counters also in case the frame was a combination of
+ * N1 and N2 segments.
+ */
+ s->N2_bits = 0;
+ s->N2_bytes = 0;
+ s->N2_tx = 0;
+ s->N2_rx = 0;
+ s->N1_bits = 0;
+ s->N1_bytes = 0;
+ s->N1_tx = 0;
+ s->N1_rx = 0;
+ pnv_spi_xfer_buffer_free(*payload);
+ *payload = NULL;
+ }
+ return stop;
+} /* end of operation_shiftn2()*/
+
+static void operation_sequencer(PnvSpi *s)
+{
+ /*
+ * Loop through each sequencer operation ID and perform the requested
+ * operations.
+ * Flag for indicating if we should send the N1 frame or wait to combine
+ * it with a preceding N2 frame.
+ */
+ bool send_n1_alone = true;
+ bool stop = false; /* Flag to stop the sequencer */
+ uint8_t opcode = 0;
+ uint8_t masked_opcode = 0;
+
+ /*
+ * PnvXferBuffer for containing the payload of the SPI frame.
+ * This is a static because there are cases where a sequence has to stop
+ * and wait for the target application to unload the RDR. If this occurs
+ * during a sequence where N1 is not sent alone and instead combined with
+ * N2 since the N1 tx length + the N2 tx length is less than the size of
+ * the TDR.
+ */
+ static PnvXferBuffer *payload;
+
+ if (payload == NULL) {
+ payload = pnv_spi_xfer_buffer_new();
+ }
+ /*
+ * Clear the sequencer FSM error bit - general_SPI_status[3]
+ * before starting a sequence.
+ */
+ s->status = SETFIELD(SPI_STS_GEN_STATUS_B3, s->status, 0);
+ /*
+ * If the FSM is idle set the sequencer index to 0
+ * (new/restarted sequence)
+ */
+ if (GETFIELD(SPI_STS_SEQ_FSM, s->status) == SEQ_STATE_IDLE) {
+ s->status = SETFIELD(SPI_STS_SEQ_INDEX, s->status, 0);
+ }
+ /*
+ * There are only 8 possible operation IDs to iterate through though
+ * some operations may cause more than one frame to be sequenced.
+ */
+ while (get_seq_index(s) < NUM_SEQ_OPS) {
+ opcode = s->seq_op[get_seq_index(s)];
+ /* Set sequencer state to decode */
+ s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_DECODE);
+ /*
+ * Only the upper nibble of the operation ID is needed to know what
+ * kind of operation is requested.
+ */
+ masked_opcode = PNV_SPI_MASKED_OPCODE(opcode);
+ switch (masked_opcode) {
+ /*
+ * Increment the operation index in each case instead of just
+ * once at the end in case an operation like the branch
+ * operation needs to change the index.
+ */
+ case SEQ_OP_STOP:
+ s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_EXECUTE);
+ /* A stop operation in any position stops the sequencer */
+ trace_pnv_spi_sequencer_op("STOP", get_seq_index(s));
+
+ stop = true;
+ s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status, FSM_IDLE);
+ s->loop_counter_1 = 0;
+ s->loop_counter_2 = 0;
+ s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_IDLE);
+ break;
+
+ case SEQ_OP_SELECT_SLAVE:
+ s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_EXECUTE);
+ trace_pnv_spi_sequencer_op("SELECT_SLAVE", get_seq_index(s));
+ /*
+ * This device currently only supports a single responder
+ * connection at position 0. De-selecting a responder is fine
+ * and expected at the end of a sequence but selecting any
+ * responder other than 0 should cause an error.
+ */
+ s->responder_select = PNV_SPI_OPCODE_LO_NIBBLE(opcode);
+ if (s->responder_select == 0) {
+ trace_pnv_spi_shifter_done();
+ qemu_set_irq(s->cs_line[0], 1);
+ s->status = SETFIELD(SPI_STS_SEQ_INDEX, s->status,
+ (get_seq_index(s) + 1));
+ s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status, FSM_DONE);
+ } else if (s->responder_select != 1) {
+ qemu_log_mask(LOG_GUEST_ERROR, "Slave selection other than 1 "
+ "not supported, select = 0x%x\n",
+ s->responder_select);
+ trace_pnv_spi_sequencer_stop_requested("invalid "
+ "responder select");
+ s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status, FSM_IDLE);
+ stop = true;
+ } else {
+ /*
+ * Only allow an FSM_START state when a responder is
+ * selected
+ */
+ s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status, FSM_START);
+ trace_pnv_spi_shifter_stating();
+ qemu_set_irq(s->cs_line[0], 0);
+ /*
+ * A Shift_N2 operation is only valid after a Shift_N1
+ * according to the spec. The spec doesn't say if that means
+ * immediately after or just after at any point. We will track
+ * the occurrence of a Shift_N1 to enforce this requirement in
+ * the most generic way possible by assuming that the rule
+ * applies once a valid responder select has occurred.
+ */
+ s->shift_n1_done = false;
+ next_sequencer_fsm(s);
+ }
+ break;
+
+ case SEQ_OP_SHIFT_N1:
+ s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_EXECUTE);
+ trace_pnv_spi_sequencer_op("SHIFT_N1", get_seq_index(s));
+ /*
+ * Only allow a shift_n1 when the state is not IDLE or DONE.
+ * In either of those two cases the sequencer is not in a proper
+ * state to perform shift operations because the sequencer has:
+ * - processed a responder deselect (DONE)
+ * - processed a stop opcode (IDLE)
+ * - encountered an error (IDLE)
+ */
+ if ((GETFIELD(SPI_STS_SHIFTER_FSM, s->status) == FSM_IDLE) ||
+ (GETFIELD(SPI_STS_SHIFTER_FSM, s->status) == FSM_DONE)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "Shift_N1 not allowed in "
+ "shifter state = 0x%llx", GETFIELD(
+ SPI_STS_SHIFTER_FSM, s->status));
+ /*
+ * Set sequencer FSM error bit 3 (general_SPI_status[3])
+ * in status reg.
+ */
+ s->status = SETFIELD(SPI_STS_GEN_STATUS_B3, s->status, 1);
+ trace_pnv_spi_sequencer_stop_requested("invalid shifter state");
+ stop = true;
+ } else {
+ /*
+ * Look for the special case where there is a shift_n1 set for
+ * transmit and it is followed by a shift_n2 set for transmit
+ * AND the combined transmit length of the two operations is
+ * less than or equal to the size of the TDR register. In this
+ * case we want to use both this current shift_n1 opcode and the
+ * following shift_n2 opcode to assemble the frame for
+ * transmission to the responder without requiring a refill of
+ * the TDR between the two operations.
+ */
+ if (PNV_SPI_MASKED_OPCODE(s->seq_op[get_seq_index(s) + 1])
+ == SEQ_OP_SHIFT_N2) {
+ send_n1_alone = false;
+ }
+ s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status,
+ FSM_SHIFT_N1);
+ stop = operation_shiftn1(s, opcode, &payload, send_n1_alone);
+ if (stop) {
+ /*
+ * The operation code says to stop, this can occur if:
+ * (1) RDR is full and the N1 shift is set for receive
+ * (2) TDR was empty at the time of the N1 shift so we need
+ * to wait for data.
+ * (3) Neither 1 nor 2 are occurring and we aren't sending
+ * N1 alone and N2 counter reload is set (bit 0 of the N2
+ * counter reload field). In this case TDR_underrun will
+ * will be set and the Payload has been loaded so it is
+ * ok to advance the sequencer.
+ */
+ if (GETFIELD(SPI_STS_TDR_UNDERRUN, s->status)) {
+ s->shift_n1_done = true;
+ s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status,
+ FSM_SHIFT_N2);
+ s->status = SETFIELD(SPI_STS_SEQ_INDEX, s->status,
+ (get_seq_index(s) + 1));
+ } else {
+ /*
+ * This is case (1) or (2) so the sequencer needs to
+ * wait and NOT go to the next sequence yet.
+ */
+ s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status,
+ FSM_WAIT);
+ }
+ } else {
+ /* Ok to move on to the next index */
+ s->shift_n1_done = true;
+ next_sequencer_fsm(s);
+ }
+ }
+ break;
+
+ case SEQ_OP_SHIFT_N2:
+ s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_EXECUTE);
+ trace_pnv_spi_sequencer_op("SHIFT_N2", get_seq_index(s));
+ if (!s->shift_n1_done) {
+ qemu_log_mask(LOG_GUEST_ERROR, "Shift_N2 is not allowed if a "
+ "Shift_N1 is not done, shifter state = 0x%llx",
+ GETFIELD(SPI_STS_SHIFTER_FSM, s->status));
+ /*
+ * In case the sequencer actually stops if an N2 shift is
+ * requested before any N1 shift is done. Set sequencer FSM
+ * error bit 3 (general_SPI_status[3]) in status reg.
+ */
+ s->status = SETFIELD(SPI_STS_GEN_STATUS_B3, s->status, 1);
+ trace_pnv_spi_sequencer_stop_requested("shift_n2 "
+ "w/no shift_n1 done");
+ stop = true;
+ } else {
+ /* Ok to do a Shift_N2 */
+ s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status,
+ FSM_SHIFT_N2);
+ stop = operation_shiftn2(s, opcode, &payload);
+ /*
+ * If the operation code says to stop set the shifter state to
+ * wait and stop
+ */
+ if (stop) {
+ s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status,
+ FSM_WAIT);
+ } else {
+ /* Ok to move on to the next index */
+ next_sequencer_fsm(s);
+ }
+ }
+ break;
+
+ case SEQ_OP_BRANCH_IFNEQ_RDR:
+ s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_EXECUTE);
+ trace_pnv_spi_sequencer_op("BRANCH_IFNEQ_RDR", get_seq_index(s));
+ /*
+ * The memory mapping register RDR match value is compared against
+ * the 16 rightmost bytes of the RDR (potentially with masking).
+ * Since this comparison is performed against the contents of the
+ * RDR then a receive must have previously occurred otherwise
+ * there is no data to compare and the operation cannot be
+ * completed and will stop the sequencer until RDR full is set to
+ * 1.
+ */
+ if (GETFIELD(SPI_STS_RDR_FULL, s->status) == 1) {
+ bool rdr_matched = false;
+ rdr_matched = does_rdr_match(s);
+ if (rdr_matched) {
+ trace_pnv_spi_RDR_match("success");
+ /* A match occurred, increment the sequencer index. */
+ next_sequencer_fsm(s);
+ } else {
+ trace_pnv_spi_RDR_match("failed");
+ /*
+ * Branch the sequencer to the index coded into the op
+ * code.
+ */
+ s->status = SETFIELD(SPI_STS_SEQ_INDEX, s->status,
+ PNV_SPI_OPCODE_LO_NIBBLE(opcode));
+ }
+ /*
+ * Regardless of where the branch ended up we want the
+ * sequencer to continue shifting so we have to clear
+ * RDR_full.
+ */
+ s->status = SETFIELD(SPI_STS_RDR_FULL, s->status, 0);
+ } else {
+ trace_pnv_spi_sequencer_stop_requested("RDR not"
+ "full for 0x6x opcode");
+ stop = true;
+ s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status, FSM_WAIT);
+ }
+ break;
+
+ case SEQ_OP_TRANSFER_TDR:
+ s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_EXECUTE);
+ qemu_log_mask(LOG_GUEST_ERROR, "Transfer TDR is not supported\n");
+ next_sequencer_fsm(s);
+ break;
+
+ case SEQ_OP_BRANCH_IFNEQ_INC_1:
+ s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_EXECUTE);
+ trace_pnv_spi_sequencer_op("BRANCH_IFNEQ_INC_1", get_seq_index(s));
+ /*
+ * The spec says the loop should execute count compare + 1 times.
+ * However we learned from engineering that we really only loop
+ * count_compare times, count compare = 0 makes this op code a
+ * no-op
+ */
+ if (s->loop_counter_1 !=
+ GETFIELD(SPI_CTR_CFG_CMP1, s->regs[SPI_CTR_CFG_REG])) {
+ /*
+ * Next index is the lower nibble of the branch operation ID,
+ * mask off all but the first three bits so we don't try to
+ * access beyond the sequencer_operation_reg boundary.
+ */
+ s->status = SETFIELD(SPI_STS_SEQ_INDEX, s->status,
+ PNV_SPI_OPCODE_LO_NIBBLE(opcode));
+ s->loop_counter_1++;
+ } else {
+ /* Continue to next index if loop counter is reached */
+ next_sequencer_fsm(s);
+ }
+ break;
+
+ case SEQ_OP_BRANCH_IFNEQ_INC_2:
+ s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_EXECUTE);
+ trace_pnv_spi_sequencer_op("BRANCH_IFNEQ_INC_2", get_seq_index(s));
+ uint8_t condition2 = GETFIELD(SPI_CTR_CFG_CMP2,
+ s->regs[SPI_CTR_CFG_REG]);
+ /*
+ * The spec says the loop should execute count compare + 1 times.
+ * However we learned from engineering that we really only loop
+ * count_compare times, count compare = 0 makes this op code a
+ * no-op
+ */
+ if (s->loop_counter_2 != condition2) {
+ /*
+ * Next index is the lower nibble of the branch operation ID,
+ * mask off all but the first three bits so we don't try to
+ * access beyond the sequencer_operation_reg boundary.
+ */
+ s->status = SETFIELD(SPI_STS_SEQ_INDEX,
+ s->status, PNV_SPI_OPCODE_LO_NIBBLE(opcode));
+ s->loop_counter_2++;
+ } else {
+ /* Continue to next index if loop counter is reached */
+ next_sequencer_fsm(s);
+ }
+ break;
+
+ default:
+ s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_EXECUTE);
+ /* Ignore unsupported operations. */
+ next_sequencer_fsm(s);
+ break;
+ } /* end of switch */
+ /*
+ * If we used all 8 opcodes without seeing a 00 - STOP in the sequence
+ * we need to go ahead and end things as if there was a STOP at the
+ * end.
+ */
+ if (get_seq_index(s) == NUM_SEQ_OPS) {
+ /* All 8 opcodes completed, sequencer idling */
+ s->status = SETFIELD(SPI_STS_SHIFTER_FSM, s->status, FSM_IDLE);
+ s->status = SETFIELD(SPI_STS_SEQ_INDEX, s->status, 0);
+ s->loop_counter_1 = 0;
+ s->loop_counter_2 = 0;
+ s->status = SETFIELD(SPI_STS_SEQ_FSM, s->status, SEQ_STATE_IDLE);
+ break;
+ }
+ /* Break the loop if a stop was requested */
+ if (stop) {
+ break;
+ }
+ } /* end of while */
+ return;
+} /* end of operation_sequencer() */
+
+/*
+ * The SPIC engine and its internal sequencer can be interrupted and reset by
+ * a hardware signal, the sbe_spicst_hard_reset bits from Pervasive
+ * Miscellaneous Register of sbe_register_bo device.
+ * Reset immediately aborts any SPI transaction in progress and returns the
+ * sequencer and state machines to idle state.
+ * The configuration register values are not changed. The status register is
+ * not reset. The engine registers are not reset.
+ * The SPIC engine reset does not have any affect on the attached devices.
+ * Reset handling of any attached devices is beyond the scope of the engine.
+ */
+static void do_reset(DeviceState *dev)
+{
+ PnvSpi *s = PNV_SPI(dev);
+ DeviceState *ssi_dev;
+
+ trace_pnv_spi_reset();
+
+ /* Connect cs irq */
+ ssi_dev = ssi_get_cs(s->ssi_bus, 0);
+ if (ssi_dev) {
+ qemu_irq cs_line = qdev_get_gpio_in_named(ssi_dev, SSI_GPIO_CS, 0);
+ qdev_connect_gpio_out_named(DEVICE(s), "cs", 0, cs_line);
+ }
+
+ /* Reset all N1 and N2 counters, and other constants */
+ s->N2_bits = 0;
+ s->N2_bytes = 0;
+ s->N2_tx = 0;
+ s->N2_rx = 0;
+ s->N1_bits = 0;
+ s->N1_bytes = 0;
+ s->N1_tx = 0;
+ s->N1_rx = 0;
+ s->loop_counter_1 = 0;
+ s->loop_counter_2 = 0;
+ /* Disconnected from responder */
+ qemu_set_irq(s->cs_line[0], 1);
+}
+
+static uint64_t pnv_spi_xscom_read(void *opaque, hwaddr addr, unsigned size)
+{
+ PnvSpi *s = PNV_SPI(opaque);
+ uint32_t reg = addr >> 3;
+ uint64_t val = ~0ull;
+
+ switch (reg) {
+ case ERROR_REG:
+ case SPI_CTR_CFG_REG:
+ case CONFIG_REG1:
+ case SPI_CLK_CFG_REG:
+ case SPI_MM_REG:
+ case SPI_XMIT_DATA_REG:
+ val = s->regs[reg];
+ break;
+ case SPI_RCV_DATA_REG:
+ val = s->regs[reg];
+ trace_pnv_spi_read_RDR(val);
+ s->status = SETFIELD(SPI_STS_RDR_FULL, s->status, 0);
+ if (GETFIELD(SPI_STS_SHIFTER_FSM, s->status) == FSM_WAIT) {
+ trace_pnv_spi_start_sequencer();
+ operation_sequencer(s);
+ }
+ break;
+ case SPI_SEQ_OP_REG:
+ val = 0;
+ for (int i = 0; i < PNV_SPI_REG_SIZE; i++) {
+ val = (val << 8) | s->seq_op[i];
+ }
+ break;
+ case SPI_STS_REG:
+ val = s->status;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "pnv_spi_regs: Invalid xscom "
+ "read at 0x%" PRIx32 "\n", reg);
+ }
+
+ trace_pnv_spi_read(addr, val);
+ return val;
+}
+
+static void pnv_spi_xscom_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ PnvSpi *s = PNV_SPI(opaque);
+ uint32_t reg = addr >> 3;
+
+ trace_pnv_spi_write(addr, val);
+
+ switch (reg) {
+ case ERROR_REG:
+ case SPI_CTR_CFG_REG:
+ case CONFIG_REG1:
+ case SPI_MM_REG:
+ case SPI_RCV_DATA_REG:
+ s->regs[reg] = val;
+ break;
+ case SPI_CLK_CFG_REG:
+ /*
+ * To reset the SPI controller write the sequence 0x5 0xA to
+ * reset_control field
+ */
+ if ((GETFIELD(SPI_CLK_CFG_RST_CTRL, s->regs[SPI_CLK_CFG_REG]) == 0x5)
+ && (GETFIELD(SPI_CLK_CFG_RST_CTRL, val) == 0xA)) {
+ /* SPI controller reset sequence completed, resetting */
+ s->regs[reg] = SPI_CLK_CFG_HARD_RST;
+ } else {
+ s->regs[reg] = val;
+ }
+ break;
+ case SPI_XMIT_DATA_REG:
+ /*
+ * Writing to the transmit data register causes the transmit data
+ * register full status bit in the status register to be set. Writing
+ * when the transmit data register full status bit is already set
+ * causes a "Resource Not Available" condition. This is not possible
+ * in the model since writes to this register are not asynchronous to
+ * the operation sequence like it would be in hardware.
+ */
+ s->regs[reg] = val;
+ trace_pnv_spi_write_TDR(val);
+ s->status = SETFIELD(SPI_STS_TDR_FULL, s->status, 1);
+ s->status = SETFIELD(SPI_STS_TDR_UNDERRUN, s->status, 0);
+ trace_pnv_spi_start_sequencer();
+ operation_sequencer(s);
+ break;
+ case SPI_SEQ_OP_REG:
+ for (int i = 0; i < PNV_SPI_REG_SIZE; i++) {
+ s->seq_op[i] = (val >> (56 - i * 8)) & 0xFF;
+ }
+ break;
+ case SPI_STS_REG:
+ /* other fields are ignore_write */
+ s->status = SETFIELD(SPI_STS_RDR_OVERRUN, s->status,
+ GETFIELD(SPI_STS_RDR, val));
+ s->status = SETFIELD(SPI_STS_TDR_OVERRUN, s->status,
+ GETFIELD(SPI_STS_TDR, val));
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "pnv_spi_regs: Invalid xscom "
+ "write at 0x%" PRIx32 "\n", reg);
+ }
+ return;
+}
+
+static const MemoryRegionOps pnv_spi_xscom_ops = {
+ .read = pnv_spi_xscom_read,
+ .write = pnv_spi_xscom_write,
+ .valid.min_access_size = 8,
+ .valid.max_access_size = 8,
+ .impl.min_access_size = 8,
+ .impl.max_access_size = 8,
+ .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static Property pnv_spi_properties[] = {
+ DEFINE_PROP_UINT32("spic_num", PnvSpi, spic_num, 0),
+ DEFINE_PROP_UINT8("transfer_len", PnvSpi, transfer_len, 4),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pnv_spi_realize(DeviceState *dev, Error **errp)
+{
+ PnvSpi *s = PNV_SPI(dev);
+ g_autofree char *name = g_strdup_printf(TYPE_PNV_SPI_BUS ".%d",
+ s->spic_num);
+ s->ssi_bus = ssi_create_bus(dev, name);
+ s->cs_line = g_new0(qemu_irq, 1);
+ qdev_init_gpio_out_named(DEVICE(s), s->cs_line, "cs", 1);
+
+ /* spi scoms */
+ pnv_xscom_region_init(&s->xscom_spic_regs, OBJECT(s), &pnv_spi_xscom_ops,
+ s, "xscom-spi", PNV10_XSCOM_PIB_SPIC_SIZE);
+}
+
+static int pnv_spi_dt_xscom(PnvXScomInterface *dev, void *fdt,
+ int offset)
+{
+ PnvSpi *s = PNV_SPI(dev);
+ g_autofree char *name;
+ int s_offset;
+ const char compat[] = "ibm,power10-spi";
+ uint32_t spic_pcba = PNV10_XSCOM_PIB_SPIC_BASE +
+ s->spic_num * PNV10_XSCOM_PIB_SPIC_SIZE;
+ uint32_t reg[] = {
+ cpu_to_be32(spic_pcba),
+ cpu_to_be32(PNV10_XSCOM_PIB_SPIC_SIZE)
+ };
+ name = g_strdup_printf("pnv_spi@%x", spic_pcba);
+ s_offset = fdt_add_subnode(fdt, offset, name);
+ _FDT(s_offset);
+
+ _FDT(fdt_setprop(fdt, s_offset, "reg", reg, sizeof(reg)));
+ _FDT(fdt_setprop(fdt, s_offset, "compatible", compat, sizeof(compat)));
+ _FDT((fdt_setprop_cell(fdt, s_offset, "spic_num#", s->spic_num)));
+ return 0;
+}
+
+static void pnv_spi_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PnvXScomInterfaceClass *xscomc = PNV_XSCOM_INTERFACE_CLASS(klass);
+
+ xscomc->dt_xscom = pnv_spi_dt_xscom;
+
+ dc->desc = "PowerNV SPI";
+ dc->realize = pnv_spi_realize;
+ device_class_set_legacy_reset(dc, do_reset);
+ device_class_set_props(dc, pnv_spi_properties);
+}
+
+static const TypeInfo pnv_spi_info = {
+ .name = TYPE_PNV_SPI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PnvSpi),
+ .class_init = pnv_spi_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_PNV_XSCOM_INTERFACE },
+ { }
+ }
+};
+
+static void pnv_spi_register_types(void)
+{
+ type_register_static(&pnv_spi_info);
+}
+
+type_init(pnv_spi_register_types);
diff --git a/hw/ssi/sifive_spi.c b/hw/ssi/sifive_spi.c
index 1b4a401..08a1077 100644
--- a/hw/ssi/sifive_spi.c
+++ b/hw/ssi/sifive_spi.c
@@ -338,7 +338,7 @@ static void sifive_spi_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_props(dc, sifive_spi_properties);
- dc->reset = sifive_spi_reset;
+ device_class_set_legacy_reset(dc, sifive_spi_reset);
dc->realize = sifive_spi_realize;
}
diff --git a/hw/ssi/stm32f2xx_spi.c b/hw/ssi/stm32f2xx_spi.c
index a37139f..ea9b74a 100644
--- a/hw/ssi/stm32f2xx_spi.c
+++ b/hw/ssi/stm32f2xx_spi.c
@@ -206,7 +206,7 @@ static void stm32f2xx_spi_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = stm32f2xx_spi_reset;
+ device_class_set_legacy_reset(dc, stm32f2xx_spi_reset);
dc->vmsd = &vmstate_stm32f2xx_spi;
}
diff --git a/hw/ssi/trace-events b/hw/ssi/trace-events
index 7b5ad6a..2f36cf9 100644
--- a/hw/ssi/trace-events
+++ b/hw/ssi/trace-events
@@ -32,3 +32,34 @@ ibex_spi_host_reset(const char *msg) "%s"
ibex_spi_host_transfer(uint32_t tx_data, uint32_t rx_data) "tx_data: 0x%" PRIx32 " rx_data: @0x%" PRIx32
ibex_spi_host_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size %u: 0x%" PRIx64
ibex_spi_host_read(uint64_t addr, uint32_t size) "@0x%" PRIx64 " size %u:"
+
+#pnv_spi.c
+pnv_spi_read(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " val 0x%" PRIx64
+pnv_spi_write(uint64_t addr, uint64_t val) "addr 0x%" PRIx64 " val 0x%" PRIx64
+pnv_spi_read_RDR(uint64_t val) "data extracted = 0x%" PRIx64
+pnv_spi_write_TDR(uint64_t val) "being written, data written = 0x%" PRIx64
+pnv_spi_start_sequencer(void) ""
+pnv_spi_reset(void) "spic engine sequencer configuration and spi communication"
+pnv_spi_sequencer_op(const char* op, uint8_t index) "%s at index = 0x%x"
+pnv_spi_shifter_stating(void) "pull CS line low"
+pnv_spi_shifter_done(void) "pull the CS line high"
+pnv_spi_log_Ncounts(uint8_t N1_bits, uint8_t N1_bytes, uint8_t N1_tx, uint8_t N1_rx, uint8_t N2_bits, uint8_t N2_bytes, uint8_t N2_tx, uint8_t N2_rx) "N1_bits = %d, N1_bytes = %d, N1_tx = %d, N1_rx = %d, N2_bits = %d, N2_bytes = %d, N2_tx = %d, N2_rx = %d"
+pnv_spi_tx_append(const char* frame, uint8_t byte, uint8_t tdr_index) "%s = 0x%2.2x to payload from TDR at index %d"
+pnv_spi_tx_append_FF(const char* frame) "%s to Payload"
+pnv_spi_tx_request(const char* frame, uint32_t payload_len) "%s, payload len = %d"
+pnv_spi_rx_received(uint32_t payload_len) "payload len = %d"
+pnv_spi_rx_read_N1frame(void) ""
+pnv_spi_rx_read_N2frame(void) ""
+pnv_spi_shift_rx(uint8_t byte, uint32_t index) "byte = 0x%2.2x into RDR from payload index %d"
+pnv_spi_sequencer_stop_requested(const char* reason) "due to %s"
+pnv_spi_RDR_match(const char* result) "%s"
+
+# allwinner_a10_spi.c
+allwinner_a10_spi_update_irq(uint32_t level) "IRQ level is %d"
+allwinner_a10_spi_flush_txfifo_begin(uint32_t tx, uint32_t rx) "Begin: TX Fifo Size = %d, RX Fifo Size = %d"
+allwinner_a10_spi_flush_txfifo_end(uint32_t tx, uint32_t rx) "End: TX Fifo Size = %d, RX Fifo Size = %d"
+allwinner_a10_spi_burst_length(uint32_t len) "Burst length = %d"
+allwinner_a10_spi_tx(uint8_t byte) "write 0x%02x"
+allwinner_a10_spi_rx(uint8_t byte) "read 0x%02x"
+allwinner_a10_spi_read(const char* regname, uint32_t value) "reg[%s] => 0x%08x"
+allwinner_a10_spi_write(const char* regname, uint32_t value) "reg[%s] <= 0x%08x"
diff --git a/hw/ssi/xilinx_spi.c b/hw/ssi/xilinx_spi.c
index 2e0687a..7f1e180 100644
--- a/hw/ssi/xilinx_spi.c
+++ b/hw/ssi/xilinx_spi.c
@@ -371,7 +371,7 @@ static void xilinx_spi_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = xilinx_spi_realize;
- dc->reset = xlx_spi_reset;
+ device_class_set_legacy_reset(dc, xlx_spi_reset);
device_class_set_props(dc, xilinx_spi_properties);
dc->vmsd = &vmstate_xilinx_spi;
}
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index 71952a4..aeb462c 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -620,7 +620,9 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
} else if (s->snoop_state == SNOOP_STRIPING ||
s->snoop_state == SNOOP_NONE) {
for (i = 0; i < num_effective_busses(s); ++i) {
- tx_rx[i] = fifo8_pop(&s->tx_fifo);
+ if (!fifo8_is_empty(&s->tx_fifo)) {
+ tx_rx[i] = fifo8_pop(&s->tx_fifo);
+ }
}
stripe8(tx_rx, num_effective_busses(s), false);
} else if (s->snoop_state >= SNOOP_ADDR) {
@@ -1448,7 +1450,7 @@ static void xilinx_spips_class_init(ObjectClass *klass, void *data)
XilinxSPIPSClass *xsc = XILINX_SPIPS_CLASS(klass);
dc->realize = xilinx_spips_realize;
- dc->reset = xilinx_spips_reset;
+ device_class_set_legacy_reset(dc, xilinx_spips_reset);
device_class_set_props(dc, xilinx_spips_properties);
dc->vmsd = &vmstate_xilinx_spips;
@@ -1464,7 +1466,7 @@ static void xlnx_zynqmp_qspips_class_init(ObjectClass *klass, void * data)
XilinxSPIPSClass *xsc = XILINX_SPIPS_CLASS(klass);
dc->realize = xlnx_zynqmp_qspips_realize;
- dc->reset = xlnx_zynqmp_qspips_reset;
+ device_class_set_legacy_reset(dc, xlnx_zynqmp_qspips_reset);
dc->vmsd = &vmstate_xlnx_zynqmp_qspips;
device_class_set_props(dc, xilinx_zynqmp_qspips_properties);
xsc->reg_ops = &xlnx_zynqmp_qspips_ops;
diff --git a/hw/ssi/xlnx-versal-ospi.c b/hw/ssi/xlnx-versal-ospi.c
index c479138..ecc1903 100644
--- a/hw/ssi/xlnx-versal-ospi.c
+++ b/hw/ssi/xlnx-versal-ospi.c
@@ -1836,7 +1836,7 @@ static void xlnx_versal_ospi_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = xlnx_versal_ospi_reset;
+ device_class_set_legacy_reset(dc, xlnx_versal_ospi_reset);
dc->realize = xlnx_versal_ospi_realize;
dc->vmsd = &vmstate_xlnx_versal_ospi;
device_class_set_props(dc, xlnx_versal_ospi_properties);
diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig
index 61fbb62..c96fd5d 100644
--- a/hw/timer/Kconfig
+++ b/hw/timer/Kconfig
@@ -21,6 +21,9 @@ config ALLWINNER_A10_PIT
bool
select PTIMER
+config PXA2XX_TIMER
+ bool
+
config SIFIVE_PWM
bool
diff --git a/hw/timer/a9gtimer.c b/hw/timer/a9gtimer.c
index 64d80cd..8091ec1 100644
--- a/hw/timer/a9gtimer.c
+++ b/hw/timer/a9gtimer.c
@@ -384,7 +384,7 @@ static void a9_gtimer_class_init(ObjectClass *klass, void *data)
dc->realize = a9_gtimer_realize;
dc->vmsd = &vmstate_a9_gtimer;
- dc->reset = a9_gtimer_reset;
+ device_class_set_legacy_reset(dc, a9_gtimer_reset);
device_class_set_props(dc, a9_gtimer_properties);
}
diff --git a/hw/timer/allwinner-a10-pit.c b/hw/timer/allwinner-a10-pit.c
index a524de1..d488e97 100644
--- a/hw/timer/allwinner-a10-pit.c
+++ b/hw/timer/allwinner-a10-pit.c
@@ -293,7 +293,7 @@ static void a10_pit_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = a10_pit_reset;
+ device_class_set_legacy_reset(dc, a10_pit_reset);
device_class_set_props(dc, a10_pit_properties);
dc->desc = "allwinner a10 timer";
dc->vmsd = &vmstate_a10_pit;
diff --git a/hw/timer/arm_mptimer.c b/hw/timer/arm_mptimer.c
index bca4cee..defa30b 100644
--- a/hw/timer/arm_mptimer.c
+++ b/hw/timer/arm_mptimer.c
@@ -311,7 +311,7 @@ static void arm_mptimer_class_init(ObjectClass *klass, void *data)
dc->realize = arm_mptimer_realize;
dc->vmsd = &vmstate_arm_mptimer;
- dc->reset = arm_mptimer_reset;
+ device_class_set_legacy_reset(dc, arm_mptimer_reset);
device_class_set_props(dc, arm_mptimer_properties);
}
diff --git a/hw/timer/armv7m_systick.c b/hw/timer/armv7m_systick.c
index f6b1ace..a07febd 100644
--- a/hw/timer/armv7m_systick.c
+++ b/hw/timer/armv7m_systick.c
@@ -290,7 +290,7 @@ static void systick_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_systick;
- dc->reset = systick_reset;
+ device_class_set_legacy_reset(dc, systick_reset);
dc->realize = systick_realize;
}
diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c
index fc5c94b..b1f860e 100644
--- a/hw/timer/aspeed_timer.c
+++ b/hw/timer/aspeed_timer.c
@@ -682,7 +682,7 @@ static void timer_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_timer_realize;
- dc->reset = aspeed_timer_reset;
+ device_class_set_legacy_reset(dc, aspeed_timer_reset);
dc->desc = "ASPEED Timer";
dc->vmsd = &vmstate_aspeed_timer_state;
device_class_set_props(dc, aspeed_timer_properties);
diff --git a/hw/timer/avr_timer16.c b/hw/timer/avr_timer16.c
index c48555d..4219200 100644
--- a/hw/timer/avr_timer16.c
+++ b/hw/timer/avr_timer16.c
@@ -600,7 +600,7 @@ static void avr_timer16_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = avr_timer16_reset;
+ device_class_set_legacy_reset(dc, avr_timer16_reset);
dc->realize = avr_timer16_realize;
device_class_set_props(dc, avr_timer16_properties);
}
diff --git a/hw/timer/bcm2835_systmr.c b/hw/timer/bcm2835_systmr.c
index 3ec6460..2f0fee3 100644
--- a/hw/timer/bcm2835_systmr.c
+++ b/hw/timer/bcm2835_systmr.c
@@ -159,7 +159,7 @@ static void bcm2835_systmr_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = bcm2835_systmr_realize;
- dc->reset = bcm2835_systmr_reset;
+ device_class_set_legacy_reset(dc, bcm2835_systmr_reset);
dc->vmsd = &bcm2835_systmr_vmstate;
}
diff --git a/hw/timer/cmsdk-apb-dualtimer.c b/hw/timer/cmsdk-apb-dualtimer.c
index ddf9070..2ecd8df 100644
--- a/hw/timer/cmsdk-apb-dualtimer.c
+++ b/hw/timer/cmsdk-apb-dualtimer.c
@@ -540,7 +540,7 @@ static void cmsdk_apb_dualtimer_class_init(ObjectClass *klass, void *data)
dc->realize = cmsdk_apb_dualtimer_realize;
dc->vmsd = &cmsdk_apb_dualtimer_vmstate;
- dc->reset = cmsdk_apb_dualtimer_reset;
+ device_class_set_legacy_reset(dc, cmsdk_apb_dualtimer_reset);
}
static const TypeInfo cmsdk_apb_dualtimer_info = {
diff --git a/hw/timer/cmsdk-apb-timer.c b/hw/timer/cmsdk-apb-timer.c
index 814545c..16d0b21 100644
--- a/hw/timer/cmsdk-apb-timer.c
+++ b/hw/timer/cmsdk-apb-timer.c
@@ -267,7 +267,7 @@ static void cmsdk_apb_timer_class_init(ObjectClass *klass, void *data)
dc->realize = cmsdk_apb_timer_realize;
dc->vmsd = &cmsdk_apb_timer_vmstate;
- dc->reset = cmsdk_apb_timer_reset;
+ device_class_set_legacy_reset(dc, cmsdk_apb_timer_reset);
}
static const TypeInfo cmsdk_apb_timer_info = {
diff --git a/hw/timer/digic-timer.c b/hw/timer/digic-timer.c
index 9fc5c1d..00c3297 100644
--- a/hw/timer/digic-timer.c
+++ b/hw/timer/digic-timer.c
@@ -165,7 +165,7 @@ static void digic_timer_class_init(ObjectClass *klass, void *class_data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = digic_timer_reset;
+ device_class_set_legacy_reset(dc, digic_timer_reset);
dc->vmsd = &vmstate_digic_timer;
}
diff --git a/hw/timer/etraxfs_timer.c b/hw/timer/etraxfs_timer.c
deleted file mode 100644
index dd6d96b..0000000
--- a/hw/timer/etraxfs_timer.c
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- * QEMU ETRAX Timers
- *
- * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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/sysbus.h"
-#include "sysemu/reset.h"
-#include "sysemu/runstate.h"
-#include "migration/vmstate.h"
-#include "qemu/module.h"
-#include "qemu/timer.h"
-#include "hw/irq.h"
-#include "hw/ptimer.h"
-#include "qom/object.h"
-
-#define D(x)
-
-#define RW_TMR0_DIV 0x00
-#define R_TMR0_DATA 0x04
-#define RW_TMR0_CTRL 0x08
-#define RW_TMR1_DIV 0x10
-#define R_TMR1_DATA 0x14
-#define RW_TMR1_CTRL 0x18
-#define R_TIME 0x38
-#define RW_WD_CTRL 0x40
-#define R_WD_STAT 0x44
-#define RW_INTR_MASK 0x48
-#define RW_ACK_INTR 0x4c
-#define R_INTR 0x50
-#define R_MASKED_INTR 0x54
-
-#define TYPE_ETRAX_FS_TIMER "etraxfs-timer"
-typedef struct ETRAXTimerState ETRAXTimerState;
-DECLARE_INSTANCE_CHECKER(ETRAXTimerState, ETRAX_TIMER,
- TYPE_ETRAX_FS_TIMER)
-
-struct ETRAXTimerState {
- SysBusDevice parent_obj;
-
- MemoryRegion mmio;
- qemu_irq irq;
- qemu_irq nmi;
-
- ptimer_state *ptimer_t0;
- ptimer_state *ptimer_t1;
- ptimer_state *ptimer_wd;
-
- uint32_t wd_hits;
-
- /* Control registers. */
- uint32_t rw_tmr0_div;
- uint32_t r_tmr0_data;
- uint32_t rw_tmr0_ctrl;
-
- uint32_t rw_tmr1_div;
- uint32_t r_tmr1_data;
- uint32_t rw_tmr1_ctrl;
-
- uint32_t rw_wd_ctrl;
-
- uint32_t rw_intr_mask;
- uint32_t rw_ack_intr;
- uint32_t r_intr;
- uint32_t r_masked_intr;
-};
-
-static const VMStateDescription vmstate_etraxfs = {
- .name = "etraxfs",
- .version_id = 0,
- .minimum_version_id = 0,
- .fields = (const VMStateField[]) {
- VMSTATE_PTIMER(ptimer_t0, ETRAXTimerState),
- VMSTATE_PTIMER(ptimer_t1, ETRAXTimerState),
- VMSTATE_PTIMER(ptimer_wd, ETRAXTimerState),
-
- VMSTATE_UINT32(wd_hits, ETRAXTimerState),
-
- VMSTATE_UINT32(rw_tmr0_div, ETRAXTimerState),
- VMSTATE_UINT32(r_tmr0_data, ETRAXTimerState),
- VMSTATE_UINT32(rw_tmr0_ctrl, ETRAXTimerState),
-
- VMSTATE_UINT32(rw_tmr1_div, ETRAXTimerState),
- VMSTATE_UINT32(r_tmr1_data, ETRAXTimerState),
- VMSTATE_UINT32(rw_tmr1_ctrl, ETRAXTimerState),
-
- VMSTATE_UINT32(rw_wd_ctrl, ETRAXTimerState),
-
- VMSTATE_UINT32(rw_intr_mask, ETRAXTimerState),
- VMSTATE_UINT32(rw_ack_intr, ETRAXTimerState),
- VMSTATE_UINT32(r_intr, ETRAXTimerState),
- VMSTATE_UINT32(r_masked_intr, ETRAXTimerState),
-
- VMSTATE_END_OF_LIST()
- }
-};
-
-static uint64_t
-timer_read(void *opaque, hwaddr addr, unsigned int size)
-{
- ETRAXTimerState *t = opaque;
- uint32_t r = 0;
-
- switch (addr) {
- case R_TMR0_DATA:
- r = ptimer_get_count(t->ptimer_t0);
- break;
- case R_TMR1_DATA:
- r = ptimer_get_count(t->ptimer_t1);
- break;
- case R_TIME:
- r = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / 10;
- break;
- case RW_INTR_MASK:
- r = t->rw_intr_mask;
- break;
- case R_MASKED_INTR:
- r = t->r_intr & t->rw_intr_mask;
- break;
- default:
- D(printf ("%s %x\n", __func__, addr));
- break;
- }
- return r;
-}
-
-static void update_ctrl(ETRAXTimerState *t, int tnum)
-{
- unsigned int op;
- unsigned int freq;
- unsigned int freq_hz;
- unsigned int div;
- uint32_t ctrl;
-
- ptimer_state *timer;
-
- if (tnum == 0) {
- ctrl = t->rw_tmr0_ctrl;
- div = t->rw_tmr0_div;
- timer = t->ptimer_t0;
- } else {
- ctrl = t->rw_tmr1_ctrl;
- div = t->rw_tmr1_div;
- timer = t->ptimer_t1;
- }
-
-
- op = ctrl & 3;
- freq = ctrl >> 2;
- freq_hz = 32000000;
-
- switch (freq)
- {
- case 0:
- case 1:
- D(printf ("extern or disabled timer clock?\n"));
- break;
- case 4: freq_hz = 29493000; break;
- case 5: freq_hz = 32000000; break;
- case 6: freq_hz = 32768000; break;
- case 7: freq_hz = 100000000; break;
- default:
- abort();
- break;
- }
-
- D(printf ("freq_hz=%d div=%d\n", freq_hz, div));
- ptimer_transaction_begin(timer);
- ptimer_set_freq(timer, freq_hz);
- ptimer_set_limit(timer, div, 0);
-
- switch (op)
- {
- case 0:
- /* Load. */
- ptimer_set_limit(timer, div, 1);
- break;
- case 1:
- /* Hold. */
- ptimer_stop(timer);
- break;
- case 2:
- /* Run. */
- ptimer_run(timer, 0);
- break;
- default:
- abort();
- break;
- }
- ptimer_transaction_commit(timer);
-}
-
-static void timer_update_irq(ETRAXTimerState *t)
-{
- t->r_intr &= ~(t->rw_ack_intr);
- t->r_masked_intr = t->r_intr & t->rw_intr_mask;
-
- D(printf("%s: masked_intr=%x\n", __func__, t->r_masked_intr));
- qemu_set_irq(t->irq, !!t->r_masked_intr);
-}
-
-static void timer0_hit(void *opaque)
-{
- ETRAXTimerState *t = opaque;
- t->r_intr |= 1;
- timer_update_irq(t);
-}
-
-static void timer1_hit(void *opaque)
-{
- ETRAXTimerState *t = opaque;
- t->r_intr |= 2;
- timer_update_irq(t);
-}
-
-static void watchdog_hit(void *opaque)
-{
- ETRAXTimerState *t = opaque;
- if (t->wd_hits == 0) {
- /* real hw gives a single tick before resetting but we are
- a bit friendlier to compensate for our slower execution. */
- ptimer_set_count(t->ptimer_wd, 10);
- ptimer_run(t->ptimer_wd, 1);
- qemu_irq_raise(t->nmi);
- }
- else
- qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
-
- t->wd_hits++;
-}
-
-static inline void timer_watchdog_update(ETRAXTimerState *t, uint32_t value)
-{
- unsigned int wd_en = t->rw_wd_ctrl & (1 << 8);
- unsigned int wd_key = t->rw_wd_ctrl >> 9;
- unsigned int wd_cnt = t->rw_wd_ctrl & 511;
- unsigned int new_key = value >> 9 & ((1 << 7) - 1);
- unsigned int new_cmd = (value >> 8) & 1;
-
- /* If the watchdog is enabled, they written key must match the
- complement of the previous. */
- wd_key = ~wd_key & ((1 << 7) - 1);
-
- if (wd_en && wd_key != new_key)
- return;
-
- D(printf("en=%d new_key=%x oldkey=%x cmd=%d cnt=%d\n",
- wd_en, new_key, wd_key, new_cmd, wd_cnt));
-
- if (t->wd_hits)
- qemu_irq_lower(t->nmi);
-
- t->wd_hits = 0;
-
- ptimer_transaction_begin(t->ptimer_wd);
- ptimer_set_freq(t->ptimer_wd, 760);
- if (wd_cnt == 0)
- wd_cnt = 256;
- ptimer_set_count(t->ptimer_wd, wd_cnt);
- if (new_cmd)
- ptimer_run(t->ptimer_wd, 1);
- else
- ptimer_stop(t->ptimer_wd);
-
- t->rw_wd_ctrl = value;
- ptimer_transaction_commit(t->ptimer_wd);
-}
-
-static void
-timer_write(void *opaque, hwaddr addr,
- uint64_t val64, unsigned int size)
-{
- ETRAXTimerState *t = opaque;
- uint32_t value = val64;
-
- switch (addr)
- {
- case RW_TMR0_DIV:
- t->rw_tmr0_div = value;
- break;
- case RW_TMR0_CTRL:
- D(printf ("RW_TMR0_CTRL=%x\n", value));
- t->rw_tmr0_ctrl = value;
- update_ctrl(t, 0);
- break;
- case RW_TMR1_DIV:
- t->rw_tmr1_div = value;
- break;
- case RW_TMR1_CTRL:
- D(printf ("RW_TMR1_CTRL=%x\n", value));
- t->rw_tmr1_ctrl = value;
- update_ctrl(t, 1);
- break;
- case RW_INTR_MASK:
- D(printf ("RW_INTR_MASK=%x\n", value));
- t->rw_intr_mask = value;
- timer_update_irq(t);
- break;
- case RW_WD_CTRL:
- timer_watchdog_update(t, value);
- break;
- case RW_ACK_INTR:
- t->rw_ack_intr = value;
- timer_update_irq(t);
- t->rw_ack_intr = 0;
- break;
- default:
- printf("%s " HWADDR_FMT_plx " %x\n", __func__, addr, value);
- break;
- }
-}
-
-static const MemoryRegionOps timer_ops = {
- .read = timer_read,
- .write = timer_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4
- }
-};
-
-static void etraxfs_timer_reset_enter(Object *obj, ResetType type)
-{
- ETRAXTimerState *t = ETRAX_TIMER(obj);
-
- ptimer_transaction_begin(t->ptimer_t0);
- ptimer_stop(t->ptimer_t0);
- ptimer_transaction_commit(t->ptimer_t0);
- ptimer_transaction_begin(t->ptimer_t1);
- ptimer_stop(t->ptimer_t1);
- ptimer_transaction_commit(t->ptimer_t1);
- ptimer_transaction_begin(t->ptimer_wd);
- ptimer_stop(t->ptimer_wd);
- ptimer_transaction_commit(t->ptimer_wd);
- t->rw_wd_ctrl = 0;
- t->r_intr = 0;
- t->rw_intr_mask = 0;
-}
-
-static void etraxfs_timer_reset_hold(Object *obj, ResetType type)
-{
- ETRAXTimerState *t = ETRAX_TIMER(obj);
-
- qemu_irq_lower(t->irq);
-}
-
-static void etraxfs_timer_realize(DeviceState *dev, Error **errp)
-{
- ETRAXTimerState *t = ETRAX_TIMER(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-
- t->ptimer_t0 = ptimer_init(timer0_hit, t, PTIMER_POLICY_LEGACY);
- t->ptimer_t1 = ptimer_init(timer1_hit, t, PTIMER_POLICY_LEGACY);
- t->ptimer_wd = ptimer_init(watchdog_hit, t, PTIMER_POLICY_LEGACY);
-
- sysbus_init_irq(sbd, &t->irq);
- sysbus_init_irq(sbd, &t->nmi);
-
- memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t,
- "etraxfs-timer", 0x5c);
- sysbus_init_mmio(sbd, &t->mmio);
-}
-
-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;
- dc->vmsd = &vmstate_etraxfs;
- rc->phases.enter = etraxfs_timer_reset_enter;
- rc->phases.hold = etraxfs_timer_reset_hold;
-}
-
-static const TypeInfo etraxfs_timer_info = {
- .name = TYPE_ETRAX_FS_TIMER,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(ETRAXTimerState),
- .class_init = etraxfs_timer_class_init,
-};
-
-static void etraxfs_timer_register_types(void)
-{
- type_register_static(&etraxfs_timer_info);
-}
-
-type_init(etraxfs_timer_register_types)
diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c
index 75098cd..e807fe2 100644
--- a/hw/timer/exynos4210_mct.c
+++ b/hw/timer/exynos4210_mct.c
@@ -1550,7 +1550,7 @@ static void exynos4210_mct_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = exynos4210_mct_reset;
+ device_class_set_legacy_reset(dc, exynos4210_mct_reset);
dc->vmsd = &vmstate_exynos4210_mct_state;
}
diff --git a/hw/timer/exynos4210_pwm.c b/hw/timer/exynos4210_pwm.c
index ca330e9..703d1d2 100644
--- a/hw/timer/exynos4210_pwm.c
+++ b/hw/timer/exynos4210_pwm.c
@@ -424,7 +424,7 @@ static void exynos4210_pwm_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = exynos4210_pwm_reset;
+ device_class_set_legacy_reset(dc, exynos4210_pwm_reset);
dc->vmsd = &vmstate_exynos4210_pwm_state;
}
diff --git a/hw/timer/grlib_gptimer.c b/hw/timer/grlib_gptimer.c
index 4990885..6ef08f2 100644
--- a/hw/timer/grlib_gptimer.c
+++ b/hw/timer/grlib_gptimer.c
@@ -415,7 +415,7 @@ static void grlib_gptimer_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = grlib_gptimer_realize;
- dc->reset = grlib_gptimer_reset;
+ device_class_set_legacy_reset(dc, grlib_gptimer_reset);
device_class_set_props(dc, grlib_gptimer_properties);
}
diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c
index 4cb5393..5399f1b 100644
--- a/hw/timer/hpet.c
+++ b/hw/timer/hpet.c
@@ -54,10 +54,12 @@ typedef struct HPETTimer { /* timers */
uint64_t cmp; /* comparator */
uint64_t fsb; /* FSB route */
/* Hidden register state */
+ uint64_t cmp64; /* comparator (extended to counter width) */
uint64_t period; /* Last value written to comparator */
uint8_t wrap_flag; /* timer pop will indicate wrap for one-shot 32-bit
* mode. Next pop will be actual timer expiration.
*/
+ uint64_t last; /* last value armed, to avoid timer storms */
} HPETTimer;
struct HPETState {
@@ -116,11 +118,6 @@ static uint32_t timer_enabled(HPETTimer *t)
static uint32_t hpet_time_after(uint64_t a, uint64_t b)
{
- return ((int32_t)(b - a) < 0);
-}
-
-static uint32_t hpet_time_after64(uint64_t a, uint64_t b)
-{
return ((int64_t)(b - a) < 0);
}
@@ -156,29 +153,34 @@ static uint64_t hpet_get_ticks(HPETState *s)
return ns_to_ticks(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->hpet_offset);
}
+static uint64_t hpet_get_ns(HPETState *s, uint64_t tick)
+{
+ return ticks_to_ns(tick) - s->hpet_offset;
+}
+
/*
- * calculate diff between comparator value and current ticks
+ * calculate next value of the general counter that matches the
+ * target (either entirely, or the low 32-bit only depending on
+ * the timer mode).
*/
-static inline uint64_t hpet_calculate_diff(HPETTimer *t, uint64_t current)
+static uint64_t hpet_calculate_cmp64(HPETTimer *t, uint64_t cur_tick, uint64_t target)
{
-
if (t->config & HPET_TN_32BIT) {
- uint32_t diff, cmp;
-
- cmp = (uint32_t)t->cmp;
- diff = cmp - (uint32_t)current;
- diff = (int32_t)diff > 0 ? diff : (uint32_t)1;
- return (uint64_t)diff;
+ uint64_t result = deposit64(cur_tick, 0, 32, target);
+ if (result < cur_tick) {
+ result += 0x100000000ULL;
+ }
+ return result;
} else {
- uint64_t diff, cmp;
-
- cmp = t->cmp;
- diff = cmp - current;
- diff = (int64_t)diff > 0 ? diff : (uint64_t)1;
- return diff;
+ return target;
}
}
+static uint64_t hpet_next_wrap(uint64_t cur_tick)
+{
+ return (cur_tick | 0xffffffffU) + 1;
+}
+
static void update_irq(struct HPETTimer *timer, int set)
{
uint64_t mask;
@@ -196,21 +198,31 @@ static void update_irq(struct HPETTimer *timer, int set)
}
s = timer->state;
mask = 1 << timer->tn;
- if (!set || !timer_enabled(timer) || !hpet_enabled(timer->state)) {
+
+ if (set && (timer->config & HPET_TN_TYPE_LEVEL)) {
+ /*
+ * If HPET_TN_ENABLE bit is 0, "the timer will still operate and
+ * generate appropriate status bits, but will not cause an interrupt"
+ */
+ s->isr |= mask;
+ } else {
s->isr &= ~mask;
+ }
+
+ if (set && timer_enabled(timer) && hpet_enabled(s)) {
+ if (timer_fsb_route(timer)) {
+ address_space_stl_le(&address_space_memory, timer->fsb >> 32,
+ timer->fsb & 0xffffffff, MEMTXATTRS_UNSPECIFIED,
+ NULL);
+ } else if (timer->config & HPET_TN_TYPE_LEVEL) {
+ qemu_irq_raise(s->irqs[route]);
+ } else {
+ qemu_irq_pulse(s->irqs[route]);
+ }
+ } else {
if (!timer_fsb_route(timer)) {
qemu_irq_lower(s->irqs[route]);
}
- } else if (timer_fsb_route(timer)) {
- address_space_stl_le(&address_space_memory, timer->fsb >> 32,
- timer->fsb & 0xffffffff, MEMTXATTRS_UNSPECIFIED,
- NULL);
- } else if (timer->config & HPET_TN_TYPE_LEVEL) {
- s->isr |= mask;
- qemu_irq_raise(s->irqs[route]);
- } else {
- s->isr &= ~mask;
- qemu_irq_pulse(s->irqs[route]);
}
}
@@ -250,7 +262,13 @@ static bool hpet_validate_num_timers(void *opaque, int version_id)
static int hpet_post_load(void *opaque, int version_id)
{
HPETState *s = opaque;
+ int i;
+ for (i = 0; i < s->num_timers; i++) {
+ HPETTimer *t = &s->timer[i];
+ t->cmp64 = hpet_calculate_cmp64(t, s->hpet_counter, t->cmp);
+ t->last = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - NANOSECONDS_PER_SECOND;
+ }
/* Recalculate the offset between the main counter and guest time */
if (!s->hpet_offset_saved) {
s->hpet_offset = ticks_to_ns(s->hpet_counter)
@@ -346,14 +364,17 @@ static const VMStateDescription vmstate_hpet = {
}
};
-static void hpet_arm(HPETTimer *t, uint64_t ticks)
+static void hpet_arm(HPETTimer *t, uint64_t tick)
{
- if (ticks < ns_to_ticks(INT64_MAX / 2)) {
- timer_mod(t->qemu_timer,
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ticks_to_ns(ticks));
- } else {
- timer_del(t->qemu_timer);
+ uint64_t ns = hpet_get_ns(t->state, tick);
+
+ /* Clamp period to reasonable min value (1 us) */
+ if (timer_is_periodic(t) && ns - t->last < 1000) {
+ ns = t->last + 1000;
}
+
+ t->last = ns;
+ timer_mod(t->qemu_timer, ns);
}
/*
@@ -362,72 +383,68 @@ static void hpet_arm(HPETTimer *t, uint64_t ticks)
static void hpet_timer(void *opaque)
{
HPETTimer *t = opaque;
- uint64_t diff;
-
uint64_t period = t->period;
uint64_t cur_tick = hpet_get_ticks(t->state);
if (timer_is_periodic(t) && period != 0) {
+ while (hpet_time_after(cur_tick, t->cmp64)) {
+ t->cmp64 += period;
+ }
if (t->config & HPET_TN_32BIT) {
- while (hpet_time_after(cur_tick, t->cmp)) {
- t->cmp = (uint32_t)(t->cmp + t->period);
- }
+ t->cmp = (uint32_t)t->cmp64;
} else {
- while (hpet_time_after64(cur_tick, t->cmp)) {
- t->cmp += period;
- }
- }
- diff = hpet_calculate_diff(t, cur_tick);
- hpet_arm(t, diff);
- } else if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) {
- if (t->wrap_flag) {
- diff = hpet_calculate_diff(t, cur_tick);
- hpet_arm(t, diff);
- t->wrap_flag = 0;
+ t->cmp = t->cmp64;
}
+ hpet_arm(t, t->cmp64);
+ } else if (t->wrap_flag) {
+ t->wrap_flag = 0;
+ hpet_arm(t, t->cmp64);
}
update_irq(t, 1);
}
static void hpet_set_timer(HPETTimer *t)
{
- uint64_t diff;
- uint32_t wrap_diff; /* how many ticks until we wrap? */
uint64_t cur_tick = hpet_get_ticks(t->state);
- /* whenever new timer is being set up, make sure wrap_flag is 0 */
t->wrap_flag = 0;
- diff = hpet_calculate_diff(t, cur_tick);
-
- /* hpet spec says in one-shot 32-bit mode, generate an interrupt when
- * counter wraps in addition to an interrupt with comparator match.
- */
- if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) {
- wrap_diff = 0xffffffff - (uint32_t)cur_tick;
- if (wrap_diff < (uint32_t)diff) {
- diff = wrap_diff;
+ t->cmp64 = hpet_calculate_cmp64(t, cur_tick, t->cmp);
+ if (t->config & HPET_TN_32BIT) {
+
+ /* hpet spec says in one-shot 32-bit mode, generate an interrupt when
+ * counter wraps in addition to an interrupt with comparator match.
+ */
+ if (!timer_is_periodic(t) && t->cmp64 > hpet_next_wrap(cur_tick)) {
t->wrap_flag = 1;
+ hpet_arm(t, hpet_next_wrap(cur_tick));
+ return;
}
}
- hpet_arm(t, diff);
+ hpet_arm(t, t->cmp64);
}
static void hpet_del_timer(HPETTimer *t)
{
+ HPETState *s = t->state;
timer_del(t->qemu_timer);
- update_irq(t, 0);
+
+ if (s->isr & (1 << t->tn)) {
+ /* For level-triggered interrupt, this leaves ISR set but lowers irq. */
+ update_irq(t, 1);
+ }
}
static uint64_t hpet_ram_read(void *opaque, hwaddr addr,
unsigned size)
{
HPETState *s = opaque;
- uint64_t cur_tick, index;
+ int shift = (addr & 4) * 8;
+ uint64_t cur_tick;
trace_hpet_ram_read(addr);
- index = addr;
+
/*address range of all TN regs*/
- if (index >= 0x100 && index <= 0x3ff) {
+ if (addr >= 0x100 && addr <= 0x3ff) {
uint8_t timer_id = (addr - 0x100) / 0x20;
HPETTimer *timer = &s->timer[timer_id];
@@ -436,52 +453,33 @@ static uint64_t hpet_ram_read(void *opaque, hwaddr addr,
return 0;
}
- switch ((addr - 0x100) % 0x20) {
- case HPET_TN_CFG:
- return timer->config;
- case HPET_TN_CFG + 4: // Interrupt capabilities
- return timer->config >> 32;
+ switch (addr & 0x18) {
+ case HPET_TN_CFG: // including interrupt capabilities
+ return timer->config >> shift;
case HPET_TN_CMP: // comparator register
- return timer->cmp;
- case HPET_TN_CMP + 4:
- return timer->cmp >> 32;
+ return timer->cmp >> shift;
case HPET_TN_ROUTE:
- return timer->fsb;
- case HPET_TN_ROUTE + 4:
- return timer->fsb >> 32;
+ return timer->fsb >> shift;
default:
trace_hpet_ram_read_invalid();
break;
}
} else {
- switch (index) {
- case HPET_ID:
- return s->capability;
- case HPET_PERIOD:
- return s->capability >> 32;
+ switch (addr & ~4) {
+ case HPET_ID: // including HPET_PERIOD
+ return s->capability >> shift;
case HPET_CFG:
- return s->config;
- case HPET_CFG + 4:
- trace_hpet_invalid_hpet_cfg(4);
- return 0;
+ return s->config >> shift;
case HPET_COUNTER:
if (hpet_enabled(s)) {
cur_tick = hpet_get_ticks(s);
} else {
cur_tick = s->hpet_counter;
}
- trace_hpet_ram_read_reading_counter(0, cur_tick);
- return cur_tick;
- case HPET_COUNTER + 4:
- if (hpet_enabled(s)) {
- cur_tick = hpet_get_ticks(s);
- } else {
- cur_tick = s->hpet_counter;
- }
- trace_hpet_ram_read_reading_counter(4, cur_tick);
- return cur_tick >> 32;
+ trace_hpet_ram_read_reading_counter(addr & 4, cur_tick);
+ return cur_tick >> shift;
case HPET_STATUS:
- return s->isr;
+ return s->isr >> shift;
default:
trace_hpet_ram_read_invalid();
break;
@@ -495,15 +493,14 @@ static void hpet_ram_write(void *opaque, hwaddr addr,
{
int i;
HPETState *s = opaque;
- uint64_t old_val, new_val, val, index;
+ int shift = (addr & 4) * 8;
+ int len = MIN(size * 8, 64 - shift);
+ uint64_t old_val, new_val, cleared;
trace_hpet_ram_write(addr, value);
- index = addr;
- old_val = hpet_ram_read(opaque, addr, 4);
- new_val = value;
/*address range of all TN regs*/
- if (index >= 0x100 && index <= 0x3ff) {
+ if (addr >= 0x100 && addr <= 0x3ff) {
uint8_t timer_id = (addr - 0x100) / 0x20;
HPETTimer *timer = &s->timer[timer_id];
@@ -512,71 +509,49 @@ static void hpet_ram_write(void *opaque, hwaddr addr,
trace_hpet_timer_id_out_of_range(timer_id);
return;
}
- switch ((addr - 0x100) % 0x20) {
+ switch (addr & 0x18) {
case HPET_TN_CFG:
- trace_hpet_ram_write_tn_cfg();
- if (activating_bit(old_val, new_val, HPET_TN_FSB_ENABLE)) {
+ trace_hpet_ram_write_tn_cfg(addr & 4);
+ old_val = timer->config;
+ new_val = deposit64(old_val, shift, len, value);
+ new_val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK);
+ if (deactivating_bit(old_val, new_val, HPET_TN_TYPE_LEVEL)) {
+ /*
+ * Do this before changing timer->config; otherwise, if
+ * HPET_TN_FSB is set, update_irq will not lower the qemu_irq.
+ */
update_irq(timer, 0);
}
- val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK);
- timer->config = (timer->config & 0xffffffff00000000ULL) | val;
+ timer->config = new_val;
+ if (activating_bit(old_val, new_val, HPET_TN_ENABLE)
+ && (s->isr & (1 << timer_id))) {
+ update_irq(timer, 1);
+ }
if (new_val & HPET_TN_32BIT) {
timer->cmp = (uint32_t)timer->cmp;
timer->period = (uint32_t)timer->period;
}
- if (activating_bit(old_val, new_val, HPET_TN_ENABLE) &&
- hpet_enabled(s)) {
+ if (hpet_enabled(s)) {
hpet_set_timer(timer);
- } else if (deactivating_bit(old_val, new_val, HPET_TN_ENABLE)) {
- hpet_del_timer(timer);
}
break;
- case HPET_TN_CFG + 4: // Interrupt capabilities
- trace_hpet_ram_write_invalid_tn_cfg(4);
- break;
case HPET_TN_CMP: // comparator register
- trace_hpet_ram_write_tn_cmp(0);
if (timer->config & HPET_TN_32BIT) {
- new_val = (uint32_t)new_val;
- }
- if (!timer_is_periodic(timer)
- || (timer->config & HPET_TN_SETVAL)) {
- timer->cmp = (timer->cmp & 0xffffffff00000000ULL) | new_val;
- }
- if (timer_is_periodic(timer)) {
- /*
- * FIXME: Clamp period to reasonable min value?
- * Clamp period to reasonable max value
- */
- if (timer->config & HPET_TN_32BIT) {
- new_val = MIN(new_val, ~0u >> 1);
+ /* High 32-bits are zero, leave them untouched. */
+ if (shift) {
+ trace_hpet_ram_write_invalid_tn_cmp();
+ break;
}
- timer->period =
- (timer->period & 0xffffffff00000000ULL) | new_val;
- }
- /*
- * FIXME: on a 64-bit write, HPET_TN_SETVAL should apply to the
- * high bits part as well.
- */
- timer->config &= ~HPET_TN_SETVAL;
- if (hpet_enabled(s)) {
- hpet_set_timer(timer);
+ len = 64;
+ value = (uint32_t) value;
}
- break;
- case HPET_TN_CMP + 4: // comparator register high order
- trace_hpet_ram_write_tn_cmp(4);
+ trace_hpet_ram_write_tn_cmp(addr & 4);
if (!timer_is_periodic(timer)
|| (timer->config & HPET_TN_SETVAL)) {
- timer->cmp = (timer->cmp & 0xffffffffULL) | new_val << 32;
+ timer->cmp = deposit64(timer->cmp, shift, len, value);
}
if (timer_is_periodic(timer)) {
- /*
- * FIXME: Clamp period to reasonable min value?
- * Clamp period to reasonable max value
- */
- new_val = MIN(new_val, ~0u >> 1);
- timer->period =
- (timer->period & 0xffffffffULL) | new_val << 32;
+ timer->period = deposit64(timer->period, shift, len, value);
}
timer->config &= ~HPET_TN_SETVAL;
if (hpet_enabled(s)) {
@@ -584,10 +559,7 @@ static void hpet_ram_write(void *opaque, hwaddr addr,
}
break;
case HPET_TN_ROUTE:
- timer->fsb = (timer->fsb & 0xffffffff00000000ULL) | new_val;
- break;
- case HPET_TN_ROUTE + 4:
- timer->fsb = (new_val << 32) | (timer->fsb & 0xffffffff);
+ timer->fsb = deposit64(timer->fsb, shift, len, value);
break;
default:
trace_hpet_ram_write_invalid();
@@ -595,20 +567,23 @@ static void hpet_ram_write(void *opaque, hwaddr addr,
}
return;
} else {
- switch (index) {
+ switch (addr & ~4) {
case HPET_ID:
return;
case HPET_CFG:
- val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK);
- s->config = (s->config & 0xffffffff00000000ULL) | val;
+ old_val = s->config;
+ new_val = deposit64(old_val, shift, len, value);
+ new_val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK);
+ s->config = new_val;
if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
/* Enable main counter and interrupt generation. */
s->hpet_offset =
ticks_to_ns(s->hpet_counter) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
for (i = 0; i < s->num_timers; i++) {
- if ((&s->timer[i])->cmp != ~0ULL) {
- hpet_set_timer(&s->timer[i]);
+ if (timer_enabled(&s->timer[i]) && (s->isr & (1 << i))) {
+ update_irq(&s->timer[i], 1);
}
+ hpet_set_timer(&s->timer[i]);
}
} else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
/* Halt main counter and disable interrupt generation. */
@@ -629,13 +604,11 @@ static void hpet_ram_write(void *opaque, hwaddr addr,
qemu_set_irq(s->irqs[RTC_ISA_IRQ], s->rtc_irq_level);
}
break;
- case HPET_CFG + 4:
- trace_hpet_invalid_hpet_cfg(4);
- break;
case HPET_STATUS:
- val = new_val & s->isr;
+ new_val = value << shift;
+ cleared = new_val & s->isr;
for (i = 0; i < s->num_timers; i++) {
- if (val & (1 << i)) {
+ if (cleared & (1 << i)) {
update_irq(&s->timer[i], 0);
}
}
@@ -644,15 +617,7 @@ static void hpet_ram_write(void *opaque, hwaddr addr,
if (hpet_enabled(s)) {
trace_hpet_ram_write_counter_write_while_enabled();
}
- s->hpet_counter =
- (s->hpet_counter & 0xffffffff00000000ULL) | value;
- trace_hpet_ram_write_counter_written(0, value, s->hpet_counter);
- break;
- case HPET_COUNTER + 4:
- trace_hpet_ram_write_counter_write_while_enabled();
- s->hpet_counter =
- (s->hpet_counter & 0xffffffffULL) | (((uint64_t)value) << 32);
- trace_hpet_ram_write_counter_written(4, value, s->hpet_counter);
+ s->hpet_counter = deposit64(s->hpet_counter, shift, len, value);
break;
default:
trace_hpet_ram_write_invalid();
@@ -666,7 +631,11 @@ static const MemoryRegionOps hpet_ram_ops = {
.write = hpet_ram_write,
.valid = {
.min_access_size = 4,
- .max_access_size = 4,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 8,
},
.endianness = DEVICE_NATIVE_ENDIAN,
};
@@ -789,7 +758,7 @@ static void hpet_device_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = hpet_realize;
- dc->reset = hpet_reset;
+ device_class_set_legacy_reset(dc, hpet_reset);
dc->vmsd = &vmstate_hpet;
device_class_set_props(dc, hpet_device_properties);
}
diff --git a/hw/timer/i8254.c b/hw/timer/i8254.c
index c235496..058fc61 100644
--- a/hw/timer/i8254.c
+++ b/hw/timer/i8254.c
@@ -360,7 +360,7 @@ static void pit_class_initfn(ObjectClass *klass, void *data)
k->set_channel_gate = pit_set_channel_gate;
k->get_channel_info = pit_get_channel_info_common;
k->post_load = pit_post_load;
- dc->reset = pit_reset;
+ device_class_set_legacy_reset(dc, pit_reset);
}
static const TypeInfo pit_info = {
diff --git a/hw/timer/ibex_timer.c b/hw/timer/ibex_timer.c
index 4917388..2bdcff5 100644
--- a/hw/timer/ibex_timer.c
+++ b/hw/timer/ibex_timer.c
@@ -291,7 +291,7 @@ static void ibex_timer_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = ibex_timer_reset;
+ device_class_set_legacy_reset(dc, ibex_timer_reset);
dc->vmsd = &vmstate_ibex_timer;
dc->realize = ibex_timer_realize;
device_class_set_props(dc, ibex_timer_properties);
diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c
index bd62520..f40ab16 100644
--- a/hw/timer/imx_epit.c
+++ b/hw/timer/imx_epit.c
@@ -432,7 +432,7 @@ static void imx_epit_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = imx_epit_realize;
- dc->reset = imx_epit_dev_reset;
+ device_class_set_legacy_reset(dc, imx_epit_dev_reset);
dc->vmsd = &vmstate_imx_timer_epit;
dc->desc = "i.MX periodic timer";
}
diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c
index a8edaec..23b3d79 100644
--- a/hw/timer/imx_gpt.c
+++ b/hw/timer/imx_gpt.c
@@ -524,7 +524,7 @@ static void imx_gpt_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = imx_gpt_realize;
- dc->reset = imx_gpt_reset;
+ device_class_set_legacy_reset(dc, imx_gpt_reset);
dc->vmsd = &vmstate_imx_timer_gpt;
dc->desc = "i.MX general timer";
}
diff --git a/hw/timer/meson.build b/hw/timer/meson.build
index 8042785..f5f9eed 100644
--- a/hw/timer/meson.build
+++ b/hw/timer/meson.build
@@ -10,7 +10,6 @@ system_ss.add(when: 'CONFIG_CMSDK_APB_TIMER', if_true: files('cmsdk-apb-timer.c'
system_ss.add(when: 'CONFIG_RENESAS_TMR', if_true: files('renesas_tmr.c'))
system_ss.add(when: 'CONFIG_RENESAS_CMT', if_true: files('renesas_cmt.c'))
system_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic-timer.c'))
-system_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_timer.c'))
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_mct.c'))
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_pwm.c'))
system_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_gptimer.c'))
@@ -22,9 +21,7 @@ system_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('mips_gictimer.c'))
system_ss.add(when: 'CONFIG_MSF2', if_true: files('mss-timer.c'))
system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_timer.c'))
system_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_timer.c'))
-system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_gptimer.c'))
-system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_synctimer.c'))
-system_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_timer.c'))
+system_ss.add(when: 'CONFIG_PXA2XX_TIMER', if_true: files('pxa2xx_timer.c'))
system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_systmr.c'))
system_ss.add(when: 'CONFIG_SH_TIMER', if_true: files('sh_timer.c'))
system_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_timer.c'))
diff --git a/hw/timer/nrf51_timer.c b/hw/timer/nrf51_timer.c
index a33166a..35b0e62 100644
--- a/hw/timer/nrf51_timer.c
+++ b/hw/timer/nrf51_timer.c
@@ -388,7 +388,7 @@ static void nrf51_timer_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = nrf51_timer_reset;
+ device_class_set_legacy_reset(dc, nrf51_timer_reset);
dc->vmsd = &vmstate_nrf51_timer;
device_class_set_props(dc, nrf51_timer_properties);
}
diff --git a/hw/timer/omap_gptimer.c b/hw/timer/omap_gptimer.c
deleted file mode 100644
index 34e6af7..0000000
--- a/hw/timer/omap_gptimer.c
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- * TI OMAP2 general purpose timers emulation.
- *
- * Copyright (C) 2007-2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "hw/irq.h"
-#include "qemu/timer.h"
-#include "hw/arm/omap.h"
-
-/* GP timers */
-struct omap_gp_timer_s {
- MemoryRegion iomem;
- qemu_irq irq;
- qemu_irq wkup;
- qemu_irq in;
- qemu_irq out;
- omap_clk clk;
- QEMUTimer *timer;
- QEMUTimer *match;
- struct omap_target_agent_s *ta;
-
- int in_val;
- int out_val;
- int64_t time;
- int64_t rate;
- int64_t ticks_per_sec;
-
- int16_t config;
- int status;
- int it_ena;
- int wu_ena;
- int enable;
- int inout;
- int capt2;
- int pt;
- enum {
- gpt_trigger_none, gpt_trigger_overflow, gpt_trigger_both
- } trigger;
- enum {
- gpt_capture_none, gpt_capture_rising,
- gpt_capture_falling, gpt_capture_both
- } capture;
- int scpwm;
- int ce;
- int pre;
- int ptv;
- int ar;
- int st;
- int posted;
- uint32_t val;
- uint32_t load_val;
- uint32_t capture_val[2];
- uint32_t match_val;
- int capt_num;
-
- uint16_t writeh; /* LSB */
- uint16_t readh; /* MSB */
-};
-
-#define GPT_TCAR_IT (1 << 2)
-#define GPT_OVF_IT (1 << 1)
-#define GPT_MAT_IT (1 << 0)
-
-static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it)
-{
- if (timer->it_ena & it) {
- if (!timer->status)
- qemu_irq_raise(timer->irq);
-
- timer->status |= it;
- /* Or are the status bits set even when masked?
- * i.e. is masking applied before or after the status register? */
- }
-
- if (timer->wu_ena & it)
- qemu_irq_pulse(timer->wkup);
-}
-
-static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level)
-{
- if (!timer->inout && timer->out_val != level) {
- timer->out_val = level;
- qemu_set_irq(timer->out, level);
- }
-}
-
-static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer)
-{
- uint64_t distance;
-
- if (timer->st && timer->rate) {
- distance = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->time;
- distance = muldiv64(distance, timer->rate, timer->ticks_per_sec);
-
- if (distance >= 0xffffffff - timer->val)
- return 0xffffffff;
- else
- return timer->val + distance;
- } else
- return timer->val;
-}
-
-static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer)
-{
- if (timer->st) {
- timer->val = omap_gp_timer_read(timer);
- timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- }
-}
-
-static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer)
-{
- int64_t expires, matches;
-
- if (timer->st && timer->rate) {
- expires = muldiv64(0x100000000ll - timer->val,
- timer->ticks_per_sec, timer->rate);
- timer_mod(timer->timer, timer->time + expires);
-
- if (timer->ce && timer->match_val >= timer->val) {
- matches = muldiv64(timer->ticks_per_sec,
- timer->match_val - timer->val, timer->rate);
- timer_mod(timer->match, timer->time + matches);
- } else
- timer_del(timer->match);
- } else {
- timer_del(timer->timer);
- timer_del(timer->match);
- omap_gp_timer_out(timer, timer->scpwm);
- }
-}
-
-static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer)
-{
- if (timer->pt)
- /* TODO in overflow-and-match mode if the first event to
- * occur is the match, don't toggle. */
- omap_gp_timer_out(timer, !timer->out_val);
- else
- /* TODO inverted pulse on timer->out_val == 1? */
- qemu_irq_pulse(timer->out);
-}
-
-static void omap_gp_timer_tick(void *opaque)
-{
- struct omap_gp_timer_s *timer = opaque;
-
- if (!timer->ar) {
- timer->st = 0;
- timer->val = 0;
- } else {
- timer->val = timer->load_val;
- timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- }
-
- if (timer->trigger == gpt_trigger_overflow ||
- timer->trigger == gpt_trigger_both)
- omap_gp_timer_trigger(timer);
-
- omap_gp_timer_intr(timer, GPT_OVF_IT);
- omap_gp_timer_update(timer);
-}
-
-static void omap_gp_timer_match(void *opaque)
-{
- struct omap_gp_timer_s *timer = opaque;
-
- if (timer->trigger == gpt_trigger_both)
- omap_gp_timer_trigger(timer);
-
- omap_gp_timer_intr(timer, GPT_MAT_IT);
-}
-
-static void omap_gp_timer_input(void *opaque, int line, int on)
-{
- struct omap_gp_timer_s *s = opaque;
- int trigger;
-
- switch (s->capture) {
- default:
- case gpt_capture_none:
- trigger = 0;
- break;
- case gpt_capture_rising:
- trigger = !s->in_val && on;
- break;
- case gpt_capture_falling:
- trigger = s->in_val && !on;
- break;
- case gpt_capture_both:
- trigger = (s->in_val == !on);
- break;
- }
- s->in_val = on;
-
- if (s->inout && trigger && s->capt_num < 2) {
- s->capture_val[s->capt_num] = omap_gp_timer_read(s);
-
- if (s->capt2 == s->capt_num ++)
- omap_gp_timer_intr(s, GPT_TCAR_IT);
- }
-}
-
-static void omap_gp_timer_clk_update(void *opaque, int line, int on)
-{
- struct omap_gp_timer_s *timer = opaque;
-
- omap_gp_timer_sync(timer);
- timer->rate = on ? omap_clk_getrate(timer->clk) : 0;
- omap_gp_timer_update(timer);
-}
-
-static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer)
-{
- omap_clk_adduser(timer->clk,
- qemu_allocate_irq(omap_gp_timer_clk_update, timer, 0));
- timer->rate = omap_clk_getrate(timer->clk);
-}
-
-void omap_gp_timer_reset(struct omap_gp_timer_s *s)
-{
- s->config = 0x000;
- s->status = 0;
- s->it_ena = 0;
- s->wu_ena = 0;
- s->inout = 0;
- s->capt2 = 0;
- s->capt_num = 0;
- s->pt = 0;
- s->trigger = gpt_trigger_none;
- s->capture = gpt_capture_none;
- s->scpwm = 0;
- s->ce = 0;
- s->pre = 0;
- s->ptv = 0;
- s->ar = 0;
- s->st = 0;
- s->posted = 1;
- s->val = 0x00000000;
- s->load_val = 0x00000000;
- s->capture_val[0] = 0x00000000;
- s->capture_val[1] = 0x00000000;
- s->match_val = 0x00000000;
- omap_gp_timer_update(s);
-}
-
-static uint32_t omap_gp_timer_readw(void *opaque, hwaddr addr)
-{
- struct omap_gp_timer_s *s = opaque;
-
- switch (addr) {
- case 0x00: /* TIDR */
- return 0x21;
-
- case 0x10: /* TIOCP_CFG */
- return s->config;
-
- case 0x14: /* TISTAT */
- /* ??? When's this bit reset? */
- return 1; /* RESETDONE */
-
- case 0x18: /* TISR */
- return s->status;
-
- case 0x1c: /* TIER */
- return s->it_ena;
-
- case 0x20: /* TWER */
- return s->wu_ena;
-
- case 0x24: /* TCLR */
- return (s->inout << 14) |
- (s->capt2 << 13) |
- (s->pt << 12) |
- (s->trigger << 10) |
- (s->capture << 8) |
- (s->scpwm << 7) |
- (s->ce << 6) |
- (s->pre << 5) |
- (s->ptv << 2) |
- (s->ar << 1) |
- (s->st << 0);
-
- case 0x28: /* TCRR */
- return omap_gp_timer_read(s);
-
- case 0x2c: /* TLDR */
- return s->load_val;
-
- case 0x30: /* TTGR */
- return 0xffffffff;
-
- case 0x34: /* TWPS */
- return 0x00000000; /* No posted writes pending. */
-
- case 0x38: /* TMAR */
- return s->match_val;
-
- case 0x3c: /* TCAR1 */
- return s->capture_val[0];
-
- case 0x40: /* TSICR */
- return s->posted << 2;
-
- case 0x44: /* TCAR2 */
- return s->capture_val[1];
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static uint32_t omap_gp_timer_readh(void *opaque, hwaddr addr)
-{
- struct omap_gp_timer_s *s = opaque;
- uint32_t ret;
-
- if (addr & 2)
- return s->readh;
- else {
- ret = omap_gp_timer_readw(opaque, addr);
- s->readh = ret >> 16;
- return ret & 0xffff;
- }
-}
-
-static void omap_gp_timer_write(void *opaque, hwaddr addr, uint32_t value)
-{
- struct omap_gp_timer_s *s = opaque;
-
- switch (addr) {
- case 0x00: /* TIDR */
- case 0x14: /* TISTAT */
- case 0x34: /* TWPS */
- case 0x3c: /* TCAR1 */
- case 0x44: /* TCAR2 */
- OMAP_RO_REG(addr);
- break;
-
- case 0x10: /* TIOCP_CFG */
- s->config = value & 0x33d;
- if (((value >> 3) & 3) == 3) /* IDLEMODE */
- fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n",
- __func__);
- if (value & 2) /* SOFTRESET */
- omap_gp_timer_reset(s);
- break;
-
- case 0x18: /* TISR */
- if (value & GPT_TCAR_IT)
- s->capt_num = 0;
- if (s->status && !(s->status &= ~value))
- qemu_irq_lower(s->irq);
- break;
-
- case 0x1c: /* TIER */
- s->it_ena = value & 7;
- break;
-
- case 0x20: /* TWER */
- s->wu_ena = value & 7;
- break;
-
- case 0x24: /* TCLR */
- omap_gp_timer_sync(s);
- s->inout = (value >> 14) & 1;
- s->capt2 = (value >> 13) & 1;
- s->pt = (value >> 12) & 1;
- s->trigger = (value >> 10) & 3;
- if (s->capture == gpt_capture_none &&
- ((value >> 8) & 3) != gpt_capture_none)
- s->capt_num = 0;
- s->capture = (value >> 8) & 3;
- s->scpwm = (value >> 7) & 1;
- s->ce = (value >> 6) & 1;
- s->pre = (value >> 5) & 1;
- s->ptv = (value >> 2) & 7;
- s->ar = (value >> 1) & 1;
- s->st = (value >> 0) & 1;
- if (s->inout && s->trigger != gpt_trigger_none)
- fprintf(stderr, "%s: GP timer pin must be an output "
- "for this trigger mode\n", __func__);
- if (!s->inout && s->capture != gpt_capture_none)
- fprintf(stderr, "%s: GP timer pin must be an input "
- "for this capture mode\n", __func__);
- if (s->trigger == gpt_trigger_none)
- omap_gp_timer_out(s, s->scpwm);
- /* TODO: make sure this doesn't overflow 32-bits */
- s->ticks_per_sec = NANOSECONDS_PER_SECOND << (s->pre ? s->ptv + 1 : 0);
- omap_gp_timer_update(s);
- break;
-
- case 0x28: /* TCRR */
- s->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- s->val = value;
- omap_gp_timer_update(s);
- break;
-
- case 0x2c: /* TLDR */
- s->load_val = value;
- break;
-
- case 0x30: /* TTGR */
- s->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- s->val = s->load_val;
- omap_gp_timer_update(s);
- break;
-
- case 0x38: /* TMAR */
- omap_gp_timer_sync(s);
- s->match_val = value;
- omap_gp_timer_update(s);
- break;
-
- case 0x40: /* TSICR */
- s->posted = (value >> 2) & 1;
- if (value & 2) /* How much exactly are we supposed to reset? */
- omap_gp_timer_reset(s);
- break;
-
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static void omap_gp_timer_writeh(void *opaque, hwaddr addr, uint32_t value)
-{
- struct omap_gp_timer_s *s = opaque;
-
- if (addr & 2)
- omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh);
- else
- s->writeh = (uint16_t) value;
-}
-
-static uint64_t omap_gp_timer_readfn(void *opaque, hwaddr addr,
- unsigned size)
-{
- switch (size) {
- case 1:
- return omap_badwidth_read32(opaque, addr);
- case 2:
- return omap_gp_timer_readh(opaque, addr);
- case 4:
- return omap_gp_timer_readw(opaque, addr);
- default:
- g_assert_not_reached();
- }
-}
-
-static void omap_gp_timer_writefn(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- switch (size) {
- case 1:
- omap_badwidth_write32(opaque, addr, value);
- break;
- case 2:
- omap_gp_timer_writeh(opaque, addr, value);
- break;
- case 4:
- omap_gp_timer_write(opaque, addr, value);
- break;
- default:
- g_assert_not_reached();
- }
-}
-
-static const MemoryRegionOps omap_gp_timer_ops = {
- .read = omap_gp_timer_readfn,
- .write = omap_gp_timer_writefn,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
- qemu_irq irq, omap_clk fclk, omap_clk iclk)
-{
- struct omap_gp_timer_s *s = g_new0(struct omap_gp_timer_s, 1);
-
- s->ta = ta;
- s->irq = irq;
- s->clk = fclk;
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_gp_timer_tick, s);
- s->match = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_gp_timer_match, s);
- s->in = qemu_allocate_irq(omap_gp_timer_input, s, 0);
- omap_gp_timer_reset(s);
- omap_gp_timer_clk_setup(s);
-
- memory_region_init_io(&s->iomem, NULL, &omap_gp_timer_ops, s, "omap.gptimer",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &s->iomem);
-
- return s;
-}
diff --git a/hw/timer/omap_synctimer.c b/hw/timer/omap_synctimer.c
deleted file mode 100644
index d93a934..0000000
--- a/hw/timer/omap_synctimer.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * TI OMAP2 32kHz sync timer emulation.
- *
- * Copyright (C) 2007-2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) any later version of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "qemu/osdep.h"
-#include "qemu/timer.h"
-#include "hw/arm/omap.h"
-struct omap_synctimer_s {
- MemoryRegion iomem;
- uint32_t val;
- uint16_t readh;
-};
-
-/* 32-kHz Sync Timer of the OMAP2 */
-static uint32_t omap_synctimer_read(struct omap_synctimer_s *s) {
- return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 0x8000,
- NANOSECONDS_PER_SECOND);
-}
-
-void omap_synctimer_reset(struct omap_synctimer_s *s)
-{
- s->val = omap_synctimer_read(s);
-}
-
-static uint32_t omap_synctimer_readw(void *opaque, hwaddr addr)
-{
- struct omap_synctimer_s *s = opaque;
-
- switch (addr) {
- case 0x00: /* 32KSYNCNT_REV */
- return 0x21;
-
- case 0x10: /* CR */
- return omap_synctimer_read(s) - s->val;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static uint32_t omap_synctimer_readh(void *opaque, hwaddr addr)
-{
- struct omap_synctimer_s *s = opaque;
- uint32_t ret;
-
- if (addr & 2)
- return s->readh;
- else {
- ret = omap_synctimer_readw(opaque, addr);
- s->readh = ret >> 16;
- return ret & 0xffff;
- }
-}
-
-static uint64_t omap_synctimer_readfn(void *opaque, hwaddr addr,
- unsigned size)
-{
- switch (size) {
- case 1:
- return omap_badwidth_read32(opaque, addr);
- case 2:
- return omap_synctimer_readh(opaque, addr);
- case 4:
- return omap_synctimer_readw(opaque, addr);
- default:
- g_assert_not_reached();
- }
-}
-
-static void omap_synctimer_writefn(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- OMAP_BAD_REG(addr);
-}
-
-static const MemoryRegionOps omap_synctimer_ops = {
- .read = omap_synctimer_readfn,
- .write = omap_synctimer_writefn,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_synctimer_s *omap_synctimer_init(struct omap_target_agent_s *ta,
- struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk)
-{
- struct omap_synctimer_s *s = g_malloc0(sizeof(*s));
-
- omap_synctimer_reset(s);
- memory_region_init_io(&s->iomem, NULL, &omap_synctimer_ops, s, "omap.synctimer",
- omap_l4_region_size(ta, 0));
- omap_l4_attach(ta, 0, &s->iomem);
-
- return s;
-}
diff --git a/hw/timer/pxa2xx_timer.c b/hw/timer/pxa2xx_timer.c
index 6479ab1..3234bbb 100644
--- a/hw/timer/pxa2xx_timer.c
+++ b/hw/timer/pxa2xx_timer.c
@@ -12,7 +12,6 @@
#include "hw/qdev-properties.h"
#include "qemu/timer.h"
#include "sysemu/runstate.h"
-#include "hw/arm/pxa.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "qemu/log.h"
@@ -55,7 +54,6 @@
#define OSNR 0x20
#define PXA25X_FREQ 3686400 /* 3.6864 MHz */
-#define PXA27X_FREQ 3250000 /* 3.25 MHz */
static int pxa2xx_timer4_freq[8] = {
[0] = 0,
@@ -573,28 +571,6 @@ static const TypeInfo pxa25x_timer_dev_info = {
.class_init = pxa25x_timer_dev_class_init,
};
-static Property pxa27x_timer_dev_properties[] = {
- DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ),
- DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
- PXA2XX_TIMER_HAVE_TM4, true),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->desc = "PXA27x timer";
- device_class_set_props(dc, pxa27x_timer_dev_properties);
-}
-
-static const TypeInfo pxa27x_timer_dev_info = {
- .name = "pxa27x-timer",
- .parent = TYPE_PXA2XX_TIMER,
- .instance_size = sizeof(PXA2xxTimerInfo),
- .class_init = pxa27x_timer_dev_class_init,
-};
-
static void pxa2xx_timer_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -616,7 +592,6 @@ static void pxa2xx_timer_register_types(void)
{
type_register_static(&pxa2xx_timer_type_info);
type_register_static(&pxa25x_timer_dev_info);
- type_register_static(&pxa27x_timer_dev_info);
}
type_init(pxa2xx_timer_register_types)
diff --git a/hw/timer/renesas_cmt.c b/hw/timer/renesas_cmt.c
index 0883293..cd59b08 100644
--- a/hw/timer/renesas_cmt.c
+++ b/hw/timer/renesas_cmt.c
@@ -263,7 +263,7 @@ static void rcmt_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_rcmt;
- dc->reset = rcmt_reset;
+ device_class_set_legacy_reset(dc, rcmt_reset);
device_class_set_props(dc, rcmt_properties);
}
diff --git a/hw/timer/renesas_tmr.c b/hw/timer/renesas_tmr.c
index 1d47d06..a93e075 100644
--- a/hw/timer/renesas_tmr.c
+++ b/hw/timer/renesas_tmr.c
@@ -473,7 +473,7 @@ static void rtmr_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_rtmr;
- dc->reset = rtmr_reset;
+ device_class_set_legacy_reset(dc, rtmr_reset);
device_class_set_props(dc, rtmr_properties);
}
diff --git a/hw/timer/sifive_pwm.c b/hw/timer/sifive_pwm.c
index e8610c3..4602fc1 100644
--- a/hw/timer/sifive_pwm.c
+++ b/hw/timer/sifive_pwm.c
@@ -446,7 +446,7 @@ static void sifive_pwm_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = sifive_pwm_reset;
+ device_class_set_legacy_reset(dc, sifive_pwm_reset);
device_class_set_props(dc, sifive_pwm_properties);
dc->vmsd = &vmstate_sifive_pwm;
dc->realize = sifive_pwm_realize;
diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c
index 5507b01..12cb3ba 100644
--- a/hw/timer/slavio_timer.c
+++ b/hw/timer/slavio_timer.c
@@ -429,7 +429,7 @@ static void slavio_timer_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = slavio_timer_reset;
+ device_class_set_legacy_reset(dc, slavio_timer_reset);
dc->vmsd = &vmstate_slavio_timer;
device_class_set_props(dc, slavio_timer_properties);
}
diff --git a/hw/timer/sse-counter.c b/hw/timer/sse-counter.c
index daceedf..f17064a 100644
--- a/hw/timer/sse-counter.c
+++ b/hw/timer/sse-counter.c
@@ -454,7 +454,7 @@ static void sse_counter_class_init(ObjectClass *klass, void *data)
dc->realize = sse_counter_realize;
dc->vmsd = &sse_counter_vmstate;
- dc->reset = sse_counter_reset;
+ device_class_set_legacy_reset(dc, sse_counter_reset);
}
static const TypeInfo sse_counter_info = {
diff --git a/hw/timer/sse-timer.c b/hw/timer/sse-timer.c
index cb20a9e..115b013 100644
--- a/hw/timer/sse-timer.c
+++ b/hw/timer/sse-timer.c
@@ -451,7 +451,7 @@ static void sse_timer_class_init(ObjectClass *klass, void *data)
dc->realize = sse_timer_realize;
dc->vmsd = &sse_timer_vmstate;
- dc->reset = sse_timer_reset;
+ device_class_set_legacy_reset(dc, sse_timer_reset);
device_class_set_props(dc, sse_timer_properties);
}
diff --git a/hw/timer/stm32f2xx_timer.c b/hw/timer/stm32f2xx_timer.c
index de4208b..16b4788 100644
--- a/hw/timer/stm32f2xx_timer.c
+++ b/hw/timer/stm32f2xx_timer.c
@@ -325,7 +325,7 @@ static void stm32f2xx_timer_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = stm32f2xx_timer_reset;
+ device_class_set_legacy_reset(dc, stm32f2xx_timer_reset);
device_class_set_props(dc, stm32f2xx_timer_properties);
dc->vmsd = &vmstate_stm32f2xx_timer;
dc->realize = stm32f2xx_timer_realize;
diff --git a/hw/timer/trace-events b/hw/timer/trace-events
index de769f4..f48a712 100644
--- a/hw/timer/trace-events
+++ b/hw/timer/trace-events
@@ -108,9 +108,9 @@ hpet_ram_read_reading_counter(uint8_t reg_off, uint64_t cur_tick) "reading count
hpet_ram_read_invalid(void) "invalid hpet_ram_readl"
hpet_ram_write(uint64_t addr, uint64_t value) "enter hpet_ram_writel at 0x%" PRIx64 " = 0x%" PRIx64
hpet_ram_write_timer_id(uint64_t timer_id) "hpet_ram_writel timer_id = 0x%" PRIx64
-hpet_ram_write_tn_cfg(void) "hpet_ram_writel HPET_TN_CFG"
-hpet_ram_write_invalid_tn_cfg(uint8_t reg_off) "invalid HPET_TN_CFG + %" PRIu8 " write"
+hpet_ram_write_tn_cfg(uint8_t reg_off) "hpet_ram_writel HPET_TN_CFG + %" PRIu8
hpet_ram_write_tn_cmp(uint8_t reg_off) "hpet_ram_writel HPET_TN_CMP + %" PRIu8
+hpet_ram_write_invalid_tn_cmp(void) "invalid HPET_TN_CMP + 4 write"
hpet_ram_write_invalid(void) "invalid hpet_ram_writel"
hpet_ram_write_counter_write_while_enabled(void) "Writing counter while HPET enabled!"
hpet_ram_write_counter_written(uint8_t reg_off, uint64_t value, uint64_t counter) "HPET counter + %" PRIu8 "written. crt = 0x%" PRIx64 " -> 0x%" PRIx64
diff --git a/hw/tpm/tpm_spapr.c b/hw/tpm/tpm_spapr.c
index e084e98..5f7a0df 100644
--- a/hw/tpm/tpm_spapr.c
+++ b/hw/tpm/tpm_spapr.c
@@ -206,7 +206,6 @@ static int tpm_spapr_do_crq(struct SpaprVioDevice *dev, uint8_t *crq_data)
break;
default:
g_assert_not_reached();
- break;
}
trace_tpm_spapr_do_crq_get_version(be32_to_cpu(local_crq.data));
spapr_tpm_send_crq(dev, &local_crq);
diff --git a/hw/tpm/tpm_tis_i2c.c b/hw/tpm/tpm_tis_i2c.c
index 4bb0965..c5548b0 100644
--- a/hw/tpm/tpm_tis_i2c.c
+++ b/hw/tpm/tpm_tis_i2c.c
@@ -538,7 +538,7 @@ static void tpm_tis_i2c_class_init(ObjectClass *klass, void *data)
TPMIfClass *tc = TPM_IF_CLASS(klass);
dc->realize = tpm_tis_i2c_realizefn;
- dc->reset = tpm_tis_i2c_reset;
+ device_class_set_legacy_reset(dc, tpm_tis_i2c_reset);
dc->vmsd = &vmstate_tpm_tis_i2c;
device_class_set_props(dc, tpm_tis_i2c_properties);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
diff --git a/hw/tpm/tpm_tis_isa.c b/hw/tpm/tpm_tis_isa.c
index 8887b3c..21109ed 100644
--- a/hw/tpm/tpm_tis_isa.c
+++ b/hw/tpm/tpm_tis_isa.c
@@ -177,7 +177,7 @@ static void tpm_tis_isa_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_tpm_tis_isa;
tc->model = TPM_MODEL_TPM_TIS;
dc->realize = tpm_tis_isa_realizefn;
- dc->reset = tpm_tis_isa_reset;
+ device_class_set_legacy_reset(dc, tpm_tis_isa_reset);
tc->request_completed = tpm_tis_isa_request_completed;
tc->get_version = tpm_tis_isa_get_tpm_version;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
diff --git a/hw/tpm/tpm_tis_sysbus.c b/hw/tpm/tpm_tis_sysbus.c
index 941f7f7..967f264 100644
--- a/hw/tpm/tpm_tis_sysbus.c
+++ b/hw/tpm/tpm_tis_sysbus.c
@@ -135,7 +135,7 @@ static void tpm_tis_sysbus_class_init(ObjectClass *klass, void *data)
tc->model = TPM_MODEL_TPM_TIS;
dc->realize = tpm_tis_sysbus_realizefn;
dc->user_creatable = true;
- dc->reset = tpm_tis_sysbus_reset;
+ device_class_set_legacy_reset(dc, tpm_tis_sysbus_reset);
tc->request_completed = tpm_tis_sysbus_request_completed;
tc->get_version = tpm_tis_sysbus_get_tpm_version;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
diff --git a/hw/tricore/tricore_testdevice.c b/hw/tricore/tricore_testdevice.c
index 9028d97..ae95c49 100644
--- a/hw/tricore/tricore_testdevice.c
+++ b/hw/tricore/tricore_testdevice.c
@@ -67,7 +67,7 @@ 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;
+ device_class_set_legacy_reset(dc, tricore_testdevice_reset);
}
static const TypeInfo tricore_testdevice_info = {
diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
index 945a0ea..79f786e 100644
--- a/hw/ufs/ufs.c
+++ b/hw/ufs/ufs.c
@@ -851,6 +851,14 @@ void ufs_build_upiu_header(UfsRequest *req, uint8_t trans_type, uint8_t flags,
req->rsp_upiu.header.data_segment_length = cpu_to_be16(data_segment_length);
}
+void ufs_build_query_response(UfsRequest *req)
+{
+ req->rsp_upiu.qr.opcode = req->req_upiu.qr.opcode;
+ req->rsp_upiu.qr.idn = req->req_upiu.qr.idn;
+ req->rsp_upiu.qr.index = req->req_upiu.qr.index;
+ req->rsp_upiu.qr.selector = req->req_upiu.qr.selector;
+}
+
static UfsReqResult ufs_exec_scsi_cmd(UfsRequest *req)
{
UfsHc *u = req->hc;
@@ -1103,10 +1111,13 @@ static uint32_t ufs_read_attr_value(UfsHc *u, uint8_t idn)
return 0;
}
-static void ufs_write_attr_value(UfsHc *u, uint8_t idn, uint32_t value)
+static QueryRespCode ufs_write_attr_value(UfsHc *u, uint8_t idn, uint32_t value)
{
switch (idn) {
case UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL:
+ if (value > UFS_QUERY_ATTR_ACTIVE_ICC_MAXVALUE) {
+ return UFS_QUERY_RESULT_INVALID_VALUE;
+ }
u->attributes.active_icc_level = value;
break;
case UFS_QUERY_ATTR_IDN_MAX_DATA_IN:
@@ -1134,6 +1145,7 @@ static void ufs_write_attr_value(UfsHc *u, uint8_t idn, uint32_t value)
u->attributes.psa_data_size = cpu_to_be32(value);
break;
}
+ return UFS_QUERY_RESULT_SUCCESS;
}
static QueryRespCode ufs_exec_query_attr(UfsRequest *req, int op)
@@ -1150,13 +1162,13 @@ static QueryRespCode ufs_exec_query_attr(UfsRequest *req, int op)
if (op == UFS_QUERY_ATTR_READ) {
value = ufs_read_attr_value(u, idn);
+ ret = UFS_QUERY_RESULT_SUCCESS;
} else {
- value = be32_to_cpu(req->req_upiu.qr.value);
- ufs_write_attr_value(u, idn, value);
+ value = req->req_upiu.qr.value;
+ ret = ufs_write_attr_value(u, idn, value);
}
-
req->rsp_upiu.qr.value = cpu_to_be32(value);
- return UFS_QUERY_RESULT_SUCCESS;
+ return ret;
}
static const RpmbUnitDescriptor rpmb_unit_desc = {
@@ -1279,9 +1291,12 @@ static QueryRespCode ufs_read_desc(UfsRequest *req)
UfsHc *u = req->hc;
QueryRespCode status;
uint8_t idn = req->req_upiu.qr.idn;
+ uint8_t selector = req->req_upiu.qr.selector;
uint16_t length = be16_to_cpu(req->req_upiu.qr.length);
InterconnectDescriptor desc;
-
+ if (selector != 0) {
+ return UFS_QUERY_RESULT_INVALID_SELECTOR;
+ }
switch (idn) {
case UFS_QUERY_DESC_IDN_DEVICE:
memcpy(&req->rsp_upiu.qr.data, &u->device_desc, sizeof(u->device_desc));
@@ -1327,10 +1342,6 @@ static QueryRespCode ufs_read_desc(UfsRequest *req)
if (length > req->rsp_upiu.qr.data[0]) {
length = req->rsp_upiu.qr.data[0];
}
- req->rsp_upiu.qr.opcode = req->req_upiu.qr.opcode;
- req->rsp_upiu.qr.idn = req->req_upiu.qr.idn;
- req->rsp_upiu.qr.index = req->req_upiu.qr.index;
- req->rsp_upiu.qr.selector = req->req_upiu.qr.selector;
req->rsp_upiu.qr.length = cpu_to_be16(length);
return status;
@@ -1411,6 +1422,7 @@ static UfsReqResult ufs_exec_query_cmd(UfsRequest *req)
data_segment_length = be16_to_cpu(req->rsp_upiu.qr.length);
ufs_build_upiu_header(req, UFS_UPIU_TRANSACTION_QUERY_RSP, 0, status, 0,
data_segment_length);
+ ufs_build_query_response(req);
if (status != UFS_QUERY_RESULT_SUCCESS) {
return UFS_REQUEST_FAIL;
diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h
index 6c9382c..4bcc41f 100644
--- a/hw/ufs/ufs.h
+++ b/hw/ufs/ufs.h
@@ -228,6 +228,7 @@ static inline bool is_wlun(uint8_t lun)
void ufs_build_upiu_header(UfsRequest *req, uint8_t trans_type, uint8_t flags,
uint8_t response, uint8_t scsi_status,
uint16_t data_segment_length);
+void ufs_build_query_response(UfsRequest *req);
void ufs_complete_req(UfsRequest *req, UfsReqResult req_result);
void ufs_init_wlu(UfsLu *wlu, uint8_t wlun);
#endif /* HW_UFS_UFS_H */
diff --git a/hw/usb/Kconfig b/hw/usb/Kconfig
index 84bc7fb..5fbecd2 100644
--- a/hw/usb/Kconfig
+++ b/hw/usb/Kconfig
@@ -53,18 +53,10 @@ config USB_XHCI_SYSBUS
bool
select USB_XHCI
-config USB_MUSB
- bool
- select USB
-
config USB_DWC2
bool
select USB
-config TUSB6010
- bool
- select USB_MUSB
-
config USB_HUB
bool
default y
diff --git a/hw/usb/hcd-dwc3.c b/hw/usb/hcd-dwc3.c
index 09d8e25..e7d8c79 100644
--- a/hw/usb/hcd-dwc3.c
+++ b/hw/usb/hcd-dwc3.c
@@ -666,7 +666,7 @@ static void usb_dwc3_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = usb_dwc3_reset;
+ device_class_set_legacy_reset(dc, usb_dwc3_reset);
dc->realize = usb_dwc3_realize;
dc->vmsd = &vmstate_usb_dwc3;
device_class_set_props(dc, usb_dwc3_properties);
diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c
index 3ff54ed..c94fc9f 100644
--- a/hw/usb/hcd-ehci-pci.c
+++ b/hw/usb/hcd-ehci-pci.c
@@ -162,7 +162,7 @@ static void ehci_class_init(ObjectClass *klass, void *data)
k->config_write = usb_ehci_pci_write_config;
dc->vmsd = &vmstate_ehci_pci;
device_class_set_props(dc, ehci_pci_properties);
- dc->reset = usb_ehci_pci_reset;
+ device_class_set_legacy_reset(dc, usb_ehci_pci_reset);
}
static const TypeInfo ehci_pci_type_info = {
diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c
index fe1dabd..2b1652f 100644
--- a/hw/usb/hcd-ehci-sysbus.c
+++ b/hw/usb/hcd-ehci-sysbus.c
@@ -93,7 +93,7 @@ static void ehci_sysbus_class_init(ObjectClass *klass, void *data)
dc->realize = usb_ehci_sysbus_realize;
dc->vmsd = &vmstate_ehci_sysbus;
device_class_set_props(dc, ehci_sysbus_properties);
- dc->reset = usb_ehci_sysbus_reset;
+ device_class_set_legacy_reset(dc, usb_ehci_sysbus_reset);
set_bit(DEVICE_CATEGORY_USB, dc->categories);
}
diff --git a/hw/usb/hcd-musb.c b/hw/usb/hcd-musb.c
deleted file mode 100644
index 6dca373..0000000
--- a/hw/usb/hcd-musb.c
+++ /dev/null
@@ -1,1553 +0,0 @@
-/*
- * "Inventra" High-speed Dual-Role Controller (MUSB-HDRC), Mentor Graphics,
- * USB2.0 OTG compliant core used in various chips.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Only host-mode and non-DMA accesses are currently supported.
- */
-#include "qemu/osdep.h"
-#include "qemu/timer.h"
-#include "hw/usb.h"
-#include "hw/usb/hcd-musb.h"
-#include "hw/irq.h"
-#include "hw/hw.h"
-
-/* Common USB registers */
-#define MUSB_HDRC_FADDR 0x00 /* 8-bit */
-#define MUSB_HDRC_POWER 0x01 /* 8-bit */
-
-#define MUSB_HDRC_INTRTX 0x02 /* 16-bit */
-#define MUSB_HDRC_INTRRX 0x04
-#define MUSB_HDRC_INTRTXE 0x06
-#define MUSB_HDRC_INTRRXE 0x08
-#define MUSB_HDRC_INTRUSB 0x0a /* 8 bit */
-#define MUSB_HDRC_INTRUSBE 0x0b /* 8 bit */
-#define MUSB_HDRC_FRAME 0x0c /* 16-bit */
-#define MUSB_HDRC_INDEX 0x0e /* 8 bit */
-#define MUSB_HDRC_TESTMODE 0x0f /* 8 bit */
-
-/* Per-EP registers in indexed mode */
-#define MUSB_HDRC_EP_IDX 0x10 /* 8-bit */
-
-/* EP FIFOs */
-#define MUSB_HDRC_FIFO 0x20
-
-/* Additional Control Registers */
-#define MUSB_HDRC_DEVCTL 0x60 /* 8 bit */
-
-/* These are indexed */
-#define MUSB_HDRC_TXFIFOSZ 0x62 /* 8 bit (see masks) */
-#define MUSB_HDRC_RXFIFOSZ 0x63 /* 8 bit (see masks) */
-#define MUSB_HDRC_TXFIFOADDR 0x64 /* 16 bit offset shifted right 3 */
-#define MUSB_HDRC_RXFIFOADDR 0x66 /* 16 bit offset shifted right 3 */
-
-/* Some more registers */
-#define MUSB_HDRC_VCTRL 0x68 /* 8 bit */
-#define MUSB_HDRC_HWVERS 0x6c /* 8 bit */
-
-/* Added in HDRC 1.9(?) & MHDRC 1.4 */
-/* ULPI pass-through */
-#define MUSB_HDRC_ULPI_VBUSCTL 0x70
-#define MUSB_HDRC_ULPI_REGDATA 0x74
-#define MUSB_HDRC_ULPI_REGADDR 0x75
-#define MUSB_HDRC_ULPI_REGCTL 0x76
-
-/* Extended config & PHY control */
-#define MUSB_HDRC_ENDCOUNT 0x78 /* 8 bit */
-#define MUSB_HDRC_DMARAMCFG 0x79 /* 8 bit */
-#define MUSB_HDRC_PHYWAIT 0x7a /* 8 bit */
-#define MUSB_HDRC_PHYVPLEN 0x7b /* 8 bit */
-#define MUSB_HDRC_HS_EOF1 0x7c /* 8 bit, units of 546.1 us */
-#define MUSB_HDRC_FS_EOF1 0x7d /* 8 bit, units of 533.3 ns */
-#define MUSB_HDRC_LS_EOF1 0x7e /* 8 bit, units of 1.067 us */
-
-/* Per-EP BUSCTL registers */
-#define MUSB_HDRC_BUSCTL 0x80
-
-/* Per-EP registers in flat mode */
-#define MUSB_HDRC_EP 0x100
-
-/* offsets to registers in flat model */
-#define MUSB_HDRC_TXMAXP 0x00 /* 16 bit apparently */
-#define MUSB_HDRC_TXCSR 0x02 /* 16 bit apparently */
-#define MUSB_HDRC_CSR0 MUSB_HDRC_TXCSR /* re-used for EP0 */
-#define MUSB_HDRC_RXMAXP 0x04 /* 16 bit apparently */
-#define MUSB_HDRC_RXCSR 0x06 /* 16 bit apparently */
-#define MUSB_HDRC_RXCOUNT 0x08 /* 16 bit apparently */
-#define MUSB_HDRC_COUNT0 MUSB_HDRC_RXCOUNT /* re-used for EP0 */
-#define MUSB_HDRC_TXTYPE 0x0a /* 8 bit apparently */
-#define MUSB_HDRC_TYPE0 MUSB_HDRC_TXTYPE /* re-used for EP0 */
-#define MUSB_HDRC_TXINTERVAL 0x0b /* 8 bit apparently */
-#define MUSB_HDRC_NAKLIMIT0 MUSB_HDRC_TXINTERVAL /* re-used for EP0 */
-#define MUSB_HDRC_RXTYPE 0x0c /* 8 bit apparently */
-#define MUSB_HDRC_RXINTERVAL 0x0d /* 8 bit apparently */
-#define MUSB_HDRC_FIFOSIZE 0x0f /* 8 bit apparently */
-#define MUSB_HDRC_CONFIGDATA MGC_O_HDRC_FIFOSIZE /* re-used for EP0 */
-
-/* "Bus control" registers */
-#define MUSB_HDRC_TXFUNCADDR 0x00
-#define MUSB_HDRC_TXHUBADDR 0x02
-#define MUSB_HDRC_TXHUBPORT 0x03
-
-#define MUSB_HDRC_RXFUNCADDR 0x04
-#define MUSB_HDRC_RXHUBADDR 0x06
-#define MUSB_HDRC_RXHUBPORT 0x07
-
-/*
- * MUSBHDRC Register bit masks
- */
-
-/* POWER */
-#define MGC_M_POWER_ISOUPDATE 0x80
-#define MGC_M_POWER_SOFTCONN 0x40
-#define MGC_M_POWER_HSENAB 0x20
-#define MGC_M_POWER_HSMODE 0x10
-#define MGC_M_POWER_RESET 0x08
-#define MGC_M_POWER_RESUME 0x04
-#define MGC_M_POWER_SUSPENDM 0x02
-#define MGC_M_POWER_ENSUSPEND 0x01
-
-/* INTRUSB */
-#define MGC_M_INTR_SUSPEND 0x01
-#define MGC_M_INTR_RESUME 0x02
-#define MGC_M_INTR_RESET 0x04
-#define MGC_M_INTR_BABBLE 0x04
-#define MGC_M_INTR_SOF 0x08
-#define MGC_M_INTR_CONNECT 0x10
-#define MGC_M_INTR_DISCONNECT 0x20
-#define MGC_M_INTR_SESSREQ 0x40
-#define MGC_M_INTR_VBUSERROR 0x80 /* FOR SESSION END */
-#define MGC_M_INTR_EP0 0x01 /* FOR EP0 INTERRUPT */
-
-/* DEVCTL */
-#define MGC_M_DEVCTL_BDEVICE 0x80
-#define MGC_M_DEVCTL_FSDEV 0x40
-#define MGC_M_DEVCTL_LSDEV 0x20
-#define MGC_M_DEVCTL_VBUS 0x18
-#define MGC_S_DEVCTL_VBUS 3
-#define MGC_M_DEVCTL_HM 0x04
-#define MGC_M_DEVCTL_HR 0x02
-#define MGC_M_DEVCTL_SESSION 0x01
-
-/* TESTMODE */
-#define MGC_M_TEST_FORCE_HOST 0x80
-#define MGC_M_TEST_FIFO_ACCESS 0x40
-#define MGC_M_TEST_FORCE_FS 0x20
-#define MGC_M_TEST_FORCE_HS 0x10
-#define MGC_M_TEST_PACKET 0x08
-#define MGC_M_TEST_K 0x04
-#define MGC_M_TEST_J 0x02
-#define MGC_M_TEST_SE0_NAK 0x01
-
-/* CSR0 */
-#define MGC_M_CSR0_FLUSHFIFO 0x0100
-#define MGC_M_CSR0_TXPKTRDY 0x0002
-#define MGC_M_CSR0_RXPKTRDY 0x0001
-
-/* CSR0 in Peripheral mode */
-#define MGC_M_CSR0_P_SVDSETUPEND 0x0080
-#define MGC_M_CSR0_P_SVDRXPKTRDY 0x0040
-#define MGC_M_CSR0_P_SENDSTALL 0x0020
-#define MGC_M_CSR0_P_SETUPEND 0x0010
-#define MGC_M_CSR0_P_DATAEND 0x0008
-#define MGC_M_CSR0_P_SENTSTALL 0x0004
-
-/* CSR0 in Host mode */
-#define MGC_M_CSR0_H_NO_PING 0x0800
-#define MGC_M_CSR0_H_WR_DATATOGGLE 0x0400 /* set to allow setting: */
-#define MGC_M_CSR0_H_DATATOGGLE 0x0200 /* data toggle control */
-#define MGC_M_CSR0_H_NAKTIMEOUT 0x0080
-#define MGC_M_CSR0_H_STATUSPKT 0x0040
-#define MGC_M_CSR0_H_REQPKT 0x0020
-#define MGC_M_CSR0_H_ERROR 0x0010
-#define MGC_M_CSR0_H_SETUPPKT 0x0008
-#define MGC_M_CSR0_H_RXSTALL 0x0004
-
-/* CONFIGDATA */
-#define MGC_M_CONFIGDATA_MPRXE 0x80 /* auto bulk pkt combining */
-#define MGC_M_CONFIGDATA_MPTXE 0x40 /* auto bulk pkt splitting */
-#define MGC_M_CONFIGDATA_BIGENDIAN 0x20
-#define MGC_M_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */
-#define MGC_M_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */
-#define MGC_M_CONFIGDATA_DYNFIFO 0x04 /* dynamic FIFO sizing */
-#define MGC_M_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */
-#define MGC_M_CONFIGDATA_UTMIDW 0x01 /* Width, 0 => 8b, 1 => 16b */
-
-/* TXCSR in Peripheral and Host mode */
-#define MGC_M_TXCSR_AUTOSET 0x8000
-#define MGC_M_TXCSR_ISO 0x4000
-#define MGC_M_TXCSR_MODE 0x2000
-#define MGC_M_TXCSR_DMAENAB 0x1000
-#define MGC_M_TXCSR_FRCDATATOG 0x0800
-#define MGC_M_TXCSR_DMAMODE 0x0400
-#define MGC_M_TXCSR_CLRDATATOG 0x0040
-#define MGC_M_TXCSR_FLUSHFIFO 0x0008
-#define MGC_M_TXCSR_FIFONOTEMPTY 0x0002
-#define MGC_M_TXCSR_TXPKTRDY 0x0001
-
-/* TXCSR in Peripheral mode */
-#define MGC_M_TXCSR_P_INCOMPTX 0x0080
-#define MGC_M_TXCSR_P_SENTSTALL 0x0020
-#define MGC_M_TXCSR_P_SENDSTALL 0x0010
-#define MGC_M_TXCSR_P_UNDERRUN 0x0004
-
-/* TXCSR in Host mode */
-#define MGC_M_TXCSR_H_WR_DATATOGGLE 0x0200
-#define MGC_M_TXCSR_H_DATATOGGLE 0x0100
-#define MGC_M_TXCSR_H_NAKTIMEOUT 0x0080
-#define MGC_M_TXCSR_H_RXSTALL 0x0020
-#define MGC_M_TXCSR_H_ERROR 0x0004
-
-/* RXCSR in Peripheral and Host mode */
-#define MGC_M_RXCSR_AUTOCLEAR 0x8000
-#define MGC_M_RXCSR_DMAENAB 0x2000
-#define MGC_M_RXCSR_DISNYET 0x1000
-#define MGC_M_RXCSR_DMAMODE 0x0800
-#define MGC_M_RXCSR_INCOMPRX 0x0100
-#define MGC_M_RXCSR_CLRDATATOG 0x0080
-#define MGC_M_RXCSR_FLUSHFIFO 0x0010
-#define MGC_M_RXCSR_DATAERROR 0x0008
-#define MGC_M_RXCSR_FIFOFULL 0x0002
-#define MGC_M_RXCSR_RXPKTRDY 0x0001
-
-/* RXCSR in Peripheral mode */
-#define MGC_M_RXCSR_P_ISO 0x4000
-#define MGC_M_RXCSR_P_SENTSTALL 0x0040
-#define MGC_M_RXCSR_P_SENDSTALL 0x0020
-#define MGC_M_RXCSR_P_OVERRUN 0x0004
-
-/* RXCSR in Host mode */
-#define MGC_M_RXCSR_H_AUTOREQ 0x4000
-#define MGC_M_RXCSR_H_WR_DATATOGGLE 0x0400
-#define MGC_M_RXCSR_H_DATATOGGLE 0x0200
-#define MGC_M_RXCSR_H_RXSTALL 0x0040
-#define MGC_M_RXCSR_H_REQPKT 0x0020
-#define MGC_M_RXCSR_H_ERROR 0x0004
-
-/* HUBADDR */
-#define MGC_M_HUBADDR_MULTI_TT 0x80
-
-/* ULPI: Added in HDRC 1.9(?) & MHDRC 1.4 */
-#define MGC_M_ULPI_VBCTL_USEEXTVBUSIND 0x02
-#define MGC_M_ULPI_VBCTL_USEEXTVBUS 0x01
-#define MGC_M_ULPI_REGCTL_INT_ENABLE 0x08
-#define MGC_M_ULPI_REGCTL_READNOTWRITE 0x04
-#define MGC_M_ULPI_REGCTL_COMPLETE 0x02
-#define MGC_M_ULPI_REGCTL_REG 0x01
-
-/* #define MUSB_DEBUG */
-
-#ifdef MUSB_DEBUG
-#define TRACE(fmt, ...) fprintf(stderr, "%s@%d: " fmt "\n", __func__, \
- __LINE__, ##__VA_ARGS__)
-#else
-#define TRACE(...)
-#endif
-
-
-static void musb_attach(USBPort *port);
-static void musb_detach(USBPort *port);
-static void musb_child_detach(USBPort *port, USBDevice *child);
-static void musb_schedule_cb(USBPort *port, USBPacket *p);
-static void musb_async_cancel_device(MUSBState *s, USBDevice *dev);
-
-static USBPortOps musb_port_ops = {
- .attach = musb_attach,
- .detach = musb_detach,
- .child_detach = musb_child_detach,
- .complete = musb_schedule_cb,
-};
-
-static USBBusOps musb_bus_ops = {
-};
-
-typedef struct MUSBPacket MUSBPacket;
-typedef struct MUSBEndPoint MUSBEndPoint;
-
-struct MUSBPacket {
- USBPacket p;
- MUSBEndPoint *ep;
- int dir;
-};
-
-struct MUSBEndPoint {
- uint16_t faddr[2];
- uint8_t haddr[2];
- uint8_t hport[2];
- uint16_t csr[2];
- uint16_t maxp[2];
- uint16_t rxcount;
- uint8_t type[2];
- uint8_t interval[2];
- uint8_t config;
- uint8_t fifosize;
- int timeout[2]; /* Always in microframes */
-
- uint8_t *buf[2];
- int fifolen[2];
- int fifostart[2];
- int fifoaddr[2];
- MUSBPacket packey[2];
- int status[2];
- int ext_size[2];
-
- /* For callbacks' use */
- int epnum;
- int interrupt[2];
- MUSBState *musb;
- USBCallback *delayed_cb[2];
- QEMUTimer *intv_timer[2];
-};
-
-struct MUSBState {
- qemu_irq irqs[musb_irq_max];
- USBBus bus;
- USBPort port;
-
- int idx;
- uint8_t devctl;
- uint8_t power;
- uint8_t faddr;
-
- uint8_t intr;
- uint8_t mask;
- uint16_t tx_intr;
- uint16_t tx_mask;
- uint16_t rx_intr;
- uint16_t rx_mask;
-
- int setup_len;
- int session;
-
- uint8_t buf[0x8000];
-
- /* Duplicating the world since 2008!... probably we should have 32
- * logical, single endpoints instead. */
- MUSBEndPoint ep[16];
-};
-
-void musb_reset(MUSBState *s)
-{
- int i;
-
- s->faddr = 0x00;
- s->devctl = 0;
- s->power = MGC_M_POWER_HSENAB;
- s->tx_intr = 0x0000;
- s->rx_intr = 0x0000;
- s->tx_mask = 0xffff;
- s->rx_mask = 0xffff;
- s->intr = 0x00;
- s->mask = 0x06;
- s->idx = 0;
-
- s->setup_len = 0;
- s->session = 0;
- memset(s->buf, 0, sizeof(s->buf));
-
- /* TODO: _DW */
- s->ep[0].config = MGC_M_CONFIGDATA_SOFTCONE | MGC_M_CONFIGDATA_DYNFIFO;
- for (i = 0; i < 16; i ++) {
- s->ep[i].fifosize = 64;
- s->ep[i].maxp[0] = 0x40;
- s->ep[i].maxp[1] = 0x40;
- s->ep[i].musb = s;
- s->ep[i].epnum = i;
- usb_packet_init(&s->ep[i].packey[0].p);
- usb_packet_init(&s->ep[i].packey[1].p);
- }
-}
-
-struct MUSBState *musb_init(DeviceState *parent_device, int gpio_base)
-{
- MUSBState *s = g_malloc0(sizeof(*s));
- int i;
-
- for (i = 0; i < musb_irq_max; i++) {
- s->irqs[i] = qdev_get_gpio_in(parent_device, gpio_base + i);
- }
-
- musb_reset(s);
-
- usb_bus_new(&s->bus, sizeof(s->bus), &musb_bus_ops, parent_device);
- usb_register_port(&s->bus, &s->port, s, 0, &musb_port_ops,
- USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
-
- return s;
-}
-
-static void musb_vbus_set(MUSBState *s, int level)
-{
- if (level)
- s->devctl |= 3 << MGC_S_DEVCTL_VBUS;
- else
- s->devctl &= ~MGC_M_DEVCTL_VBUS;
-
- qemu_set_irq(s->irqs[musb_set_vbus], level);
-}
-
-static void musb_intr_set(MUSBState *s, int line, int level)
-{
- if (!level) {
- s->intr &= ~(1 << line);
- qemu_irq_lower(s->irqs[line]);
- } else if (s->mask & (1 << line)) {
- s->intr |= 1 << line;
- qemu_irq_raise(s->irqs[line]);
- }
-}
-
-static void musb_tx_intr_set(MUSBState *s, int line, int level)
-{
- if (!level) {
- s->tx_intr &= ~(1 << line);
- if (!s->tx_intr)
- qemu_irq_lower(s->irqs[musb_irq_tx]);
- } else if (s->tx_mask & (1 << line)) {
- s->tx_intr |= 1 << line;
- qemu_irq_raise(s->irqs[musb_irq_tx]);
- }
-}
-
-static void musb_rx_intr_set(MUSBState *s, int line, int level)
-{
- if (line) {
- if (!level) {
- s->rx_intr &= ~(1 << line);
- if (!s->rx_intr)
- qemu_irq_lower(s->irqs[musb_irq_rx]);
- } else if (s->rx_mask & (1 << line)) {
- s->rx_intr |= 1 << line;
- qemu_irq_raise(s->irqs[musb_irq_rx]);
- }
- } else
- musb_tx_intr_set(s, line, level);
-}
-
-uint32_t musb_core_intr_get(MUSBState *s)
-{
- return (s->rx_intr << 15) | s->tx_intr;
-}
-
-void musb_core_intr_clear(MUSBState *s, uint32_t mask)
-{
- if (s->rx_intr) {
- s->rx_intr &= mask >> 15;
- if (!s->rx_intr)
- qemu_irq_lower(s->irqs[musb_irq_rx]);
- }
-
- if (s->tx_intr) {
- s->tx_intr &= mask & 0xffff;
- if (!s->tx_intr)
- qemu_irq_lower(s->irqs[musb_irq_tx]);
- }
-}
-
-void musb_set_size(MUSBState *s, int epnum, int size, int is_tx)
-{
- s->ep[epnum].ext_size[!is_tx] = size;
- s->ep[epnum].fifostart[0] = 0;
- s->ep[epnum].fifostart[1] = 0;
- s->ep[epnum].fifolen[0] = 0;
- s->ep[epnum].fifolen[1] = 0;
-}
-
-static void musb_session_update(MUSBState *s, int prev_dev, int prev_sess)
-{
- int detect_prev = prev_dev && prev_sess;
- int detect = !!s->port.dev && s->session;
-
- if (detect && !detect_prev) {
- /* Let's skip the ID pin sense and VBUS sense formalities and
- * and signal a successful SRP directly. This should work at least
- * for the Linux driver stack. */
- musb_intr_set(s, musb_irq_connect, 1);
-
- if (s->port.dev->speed == USB_SPEED_LOW) {
- s->devctl &= ~MGC_M_DEVCTL_FSDEV;
- s->devctl |= MGC_M_DEVCTL_LSDEV;
- } else {
- s->devctl |= MGC_M_DEVCTL_FSDEV;
- s->devctl &= ~MGC_M_DEVCTL_LSDEV;
- }
-
- /* A-mode? */
- s->devctl &= ~MGC_M_DEVCTL_BDEVICE;
-
- /* Host-mode bit? */
- s->devctl |= MGC_M_DEVCTL_HM;
-#if 1
- musb_vbus_set(s, 1);
-#endif
- } else if (!detect && detect_prev) {
-#if 1
- musb_vbus_set(s, 0);
-#endif
- }
-}
-
-/* Attach or detach a device on our only port. */
-static void musb_attach(USBPort *port)
-{
- MUSBState *s = (MUSBState *) port->opaque;
-
- musb_intr_set(s, musb_irq_vbus_request, 1);
- musb_session_update(s, 0, s->session);
-}
-
-static void musb_detach(USBPort *port)
-{
- MUSBState *s = (MUSBState *) port->opaque;
-
- musb_async_cancel_device(s, port->dev);
-
- musb_intr_set(s, musb_irq_disconnect, 1);
- musb_session_update(s, 1, s->session);
-}
-
-static void musb_child_detach(USBPort *port, USBDevice *child)
-{
- MUSBState *s = (MUSBState *) port->opaque;
-
- musb_async_cancel_device(s, child);
-}
-
-static void musb_cb_tick0(void *opaque)
-{
- MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
-
- ep->delayed_cb[0](&ep->packey[0].p, opaque);
-}
-
-static void musb_cb_tick1(void *opaque)
-{
- MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
-
- ep->delayed_cb[1](&ep->packey[1].p, opaque);
-}
-
-#define musb_cb_tick (dir ? musb_cb_tick1 : musb_cb_tick0)
-
-static void musb_schedule_cb(USBPort *port, USBPacket *packey)
-{
- MUSBPacket *p = container_of(packey, MUSBPacket, p);
- MUSBEndPoint *ep = p->ep;
- int dir = p->dir;
- int timeout = 0;
-
- if (ep->status[dir] == USB_RET_NAK)
- timeout = ep->timeout[dir];
- else if (ep->interrupt[dir])
- timeout = 8;
- else {
- musb_cb_tick(ep);
- return;
- }
-
- if (!ep->intv_timer[dir])
- ep->intv_timer[dir] = timer_new_ns(QEMU_CLOCK_VIRTUAL, musb_cb_tick, ep);
-
- timer_mod(ep->intv_timer[dir], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- muldiv64(timeout, NANOSECONDS_PER_SECOND, 8000));
-}
-
-static int musb_timeout(int ttype, int speed, int val)
-{
-#if 1
- return val << 3;
-#endif
-
- switch (ttype) {
- case USB_ENDPOINT_XFER_CONTROL:
- if (val < 2)
- return 0;
- else if (speed == USB_SPEED_HIGH)
- return 1 << (val - 1);
- else
- return 8 << (val - 1);
-
- case USB_ENDPOINT_XFER_INT:
- if (speed == USB_SPEED_HIGH)
- if (val < 2)
- return 0;
- else
- return 1 << (val - 1);
- else
- return val << 3;
-
- case USB_ENDPOINT_XFER_BULK:
- case USB_ENDPOINT_XFER_ISOC:
- if (val < 2)
- return 0;
- else if (speed == USB_SPEED_HIGH)
- return 1 << (val - 1);
- else
- return 8 << (val - 1);
- /* TODO: what with low-speed Bulk and Isochronous? */
- }
-
- hw_error("bad interval\n");
-}
-
-static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
- int epnum, int pid, int len, USBCallback cb, int dir)
-{
- USBDevice *dev;
- USBEndpoint *uep;
- int idx = epnum && dir;
- int id;
- int ttype;
-
- /* ep->type[0,1] contains:
- * in bits 7:6 the speed (0 - invalid, 1 - high, 2 - full, 3 - slow)
- * in bits 5:4 the transfer type (BULK / INT)
- * in bits 3:0 the EP num
- */
- ttype = epnum ? (ep->type[idx] >> 4) & 3 : 0;
-
- ep->timeout[dir] = musb_timeout(ttype,
- ep->type[idx] >> 6, ep->interval[idx]);
- ep->interrupt[dir] = ttype == USB_ENDPOINT_XFER_INT;
- ep->delayed_cb[dir] = cb;
-
- /* A wild guess on the FADDR semantics... */
- dev = usb_find_device(&s->port, ep->faddr[idx]);
- if (dev == NULL) {
- return;
- }
- uep = usb_ep_get(dev, pid, ep->type[idx] & 0xf);
- id = pid | (dev->addr << 16) | (uep->nr << 8);
- usb_packet_setup(&ep->packey[dir].p, pid, uep, 0, id, false, true);
- usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len);
- ep->packey[dir].ep = ep;
- ep->packey[dir].dir = dir;
-
- usb_handle_packet(dev, &ep->packey[dir].p);
-
- if (ep->packey[dir].p.status == USB_RET_ASYNC) {
- usb_device_flush_ep_queue(dev, uep);
- ep->status[dir] = len;
- return;
- }
-
- if (ep->packey[dir].p.status == USB_RET_SUCCESS) {
- ep->status[dir] = ep->packey[dir].p.actual_length;
- } else {
- ep->status[dir] = ep->packey[dir].p.status;
- }
- musb_schedule_cb(&s->port, &ep->packey[dir].p);
-}
-
-static void musb_tx_packet_complete(USBPacket *packey, void *opaque)
-{
- /* Unfortunately we can't use packey->devep because that's the remote
- * endpoint number and may be different than our local. */
- MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
- int epnum = ep->epnum;
- MUSBState *s = ep->musb;
-
- ep->fifostart[0] = 0;
- ep->fifolen[0] = 0;
-#ifdef CLEAR_NAK
- if (ep->status[0] != USB_RET_NAK) {
-#endif
- if (epnum)
- ep->csr[0] &= ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY);
- else
- ep->csr[0] &= ~MGC_M_CSR0_TXPKTRDY;
-#ifdef CLEAR_NAK
- }
-#endif
-
- /* Clear all of the error bits first */
- if (epnum)
- ep->csr[0] &= ~(MGC_M_TXCSR_H_ERROR | MGC_M_TXCSR_H_RXSTALL |
- MGC_M_TXCSR_H_NAKTIMEOUT);
- else
- ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |
- MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);
-
- if (ep->status[0] == USB_RET_STALL) {
- /* Command not supported by target! */
- ep->status[0] = 0;
-
- if (epnum)
- ep->csr[0] |= MGC_M_TXCSR_H_RXSTALL;
- else
- ep->csr[0] |= MGC_M_CSR0_H_RXSTALL;
- }
-
- if (ep->status[0] == USB_RET_NAK) {
- ep->status[0] = 0;
-
- /* NAK timeouts are only generated in Bulk transfers and
- * Data-errors in Isochronous. */
- if (ep->interrupt[0]) {
- return;
- }
-
- if (epnum)
- ep->csr[0] |= MGC_M_TXCSR_H_NAKTIMEOUT;
- else
- ep->csr[0] |= MGC_M_CSR0_H_NAKTIMEOUT;
- }
-
- if (ep->status[0] < 0) {
- if (ep->status[0] == USB_RET_BABBLE)
- musb_intr_set(s, musb_irq_rst_babble, 1);
-
- /* Pretend we've tried three times already and failed (in
- * case of USB_TOKEN_SETUP). */
- if (epnum)
- ep->csr[0] |= MGC_M_TXCSR_H_ERROR;
- else
- ep->csr[0] |= MGC_M_CSR0_H_ERROR;
-
- musb_tx_intr_set(s, epnum, 1);
- return;
- }
- /* TODO: check len for over/underruns of an OUT packet? */
-
-#ifdef SETUPLEN_HACK
- if (!epnum && ep->packey[0].pid == USB_TOKEN_SETUP)
- s->setup_len = ep->packey[0].data[6];
-#endif
-
- /* In DMA mode: if no error, assert DMA request for this EP,
- * and skip the interrupt. */
- musb_tx_intr_set(s, epnum, 1);
-}
-
-static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
-{
- /* Unfortunately we can't use packey->devep because that's the remote
- * endpoint number and may be different than our local. */
- MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
- int epnum = ep->epnum;
- MUSBState *s = ep->musb;
-
- ep->fifostart[1] = 0;
- ep->fifolen[1] = 0;
-
-#ifdef CLEAR_NAK
- if (ep->status[1] != USB_RET_NAK) {
-#endif
- ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;
- if (!epnum)
- ep->csr[0] &= ~MGC_M_CSR0_H_REQPKT;
-#ifdef CLEAR_NAK
- }
-#endif
-
- /* Clear all of the imaginable error bits first */
- ep->csr[1] &= ~(MGC_M_RXCSR_H_ERROR | MGC_M_RXCSR_H_RXSTALL |
- MGC_M_RXCSR_DATAERROR);
- if (!epnum)
- ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |
- MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);
-
- if (ep->status[1] == USB_RET_STALL) {
- ep->status[1] = 0;
-
- ep->csr[1] |= MGC_M_RXCSR_H_RXSTALL;
- if (!epnum)
- ep->csr[0] |= MGC_M_CSR0_H_RXSTALL;
- }
-
- if (ep->status[1] == USB_RET_NAK) {
- ep->status[1] = 0;
-
- /* NAK timeouts are only generated in Bulk transfers and
- * Data-errors in Isochronous. */
- if (ep->interrupt[1]) {
- musb_packet(s, ep, epnum, USB_TOKEN_IN,
- packey->iov.size, musb_rx_packet_complete, 1);
- return;
- }
-
- ep->csr[1] |= MGC_M_RXCSR_DATAERROR;
- if (!epnum)
- ep->csr[0] |= MGC_M_CSR0_H_NAKTIMEOUT;
- }
-
- if (ep->status[1] < 0) {
- if (ep->status[1] == USB_RET_BABBLE) {
- musb_intr_set(s, musb_irq_rst_babble, 1);
- return;
- }
-
- /* Pretend we've tried three times already and failed (in
- * case of a control transfer). */
- ep->csr[1] |= MGC_M_RXCSR_H_ERROR;
- if (!epnum)
- ep->csr[0] |= MGC_M_CSR0_H_ERROR;
-
- musb_rx_intr_set(s, epnum, 1);
- return;
- }
- /* TODO: check len for over/underruns of an OUT packet? */
- /* TODO: perhaps make use of e->ext_size[1] here. */
-
- if (!(ep->csr[1] & (MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_DATAERROR))) {
- ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;
- if (!epnum)
- ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;
-
- ep->rxcount = ep->status[1]; /* XXX: MIN(packey->len, ep->maxp[1]); */
- /* In DMA mode: assert DMA request for this EP */
- }
-
- /* Only if DMA has not been asserted */
- musb_rx_intr_set(s, epnum, 1);
-}
-
-static void musb_async_cancel_device(MUSBState *s, USBDevice *dev)
-{
- int ep, dir;
-
- for (ep = 0; ep < 16; ep++) {
- for (dir = 0; dir < 2; dir++) {
- if (!usb_packet_is_inflight(&s->ep[ep].packey[dir].p) ||
- s->ep[ep].packey[dir].p.ep->dev != dev) {
- continue;
- }
- usb_cancel_packet(&s->ep[ep].packey[dir].p);
- /* status updates needed here? */
- }
- }
-}
-
-static void musb_tx_rdy(MUSBState *s, int epnum)
-{
- MUSBEndPoint *ep = s->ep + epnum;
- int pid;
- int total, valid = 0;
- TRACE("start %d, len %d", ep->fifostart[0], ep->fifolen[0] );
- ep->fifostart[0] += ep->fifolen[0];
- ep->fifolen[0] = 0;
-
- /* XXX: how's the total size of the packet retrieved exactly in
- * the generic case? */
- total = ep->maxp[0] & 0x3ff;
-
- if (ep->ext_size[0]) {
- total = ep->ext_size[0];
- ep->ext_size[0] = 0;
- valid = 1;
- }
-
- /* If the packet is not fully ready yet, wait for a next segment. */
- if (epnum && (ep->fifostart[0]) < total)
- return;
-
- if (!valid)
- total = ep->fifostart[0];
-
- pid = USB_TOKEN_OUT;
- if (!epnum && (ep->csr[0] & MGC_M_CSR0_H_SETUPPKT)) {
- pid = USB_TOKEN_SETUP;
- if (total != 8) {
- TRACE("illegal SETUPPKT length of %i bytes", total);
- }
- /* Controller should retry SETUP packets three times on errors
- * but it doesn't make sense for us to do that. */
- }
-
- musb_packet(s, ep, epnum, pid, total, musb_tx_packet_complete, 0);
-}
-
-static void musb_rx_req(MUSBState *s, int epnum)
-{
- MUSBEndPoint *ep = s->ep + epnum;
- int total;
-
- /* If we already have a packet, which didn't fit into the
- * 64 bytes of the FIFO, only move the FIFO start and return. (Obsolete) */
- if (ep->packey[1].p.pid == USB_TOKEN_IN && ep->status[1] >= 0 &&
- (ep->fifostart[1]) + ep->rxcount <
- ep->packey[1].p.iov.size) {
- TRACE("0x%08x, %d", ep->fifostart[1], ep->rxcount );
- ep->fifostart[1] += ep->rxcount;
- ep->fifolen[1] = 0;
-
- ep->rxcount = MIN(ep->packey[0].p.iov.size - (ep->fifostart[1]),
- ep->maxp[1]);
-
- ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;
- if (!epnum)
- ep->csr[0] &= ~MGC_M_CSR0_H_REQPKT;
-
- /* Clear all of the error bits first */
- ep->csr[1] &= ~(MGC_M_RXCSR_H_ERROR | MGC_M_RXCSR_H_RXSTALL |
- MGC_M_RXCSR_DATAERROR);
- if (!epnum)
- ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |
- MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);
-
- ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;
- if (!epnum)
- ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;
- musb_rx_intr_set(s, epnum, 1);
- return;
- }
-
- /* The driver sets maxp[1] to 64 or less because it knows the hardware
- * FIFO is this deep. Bigger packets get split in
- * usb_generic_handle_packet but we can also do the splitting locally
- * for performance. It turns out we can also have a bigger FIFO and
- * ignore the limit set in ep->maxp[1]. The Linux MUSB driver deals
- * OK with single packets of even 32KB and we avoid splitting, however
- * usb_msd.c sometimes sends a packet bigger than what Linux expects
- * (e.g. 8192 bytes instead of 4096) and we get an OVERRUN. Splitting
- * hides this overrun from Linux. Up to 4096 everything is fine
- * though. Currently this is disabled.
- *
- * XXX: mind ep->fifosize. */
- total = MIN(ep->maxp[1] & 0x3ff, sizeof(s->buf));
-
-#ifdef SETUPLEN_HACK
- /* Why should *we* do that instead of Linux? */
- if (!epnum) {
- if (ep->packey[0].p.devaddr == 2) {
- total = MIN(s->setup_len, 8);
- } else {
- total = MIN(s->setup_len, 64);
- }
- s->setup_len -= total;
- }
-#endif
-
- musb_packet(s, ep, epnum, USB_TOKEN_IN, total, musb_rx_packet_complete, 1);
-}
-
-static uint8_t musb_read_fifo(MUSBEndPoint *ep)
-{
- uint8_t value;
- if (ep->fifolen[1] >= 64) {
- /* We have a FIFO underrun */
- TRACE("EP%d FIFO is now empty, stop reading", ep->epnum);
- return 0x00000000;
- }
- /* In DMA mode clear RXPKTRDY and set REQPKT automatically
- * (if AUTOREQ is set) */
-
- ep->csr[1] &= ~MGC_M_RXCSR_FIFOFULL;
- value=ep->buf[1][ep->fifostart[1] + ep->fifolen[1] ++];
- TRACE("EP%d 0x%02x, %d", ep->epnum, value, ep->fifolen[1] );
- return value;
-}
-
-static void musb_write_fifo(MUSBEndPoint *ep, uint8_t value)
-{
- TRACE("EP%d = %02x", ep->epnum, value);
- if (ep->fifolen[0] >= 64) {
- /* We have a FIFO overrun */
- TRACE("EP%d FIFO exceeded 64 bytes, stop feeding data", ep->epnum);
- return;
- }
-
- ep->buf[0][ep->fifostart[0] + ep->fifolen[0] ++] = value;
- ep->csr[0] |= MGC_M_TXCSR_FIFONOTEMPTY;
-}
-
-static void musb_ep_frame_cancel(MUSBEndPoint *ep, int dir)
-{
- if (ep->intv_timer[dir])
- timer_del(ep->intv_timer[dir]);
-}
-
-/* Bus control */
-static uint8_t musb_busctl_readb(void *opaque, int ep, int addr)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- /* For USB2.0 HS hubs only */
- case MUSB_HDRC_TXHUBADDR:
- return s->ep[ep].haddr[0];
- case MUSB_HDRC_TXHUBPORT:
- return s->ep[ep].hport[0];
- case MUSB_HDRC_RXHUBADDR:
- return s->ep[ep].haddr[1];
- case MUSB_HDRC_RXHUBPORT:
- return s->ep[ep].hport[1];
-
- default:
- TRACE("unknown register 0x%02x", addr);
- return 0x00;
- };
-}
-
-static void musb_busctl_writeb(void *opaque, int ep, int addr, uint8_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXFUNCADDR:
- s->ep[ep].faddr[0] = value;
- break;
- case MUSB_HDRC_RXFUNCADDR:
- s->ep[ep].faddr[1] = value;
- break;
- case MUSB_HDRC_TXHUBADDR:
- s->ep[ep].haddr[0] = value;
- break;
- case MUSB_HDRC_TXHUBPORT:
- s->ep[ep].hport[0] = value;
- break;
- case MUSB_HDRC_RXHUBADDR:
- s->ep[ep].haddr[1] = value;
- break;
- case MUSB_HDRC_RXHUBPORT:
- s->ep[ep].hport[1] = value;
- break;
-
- default:
- TRACE("unknown register 0x%02x", addr);
- break;
- };
-}
-
-static uint16_t musb_busctl_readh(void *opaque, int ep, int addr)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXFUNCADDR:
- return s->ep[ep].faddr[0];
- case MUSB_HDRC_RXFUNCADDR:
- return s->ep[ep].faddr[1];
-
- default:
- return musb_busctl_readb(s, ep, addr) |
- (musb_busctl_readb(s, ep, addr | 1) << 8);
- };
-}
-
-static void musb_busctl_writeh(void *opaque, int ep, int addr, uint16_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXFUNCADDR:
- s->ep[ep].faddr[0] = value;
- break;
- case MUSB_HDRC_RXFUNCADDR:
- s->ep[ep].faddr[1] = value;
- break;
-
- default:
- musb_busctl_writeb(s, ep, addr, value & 0xff);
- musb_busctl_writeb(s, ep, addr | 1, value >> 8);
- };
-}
-
-/* Endpoint control */
-static uint8_t musb_ep_readb(void *opaque, int ep, int addr)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXTYPE:
- return s->ep[ep].type[0];
- case MUSB_HDRC_TXINTERVAL:
- return s->ep[ep].interval[0];
- case MUSB_HDRC_RXTYPE:
- return s->ep[ep].type[1];
- case MUSB_HDRC_RXINTERVAL:
- return s->ep[ep].interval[1];
- case (MUSB_HDRC_FIFOSIZE & ~1):
- return 0x00;
- case MUSB_HDRC_FIFOSIZE:
- return ep ? s->ep[ep].fifosize : s->ep[ep].config;
- case MUSB_HDRC_RXCOUNT:
- return s->ep[ep].rxcount;
-
- default:
- TRACE("unknown register 0x%02x", addr);
- return 0x00;
- };
-}
-
-static void musb_ep_writeb(void *opaque, int ep, int addr, uint8_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXTYPE:
- s->ep[ep].type[0] = value;
- break;
- case MUSB_HDRC_TXINTERVAL:
- s->ep[ep].interval[0] = value;
- musb_ep_frame_cancel(&s->ep[ep], 0);
- break;
- case MUSB_HDRC_RXTYPE:
- s->ep[ep].type[1] = value;
- break;
- case MUSB_HDRC_RXINTERVAL:
- s->ep[ep].interval[1] = value;
- musb_ep_frame_cancel(&s->ep[ep], 1);
- break;
- case (MUSB_HDRC_FIFOSIZE & ~1):
- break;
- case MUSB_HDRC_FIFOSIZE:
- TRACE("somebody messes with fifosize (now %i bytes)", value);
- s->ep[ep].fifosize = value;
- break;
- default:
- TRACE("unknown register 0x%02x", addr);
- break;
- };
-}
-
-static uint16_t musb_ep_readh(void *opaque, int ep, int addr)
-{
- MUSBState *s = (MUSBState *) opaque;
- uint16_t ret;
-
- switch (addr) {
- case MUSB_HDRC_TXMAXP:
- return s->ep[ep].maxp[0];
- case MUSB_HDRC_TXCSR:
- return s->ep[ep].csr[0];
- case MUSB_HDRC_RXMAXP:
- return s->ep[ep].maxp[1];
- case MUSB_HDRC_RXCSR:
- ret = s->ep[ep].csr[1];
-
- /* TODO: This and other bits probably depend on
- * ep->csr[1] & MGC_M_RXCSR_AUTOCLEAR. */
- if (s->ep[ep].csr[1] & MGC_M_RXCSR_AUTOCLEAR)
- s->ep[ep].csr[1] &= ~MGC_M_RXCSR_RXPKTRDY;
-
- return ret;
- case MUSB_HDRC_RXCOUNT:
- return s->ep[ep].rxcount;
-
- default:
- return musb_ep_readb(s, ep, addr) |
- (musb_ep_readb(s, ep, addr | 1) << 8);
- };
-}
-
-static void musb_ep_writeh(void *opaque, int ep, int addr, uint16_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
-
- switch (addr) {
- case MUSB_HDRC_TXMAXP:
- s->ep[ep].maxp[0] = value;
- break;
- case MUSB_HDRC_TXCSR:
- if (ep) {
- s->ep[ep].csr[0] &= value & 0xa6;
- s->ep[ep].csr[0] |= value & 0xff59;
- } else {
- s->ep[ep].csr[0] &= value & 0x85;
- s->ep[ep].csr[0] |= value & 0xf7a;
- }
-
- musb_ep_frame_cancel(&s->ep[ep], 0);
-
- if ((ep && (value & MGC_M_TXCSR_FLUSHFIFO)) ||
- (!ep && (value & MGC_M_CSR0_FLUSHFIFO))) {
- s->ep[ep].fifolen[0] = 0;
- s->ep[ep].fifostart[0] = 0;
- if (ep)
- s->ep[ep].csr[0] &=
- ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY);
- else
- s->ep[ep].csr[0] &=
- ~(MGC_M_CSR0_TXPKTRDY | MGC_M_CSR0_RXPKTRDY);
- }
- if (
- (ep &&
-#ifdef CLEAR_NAK
- (value & MGC_M_TXCSR_TXPKTRDY) &&
- !(value & MGC_M_TXCSR_H_NAKTIMEOUT)) ||
-#else
- (value & MGC_M_TXCSR_TXPKTRDY)) ||
-#endif
- (!ep &&
-#ifdef CLEAR_NAK
- (value & MGC_M_CSR0_TXPKTRDY) &&
- !(value & MGC_M_CSR0_H_NAKTIMEOUT)))
-#else
- (value & MGC_M_CSR0_TXPKTRDY)))
-#endif
- musb_tx_rdy(s, ep);
- if (!ep &&
- (value & MGC_M_CSR0_H_REQPKT) &&
-#ifdef CLEAR_NAK
- !(value & (MGC_M_CSR0_H_NAKTIMEOUT |
- MGC_M_CSR0_RXPKTRDY)))
-#else
- !(value & MGC_M_CSR0_RXPKTRDY))
-#endif
- musb_rx_req(s, ep);
- break;
-
- case MUSB_HDRC_RXMAXP:
- s->ep[ep].maxp[1] = value;
- break;
- case MUSB_HDRC_RXCSR:
- /* (DMA mode only) */
- if (
- (value & MGC_M_RXCSR_H_AUTOREQ) &&
- !(value & MGC_M_RXCSR_RXPKTRDY) &&
- (s->ep[ep].csr[1] & MGC_M_RXCSR_RXPKTRDY))
- value |= MGC_M_RXCSR_H_REQPKT;
-
- s->ep[ep].csr[1] &= 0x102 | (value & 0x4d);
- s->ep[ep].csr[1] |= value & 0xfeb0;
-
- musb_ep_frame_cancel(&s->ep[ep], 1);
-
- if (value & MGC_M_RXCSR_FLUSHFIFO) {
- s->ep[ep].fifolen[1] = 0;
- s->ep[ep].fifostart[1] = 0;
- s->ep[ep].csr[1] &= ~(MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY);
- /* If double buffering and we have two packets ready, flush
- * only the first one and set up the fifo at the second packet. */
- }
-#ifdef CLEAR_NAK
- if ((value & MGC_M_RXCSR_H_REQPKT) && !(value & MGC_M_RXCSR_DATAERROR))
-#else
- if (value & MGC_M_RXCSR_H_REQPKT)
-#endif
- musb_rx_req(s, ep);
- break;
- case MUSB_HDRC_RXCOUNT:
- s->ep[ep].rxcount = value;
- break;
-
- default:
- musb_ep_writeb(s, ep, addr, value & 0xff);
- musb_ep_writeb(s, ep, addr | 1, value >> 8);
- };
-}
-
-/* Generic control */
-static uint32_t musb_readb(void *opaque, hwaddr addr)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep, i;
- uint8_t ret;
-
- switch (addr) {
- case MUSB_HDRC_FADDR:
- return s->faddr;
- case MUSB_HDRC_POWER:
- return s->power;
- case MUSB_HDRC_INTRUSB:
- ret = s->intr;
- for (i = 0; i < sizeof(ret) * 8; i ++)
- if (ret & (1 << i))
- musb_intr_set(s, i, 0);
- return ret;
- case MUSB_HDRC_INTRUSBE:
- return s->mask;
- case MUSB_HDRC_INDEX:
- return s->idx;
- case MUSB_HDRC_TESTMODE:
- return 0x00;
-
- case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
- return musb_ep_readb(s, s->idx, addr & 0xf);
-
- case MUSB_HDRC_DEVCTL:
- return s->devctl;
-
- case MUSB_HDRC_TXFIFOSZ:
- case MUSB_HDRC_RXFIFOSZ:
- case MUSB_HDRC_VCTRL:
- /* TODO */
- return 0x00;
-
- case MUSB_HDRC_HWVERS:
- return (1 << 10) | 400;
-
- case (MUSB_HDRC_VCTRL | 1):
- case (MUSB_HDRC_HWVERS | 1):
- case (MUSB_HDRC_DEVCTL | 1):
- return 0x00;
-
- case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
- ep = (addr >> 3) & 0xf;
- return musb_busctl_readb(s, ep, addr & 0x7);
-
- case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
- ep = (addr >> 4) & 0xf;
- return musb_ep_readb(s, ep, addr & 0xf);
-
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- return musb_read_fifo(s->ep + ep);
-
- default:
- TRACE("unknown register 0x%02x", (int) addr);
- return 0x00;
- };
-}
-
-static void musb_writeb(void *opaque, hwaddr addr, uint32_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep;
-
- switch (addr) {
- case MUSB_HDRC_FADDR:
- s->faddr = value & 0x7f;
- break;
- case MUSB_HDRC_POWER:
- s->power = (value & 0xef) | (s->power & 0x10);
- /* MGC_M_POWER_RESET is also read-only in Peripheral Mode */
- if ((value & MGC_M_POWER_RESET) && s->port.dev) {
- usb_device_reset(s->port.dev);
- /* Negotiate high-speed operation if MGC_M_POWER_HSENAB is set. */
- if ((value & MGC_M_POWER_HSENAB) &&
- s->port.dev->speed == USB_SPEED_HIGH)
- s->power |= MGC_M_POWER_HSMODE; /* Success */
- /* Restart frame counting. */
- }
- if (value & MGC_M_POWER_SUSPENDM) {
- /* When all transfers finish, suspend and if MGC_M_POWER_ENSUSPEND
- * is set, also go into low power mode. Frame counting stops. */
- /* XXX: Cleared when the interrupt register is read */
- }
- if (value & MGC_M_POWER_RESUME) {
- /* Wait 20ms and signal resuming on the bus. Frame counting
- * restarts. */
- }
- break;
- case MUSB_HDRC_INTRUSB:
- break;
- case MUSB_HDRC_INTRUSBE:
- s->mask = value & 0xff;
- break;
- case MUSB_HDRC_INDEX:
- s->idx = value & 0xf;
- break;
- case MUSB_HDRC_TESTMODE:
- break;
-
- case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
- musb_ep_writeb(s, s->idx, addr & 0xf, value);
- break;
-
- case MUSB_HDRC_DEVCTL:
- s->session = !!(value & MGC_M_DEVCTL_SESSION);
- musb_session_update(s,
- !!s->port.dev,
- !!(s->devctl & MGC_M_DEVCTL_SESSION));
-
- /* It seems this is the only R/W bit in this register? */
- s->devctl &= ~MGC_M_DEVCTL_SESSION;
- s->devctl |= value & MGC_M_DEVCTL_SESSION;
- break;
-
- case MUSB_HDRC_TXFIFOSZ:
- case MUSB_HDRC_RXFIFOSZ:
- case MUSB_HDRC_VCTRL:
- /* TODO */
- break;
-
- case (MUSB_HDRC_VCTRL | 1):
- case (MUSB_HDRC_DEVCTL | 1):
- break;
-
- case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
- ep = (addr >> 3) & 0xf;
- musb_busctl_writeb(s, ep, addr & 0x7, value);
- break;
-
- case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
- ep = (addr >> 4) & 0xf;
- musb_ep_writeb(s, ep, addr & 0xf, value);
- break;
-
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- musb_write_fifo(s->ep + ep, value & 0xff);
- break;
-
- default:
- TRACE("unknown register 0x%02x", (int) addr);
- break;
- };
-}
-
-static uint32_t musb_readh(void *opaque, hwaddr addr)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep, i;
- uint16_t ret;
-
- switch (addr) {
- case MUSB_HDRC_INTRTX:
- ret = s->tx_intr;
- /* Auto clear */
- for (i = 0; i < sizeof(ret) * 8; i ++)
- if (ret & (1 << i))
- musb_tx_intr_set(s, i, 0);
- return ret;
- case MUSB_HDRC_INTRRX:
- ret = s->rx_intr;
- /* Auto clear */
- for (i = 0; i < sizeof(ret) * 8; i ++)
- if (ret & (1 << i))
- musb_rx_intr_set(s, i, 0);
- return ret;
- case MUSB_HDRC_INTRTXE:
- return s->tx_mask;
- case MUSB_HDRC_INTRRXE:
- return s->rx_mask;
-
- case MUSB_HDRC_FRAME:
- /* TODO */
- return 0x0000;
- case MUSB_HDRC_TXFIFOADDR:
- return s->ep[s->idx].fifoaddr[0];
- case MUSB_HDRC_RXFIFOADDR:
- return s->ep[s->idx].fifoaddr[1];
-
- case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
- return musb_ep_readh(s, s->idx, addr & 0xf);
-
- case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
- ep = (addr >> 3) & 0xf;
- return musb_busctl_readh(s, ep, addr & 0x7);
-
- case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
- ep = (addr >> 4) & 0xf;
- return musb_ep_readh(s, ep, addr & 0xf);
-
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- return (musb_read_fifo(s->ep + ep) | musb_read_fifo(s->ep + ep) << 8);
-
- default:
- return musb_readb(s, addr) | (musb_readb(s, addr | 1) << 8);
- };
-}
-
-static void musb_writeh(void *opaque, hwaddr addr, uint32_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep;
-
- switch (addr) {
- case MUSB_HDRC_INTRTXE:
- s->tx_mask = value;
- /* XXX: the masks seem to apply on the raising edge like with
- * edge-triggered interrupts, thus no need to update. I may be
- * wrong though. */
- break;
- case MUSB_HDRC_INTRRXE:
- s->rx_mask = value;
- break;
-
- case MUSB_HDRC_FRAME:
- /* TODO */
- break;
- case MUSB_HDRC_TXFIFOADDR:
- s->ep[s->idx].fifoaddr[0] = value;
- s->ep[s->idx].buf[0] =
- s->buf + ((value << 3) & 0x7ff );
- break;
- case MUSB_HDRC_RXFIFOADDR:
- s->ep[s->idx].fifoaddr[1] = value;
- s->ep[s->idx].buf[1] =
- s->buf + ((value << 3) & 0x7ff);
- break;
-
- case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
- musb_ep_writeh(s, s->idx, addr & 0xf, value);
- break;
-
- case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
- ep = (addr >> 3) & 0xf;
- musb_busctl_writeh(s, ep, addr & 0x7, value);
- break;
-
- case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
- ep = (addr >> 4) & 0xf;
- musb_ep_writeh(s, ep, addr & 0xf, value);
- break;
-
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- musb_write_fifo(s->ep + ep, value & 0xff);
- musb_write_fifo(s->ep + ep, (value >> 8) & 0xff);
- break;
-
- default:
- musb_writeb(s, addr, value & 0xff);
- musb_writeb(s, addr | 1, value >> 8);
- };
-}
-
-static uint32_t musb_readw(void *opaque, hwaddr addr)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep;
-
- switch (addr) {
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- return ( musb_read_fifo(s->ep + ep) |
- musb_read_fifo(s->ep + ep) << 8 |
- musb_read_fifo(s->ep + ep) << 16 |
- musb_read_fifo(s->ep + ep) << 24 );
- default:
- TRACE("unknown register 0x%02x", (int) addr);
- return 0x00000000;
- };
-}
-
-static void musb_writew(void *opaque, hwaddr addr, uint32_t value)
-{
- MUSBState *s = (MUSBState *) opaque;
- int ep;
-
- switch (addr) {
- case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
- ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
- musb_write_fifo(s->ep + ep, value & 0xff);
- musb_write_fifo(s->ep + ep, (value >> 8 ) & 0xff);
- musb_write_fifo(s->ep + ep, (value >> 16) & 0xff);
- musb_write_fifo(s->ep + ep, (value >> 24) & 0xff);
- break;
- default:
- TRACE("unknown register 0x%02x", (int) addr);
- break;
- };
-}
-
-MUSBReadFunc * const musb_read[] = {
- musb_readb,
- musb_readh,
- musb_readw,
-};
-
-MUSBWriteFunc * const musb_write[] = {
- musb_writeb,
- musb_writeh,
- musb_writew,
-};
diff --git a/hw/usb/hcd-ohci-pci.c b/hw/usb/hcd-ohci-pci.c
index 33ed9b6..47fb659 100644
--- a/hw/usb/hcd-ohci-pci.c
+++ b/hw/usb/hcd-ohci-pci.c
@@ -142,7 +142,7 @@ static void ohci_pci_class_init(ObjectClass *klass, void *data)
device_class_set_props(dc, ohci_pci_properties);
dc->hotpluggable = false;
dc->vmsd = &vmstate_ohci;
- dc->reset = usb_ohci_reset_pci;
+ device_class_set_legacy_reset(dc, usb_ohci_reset_pci);
}
static const TypeInfo ohci_pci_info = {
diff --git a/hw/usb/hcd-ohci-sysbus.c b/hw/usb/hcd-ohci-sysbus.c
index 6fba7f5..313e1e7 100644
--- a/hw/usb/hcd-ohci-sysbus.c
+++ b/hw/usb/hcd-ohci-sysbus.c
@@ -73,7 +73,7 @@ static void ohci_sysbus_class_init(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_USB, dc->categories);
dc->desc = "OHCI USB Controller";
device_class_set_props(dc, ohci_sysbus_properties);
- dc->reset = ohci_sysbus_reset;
+ device_class_set_legacy_reset(dc, ohci_sysbus_reset);
}
static const TypeInfo ohci_sysbus_types[] = {
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index a03cf22..3d0339a 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -1247,7 +1247,7 @@ static void uhci_class_init(ObjectClass *klass, void *data)
k->class_id = PCI_CLASS_SERIAL_USB;
dc->vmsd = &vmstate_uhci;
- dc->reset = uhci_reset;
+ device_class_set_legacy_reset(dc, uhci_reset);
set_bit(DEVICE_CATEGORY_USB, dc->categories);
}
diff --git a/hw/usb/hcd-xhci-pci.c b/hw/usb/hcd-xhci-pci.c
index 264d7eb..a039f57 100644
--- a/hw/usb/hcd-xhci-pci.c
+++ b/hw/usb/hcd-xhci-pci.c
@@ -202,7 +202,7 @@ static void xhci_class_init(ObjectClass *klass, void *data)
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = xhci_pci_reset;
+ device_class_set_legacy_reset(dc, xhci_pci_reset);
dc->vmsd = &vmstate_xhci_pci;
set_bit(DEVICE_CATEGORY_USB, dc->categories);
k->realize = usb_xhci_pci_realize;
diff --git a/hw/usb/hcd-xhci-sysbus.c b/hw/usb/hcd-xhci-sysbus.c
index d93bae3..59cf7fd 100644
--- a/hw/usb/hcd-xhci-sysbus.c
+++ b/hw/usb/hcd-xhci-sysbus.c
@@ -101,7 +101,7 @@ static void xhci_sysbus_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = xhci_sysbus_reset;
+ device_class_set_legacy_reset(dc, xhci_sysbus_reset);
dc->realize = xhci_sysbus_realize;
dc->vmsd = &vmstate_xhci_sysbus;
device_class_set_props(dc, xhci_sysbus_props);
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index b6411f0..d85adac 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -3621,7 +3621,7 @@ static void xhci_class_init(ObjectClass *klass, void *data)
dc->realize = usb_xhci_realize;
dc->unrealize = usb_xhci_unrealize;
- dc->reset = xhci_reset;
+ device_class_set_legacy_reset(dc, xhci_reset);
device_class_set_props(dc, xhci_properties);
dc->user_creatable = false;
}
diff --git a/hw/usb/imx-usb-phy.c b/hw/usb/imx-usb-phy.c
index 18917d7..f519250 100644
--- a/hw/usb/imx-usb-phy.c
+++ b/hw/usb/imx-usb-phy.c
@@ -218,7 +218,7 @@ static void imx_usbphy_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = imx_usbphy_reset;
+ device_class_set_legacy_reset(dc, imx_usbphy_reset);
dc->vmsd = &vmstate_imx_usbphy;
dc->desc = "i.MX USB PHY Module";
dc->realize = imx_usbphy_realize;
diff --git a/hw/usb/meson.build b/hw/usb/meson.build
index d7de100..1b4d150 100644
--- a/hw/usb/meson.build
+++ b/hw/usb/meson.build
@@ -23,11 +23,9 @@ system_ss.add(when: 'CONFIG_USB_XHCI', if_true: files('hcd-xhci.c'))
system_ss.add(when: 'CONFIG_USB_XHCI_PCI', if_true: files('hcd-xhci-pci.c'))
system_ss.add(when: 'CONFIG_USB_XHCI_SYSBUS', if_true: files('hcd-xhci-sysbus.c'))
system_ss.add(when: 'CONFIG_USB_XHCI_NEC', if_true: files('hcd-xhci-nec.c'))
-system_ss.add(when: 'CONFIG_USB_MUSB', if_true: files('hcd-musb.c'))
system_ss.add(when: 'CONFIG_USB_DWC2', if_true: files('hcd-dwc2.c'))
system_ss.add(when: 'CONFIG_USB_DWC3', if_true: files('hcd-dwc3.c'))
-system_ss.add(when: 'CONFIG_TUSB6010', if_true: files('tusb6010.c'))
system_ss.add(when: 'CONFIG_IMX', if_true: files('chipidea.c'))
system_ss.add(when: 'CONFIG_IMX_USBPHY', if_true: files('imx-usb-phy.c'))
system_ss.add(when: 'CONFIG_VT82C686', if_true: files('vt82c686-uhci-pci.c'))
diff --git a/hw/usb/tusb6010.c b/hw/usb/tusb6010.c
deleted file mode 100644
index 1dd4071..0000000
--- a/hw/usb/tusb6010.c
+++ /dev/null
@@ -1,850 +0,0 @@
-/*
- * Texas Instruments TUSB6010 emulation.
- * Based on reverse-engineering of a linux driver.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu/osdep.h"
-#include "qemu/module.h"
-#include "qemu/timer.h"
-#include "hw/usb.h"
-#include "hw/usb/hcd-musb.h"
-#include "hw/arm/omap.h"
-#include "hw/hw.h"
-#include "hw/irq.h"
-#include "hw/sysbus.h"
-#include "qom/object.h"
-
-#define TYPE_TUSB6010 "tusb6010"
-OBJECT_DECLARE_SIMPLE_TYPE(TUSBState, TUSB6010)
-
-struct TUSBState {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem[2];
- qemu_irq irq;
- MUSBState *musb;
- QEMUTimer *otg_timer;
- QEMUTimer *pwr_timer;
-
- int power;
- uint32_t scratch;
- uint16_t test_reset;
- uint32_t prcm_config;
- uint32_t prcm_mngmt;
- uint16_t otg_status;
- uint32_t dev_config;
- int host_mode;
- uint32_t intr;
- uint32_t intr_ok;
- uint32_t mask;
- uint32_t usbip_intr;
- uint32_t usbip_mask;
- uint32_t gpio_intr;
- uint32_t gpio_mask;
- uint32_t gpio_config;
- uint32_t dma_intr;
- uint32_t dma_mask;
- uint32_t dma_map;
- uint32_t dma_config;
- uint32_t ep0_config;
- uint32_t rx_config[15];
- uint32_t tx_config[15];
- uint32_t wkup_mask;
- uint32_t pullup[2];
- uint32_t control_config;
- uint32_t otg_timer_val;
-};
-
-#define TUSB_DEVCLOCK 60000000 /* 60 MHz */
-
-#define TUSB_VLYNQ_CTRL 0x004
-
-/* Mentor Graphics OTG core registers. */
-#define TUSB_BASE_OFFSET 0x400
-
-/* FIFO registers, 32-bit. */
-#define TUSB_FIFO_BASE 0x600
-
-/* Device System & Control registers, 32-bit. */
-#define TUSB_SYS_REG_BASE 0x800
-
-#define TUSB_DEV_CONF (TUSB_SYS_REG_BASE + 0x000)
-#define TUSB_DEV_CONF_USB_HOST_MODE (1 << 16)
-#define TUSB_DEV_CONF_PROD_TEST_MODE (1 << 15)
-#define TUSB_DEV_CONF_SOFT_ID (1 << 1)
-#define TUSB_DEV_CONF_ID_SEL (1 << 0)
-
-#define TUSB_PHY_OTG_CTRL_ENABLE (TUSB_SYS_REG_BASE + 0x004)
-#define TUSB_PHY_OTG_CTRL (TUSB_SYS_REG_BASE + 0x008)
-#define TUSB_PHY_OTG_CTRL_WRPROTECT (0xa5 << 24)
-#define TUSB_PHY_OTG_CTRL_O_ID_PULLUP (1 << 23)
-#define TUSB_PHY_OTG_CTRL_O_VBUS_DET_EN (1 << 19)
-#define TUSB_PHY_OTG_CTRL_O_SESS_END_EN (1 << 18)
-#define TUSB_PHY_OTG_CTRL_TESTM2 (1 << 17)
-#define TUSB_PHY_OTG_CTRL_TESTM1 (1 << 16)
-#define TUSB_PHY_OTG_CTRL_TESTM0 (1 << 15)
-#define TUSB_PHY_OTG_CTRL_TX_DATA2 (1 << 14)
-#define TUSB_PHY_OTG_CTRL_TX_GZ2 (1 << 13)
-#define TUSB_PHY_OTG_CTRL_TX_ENABLE2 (1 << 12)
-#define TUSB_PHY_OTG_CTRL_DM_PULLDOWN (1 << 11)
-#define TUSB_PHY_OTG_CTRL_DP_PULLDOWN (1 << 10)
-#define TUSB_PHY_OTG_CTRL_OSC_EN (1 << 9)
-#define TUSB_PHY_OTG_CTRL_PHYREF_CLK(v) (((v) & 3) << 7)
-#define TUSB_PHY_OTG_CTRL_PD (1 << 6)
-#define TUSB_PHY_OTG_CTRL_PLL_ON (1 << 5)
-#define TUSB_PHY_OTG_CTRL_EXT_RPU (1 << 4)
-#define TUSB_PHY_OTG_CTRL_PWR_GOOD (1 << 3)
-#define TUSB_PHY_OTG_CTRL_RESET (1 << 2)
-#define TUSB_PHY_OTG_CTRL_SUSPENDM (1 << 1)
-#define TUSB_PHY_OTG_CTRL_CLK_MODE (1 << 0)
-
-/* OTG status register */
-#define TUSB_DEV_OTG_STAT (TUSB_SYS_REG_BASE + 0x00c)
-#define TUSB_DEV_OTG_STAT_PWR_CLK_GOOD (1 << 8)
-#define TUSB_DEV_OTG_STAT_SESS_END (1 << 7)
-#define TUSB_DEV_OTG_STAT_SESS_VALID (1 << 6)
-#define TUSB_DEV_OTG_STAT_VBUS_VALID (1 << 5)
-#define TUSB_DEV_OTG_STAT_VBUS_SENSE (1 << 4)
-#define TUSB_DEV_OTG_STAT_ID_STATUS (1 << 3)
-#define TUSB_DEV_OTG_STAT_HOST_DISCON (1 << 2)
-#define TUSB_DEV_OTG_STAT_LINE_STATE (3 << 0)
-#define TUSB_DEV_OTG_STAT_DP_ENABLE (1 << 1)
-#define TUSB_DEV_OTG_STAT_DM_ENABLE (1 << 0)
-
-#define TUSB_DEV_OTG_TIMER (TUSB_SYS_REG_BASE + 0x010)
-#define TUSB_DEV_OTG_TIMER_ENABLE (1 << 31)
-#define TUSB_DEV_OTG_TIMER_VAL(v) ((v) & 0x07ffffff)
-#define TUSB_PRCM_REV (TUSB_SYS_REG_BASE + 0x014)
-
-/* PRCM configuration register */
-#define TUSB_PRCM_CONF (TUSB_SYS_REG_BASE + 0x018)
-#define TUSB_PRCM_CONF_SFW_CPEN (1 << 24)
-#define TUSB_PRCM_CONF_SYS_CLKSEL(v) (((v) & 3) << 16)
-
-/* PRCM management register */
-#define TUSB_PRCM_MNGMT (TUSB_SYS_REG_BASE + 0x01c)
-#define TUSB_PRCM_MNGMT_SRP_FIX_TMR(v) (((v) & 0xf) << 25)
-#define TUSB_PRCM_MNGMT_SRP_FIX_EN (1 << 24)
-#define TUSB_PRCM_MNGMT_VBUS_VAL_TMR(v) (((v) & 0xf) << 20)
-#define TUSB_PRCM_MNGMT_VBUS_VAL_FLT_EN (1 << 19)
-#define TUSB_PRCM_MNGMT_DFT_CLK_DIS (1 << 18)
-#define TUSB_PRCM_MNGMT_VLYNQ_CLK_DIS (1 << 17)
-#define TUSB_PRCM_MNGMT_OTG_SESS_END_EN (1 << 10)
-#define TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN (1 << 9)
-#define TUSB_PRCM_MNGMT_OTG_ID_PULLUP (1 << 8)
-#define TUSB_PRCM_MNGMT_15_SW_EN (1 << 4)
-#define TUSB_PRCM_MNGMT_33_SW_EN (1 << 3)
-#define TUSB_PRCM_MNGMT_5V_CPEN (1 << 2)
-#define TUSB_PRCM_MNGMT_PM_IDLE (1 << 1)
-#define TUSB_PRCM_MNGMT_DEV_IDLE (1 << 0)
-
-/* Wake-up source clear and mask registers */
-#define TUSB_PRCM_WAKEUP_SOURCE (TUSB_SYS_REG_BASE + 0x020)
-#define TUSB_PRCM_WAKEUP_CLEAR (TUSB_SYS_REG_BASE + 0x028)
-#define TUSB_PRCM_WAKEUP_MASK (TUSB_SYS_REG_BASE + 0x02c)
-#define TUSB_PRCM_WAKEUP_RESERVED_BITS (0xffffe << 13)
-#define TUSB_PRCM_WGPIO_7 (1 << 12)
-#define TUSB_PRCM_WGPIO_6 (1 << 11)
-#define TUSB_PRCM_WGPIO_5 (1 << 10)
-#define TUSB_PRCM_WGPIO_4 (1 << 9)
-#define TUSB_PRCM_WGPIO_3 (1 << 8)
-#define TUSB_PRCM_WGPIO_2 (1 << 7)
-#define TUSB_PRCM_WGPIO_1 (1 << 6)
-#define TUSB_PRCM_WGPIO_0 (1 << 5)
-#define TUSB_PRCM_WHOSTDISCON (1 << 4) /* Host disconnect */
-#define TUSB_PRCM_WBUS (1 << 3) /* USB bus resume */
-#define TUSB_PRCM_WNORCS (1 << 2) /* NOR chip select */
-#define TUSB_PRCM_WVBUS (1 << 1) /* OTG PHY VBUS */
-#define TUSB_PRCM_WID (1 << 0) /* OTG PHY ID detect */
-
-#define TUSB_PULLUP_1_CTRL (TUSB_SYS_REG_BASE + 0x030)
-#define TUSB_PULLUP_2_CTRL (TUSB_SYS_REG_BASE + 0x034)
-#define TUSB_INT_CTRL_REV (TUSB_SYS_REG_BASE + 0x038)
-#define TUSB_INT_CTRL_CONF (TUSB_SYS_REG_BASE + 0x03c)
-#define TUSB_USBIP_INT_SRC (TUSB_SYS_REG_BASE + 0x040)
-#define TUSB_USBIP_INT_SET (TUSB_SYS_REG_BASE + 0x044)
-#define TUSB_USBIP_INT_CLEAR (TUSB_SYS_REG_BASE + 0x048)
-#define TUSB_USBIP_INT_MASK (TUSB_SYS_REG_BASE + 0x04c)
-#define TUSB_DMA_INT_SRC (TUSB_SYS_REG_BASE + 0x050)
-#define TUSB_DMA_INT_SET (TUSB_SYS_REG_BASE + 0x054)
-#define TUSB_DMA_INT_CLEAR (TUSB_SYS_REG_BASE + 0x058)
-#define TUSB_DMA_INT_MASK (TUSB_SYS_REG_BASE + 0x05c)
-#define TUSB_GPIO_INT_SRC (TUSB_SYS_REG_BASE + 0x060)
-#define TUSB_GPIO_INT_SET (TUSB_SYS_REG_BASE + 0x064)
-#define TUSB_GPIO_INT_CLEAR (TUSB_SYS_REG_BASE + 0x068)
-#define TUSB_GPIO_INT_MASK (TUSB_SYS_REG_BASE + 0x06c)
-
-/* NOR flash interrupt source registers */
-#define TUSB_INT_SRC (TUSB_SYS_REG_BASE + 0x070)
-#define TUSB_INT_SRC_SET (TUSB_SYS_REG_BASE + 0x074)
-#define TUSB_INT_SRC_CLEAR (TUSB_SYS_REG_BASE + 0x078)
-#define TUSB_INT_MASK (TUSB_SYS_REG_BASE + 0x07c)
-#define TUSB_INT_SRC_TXRX_DMA_DONE (1 << 24)
-#define TUSB_INT_SRC_USB_IP_CORE (1 << 17)
-#define TUSB_INT_SRC_OTG_TIMEOUT (1 << 16)
-#define TUSB_INT_SRC_VBUS_SENSE_CHNG (1 << 15)
-#define TUSB_INT_SRC_ID_STATUS_CHNG (1 << 14)
-#define TUSB_INT_SRC_DEV_WAKEUP (1 << 13)
-#define TUSB_INT_SRC_DEV_READY (1 << 12)
-#define TUSB_INT_SRC_USB_IP_TX (1 << 9)
-#define TUSB_INT_SRC_USB_IP_RX (1 << 8)
-#define TUSB_INT_SRC_USB_IP_VBUS_ERR (1 << 7)
-#define TUSB_INT_SRC_USB_IP_VBUS_REQ (1 << 6)
-#define TUSB_INT_SRC_USB_IP_DISCON (1 << 5)
-#define TUSB_INT_SRC_USB_IP_CONN (1 << 4)
-#define TUSB_INT_SRC_USB_IP_SOF (1 << 3)
-#define TUSB_INT_SRC_USB_IP_RST_BABBLE (1 << 2)
-#define TUSB_INT_SRC_USB_IP_RESUME (1 << 1)
-#define TUSB_INT_SRC_USB_IP_SUSPEND (1 << 0)
-
-#define TUSB_GPIO_REV (TUSB_SYS_REG_BASE + 0x080)
-#define TUSB_GPIO_CONF (TUSB_SYS_REG_BASE + 0x084)
-#define TUSB_DMA_CTRL_REV (TUSB_SYS_REG_BASE + 0x100)
-#define TUSB_DMA_REQ_CONF (TUSB_SYS_REG_BASE + 0x104)
-#define TUSB_EP0_CONF (TUSB_SYS_REG_BASE + 0x108)
-#define TUSB_EP_IN_SIZE (TUSB_SYS_REG_BASE + 0x10c)
-#define TUSB_DMA_EP_MAP (TUSB_SYS_REG_BASE + 0x148)
-#define TUSB_EP_OUT_SIZE (TUSB_SYS_REG_BASE + 0x14c)
-#define TUSB_EP_MAX_PACKET_SIZE_OFFSET (TUSB_SYS_REG_BASE + 0x188)
-#define TUSB_SCRATCH_PAD (TUSB_SYS_REG_BASE + 0x1c4)
-#define TUSB_WAIT_COUNT (TUSB_SYS_REG_BASE + 0x1c8)
-#define TUSB_PROD_TEST_RESET (TUSB_SYS_REG_BASE + 0x1d8)
-
-#define TUSB_DIDR1_LO (TUSB_SYS_REG_BASE + 0x1f8)
-#define TUSB_DIDR1_HI (TUSB_SYS_REG_BASE + 0x1fc)
-
-/* Device System & Control register bitfields */
-#define TUSB_INT_CTRL_CONF_INT_RLCYC(v) (((v) & 0x7) << 18)
-#define TUSB_INT_CTRL_CONF_INT_POLARITY (1 << 17)
-#define TUSB_INT_CTRL_CONF_INT_MODE (1 << 16)
-#define TUSB_GPIO_CONF_DMAREQ(v) (((v) & 0x3f) << 24)
-#define TUSB_DMA_REQ_CONF_BURST_SIZE(v) (((v) & 3) << 26)
-#define TUSB_DMA_REQ_CONF_DMA_RQ_EN(v) (((v) & 0x3f) << 20)
-#define TUSB_DMA_REQ_CONF_DMA_RQ_ASR(v) (((v) & 0xf) << 16)
-#define TUSB_EP0_CONFIG_SW_EN (1 << 8)
-#define TUSB_EP0_CONFIG_DIR_TX (1 << 7)
-#define TUSB_EP0_CONFIG_XFR_SIZE(v) ((v) & 0x7f)
-#define TUSB_EP_CONFIG_SW_EN (1 << 31)
-#define TUSB_EP_CONFIG_XFR_SIZE(v) ((v) & 0x7fffffff)
-#define TUSB_PROD_TEST_RESET_VAL 0xa596
-
-static void tusb_intr_update(TUSBState *s)
-{
- if (s->control_config & TUSB_INT_CTRL_CONF_INT_POLARITY)
- qemu_set_irq(s->irq, s->intr & ~s->mask & s->intr_ok);
- else
- qemu_set_irq(s->irq, (!(s->intr & ~s->mask)) & s->intr_ok);
-}
-
-static void tusb_usbip_intr_update(TUSBState *s)
-{
- /* TX interrupt in the MUSB */
- if (s->usbip_intr & 0x0000ffff & ~s->usbip_mask)
- s->intr |= TUSB_INT_SRC_USB_IP_TX;
- else
- s->intr &= ~TUSB_INT_SRC_USB_IP_TX;
-
- /* RX interrupt in the MUSB */
- if (s->usbip_intr & 0xffff0000 & ~s->usbip_mask)
- s->intr |= TUSB_INT_SRC_USB_IP_RX;
- else
- s->intr &= ~TUSB_INT_SRC_USB_IP_RX;
-
- /* XXX: What about TUSB_INT_SRC_USB_IP_CORE? */
-
- tusb_intr_update(s);
-}
-
-static void tusb_dma_intr_update(TUSBState *s)
-{
- if (s->dma_intr & ~s->dma_mask)
- s->intr |= TUSB_INT_SRC_TXRX_DMA_DONE;
- else
- s->intr &= ~TUSB_INT_SRC_TXRX_DMA_DONE;
-
- tusb_intr_update(s);
-}
-
-static void tusb_gpio_intr_update(TUSBState *s)
-{
- /* TODO: How is this signalled? */
-}
-
-static uint32_t tusb_async_readb(void *opaque, hwaddr addr)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- switch (addr & 0xfff) {
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- return musb_read[0](s->musb, addr & 0x1ff);
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- return musb_read[0](s->musb, 0x20 + ((addr >> 3) & 0x3c));
- }
-
- printf("%s: unknown register at %03x\n",
- __func__, (int) (addr & 0xfff));
- return 0;
-}
-
-static uint32_t tusb_async_readh(void *opaque, hwaddr addr)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- switch (addr & 0xfff) {
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- return musb_read[1](s->musb, addr & 0x1ff);
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- return musb_read[1](s->musb, 0x20 + ((addr >> 3) & 0x3c));
- }
-
- printf("%s: unknown register at %03x\n",
- __func__, (int) (addr & 0xfff));
- return 0;
-}
-
-static uint32_t tusb_async_readw(void *opaque, hwaddr addr)
-{
- TUSBState *s = (TUSBState *) opaque;
- int offset = addr & 0xfff;
- int epnum;
- uint32_t ret;
-
- switch (offset) {
- case TUSB_DEV_CONF:
- return s->dev_config;
-
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- return musb_read[2](s->musb, offset & 0x1ff);
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- return musb_read[2](s->musb, 0x20 + ((addr >> 3) & 0x3c));
-
- case TUSB_PHY_OTG_CTRL_ENABLE:
- case TUSB_PHY_OTG_CTRL:
- return 0x00; /* TODO */
-
- case TUSB_DEV_OTG_STAT:
- ret = s->otg_status;
-#if 0
- if (!(s->prcm_mngmt & TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN))
- ret &= ~TUSB_DEV_OTG_STAT_VBUS_VALID;
-#endif
- return ret;
- case TUSB_DEV_OTG_TIMER:
- return s->otg_timer_val;
-
- case TUSB_PRCM_REV:
- return 0x20;
- case TUSB_PRCM_CONF:
- return s->prcm_config;
- case TUSB_PRCM_MNGMT:
- return s->prcm_mngmt;
- case TUSB_PRCM_WAKEUP_SOURCE:
- case TUSB_PRCM_WAKEUP_CLEAR: /* TODO: What does this one return? */
- return 0x00000000;
- case TUSB_PRCM_WAKEUP_MASK:
- return s->wkup_mask;
-
- case TUSB_PULLUP_1_CTRL:
- return s->pullup[0];
- case TUSB_PULLUP_2_CTRL:
- return s->pullup[1];
-
- case TUSB_INT_CTRL_REV:
- return 0x20;
- case TUSB_INT_CTRL_CONF:
- return s->control_config;
-
- case TUSB_USBIP_INT_SRC:
- case TUSB_USBIP_INT_SET: /* TODO: What do these two return? */
- case TUSB_USBIP_INT_CLEAR:
- return s->usbip_intr;
- case TUSB_USBIP_INT_MASK:
- return s->usbip_mask;
-
- case TUSB_DMA_INT_SRC:
- case TUSB_DMA_INT_SET: /* TODO: What do these two return? */
- case TUSB_DMA_INT_CLEAR:
- return s->dma_intr;
- case TUSB_DMA_INT_MASK:
- return s->dma_mask;
-
- case TUSB_GPIO_INT_SRC: /* TODO: What do these two return? */
- case TUSB_GPIO_INT_SET:
- case TUSB_GPIO_INT_CLEAR:
- return s->gpio_intr;
- case TUSB_GPIO_INT_MASK:
- return s->gpio_mask;
-
- case TUSB_INT_SRC:
- case TUSB_INT_SRC_SET: /* TODO: What do these two return? */
- case TUSB_INT_SRC_CLEAR:
- return s->intr;
- case TUSB_INT_MASK:
- return s->mask;
-
- case TUSB_GPIO_REV:
- return 0x30;
- case TUSB_GPIO_CONF:
- return s->gpio_config;
-
- case TUSB_DMA_CTRL_REV:
- return 0x30;
- case TUSB_DMA_REQ_CONF:
- return s->dma_config;
- case TUSB_EP0_CONF:
- return s->ep0_config;
- case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b):
- epnum = (offset - TUSB_EP_IN_SIZE) >> 2;
- return s->tx_config[epnum];
- case TUSB_DMA_EP_MAP:
- return s->dma_map;
- case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b):
- epnum = (offset - TUSB_EP_OUT_SIZE) >> 2;
- return s->rx_config[epnum];
- case TUSB_EP_MAX_PACKET_SIZE_OFFSET ...
- (TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b):
- return 0x00000000; /* TODO */
- case TUSB_WAIT_COUNT:
- return 0x00; /* TODO */
-
- case TUSB_SCRATCH_PAD:
- return s->scratch;
-
- case TUSB_PROD_TEST_RESET:
- return s->test_reset;
-
- /* DIE IDs */
- case TUSB_DIDR1_LO:
- return 0xa9453c59;
- case TUSB_DIDR1_HI:
- return 0x54059adf;
- }
-
- printf("%s: unknown register at %03x\n", __func__, offset);
- return 0;
-}
-
-static void tusb_async_writeb(void *opaque, hwaddr addr,
- uint32_t value)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- switch (addr & 0xfff) {
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- musb_write[0](s->musb, addr & 0x1ff, value);
- break;
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- musb_write[0](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
- break;
-
- default:
- printf("%s: unknown register at %03x\n",
- __func__, (int) (addr & 0xfff));
- return;
- }
-}
-
-static void tusb_async_writeh(void *opaque, hwaddr addr,
- uint32_t value)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- switch (addr & 0xfff) {
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- musb_write[1](s->musb, addr & 0x1ff, value);
- break;
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- musb_write[1](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
- break;
-
- default:
- printf("%s: unknown register at %03x\n",
- __func__, (int) (addr & 0xfff));
- return;
- }
-}
-
-static void tusb_async_writew(void *opaque, hwaddr addr,
- uint32_t value)
-{
- TUSBState *s = (TUSBState *) opaque;
- int offset = addr & 0xfff;
- int epnum;
-
- switch (offset) {
- case TUSB_VLYNQ_CTRL:
- break;
-
- case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
- musb_write[2](s->musb, offset & 0x1ff, value);
- break;
-
- case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
- musb_write[2](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
- break;
-
- case TUSB_DEV_CONF:
- s->dev_config = value;
- s->host_mode = (value & TUSB_DEV_CONF_USB_HOST_MODE);
- if (value & TUSB_DEV_CONF_PROD_TEST_MODE)
- hw_error("%s: Product Test mode not allowed\n", __func__);
- break;
-
- case TUSB_PHY_OTG_CTRL_ENABLE:
- case TUSB_PHY_OTG_CTRL:
- return; /* TODO */
- case TUSB_DEV_OTG_TIMER:
- s->otg_timer_val = value;
- if (value & TUSB_DEV_OTG_TIMER_ENABLE)
- timer_mod(s->otg_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- muldiv64(TUSB_DEV_OTG_TIMER_VAL(value),
- NANOSECONDS_PER_SECOND, TUSB_DEVCLOCK));
- else
- timer_del(s->otg_timer);
- break;
-
- case TUSB_PRCM_CONF:
- s->prcm_config = value;
- break;
- case TUSB_PRCM_MNGMT:
- s->prcm_mngmt = value;
- break;
- case TUSB_PRCM_WAKEUP_CLEAR:
- break;
- case TUSB_PRCM_WAKEUP_MASK:
- s->wkup_mask = value;
- break;
-
- case TUSB_PULLUP_1_CTRL:
- s->pullup[0] = value;
- break;
- case TUSB_PULLUP_2_CTRL:
- s->pullup[1] = value;
- break;
- case TUSB_INT_CTRL_CONF:
- s->control_config = value;
- tusb_intr_update(s);
- break;
-
- case TUSB_USBIP_INT_SET:
- s->usbip_intr |= value;
- tusb_usbip_intr_update(s);
- break;
- case TUSB_USBIP_INT_CLEAR:
- s->usbip_intr &= ~value;
- tusb_usbip_intr_update(s);
- musb_core_intr_clear(s->musb, ~value);
- break;
- case TUSB_USBIP_INT_MASK:
- s->usbip_mask = value;
- tusb_usbip_intr_update(s);
- break;
-
- case TUSB_DMA_INT_SET:
- s->dma_intr |= value;
- tusb_dma_intr_update(s);
- break;
- case TUSB_DMA_INT_CLEAR:
- s->dma_intr &= ~value;
- tusb_dma_intr_update(s);
- break;
- case TUSB_DMA_INT_MASK:
- s->dma_mask = value;
- tusb_dma_intr_update(s);
- break;
-
- case TUSB_GPIO_INT_SET:
- s->gpio_intr |= value;
- tusb_gpio_intr_update(s);
- break;
- case TUSB_GPIO_INT_CLEAR:
- s->gpio_intr &= ~value;
- tusb_gpio_intr_update(s);
- break;
- case TUSB_GPIO_INT_MASK:
- s->gpio_mask = value;
- tusb_gpio_intr_update(s);
- break;
-
- case TUSB_INT_SRC_SET:
- s->intr |= value;
- tusb_intr_update(s);
- break;
- case TUSB_INT_SRC_CLEAR:
- s->intr &= ~value;
- tusb_intr_update(s);
- break;
- case TUSB_INT_MASK:
- s->mask = value;
- tusb_intr_update(s);
- break;
-
- case TUSB_GPIO_CONF:
- s->gpio_config = value;
- break;
- case TUSB_DMA_REQ_CONF:
- s->dma_config = value;
- break;
- case TUSB_EP0_CONF:
- s->ep0_config = value & 0x1ff;
- musb_set_size(s->musb, 0, TUSB_EP0_CONFIG_XFR_SIZE(value),
- value & TUSB_EP0_CONFIG_DIR_TX);
- break;
- case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b):
- epnum = (offset - TUSB_EP_IN_SIZE) >> 2;
- s->tx_config[epnum] = value;
- musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 1);
- break;
- case TUSB_DMA_EP_MAP:
- s->dma_map = value;
- break;
- case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b):
- epnum = (offset - TUSB_EP_OUT_SIZE) >> 2;
- s->rx_config[epnum] = value;
- musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 0);
- break;
- case TUSB_EP_MAX_PACKET_SIZE_OFFSET ...
- (TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b):
- return; /* TODO */
- case TUSB_WAIT_COUNT:
- return; /* TODO */
-
- case TUSB_SCRATCH_PAD:
- s->scratch = value;
- break;
-
- case TUSB_PROD_TEST_RESET:
- s->test_reset = value;
- break;
-
- default:
- printf("%s: unknown register at %03x\n", __func__, offset);
- return;
- }
-}
-
-static uint64_t tusb_async_readfn(void *opaque, hwaddr addr, unsigned size)
-{
- switch (size) {
- case 1:
- return tusb_async_readb(opaque, addr);
- case 2:
- return tusb_async_readh(opaque, addr);
- case 4:
- return tusb_async_readw(opaque, addr);
- default:
- g_assert_not_reached();
- }
-}
-
-static void tusb_async_writefn(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- switch (size) {
- case 1:
- tusb_async_writeb(opaque, addr, value);
- break;
- case 2:
- tusb_async_writeh(opaque, addr, value);
- break;
- case 4:
- tusb_async_writew(opaque, addr, value);
- break;
- default:
- g_assert_not_reached();
- }
-}
-
-static const MemoryRegionOps tusb_async_ops = {
- .read = tusb_async_readfn,
- .write = tusb_async_writefn,
- .valid.min_access_size = 1,
- .valid.max_access_size = 4,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void tusb_otg_tick(void *opaque)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- s->otg_timer_val = 0;
- s->intr |= TUSB_INT_SRC_OTG_TIMEOUT;
- tusb_intr_update(s);
-}
-
-static void tusb_power_tick(void *opaque)
-{
- TUSBState *s = (TUSBState *) opaque;
-
- if (s->power) {
- s->intr_ok = ~0;
- tusb_intr_update(s);
- }
-}
-
-static void tusb_musb_core_intr(void *opaque, int source, int level)
-{
- TUSBState *s = (TUSBState *) opaque;
- uint16_t otg_status = s->otg_status;
-
- switch (source) {
- case musb_set_vbus:
- if (level)
- otg_status |= TUSB_DEV_OTG_STAT_VBUS_VALID;
- else
- otg_status &= ~TUSB_DEV_OTG_STAT_VBUS_VALID;
-
- /* XXX: only if TUSB_PHY_OTG_CTRL_OTG_VBUS_DET_EN set? */
- /* XXX: only if TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN set? */
- if (s->otg_status != otg_status) {
- s->otg_status = otg_status;
- s->intr |= TUSB_INT_SRC_VBUS_SENSE_CHNG;
- tusb_intr_update(s);
- }
- break;
-
- case musb_set_session:
- /* XXX: only if TUSB_PHY_OTG_CTRL_OTG_SESS_END_EN set? */
- /* XXX: only if TUSB_PRCM_MNGMT_OTG_SESS_END_EN set? */
- if (level) {
- s->otg_status |= TUSB_DEV_OTG_STAT_SESS_VALID;
- s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_END;
- } else {
- s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_VALID;
- s->otg_status |= TUSB_DEV_OTG_STAT_SESS_END;
- }
-
- /* XXX: some IRQ or anything? */
- break;
-
- case musb_irq_tx:
- case musb_irq_rx:
- s->usbip_intr = musb_core_intr_get(s->musb);
- /* Fall through. */
- default:
- if (level)
- s->intr |= 1 << source;
- else
- s->intr &= ~(1 << source);
- tusb_intr_update(s);
- break;
- }
-}
-
-static void tusb6010_power(TUSBState *s, int on)
-{
- if (!on) {
- s->power = 0;
- } else if (!s->power && on) {
- s->power = 1;
- /* Pull the interrupt down after TUSB6010 comes up. */
- s->intr_ok = 0;
- tusb_intr_update(s);
- timer_mod(s->pwr_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- NANOSECONDS_PER_SECOND / 2);
- }
-}
-
-static void tusb6010_irq(void *opaque, int source, int level)
-{
- if (source) {
- tusb_musb_core_intr(opaque, source - 1, level);
- } else {
- tusb6010_power(opaque, level);
- }
-}
-
-static void tusb6010_reset(DeviceState *dev)
-{
- TUSBState *s = TUSB6010(dev);
- int i;
-
- s->test_reset = TUSB_PROD_TEST_RESET_VAL;
- s->host_mode = 0;
- s->dev_config = 0;
- s->otg_status = 0; /* !TUSB_DEV_OTG_STAT_ID_STATUS means host mode */
- s->power = 0;
- s->mask = 0xffffffff;
- s->intr = 0x00000000;
- s->otg_timer_val = 0;
- s->scratch = 0;
- s->prcm_config = 0;
- s->prcm_mngmt = 0;
- s->intr_ok = 0;
- s->usbip_intr = 0;
- s->usbip_mask = 0;
- s->gpio_intr = 0;
- s->gpio_mask = 0;
- s->gpio_config = 0;
- s->dma_intr = 0;
- s->dma_mask = 0;
- s->dma_map = 0;
- s->dma_config = 0;
- s->ep0_config = 0;
- s->wkup_mask = 0;
- s->pullup[0] = s->pullup[1] = 0;
- s->control_config = 0;
- for (i = 0; i < 15; i++) {
- s->rx_config[i] = s->tx_config[i] = 0;
- }
- musb_reset(s->musb);
-}
-
-static void tusb6010_realize(DeviceState *dev, Error **errp)
-{
- TUSBState *s = TUSB6010(dev);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-
- s->otg_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tusb_otg_tick, s);
- s->pwr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tusb_power_tick, s);
- memory_region_init_io(&s->iomem[1], OBJECT(s), &tusb_async_ops, s,
- "tusb-async", UINT32_MAX);
- sysbus_init_mmio(sbd, &s->iomem[0]);
- sysbus_init_mmio(sbd, &s->iomem[1]);
- sysbus_init_irq(sbd, &s->irq);
- qdev_init_gpio_in(dev, tusb6010_irq, musb_irq_max + 1);
- s->musb = musb_init(dev, 1);
-}
-
-static void tusb6010_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->realize = tusb6010_realize;
- dc->reset = tusb6010_reset;
-}
-
-static const TypeInfo tusb6010_info = {
- .name = TYPE_TUSB6010,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(TUSBState),
- .class_init = tusb6010_class_init,
-};
-
-static void tusb6010_register_types(void)
-{
- type_register_static(&tusb6010_info);
-}
-
-type_init(tusb6010_register_types)
diff --git a/hw/vfio/ap.c b/hw/vfio/ap.c
index 0c4354e..4013e7b 100644
--- a/hw/vfio/ap.c
+++ b/hw/vfio/ap.c
@@ -230,6 +230,9 @@ static void vfio_ap_instance_init(Object *obj)
*/
vfio_device_init(vbasedev, VFIO_DEVICE_TYPE_AP, &vfio_ap_ops,
DEVICE(vapdev), true);
+
+ /* AP device is mdev type device */
+ vbasedev->mdev = true;
}
#ifdef CONFIG_IOMMUFD
@@ -253,7 +256,7 @@ static void vfio_ap_class_init(ObjectClass *klass, void *data)
dc->realize = vfio_ap_realize;
dc->unrealize = vfio_ap_unrealize;
dc->hotpluggable = true;
- dc->reset = vfio_ap_reset;
+ device_class_set_legacy_reset(dc, vfio_ap_reset);
dc->bus_type = TYPE_AP_BUS;
}
diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c
index 1f8e127..24703c8 100644
--- a/hw/vfio/ccw.c
+++ b/hw/vfio/ccw.c
@@ -675,6 +675,9 @@ static void vfio_ccw_instance_init(Object *obj)
VFIOCCWDevice *vcdev = VFIO_CCW(obj);
VFIODevice *vbasedev = &vcdev->vdev;
+ /* CCW device is mdev type device */
+ vbasedev->mdev = true;
+
/*
* All vfio-ccw devices are believed to operate in a way compatible with
* discarding of memory in RAM blocks, ie. pages pinned in the host are
@@ -708,7 +711,7 @@ static void vfio_ccw_class_init(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->realize = vfio_ccw_realize;
dc->unrealize = vfio_ccw_unrealize;
- dc->reset = vfio_ccw_reset;
+ device_class_set_legacy_reset(dc, vfio_ccw_reset);
cdc->handle_request = vfio_ccw_handle_request;
cdc->handle_halt = vfio_ccw_handle_halt;
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 6d15b36..36d0cf6 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -199,6 +199,9 @@ bool vfio_devices_all_device_dirty_tracking(const VFIOContainerBase *bcontainer)
VFIODevice *vbasedev;
QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) {
+ if (vbasedev->device_dirty_page_tracking == ON_OFF_AUTO_OFF) {
+ return false;
+ }
if (!vbasedev->dirty_pages_supported) {
return false;
}
@@ -599,7 +602,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr);
int iommu_idx;
- trace_vfio_listener_region_add_iommu(iova, end);
+ trace_vfio_listener_region_add_iommu(section->mr->name, iova, end);
/*
* FIXME: For VFIO iommu types which have KVM acceleration to
* avoid bouncing all map/unmaps through qemu this way, this
@@ -725,6 +728,7 @@ static void vfio_listener_region_del(MemoryListener *listener,
if (memory_region_is_iommu(section->mr)) {
VFIOGuestIOMMU *giommu;
+ trace_vfio_listener_region_del_iommu(section->mr->name);
QLIST_FOREACH(giommu, &bcontainer->giommu_list, giommu_next) {
if (MEMORY_REGION(giommu->iommu_mr) == section->mr &&
giommu->n.start == section->offset_within_region) {
@@ -1536,7 +1540,7 @@ bool vfio_attach_device(char *name, VFIODevice *vbasedev,
{
const VFIOIOMMUClass *ops =
VFIO_IOMMU_CLASS(object_class_by_name(TYPE_VFIO_IOMMU_LEGACY));
- HostIOMMUDevice *hiod;
+ HostIOMMUDevice *hiod = NULL;
if (vbasedev->iommufd) {
ops = VFIO_IOMMU_CLASS(object_class_by_name(TYPE_VFIO_IOMMU_IOMMUFD));
@@ -1544,17 +1548,17 @@ bool vfio_attach_device(char *name, VFIODevice *vbasedev,
assert(ops);
- if (!ops->attach_device(name, vbasedev, as, errp)) {
- return false;
+
+ if (!vbasedev->mdev) {
+ hiod = HOST_IOMMU_DEVICE(object_new(ops->hiod_typename));
+ vbasedev->hiod = hiod;
}
- hiod = HOST_IOMMU_DEVICE(object_new(ops->hiod_typename));
- if (!HOST_IOMMU_DEVICE_GET_CLASS(hiod)->realize(hiod, vbasedev, errp)) {
+ if (!ops->attach_device(name, vbasedev, as, errp)) {
object_unref(hiod);
- ops->detach_device(vbasedev);
+ vbasedev->hiod = NULL;
return false;
}
- vbasedev->hiod = hiod;
return true;
}
diff --git a/hw/vfio/container.c b/hw/vfio/container.c
index 38a9df3..9ccdb63 100644
--- a/hw/vfio/container.c
+++ b/hw/vfio/container.c
@@ -656,7 +656,6 @@ static bool vfio_connect_container(VFIOGroup *group, AddressSpace *as,
return true;
listener_release_exit:
QLIST_REMOVE(group, container_next);
- QLIST_REMOVE(bcontainer, next);
vfio_kvm_device_del_group(group);
memory_listener_unregister(&bcontainer->listener);
if (vioc->release) {
@@ -915,6 +914,10 @@ static bool vfio_legacy_attach_device(const char *name, VFIODevice *vbasedev,
trace_vfio_attach_device(vbasedev->name, groupid);
+ if (!vfio_device_hiod_realize(vbasedev, errp)) {
+ return false;
+ }
+
group = vfio_get_group(groupid, as, errp);
if (!group) {
return false;
@@ -1142,7 +1145,6 @@ static bool hiod_legacy_vfio_realize(HostIOMMUDevice *hiod, void *opaque,
VFIODevice *vdev = opaque;
hiod->name = g_strdup(vdev->name);
- hiod->caps.aw_bits = vfio_device_get_aw_bits(vdev);
hiod->agent = opaque;
return true;
@@ -1151,11 +1153,9 @@ static bool hiod_legacy_vfio_realize(HostIOMMUDevice *hiod, void *opaque,
static int hiod_legacy_vfio_get_cap(HostIOMMUDevice *hiod, int cap,
Error **errp)
{
- HostIOMMUDeviceCaps *caps = &hiod->caps;
-
switch (cap) {
case HOST_IOMMU_DEVICE_CAP_AW_BITS:
- return caps->aw_bits;
+ return vfio_device_get_aw_bits(hiod->agent);
default:
error_setg(errp, "%s: unsupported capability %x", hiod->name, cap);
return -EINVAL;
diff --git a/hw/vfio/helpers.c b/hw/vfio/helpers.c
index b14edd4..913796f 100644
--- a/hw/vfio/helpers.c
+++ b/hw/vfio/helpers.c
@@ -27,6 +27,7 @@
#include "trace.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
+#include "qemu/units.h"
#include "monitor/monitor.h"
/*
@@ -395,7 +396,7 @@ static void vfio_subregion_unmap(VFIORegion *region, int index)
int vfio_region_mmap(VFIORegion *region)
{
- int i, prot = 0;
+ int i, ret, prot = 0;
char *name;
if (!region->mem) {
@@ -406,27 +407,40 @@ int vfio_region_mmap(VFIORegion *region)
prot |= region->flags & VFIO_REGION_INFO_FLAG_WRITE ? PROT_WRITE : 0;
for (i = 0; i < region->nr_mmaps; i++) {
- region->mmaps[i].mmap = mmap(NULL, region->mmaps[i].size, prot,
- MAP_SHARED, region->vbasedev->fd,
- region->fd_offset +
- region->mmaps[i].offset);
- if (region->mmaps[i].mmap == MAP_FAILED) {
- int ret = -errno;
-
- trace_vfio_region_mmap_fault(memory_region_name(region->mem), i,
- region->fd_offset +
- region->mmaps[i].offset,
- region->fd_offset +
- region->mmaps[i].offset +
- region->mmaps[i].size - 1, ret);
+ size_t align = MIN(1ULL << ctz64(region->mmaps[i].size), 1 * GiB);
+ void *map_base, *map_align;
- region->mmaps[i].mmap = NULL;
+ /*
+ * Align the mmap for more efficient mapping in the kernel. Ideally
+ * we'd know the PMD and PUD mapping sizes to use as discrete alignment
+ * intervals, but we don't. As of Linux v6.12, the largest PUD size
+ * supporting huge pfnmap is 1GiB (ARCH_SUPPORTS_PUD_PFNMAP is only set
+ * on x86_64). Align by power-of-two size, capped at 1GiB.
+ *
+ * NB. qemu_memalign() and friends actually allocate memory, whereas
+ * the region size here can exceed host memory, therefore we manually
+ * create an oversized anonymous mapping and clean it up for alignment.
+ */
+ map_base = mmap(0, region->mmaps[i].size + align, PROT_NONE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (map_base == MAP_FAILED) {
+ ret = -errno;
+ goto no_mmap;
+ }
- for (i--; i >= 0; i--) {
- vfio_subregion_unmap(region, i);
- }
+ map_align = (void *)ROUND_UP((uintptr_t)map_base, (uintptr_t)align);
+ munmap(map_base, map_align - map_base);
+ munmap(map_align + region->mmaps[i].size,
+ align - (map_align - map_base));
- return ret;
+ region->mmaps[i].mmap = mmap(map_align, region->mmaps[i].size, prot,
+ MAP_SHARED | MAP_FIXED,
+ region->vbasedev->fd,
+ region->fd_offset +
+ region->mmaps[i].offset);
+ if (region->mmaps[i].mmap == MAP_FAILED) {
+ ret = -errno;
+ goto no_mmap;
}
name = g_strdup_printf("%s mmaps[%d]",
@@ -446,6 +460,20 @@ int vfio_region_mmap(VFIORegion *region)
}
return 0;
+
+no_mmap:
+ trace_vfio_region_mmap_fault(memory_region_name(region->mem), i,
+ region->fd_offset + region->mmaps[i].offset,
+ region->fd_offset + region->mmaps[i].offset +
+ region->mmaps[i].size - 1, ret);
+
+ region->mmaps[i].mmap = NULL;
+
+ for (i--; i >= 0; i--) {
+ vfio_subregion_unmap(region, i);
+ }
+
+ return ret;
}
void vfio_region_unmap(VFIORegion *region)
@@ -675,3 +703,28 @@ int vfio_device_get_aw_bits(VFIODevice *vdev)
return HOST_IOMMU_DEVICE_CAP_AW_BITS_MAX;
}
+
+bool vfio_device_is_mdev(VFIODevice *vbasedev)
+{
+ g_autofree char *subsys = NULL;
+ g_autofree char *tmp = NULL;
+
+ if (!vbasedev->sysfsdev) {
+ return false;
+ }
+
+ tmp = g_strdup_printf("%s/subsystem", vbasedev->sysfsdev);
+ subsys = realpath(tmp, NULL);
+ return subsys && (strcmp(subsys, "/sys/bus/mdev") == 0);
+}
+
+bool vfio_device_hiod_realize(VFIODevice *vbasedev, Error **errp)
+{
+ HostIOMMUDevice *hiod = vbasedev->hiod;
+
+ if (!hiod) {
+ return true;
+ }
+
+ return HOST_IOMMU_DEVICE_GET_CLASS(hiod)->realize(hiod, vbasedev, errp);
+}
diff --git a/hw/vfio/igd.c b/hw/vfio/igd.c
index d320d03..a95d441 100644
--- a/hw/vfio/igd.c
+++ b/hw/vfio/igd.c
@@ -88,19 +88,30 @@ static int igd_gen(VFIOPCIDevice *vdev)
case 0x2200:
case 0x5900:
return 8;
+ /* ElkhartLake */
+ case 0x4500:
+ return 11;
+ /* TigerLake */
+ case 0x9A00:
+ return 12;
}
- return 8; /* Assume newer is compatible */
+ /*
+ * Unfortunately, Intel changes it's specification quite often. This makes
+ * it impossible to use a suitable default value for unknown devices.
+ */
+ return -1;
}
typedef struct VFIOIGDQuirk {
struct VFIOPCIDevice *vdev;
uint32_t index;
- uint32_t bdsm;
+ uint64_t bdsm;
} VFIOIGDQuirk;
#define IGD_GMCH 0x50 /* Graphics Control Register */
#define IGD_BDSM 0x5c /* Base Data of Stolen Memory */
+#define IGD_BDSM_GEN11 0xc0 /* Base Data of Stolen Memory of gen 11 and later */
/*
@@ -309,9 +320,13 @@ static void vfio_igd_quirk_data_write(void *opaque, hwaddr addr,
*/
if ((igd->index % 4 == 1) && igd->index < vfio_igd_gtt_max(vdev)) {
if (gen < 8 || (igd->index % 8 == 1)) {
- uint32_t base;
+ uint64_t base;
- base = pci_get_long(vdev->pdev.config + IGD_BDSM);
+ if (gen < 11) {
+ base = pci_get_long(vdev->pdev.config + IGD_BDSM);
+ } else {
+ base = pci_get_quad(vdev->pdev.config + IGD_BDSM_GEN11);
+ }
if (!base) {
hw_error("vfio-igd: Guest attempted to program IGD GTT before "
"BIOS reserved stolen memory. Unsupported BIOS?");
@@ -365,6 +380,128 @@ static const MemoryRegionOps vfio_igd_index_quirk = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
+#define IGD_BDSM_MMIO_OFFSET 0x1080C0
+
+static uint64_t vfio_igd_quirk_bdsm_read(void *opaque,
+ hwaddr addr, unsigned size)
+{
+ VFIOPCIDevice *vdev = opaque;
+ uint64_t offset;
+
+ offset = IGD_BDSM_GEN11 + addr;
+
+ switch (size) {
+ case 1:
+ return pci_get_byte(vdev->pdev.config + offset);
+ case 2:
+ return pci_get_word(vdev->pdev.config + offset);
+ case 4:
+ return pci_get_long(vdev->pdev.config + offset);
+ case 8:
+ return pci_get_quad(vdev->pdev.config + offset);
+ default:
+ hw_error("igd: unsupported read size, %u bytes", size);
+ break;
+ }
+
+ return 0;
+}
+
+static void vfio_igd_quirk_bdsm_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
+{
+ VFIOPCIDevice *vdev = opaque;
+ uint64_t offset;
+
+ offset = IGD_BDSM_GEN11 + addr;
+
+ switch (size) {
+ case 1:
+ pci_set_byte(vdev->pdev.config + offset, data);
+ break;
+ case 2:
+ pci_set_word(vdev->pdev.config + offset, data);
+ break;
+ case 4:
+ pci_set_long(vdev->pdev.config + offset, data);
+ break;
+ case 8:
+ pci_set_quad(vdev->pdev.config + offset, data);
+ break;
+ default:
+ hw_error("igd: unsupported read size, %u bytes", size);
+ break;
+ }
+}
+
+static const MemoryRegionOps vfio_igd_bdsm_quirk = {
+ .read = vfio_igd_quirk_bdsm_read,
+ .write = vfio_igd_quirk_bdsm_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+void vfio_probe_igd_bar0_quirk(VFIOPCIDevice *vdev, int nr)
+{
+ VFIOQuirk *quirk;
+ int gen;
+
+ /*
+ * This must be an Intel VGA device at address 00:02.0 for us to even
+ * consider enabling legacy mode. Some driver have dependencies on the PCI
+ * bus address.
+ */
+ if (!vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, PCI_ANY_ID) ||
+ !vfio_is_vga(vdev) || nr != 0 ||
+ &vdev->pdev != pci_find_device(pci_device_root_bus(&vdev->pdev),
+ 0, PCI_DEVFN(0x2, 0))) {
+ return;
+ }
+
+ /*
+ * Only on IGD devices of gen 11 and above, the BDSM register is mirrored
+ * into MMIO space and read from MMIO space by the Windows driver.
+ */
+ gen = igd_gen(vdev);
+ if (gen < 11) {
+ return;
+ }
+
+ quirk = vfio_quirk_alloc(1);
+ quirk->data = vdev;
+
+ memory_region_init_io(&quirk->mem[0], OBJECT(vdev), &vfio_igd_bdsm_quirk,
+ vdev, "vfio-igd-bdsm-quirk", 8);
+ memory_region_add_subregion_overlap(vdev->bars[0].region.mem,
+ IGD_BDSM_MMIO_OFFSET, &quirk->mem[0],
+ 1);
+
+ QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
+}
+
+static int igd_get_stolen_mb(int gen, uint32_t gmch)
+{
+ int gms;
+
+ if (gen < 8) {
+ gms = (gmch >> 3) & 0x1f;
+ } else {
+ gms = (gmch >> 8) & 0xff;
+ }
+
+ if (gen < 9) {
+ if (gms > 0x10) {
+ error_report("Unsupported IGD GMS value 0x%x", gms);
+ return 0;
+ }
+ return gms * 32;
+ } else {
+ if (gms < 0xf0)
+ return gms * 32;
+ else
+ return gms * 4 + 4;
+ }
+}
+
void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
{
g_autofree struct vfio_region_info *rom = NULL;
@@ -412,7 +549,7 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
* devices maintain compatibility with generation 8.
*/
gen = igd_gen(vdev);
- if (gen != 6 && gen != 8) {
+ if (gen == -1) {
error_report("IGD device %s is unsupported in legacy mode, "
"try SandyBridge or newer", vdev->vbasedev.name);
return;
@@ -515,7 +652,13 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
igd = quirk->data = g_malloc0(sizeof(*igd));
igd->vdev = vdev;
igd->index = ~0;
- igd->bdsm = vfio_pci_read_config(&vdev->pdev, IGD_BDSM, 4);
+ if (gen < 11) {
+ igd->bdsm = vfio_pci_read_config(&vdev->pdev, IGD_BDSM, 4);
+ } else {
+ igd->bdsm = vfio_pci_read_config(&vdev->pdev, IGD_BDSM_GEN11, 4);
+ igd->bdsm |=
+ (uint64_t)vfio_pci_read_config(&vdev->pdev, IGD_BDSM_GEN11 + 4, 4) << 32;
+ }
igd->bdsm &= ~((1 * MiB) - 1); /* 1MB aligned */
memory_region_init_io(&quirk->mem[0], OBJECT(vdev), &vfio_igd_index_quirk,
@@ -536,23 +679,7 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
ggms_mb = 1 << ggms_mb;
}
- /*
- * Assume we have no GMS memory, but allow it to be overridden by device
- * option (experimental). The spec doesn't actually allow zero GMS when
- * when IVD (IGD VGA Disable) is clear, but the claim is that it's unused,
- * so let's not waste VM memory for it.
- */
- gmch &= ~((gen < 8 ? 0x1f : 0xff) << (gen < 8 ? 3 : 8));
-
- if (vdev->igd_gms) {
- if (vdev->igd_gms <= 0x10) {
- gms_mb = vdev->igd_gms * 32;
- gmch |= vdev->igd_gms << (gen < 8 ? 3 : 8);
- } else {
- error_report("Unsupported IGD GMS value 0x%x", vdev->igd_gms);
- vdev->igd_gms = 0;
- }
- }
+ gms_mb = igd_get_stolen_mb(gen, gmch);
/*
* Request reserved memory for stolen memory via fw_cfg. VM firmware
@@ -573,9 +700,15 @@ void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
pci_set_long(vdev->emulated_config_bits + IGD_GMCH, ~0);
/* BDSM is read-write, emulated. The BIOS needs to be able to write it */
- pci_set_long(vdev->pdev.config + IGD_BDSM, 0);
- pci_set_long(vdev->pdev.wmask + IGD_BDSM, ~0);
- pci_set_long(vdev->emulated_config_bits + IGD_BDSM, ~0);
+ if (gen < 11) {
+ pci_set_long(vdev->pdev.config + IGD_BDSM, 0);
+ pci_set_long(vdev->pdev.wmask + IGD_BDSM, ~0);
+ pci_set_long(vdev->emulated_config_bits + IGD_BDSM, ~0);
+ } else {
+ pci_set_quad(vdev->pdev.config + IGD_BDSM_GEN11, 0);
+ pci_set_quad(vdev->pdev.wmask + IGD_BDSM_GEN11, ~0);
+ pci_set_quad(vdev->emulated_config_bits + IGD_BDSM_GEN11, ~0);
+ }
/*
* This IOBAR gives us access to GTTADR, which allows us to write to
diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c
index 7b5f87a..e7bece4 100644
--- a/hw/vfio/iommufd.c
+++ b/hw/vfio/iommufd.c
@@ -25,6 +25,7 @@
#include "qemu/cutils.h"
#include "qemu/chardev_open.h"
#include "pci.h"
+#include "exec/ram_addr.h"
static int iommufd_cdev_map(const VFIOContainerBase *bcontainer, hwaddr iova,
ram_addr_t size, void *vaddr, bool readonly)
@@ -110,6 +111,68 @@ static void iommufd_cdev_unbind_and_disconnect(VFIODevice *vbasedev)
iommufd_backend_disconnect(vbasedev->iommufd);
}
+static bool iommufd_hwpt_dirty_tracking(VFIOIOASHwpt *hwpt)
+{
+ return hwpt && hwpt->hwpt_flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING;
+}
+
+static int iommufd_set_dirty_page_tracking(const VFIOContainerBase *bcontainer,
+ bool start, Error **errp)
+{
+ const VFIOIOMMUFDContainer *container =
+ container_of(bcontainer, VFIOIOMMUFDContainer, bcontainer);
+ VFIOIOASHwpt *hwpt;
+
+ QLIST_FOREACH(hwpt, &container->hwpt_list, next) {
+ if (!iommufd_hwpt_dirty_tracking(hwpt)) {
+ continue;
+ }
+
+ if (!iommufd_backend_set_dirty_tracking(container->be,
+ hwpt->hwpt_id, start, errp)) {
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ QLIST_FOREACH(hwpt, &container->hwpt_list, next) {
+ if (!iommufd_hwpt_dirty_tracking(hwpt)) {
+ continue;
+ }
+ iommufd_backend_set_dirty_tracking(container->be,
+ hwpt->hwpt_id, !start, NULL);
+ }
+ return -EINVAL;
+}
+
+static int iommufd_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
+ VFIOBitmap *vbmap, hwaddr iova,
+ hwaddr size, Error **errp)
+{
+ VFIOIOMMUFDContainer *container = container_of(bcontainer,
+ VFIOIOMMUFDContainer,
+ bcontainer);
+ unsigned long page_size = qemu_real_host_page_size();
+ VFIOIOASHwpt *hwpt;
+
+ QLIST_FOREACH(hwpt, &container->hwpt_list, next) {
+ if (!iommufd_hwpt_dirty_tracking(hwpt)) {
+ continue;
+ }
+
+ if (!iommufd_backend_get_dirty_bitmap(container->be, hwpt->hwpt_id,
+ iova, size, page_size,
+ (uint64_t *)vbmap->bitmap,
+ errp)) {
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int iommufd_cdev_getfd(const char *sysfs_path, Error **errp)
{
ERRP_GUARD();
@@ -172,7 +235,7 @@ out:
return ret;
}
-static bool iommufd_cdev_attach_ioas_hwpt(VFIODevice *vbasedev, uint32_t id,
+static int iommufd_cdev_attach_ioas_hwpt(VFIODevice *vbasedev, uint32_t id,
Error **errp)
{
int iommufd = vbasedev->iommufd->fd;
@@ -187,12 +250,12 @@ static bool iommufd_cdev_attach_ioas_hwpt(VFIODevice *vbasedev, uint32_t id,
error_setg_errno(errp, errno,
"[iommufd=%d] error attach %s (%d) to id=%d",
iommufd, vbasedev->name, vbasedev->fd, id);
- return false;
+ return -errno;
}
trace_iommufd_cdev_attach_ioas_hwpt(iommufd, vbasedev->name,
vbasedev->fd, id);
- return true;
+ return 0;
}
static bool iommufd_cdev_detach_ioas_hwpt(VFIODevice *vbasedev, Error **errp)
@@ -212,11 +275,111 @@ static bool iommufd_cdev_detach_ioas_hwpt(VFIODevice *vbasedev, Error **errp)
return true;
}
+static bool iommufd_cdev_autodomains_get(VFIODevice *vbasedev,
+ VFIOIOMMUFDContainer *container,
+ Error **errp)
+{
+ ERRP_GUARD();
+ IOMMUFDBackend *iommufd = vbasedev->iommufd;
+ uint32_t flags = 0;
+ VFIOIOASHwpt *hwpt;
+ uint32_t hwpt_id;
+ int ret;
+
+ /* Try to find a domain */
+ QLIST_FOREACH(hwpt, &container->hwpt_list, next) {
+ ret = iommufd_cdev_attach_ioas_hwpt(vbasedev, hwpt->hwpt_id, errp);
+ if (ret) {
+ /* -EINVAL means the domain is incompatible with the device. */
+ if (ret == -EINVAL) {
+ /*
+ * It is an expected failure and it just means we will try
+ * another domain, or create one if no existing compatible
+ * domain is found. Hence why the error is discarded below.
+ */
+ error_free(*errp);
+ *errp = NULL;
+ continue;
+ }
+
+ return false;
+ } else {
+ vbasedev->hwpt = hwpt;
+ QLIST_INSERT_HEAD(&hwpt->device_list, vbasedev, hwpt_next);
+ vbasedev->iommu_dirty_tracking = iommufd_hwpt_dirty_tracking(hwpt);
+ return true;
+ }
+ }
+
+ /*
+ * This is quite early and VFIO Migration state isn't yet fully
+ * initialized, thus rely only on IOMMU hardware capabilities as to
+ * whether IOMMU dirty tracking is going to be requested. Later
+ * vfio_migration_realize() may decide to use VF dirty tracking
+ * instead.
+ */
+ if (vbasedev->hiod->caps.hw_caps & IOMMU_HW_CAP_DIRTY_TRACKING) {
+ flags = IOMMU_HWPT_ALLOC_DIRTY_TRACKING;
+ }
+
+ if (!iommufd_backend_alloc_hwpt(iommufd, vbasedev->devid,
+ container->ioas_id, flags,
+ IOMMU_HWPT_DATA_NONE, 0, NULL,
+ &hwpt_id, errp)) {
+ return false;
+ }
+
+ hwpt = g_malloc0(sizeof(*hwpt));
+ hwpt->hwpt_id = hwpt_id;
+ hwpt->hwpt_flags = flags;
+ QLIST_INIT(&hwpt->device_list);
+
+ ret = iommufd_cdev_attach_ioas_hwpt(vbasedev, hwpt->hwpt_id, errp);
+ if (ret) {
+ iommufd_backend_free_id(container->be, hwpt->hwpt_id);
+ g_free(hwpt);
+ return false;
+ }
+
+ vbasedev->hwpt = hwpt;
+ vbasedev->iommu_dirty_tracking = iommufd_hwpt_dirty_tracking(hwpt);
+ QLIST_INSERT_HEAD(&hwpt->device_list, vbasedev, hwpt_next);
+ QLIST_INSERT_HEAD(&container->hwpt_list, hwpt, next);
+ container->bcontainer.dirty_pages_supported |=
+ vbasedev->iommu_dirty_tracking;
+ if (container->bcontainer.dirty_pages_supported &&
+ !vbasedev->iommu_dirty_tracking) {
+ warn_report("IOMMU instance for device %s doesn't support dirty tracking",
+ vbasedev->name);
+ }
+ return true;
+}
+
+static void iommufd_cdev_autodomains_put(VFIODevice *vbasedev,
+ VFIOIOMMUFDContainer *container)
+{
+ VFIOIOASHwpt *hwpt = vbasedev->hwpt;
+
+ QLIST_REMOVE(vbasedev, hwpt_next);
+ vbasedev->hwpt = NULL;
+
+ if (QLIST_EMPTY(&hwpt->device_list)) {
+ QLIST_REMOVE(hwpt, next);
+ iommufd_backend_free_id(container->be, hwpt->hwpt_id);
+ g_free(hwpt);
+ }
+}
+
static bool iommufd_cdev_attach_container(VFIODevice *vbasedev,
VFIOIOMMUFDContainer *container,
Error **errp)
{
- return iommufd_cdev_attach_ioas_hwpt(vbasedev, container->ioas_id, errp);
+ /* mdevs aren't physical devices and will fail with auto domains */
+ if (!vbasedev->mdev) {
+ return iommufd_cdev_autodomains_get(vbasedev, container, errp);
+ }
+
+ return !iommufd_cdev_attach_ioas_hwpt(vbasedev, container->ioas_id, errp);
}
static void iommufd_cdev_detach_container(VFIODevice *vbasedev,
@@ -227,6 +390,11 @@ static void iommufd_cdev_detach_container(VFIODevice *vbasedev,
if (!iommufd_cdev_detach_ioas_hwpt(vbasedev, &err)) {
error_report_err(err);
}
+
+ if (vbasedev->hwpt) {
+ iommufd_cdev_autodomains_put(vbasedev, container);
+ }
+
}
static void iommufd_cdev_container_destroy(VFIOIOMMUFDContainer *container)
@@ -320,6 +488,17 @@ static bool iommufd_cdev_attach(const char *name, VFIODevice *vbasedev,
space = vfio_get_address_space(as);
+ /*
+ * The HostIOMMUDevice data from legacy backend is static and doesn't need
+ * any information from the (type1-iommu) backend to be initialized. In
+ * contrast however, the IOMMUFD HostIOMMUDevice data requires the iommufd
+ * FD to be connected and having a devid to be able to successfully call
+ * iommufd_backend_get_device_info().
+ */
+ if (!vfio_device_hiod_realize(vbasedev, errp)) {
+ goto err_alloc_ioas;
+ }
+
/* try to attach to an existing container in this space */
QLIST_FOREACH(bcontainer, &space->containers, next) {
container = container_of(bcontainer, VFIOIOMMUFDContainer, bcontainer);
@@ -354,6 +533,7 @@ static bool iommufd_cdev_attach(const char *name, VFIODevice *vbasedev,
container = VFIO_IOMMU_IOMMUFD(object_new(TYPE_VFIO_IOMMU_IOMMUFD));
container->be = vbasedev->iommufd;
container->ioas_id = ioas_id;
+ QLIST_INIT(&container->hwpt_list);
bcontainer = &container->bcontainer;
vfio_address_space_insert(space, bcontainer);
@@ -617,6 +797,8 @@ static void vfio_iommu_iommufd_class_init(ObjectClass *klass, void *data)
vioc->attach_device = iommufd_cdev_attach;
vioc->detach_device = iommufd_cdev_detach;
vioc->pci_hot_reset = iommufd_cdev_pci_hot_reset;
+ vioc->set_dirty_page_tracking = iommufd_set_dirty_page_tracking;
+ vioc->query_dirty_bitmap = iommufd_query_dirty_bitmap;
};
static bool hiod_iommufd_vfio_realize(HostIOMMUDevice *hiod, void *opaque,
@@ -628,17 +810,19 @@ static bool hiod_iommufd_vfio_realize(HostIOMMUDevice *hiod, void *opaque,
union {
struct iommu_hw_info_vtd vtd;
} data;
+ uint64_t hw_caps;
hiod->agent = opaque;
if (!iommufd_backend_get_device_info(vdev->iommufd, vdev->devid,
- &type, &data, sizeof(data), errp)) {
+ &type, &data, sizeof(data),
+ &hw_caps, errp)) {
return false;
}
hiod->name = g_strdup(vdev->name);
caps->type = type;
- caps->aw_bits = vfio_device_get_aw_bits(vdev);
+ caps->hw_caps = hw_caps;
return true;
}
diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c
index 34d4be2..992dc3b 100644
--- a/hw/vfio/migration.c
+++ b/hw/vfio/migration.c
@@ -81,7 +81,7 @@ static const char *mig_state_to_str(enum vfio_device_mig_state state)
}
}
-static VfioMigrationState
+static QapiVfioMigrationState
mig_state_to_qapi_state(enum vfio_device_mig_state state)
{
switch (state) {
@@ -576,9 +576,6 @@ static void vfio_state_pending_exact(void *opaque, uint64_t *must_precopy,
if (vfio_device_state_is_precopy(vbasedev)) {
vfio_query_precopy_size(migration);
-
- *must_precopy +=
- migration->precopy_init_size + migration->precopy_dirty_size;
}
trace_vfio_state_pending_exact(vbasedev->name, *must_precopy, *can_postcopy,
@@ -1036,16 +1033,18 @@ bool vfio_migration_realize(VFIODevice *vbasedev, Error **errp)
return !vfio_block_migration(vbasedev, err, errp);
}
- if (!vbasedev->dirty_pages_supported) {
+ if ((!vbasedev->dirty_pages_supported ||
+ vbasedev->device_dirty_page_tracking == ON_OFF_AUTO_OFF) &&
+ !vbasedev->iommu_dirty_tracking) {
if (vbasedev->enable_migration == ON_OFF_AUTO_AUTO) {
error_setg(&err,
- "%s: VFIO device doesn't support device dirty tracking",
- vbasedev->name);
+ "%s: VFIO device doesn't support device and "
+ "IOMMU dirty tracking", vbasedev->name);
goto add_blocker;
}
- warn_report("%s: VFIO device doesn't support device dirty tracking",
- vbasedev->name);
+ warn_report("%s: VFIO device doesn't support device and "
+ "IOMMU dirty tracking", vbasedev->name);
}
ret = vfio_block_multiple_devices_migration(vbasedev, errp);
diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c
index 39dae72..d37f722 100644
--- a/hw/vfio/pci-quirks.c
+++ b/hw/vfio/pci-quirks.c
@@ -1259,6 +1259,7 @@ void vfio_bar_quirk_setup(VFIOPCIDevice *vdev, int nr)
vfio_probe_nvidia_bar0_quirk(vdev, nr);
vfio_probe_rtl8168_bar2_quirk(vdev, nr);
#ifdef CONFIG_VFIO_IGD
+ vfio_probe_igd_bar0_quirk(vdev, nr);
vfio_probe_igd_bar4_quirk(vdev, nr);
#endif
}
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index e03d9f3..14bcc72 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -1452,7 +1452,7 @@ static bool vfio_pci_relocate_msix(VFIOPCIDevice *vdev, Error **errp)
int target_bar = -1;
size_t msix_sz;
- if (!vdev->msix || vdev->msix_relo == OFF_AUTOPCIBAR_OFF) {
+ if (!vdev->msix || vdev->msix_relo == OFF_AUTO_PCIBAR_OFF) {
return true;
}
@@ -1464,7 +1464,7 @@ static bool vfio_pci_relocate_msix(VFIOPCIDevice *vdev, Error **errp)
/* PCI BARs must be a power of 2 */
msix_sz = pow2ceil(msix_sz);
- if (vdev->msix_relo == OFF_AUTOPCIBAR_AUTO) {
+ if (vdev->msix_relo == OFF_AUTO_PCIBAR_AUTO) {
/*
* TODO: Lookup table for known devices.
*
@@ -1479,7 +1479,7 @@ static bool vfio_pci_relocate_msix(VFIOPCIDevice *vdev, Error **errp)
return false;
}
} else {
- target_bar = (int)(vdev->msix_relo - OFF_AUTOPCIBAR_BAR0);
+ target_bar = (int)(vdev->msix_relo - OFF_AUTO_PCIBAR_BAR0);
}
/* I/O port BARs cannot host MSI-X structures */
@@ -1624,7 +1624,7 @@ static bool vfio_msix_early_setup(VFIOPCIDevice *vdev, Error **errp)
} else if (vfio_pci_is(vdev, PCI_VENDOR_ID_BAIDU,
PCI_DEVICE_ID_KUNLUN_VF)) {
msix->pba_offset = 0xb400;
- } else if (vdev->msix_relo == OFF_AUTOPCIBAR_OFF) {
+ } else if (vdev->msix_relo == OFF_AUTO_PCIBAR_OFF) {
error_setg(errp, "hardware reports invalid configuration, "
"MSIX PBA outside of specified BAR");
g_free(msix);
@@ -2963,12 +2963,9 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
ERRP_GUARD();
VFIOPCIDevice *vdev = VFIO_PCI(pdev);
VFIODevice *vbasedev = &vdev->vbasedev;
- char *subsys;
int i, ret;
- bool is_mdev;
char uuid[UUID_STR_LEN];
g_autofree char *name = NULL;
- g_autofree char *tmp = NULL;
if (vbasedev->fd < 0 && !vbasedev->sysfsdev) {
if (!(~vdev->host.domain || ~vdev->host.bus ||
@@ -2997,14 +2994,11 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
* stays in sync with the active working set of the guest driver. Prevent
* the x-balloon-allowed option unless this is minimally an mdev device.
*/
- tmp = g_strdup_printf("%s/subsystem", vbasedev->sysfsdev);
- subsys = realpath(tmp, NULL);
- is_mdev = subsys && (strcmp(subsys, "/sys/bus/mdev") == 0);
- free(subsys);
+ vbasedev->mdev = vfio_device_is_mdev(vbasedev);
- trace_vfio_mdev(vbasedev->name, is_mdev);
+ trace_vfio_mdev(vbasedev->name, vbasedev->mdev);
- if (vbasedev->ram_block_discard_allowed && !is_mdev) {
+ if (vbasedev->ram_block_discard_allowed && !vbasedev->mdev) {
error_setg(errp, "x-balloon-allowed only potentially compatible "
"with mdev devices");
goto error;
@@ -3121,7 +3115,8 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
vfio_bars_register(vdev);
- if (!pci_device_set_iommu_device(pdev, vbasedev->hiod, errp)) {
+ if (!vbasedev->mdev &&
+ !pci_device_set_iommu_device(pdev, vbasedev->hiod, errp)) {
error_prepend(errp, "Failed to set iommu_device: ");
goto out_teardown;
}
@@ -3244,7 +3239,9 @@ out_deregister:
timer_free(vdev->intx.mmap_timer);
}
out_unset_idev:
- pci_device_unset_iommu_device(pdev);
+ if (!vbasedev->mdev) {
+ pci_device_unset_iommu_device(pdev);
+ }
out_teardown:
vfio_teardown_msi(vdev);
vfio_bars_exit(vdev);
@@ -3289,7 +3286,9 @@ static void vfio_exitfn(PCIDevice *pdev)
vfio_pci_disable_rp_atomics(vdev);
vfio_bars_exit(vdev);
vfio_migration_exit(vbasedev);
- pci_device_unset_iommu_device(pdev);
+ if (!vbasedev->mdev) {
+ pci_device_unset_iommu_device(pdev);
+ }
}
static void vfio_pci_reset(DeviceState *dev)
@@ -3362,6 +3361,9 @@ static Property vfio_pci_dev_properties[] = {
DEFINE_PROP_ON_OFF_AUTO("x-pre-copy-dirty-page-tracking", VFIOPCIDevice,
vbasedev.pre_copy_dirty_page_tracking,
ON_OFF_AUTO_ON),
+ DEFINE_PROP_ON_OFF_AUTO("x-device-dirty-page-tracking", VFIOPCIDevice,
+ vbasedev.device_dirty_page_tracking,
+ ON_OFF_AUTO_ON),
DEFINE_PROP_ON_OFF_AUTO("display", VFIOPCIDevice,
display, ON_OFF_AUTO_OFF),
DEFINE_PROP_UINT32("xres", VFIOPCIDevice, display_xres, 0),
@@ -3401,7 +3403,7 @@ static Property vfio_pci_dev_properties[] = {
nv_gpudirect_clique,
qdev_prop_nv_gpudirect_clique, uint8_t),
DEFINE_PROP_OFF_AUTO_PCIBAR("x-msix-relocation", VFIOPCIDevice, msix_relo,
- OFF_AUTOPCIBAR_OFF),
+ OFF_AUTO_PCIBAR_OFF),
#ifdef CONFIG_IOMMUFD
DEFINE_PROP_LINK("iommufd", VFIOPCIDevice, vbasedev.iommufd,
TYPE_IOMMUFD_BACKEND, IOMMUFDBackend *),
@@ -3422,7 +3424,7 @@ static void vfio_pci_dev_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *pdc = PCI_DEVICE_CLASS(klass);
- dc->reset = vfio_pci_reset;
+ device_class_set_legacy_reset(dc, vfio_pci_reset);
device_class_set_props(dc, vfio_pci_dev_properties);
#ifdef CONFIG_IOMMUFD
object_class_property_add_str(klass, "fd", NULL, vfio_pci_set_fd);
diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h
index bf67df2..5ad090a 100644
--- a/hw/vfio/pci.h
+++ b/hw/vfio/pci.h
@@ -215,6 +215,7 @@ void vfio_setup_resetfn_quirk(VFIOPCIDevice *vdev);
bool vfio_add_virt_caps(VFIOPCIDevice *vdev, Error **errp);
void vfio_quirk_reset(VFIOPCIDevice *vdev);
VFIOQuirk *vfio_quirk_alloc(int nr_mem);
+void vfio_probe_igd_bar0_quirk(VFIOPCIDevice *vdev, int nr);
void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr);
extern const PropertyInfo qdev_prop_nv_gpudirect_clique;
diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events
index e16179b..29789e8 100644
--- a/hw/vfio/trace-events
+++ b/hw/vfio/trace-events
@@ -27,7 +27,7 @@ vfio_vga_read(uint64_t addr, int size, uint64_t data) " (0x%"PRIx64", %d) = 0x%"
vfio_pci_read_config(const char *name, int addr, int len, int val) " (%s, @0x%x, len=0x%x) 0x%x"
vfio_pci_write_config(const char *name, int addr, int val, int len) " (%s, @0x%x, 0x%x, len=0x%x)"
vfio_msi_setup(const char *name, int pos) "%s PCI MSI CAP @0x%x"
-vfio_msix_early_setup(const char *name, int pos, int table_bar, int offset, int entries, bool noresize) "%s PCI MSI-X CAP @0x%x, BAR %d, offset 0x%x, entries %d, noresize %d"
+vfio_msix_early_setup(const char *name, int pos, int table_bar, uint64_t offset, int entries, bool noresize) "%s PCI MSI-X CAP @0x%x, BAR %d, offset 0x%"PRIx64", entries %d, noresize %d"
vfio_check_pcie_flr(const char *name) "%s Supports FLR via PCIe cap"
vfio_check_pm_reset(const char *name) "%s Supports PM reset"
vfio_check_af_flr(const char *name) "%s Supports FLR via AF cap"
@@ -95,7 +95,8 @@ vfio_region_read(char *name, int index, uint64_t addr, unsigned size, uint64_t d
vfio_iommu_map_notify(const char *op, uint64_t iova_start, uint64_t iova_end) "iommu %s @ 0x%"PRIx64" - 0x%"PRIx64
vfio_listener_region_skip(const char *name, uint64_t start, uint64_t end) "SKIPPING %s 0x%"PRIx64" - 0x%"PRIx64
vfio_spapr_group_attach(int groupfd, int tablefd) "Attached groupfd %d to liobn fd %d"
-vfio_listener_region_add_iommu(uint64_t start, uint64_t end) "region_add [iommu] 0x%"PRIx64" - 0x%"PRIx64
+vfio_listener_region_add_iommu(const char* name, uint64_t start, uint64_t end) "region_add [iommu] %s 0x%"PRIx64" - 0x%"PRIx64
+vfio_listener_region_del_iommu(const char *name) "region_del [iommu] %s"
vfio_listener_region_add_ram(uint64_t iova_start, uint64_t iova_end, void *vaddr) "region_add [ram] 0x%"PRIx64" - 0x%"PRIx64" [%p]"
vfio_known_safe_misalignment(const char *name, uint64_t iova, uint64_t offset_within_region, uintptr_t page_size) "Region \"%s\" iova=0x%"PRIx64" offset_within_region=0x%"PRIx64" qemu_real_host_page_size=0x%"PRIxPTR
vfio_listener_region_add_no_dma_map(const char *name, uint64_t iova, uint64_t size, uint64_t page_size) "Region \"%s\" 0x%"PRIx64" size=0x%"PRIx64" is not aligned to 0x%"PRIx64" and cannot be mapped for DMA"
@@ -150,7 +151,7 @@ vfio_display_edid_write_error(void) ""
vfio_load_cleanup(const char *name) " (%s)"
vfio_load_device_config_state(const char *name) " (%s)"
vfio_load_state(const char *name, uint64_t data) " (%s) data 0x%"PRIx64
-vfio_load_state_device_data(const char *name, uint64_t data_size, int ret) " (%s) size 0x%"PRIx64" ret %d"
+vfio_load_state_device_data(const char *name, uint64_t data_size, int ret) " (%s) size %"PRIu64" ret %d"
vfio_migration_realize(const char *name) " (%s)"
vfio_migration_set_device_state(const char *name, const char *state) " (%s) state %s"
vfio_migration_set_state(const char *name, const char *new_state, const char *recover_state) " (%s) new state %s, recover state %s"
@@ -159,10 +160,10 @@ vfio_save_block(const char *name, int data_size) " (%s) data_size %d"
vfio_save_cleanup(const char *name) " (%s)"
vfio_save_complete_precopy(const char *name, int ret) " (%s) ret %d"
vfio_save_device_config_state(const char *name) " (%s)"
-vfio_save_iterate(const char *name, uint64_t precopy_init_size, uint64_t precopy_dirty_size) " (%s) precopy initial size 0x%"PRIx64" precopy dirty size 0x%"PRIx64
-vfio_save_setup(const char *name, uint64_t data_buffer_size) " (%s) data buffer size 0x%"PRIx64
-vfio_state_pending_estimate(const char *name, uint64_t precopy, uint64_t postcopy, uint64_t precopy_init_size, uint64_t precopy_dirty_size) " (%s) precopy 0x%"PRIx64" postcopy 0x%"PRIx64" precopy initial size 0x%"PRIx64" precopy dirty size 0x%"PRIx64
-vfio_state_pending_exact(const char *name, uint64_t precopy, uint64_t postcopy, uint64_t stopcopy_size, uint64_t precopy_init_size, uint64_t precopy_dirty_size) " (%s) precopy 0x%"PRIx64" postcopy 0x%"PRIx64" stopcopy size 0x%"PRIx64" precopy initial size 0x%"PRIx64" precopy dirty size 0x%"PRIx64
+vfio_save_iterate(const char *name, uint64_t precopy_init_size, uint64_t precopy_dirty_size) " (%s) precopy initial size %"PRIu64" precopy dirty size %"PRIu64
+vfio_save_setup(const char *name, uint64_t data_buffer_size) " (%s) data buffer size %"PRIu64
+vfio_state_pending_estimate(const char *name, uint64_t precopy, uint64_t postcopy, uint64_t precopy_init_size, uint64_t precopy_dirty_size) " (%s) precopy %"PRIu64" postcopy %"PRIu64" precopy initial size %"PRIu64" precopy dirty size %"PRIu64
+vfio_state_pending_exact(const char *name, uint64_t precopy, uint64_t postcopy, uint64_t stopcopy_size, uint64_t precopy_init_size, uint64_t precopy_dirty_size) " (%s) precopy %"PRIu64" postcopy %"PRIu64" stopcopy size %"PRIu64" precopy initial size %"PRIu64" precopy dirty size %"PRIu64
vfio_vmstate_change(const char *name, int running, const char *reason, const char *dev_state) " (%s) running %d reason %s device state %s"
vfio_vmstate_change_prepare(const char *name, int running, const char *reason, const char *dev_state) " (%s) running %d reason %s device state %s"
diff --git a/hw/virtio/Kconfig b/hw/virtio/Kconfig
index aa63ff7..17595ff 100644
--- a/hw/virtio/Kconfig
+++ b/hw/virtio/Kconfig
@@ -16,6 +16,7 @@ config VIRTIO_PCI
default y if PCI_DEVICES
depends on PCI
select VIRTIO
+ select VIRTIO_MD_SUPPORTED
config VIRTIO_MMIO
bool
@@ -35,10 +36,17 @@ config VIRTIO_CRYPTO
default y
depends on VIRTIO
+# not all virtio transports support memory devices; if none does,
+# no need to include the code
+config VIRTIO_MD_SUPPORTED
+ bool
+
config VIRTIO_MD
bool
+ depends on VIRTIO_MD_SUPPORTED
select MEM_DEVICE
+# selected by the board if it has the required support code
config VIRTIO_PMEM_SUPPORTED
bool
@@ -46,9 +54,11 @@ config VIRTIO_PMEM
bool
default y
depends on VIRTIO
+ depends on VIRTIO_MD_SUPPORTED
depends on VIRTIO_PMEM_SUPPORTED
select VIRTIO_MD
+# selected by the board if it has the required support code
config VIRTIO_MEM_SUPPORTED
bool
@@ -57,6 +67,7 @@ config VIRTIO_MEM
default y
depends on VIRTIO
depends on LINUX
+ depends on VIRTIO_MD_SUPPORTED
depends on VIRTIO_MEM_SUPPORTED
select VIRTIO_MD
@@ -109,4 +120,4 @@ config VHOST_USER_SND
config VHOST_USER_SCMI
bool
default y
- depends on VIRTIO && VHOST_USER
+ depends on VIRTIO && VHOST_USER && ARM
diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events
index b7c04f0..04e36ae 100644
--- a/hw/virtio/trace-events
+++ b/hw/virtio/trace-events
@@ -116,6 +116,7 @@ virtio_iommu_get_config(uint64_t page_size_mask, uint64_t start, uint64_t end, u
virtio_iommu_set_config(uint8_t bypass) "bypass=0x%x"
virtio_iommu_attach(uint32_t domain_id, uint32_t ep_id) "domain=%d endpoint=%d"
virtio_iommu_detach(uint32_t domain_id, uint32_t ep_id) "domain=%d endpoint=%d"
+virtio_iommu_detach_endpoint_from_domain(uint32_t domain_id, uint32_t ep_id) "domain=%d endpoint=%d"
virtio_iommu_map(uint32_t domain_id, uint64_t virt_start, uint64_t virt_end, uint64_t phys_start, uint32_t flags) "domain=%d virt_start=0x%"PRIx64" virt_end=0x%"PRIx64 " phys_start=0x%"PRIx64" flags=%d"
virtio_iommu_unmap(uint32_t domain_id, uint64_t virt_start, uint64_t virt_end) "domain=%d virt_start=0x%"PRIx64" virt_end=0x%"PRIx64
virtio_iommu_unmap_done(uint32_t domain_id, uint64_t virt_start, uint64_t virt_end) "domain=%d virt_start=0x%"PRIx64" virt_end=0x%"PRIx64
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
index fc5f408..37aca8b 100644
--- a/hw/virtio/vhost-shadow-virtqueue.c
+++ b/hw/virtio/vhost-shadow-virtqueue.c
@@ -414,6 +414,7 @@ static uint16_t vhost_svq_last_desc_of_chain(const VhostShadowVirtqueue *svq,
return i;
}
+G_GNUC_WARN_UNUSED_RESULT
static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq,
uint32_t *len)
{
@@ -526,10 +527,11 @@ static void vhost_svq_flush(VhostShadowVirtqueue *svq,
size_t vhost_svq_poll(VhostShadowVirtqueue *svq, size_t num)
{
size_t len = 0;
- uint32_t r;
while (num--) {
+ g_autofree VirtQueueElement *elem = NULL;
int64_t start_us = g_get_monotonic_time();
+ uint32_t r = 0;
do {
if (vhost_svq_more_used(svq)) {
@@ -541,7 +543,7 @@ size_t vhost_svq_poll(VhostShadowVirtqueue *svq, size_t num)
}
} while (true);
- vhost_svq_get_buf(svq, &r);
+ elem = vhost_svq_get_buf(svq, &r);
len += r;
}
diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c
index ae48cc1..32ee7f4 100644
--- a/hw/virtio/vhost-user-fs.c
+++ b/hw/virtio/vhost-user-fs.c
@@ -33,6 +33,7 @@ static const int user_feature_bits[] = {
VIRTIO_F_RING_PACKED,
VIRTIO_F_IOMMU_PLATFORM,
VIRTIO_F_RING_RESET,
+ VIRTIO_F_IN_ORDER,
VIRTIO_F_NOTIFICATION_DATA,
VHOST_INVALID_FEATURE_BIT
};
diff --git a/hw/virtio/vhost-user-vsock.c b/hw/virtio/vhost-user-vsock.c
index 802b44a..da3b0e0 100644
--- a/hw/virtio/vhost-user-vsock.c
+++ b/hw/virtio/vhost-user-vsock.c
@@ -21,6 +21,7 @@ static const int user_feature_bits[] = {
VIRTIO_RING_F_INDIRECT_DESC,
VIRTIO_RING_F_EVENT_IDX,
VIRTIO_F_NOTIFY_ON_EMPTY,
+ VIRTIO_F_IN_ORDER,
VIRTIO_F_NOTIFICATION_DATA,
VHOST_INVALID_FEATURE_BIT
};
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 06fc717..76f9b2a 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -1682,9 +1682,9 @@ void vhost_dev_cleanup(struct vhost_dev *hdev)
memset(hdev, 0, sizeof(struct vhost_dev));
}
-static void vhost_dev_disable_notifiers_nvqs(struct vhost_dev *hdev,
- VirtIODevice *vdev,
- unsigned int nvqs)
+void vhost_dev_disable_notifiers_nvqs(struct vhost_dev *hdev,
+ VirtIODevice *vdev,
+ unsigned int nvqs)
{
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
int i, r;
@@ -1930,62 +1930,6 @@ void vhost_dev_free_inflight(struct vhost_inflight *inflight)
}
}
-static int vhost_dev_resize_inflight(struct vhost_inflight *inflight,
- uint64_t new_size)
-{
- Error *err = NULL;
- int fd = -1;
- void *addr = qemu_memfd_alloc("vhost-inflight", new_size,
- F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL,
- &fd, &err);
-
- if (err) {
- error_report_err(err);
- return -ENOMEM;
- }
-
- vhost_dev_free_inflight(inflight);
- inflight->offset = 0;
- inflight->addr = addr;
- inflight->fd = fd;
- inflight->size = new_size;
-
- return 0;
-}
-
-void vhost_dev_save_inflight(struct vhost_inflight *inflight, QEMUFile *f)
-{
- if (inflight->addr) {
- qemu_put_be64(f, inflight->size);
- qemu_put_be16(f, inflight->queue_size);
- qemu_put_buffer(f, inflight->addr, inflight->size);
- } else {
- qemu_put_be64(f, 0);
- }
-}
-
-int vhost_dev_load_inflight(struct vhost_inflight *inflight, QEMUFile *f)
-{
- uint64_t size;
-
- size = qemu_get_be64(f);
- if (!size) {
- return 0;
- }
-
- if (inflight->size != size) {
- int ret = vhost_dev_resize_inflight(inflight, size);
- if (ret < 0) {
- return ret;
- }
- }
- inflight->queue_size = qemu_get_be16(f);
-
- qemu_get_buffer(f, inflight->addr, size);
-
- return 0;
-}
-
int vhost_dev_prepare_inflight(struct vhost_dev *hdev, VirtIODevice *vdev)
{
int r;
diff --git a/hw/virtio/virtio-acpi.c b/hw/virtio/virtio-acpi.c
index 230a669..85becef 100644
--- a/hw/virtio/virtio-acpi.c
+++ b/hw/virtio/virtio-acpi.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* virtio ACPI Support
*
diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
index bbe8aa4..c3ffd83 100644
--- a/hw/virtio/virtio-crypto.c
+++ b/hw/virtio/virtio-crypto.c
@@ -205,6 +205,7 @@ virtio_crypto_create_asym_session(VirtIOCrypto *vcrypto,
int queue_index;
uint32_t algo, keytype, keylen;
+ sreq->info.op_code = opcode;
algo = ldl_le_p(&sess_req->para.algo);
keytype = ldl_le_p(&sess_req->para.keytype);
keylen = ldl_le_p(&sess_req->para.keylen);
@@ -224,7 +225,6 @@ virtio_crypto_create_asym_session(VirtIOCrypto *vcrypto,
iov_discard_front(&iov, &out_num, keylen);
}
- sreq->info.op_code = opcode;
asym_info = &sreq->info.u.asym_sess_info;
asym_info->algo = algo;
asym_info->keytype = keytype;
@@ -461,7 +461,7 @@ static void virtio_crypto_init_request(VirtIOCrypto *vcrypto, VirtQueue *vq,
req->in_iov = NULL;
req->in_num = 0;
req->in_len = 0;
- req->flags = QCRYPTODEV_BACKEND_ALG__MAX;
+ req->flags = QCRYPTODEV_BACKEND_ALGO_TYPE__MAX;
memset(&req->op_info, 0x00, sizeof(req->op_info));
}
@@ -471,7 +471,7 @@ static void virtio_crypto_free_request(VirtIOCryptoReq *req)
return;
}
- if (req->flags == QCRYPTODEV_BACKEND_ALG_SYM) {
+ if (req->flags == QCRYPTODEV_BACKEND_ALGO_TYPE_SYM) {
size_t max_len;
CryptoDevBackendSymOpInfo *op_info = req->op_info.u.sym_op_info;
@@ -486,7 +486,7 @@ static void virtio_crypto_free_request(VirtIOCryptoReq *req)
memset(op_info, 0, sizeof(*op_info) + max_len);
g_free(op_info);
}
- } else if (req->flags == QCRYPTODEV_BACKEND_ALG_ASYM) {
+ } else if (req->flags == QCRYPTODEV_BACKEND_ALGO_TYPE_ASYM) {
CryptoDevBackendAsymOpInfo *op_info = req->op_info.u.asym_op_info;
if (op_info) {
g_free(op_info->src);
@@ -571,10 +571,10 @@ static void virtio_crypto_req_complete(void *opaque, int ret)
VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto);
uint8_t status = -ret;
- if (req->flags == QCRYPTODEV_BACKEND_ALG_SYM) {
+ if (req->flags == QCRYPTODEV_BACKEND_ALGO_TYPE_SYM) {
virtio_crypto_sym_input_data_helper(vdev, req, status,
req->op_info.u.sym_op_info);
- } else if (req->flags == QCRYPTODEV_BACKEND_ALG_ASYM) {
+ } else if (req->flags == QCRYPTODEV_BACKEND_ALGO_TYPE_ASYM) {
virtio_crypto_akcipher_input_data_helper(vdev, req, status,
req->op_info.u.asym_op_info);
}
@@ -884,7 +884,7 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request)
switch (opcode) {
case VIRTIO_CRYPTO_CIPHER_ENCRYPT:
case VIRTIO_CRYPTO_CIPHER_DECRYPT:
- op_info->algtype = request->flags = QCRYPTODEV_BACKEND_ALG_SYM;
+ op_info->algtype = request->flags = QCRYPTODEV_BACKEND_ALGO_TYPE_SYM;
ret = virtio_crypto_handle_sym_req(vcrypto,
&req.u.sym_req, op_info,
out_iov, out_num);
@@ -894,7 +894,7 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request)
case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
case VIRTIO_CRYPTO_AKCIPHER_SIGN:
case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
- op_info->algtype = request->flags = QCRYPTODEV_BACKEND_ALG_ASYM;
+ op_info->algtype = request->flags = QCRYPTODEV_BACKEND_ALGO_TYPE_ASYM;
ret = virtio_crypto_handle_asym_req(vcrypto,
&req.u.akcipher_req, op_info,
out_iov, out_num);
@@ -1008,19 +1008,19 @@ static uint32_t virtio_crypto_init_services(uint32_t qservices)
{
uint32_t vservices = 0;
- if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_CIPHER)) {
+ if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_TYPE_CIPHER)) {
vservices |= (1 << VIRTIO_CRYPTO_SERVICE_CIPHER);
}
- if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_HASH)) {
+ if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_TYPE_HASH)) {
vservices |= (1 << VIRTIO_CRYPTO_SERVICE_HASH);
}
- if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_MAC)) {
+ if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_TYPE_MAC)) {
vservices |= (1 << VIRTIO_CRYPTO_SERVICE_MAC);
}
- if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_AEAD)) {
+ if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_TYPE_AEAD)) {
vservices |= (1 << VIRTIO_CRYPTO_SERVICE_AEAD);
}
- if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER)) {
+ if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_TYPE_AKCIPHER)) {
vservices |= (1 << VIRTIO_CRYPTO_SERVICE_AKCIPHER);
}
@@ -1247,9 +1247,21 @@ static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx)
static struct vhost_dev *virtio_crypto_get_vhost(VirtIODevice *vdev)
{
VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev);
- CryptoDevBackend *b = vcrypto->cryptodev;
- CryptoDevBackendClient *cc = b->conf.peers.ccs[0];
- CryptoDevBackendVhost *vhost_crypto = cryptodev_get_vhost(cc, b, 0);
+ CryptoDevBackend *b;
+ CryptoDevBackendClient *cc;
+ CryptoDevBackendVhost *vhost_crypto;
+
+ b = vcrypto->cryptodev;
+ if (!b) {
+ return NULL;
+ }
+
+ cc = b->conf.peers.ccs[0];
+ vhost_crypto = cryptodev_get_vhost(cc, b, 0);
+ if (!vhost_crypto) {
+ return NULL;
+ }
+
return &vhost_crypto->dev;
}
diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
index 33ae61c..59ef4fb 100644
--- a/hw/virtio/virtio-iommu.c
+++ b/hw/virtio/virtio-iommu.c
@@ -308,6 +308,7 @@ static void virtio_iommu_detach_endpoint_from_domain(VirtIOIOMMUEndpoint *ep)
if (!ep->domain) {
return;
}
+ trace_virtio_iommu_detach_endpoint_from_domain(domain->id, ep->id);
g_tree_foreach(domain->mappings, virtio_iommu_notify_unmap_cb,
ep->iommu_mr);
QLIST_REMOVE(ep, next);
@@ -467,26 +468,6 @@ static AddressSpace *virtio_iommu_find_add_as(PCIBus *bus, void *opaque,
return &sdev->as;
}
-static void virtio_iommu_device_clear(VirtIOIOMMU *s, PCIBus *bus, int devfn)
-{
- IOMMUPciBus *sbus = g_hash_table_lookup(s->as_by_busptr, bus);
- IOMMUDevice *sdev;
-
- if (!sbus) {
- return;
- }
-
- sdev = sbus->pbdev[devfn];
- if (!sdev) {
- return;
- }
-
- g_list_free_full(sdev->resv_regions, g_free);
- sdev->resv_regions = NULL;
- g_free(sdev);
- sbus->pbdev[devfn] = NULL;
-}
-
static gboolean hiod_equal(gconstpointer v1, gconstpointer v2)
{
const struct hiod_key *key1 = v1;
@@ -558,8 +539,6 @@ static int virtio_iommu_set_host_iova_ranges(VirtIOIOMMU *s, PCIBus *bus,
{
IOMMUPciBus *sbus = g_hash_table_lookup(s->as_by_busptr, bus);
IOMMUDevice *sdev;
- GList *current_ranges;
- GList *l, *tmp, *new_ranges = NULL;
int ret = -EINVAL;
if (!sbus) {
@@ -573,35 +552,10 @@ static int virtio_iommu_set_host_iova_ranges(VirtIOIOMMU *s, PCIBus *bus,
return ret;
}
- current_ranges = sdev->host_resv_ranges;
-
- g_assert(!sdev->probe_done);
-
- /* check that each new resv region is included in an existing one */
if (sdev->host_resv_ranges) {
- range_inverse_array(iova_ranges,
- &new_ranges,
- 0, UINT64_MAX);
-
- for (tmp = new_ranges; tmp; tmp = tmp->next) {
- Range *newr = (Range *)tmp->data;
- bool included = false;
-
- for (l = current_ranges; l; l = l->next) {
- Range * r = (Range *)l->data;
-
- if (range_contains_range(r, newr)) {
- included = true;
- break;
- }
- }
- if (!included) {
- goto error;
- }
- }
- /* all new reserved ranges are included in existing ones */
- ret = 0;
- goto out;
+ error_setg(errp, "%s virtio-iommu does not support aliased BDF",
+ __func__);
+ return ret;
}
range_inverse_array(iova_ranges,
@@ -610,14 +564,31 @@ static int virtio_iommu_set_host_iova_ranges(VirtIOIOMMU *s, PCIBus *bus,
rebuild_resv_regions(sdev);
return 0;
-error:
- error_setg(errp, "%s Conflicting host reserved ranges set!",
- __func__);
-out:
- g_list_free_full(new_ranges, g_free);
- return ret;
}
+static void virtio_iommu_unset_host_iova_ranges(VirtIOIOMMU *s, PCIBus *bus,
+ int devfn)
+{
+ IOMMUPciBus *sbus = g_hash_table_lookup(s->as_by_busptr, bus);
+ IOMMUDevice *sdev;
+
+ if (!sbus) {
+ return;
+ }
+
+ sdev = sbus->pbdev[devfn];
+ if (!sdev) {
+ return;
+ }
+
+ g_list_free_full(g_steal_pointer(&sdev->host_resv_ranges), g_free);
+ g_list_free_full(sdev->resv_regions, g_free);
+ sdev->host_resv_ranges = NULL;
+ sdev->resv_regions = NULL;
+ add_prop_resv_regions(sdev);
+}
+
+
static bool check_page_size_mask(VirtIOIOMMU *viommu, uint64_t new_mask,
Error **errp)
{
@@ -726,9 +697,10 @@ virtio_iommu_unset_iommu_device(PCIBus *bus, void *opaque, int devfn)
if (!hiod) {
return;
}
+ virtio_iommu_unset_host_iova_ranges(viommu, hiod->aliased_bus,
+ hiod->aliased_devfn);
g_hash_table_remove(viommu->host_iommu_devices, &key);
- virtio_iommu_device_clear(viommu, bus, devfn);
}
static const PCIIOMMUOps virtio_iommu_ops = {
@@ -815,6 +787,7 @@ static int virtio_iommu_detach(VirtIOIOMMU *s,
if (QLIST_EMPTY(&domain->endpoint_list)) {
g_tree_remove(s->domains, GUINT_TO_POINTER(domain->id));
}
+ g_tree_remove(s->endpoints, GUINT_TO_POINTER(ep_id));
return VIRTIO_IOMMU_S_OK;
}
@@ -977,7 +950,6 @@ static int virtio_iommu_probe(VirtIOIOMMU *s,
}
buf += count;
free -= count;
- sdev->probe_done = true;
return VIRTIO_IOMMU_S_OK;
}
diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c
index ef64bf1..ae1e81d 100644
--- a/hw/virtio/virtio-mem.c
+++ b/hw/virtio/virtio-mem.c
@@ -88,6 +88,7 @@ static uint32_t virtio_mem_default_thp_size(void)
static uint32_t thp_size;
#define HPAGE_PMD_SIZE_PATH "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size"
+#define HPAGE_PATH "/sys/kernel/mm/transparent_hugepage/"
static uint32_t virtio_mem_thp_size(void)
{
gchar *content = NULL;
@@ -98,6 +99,12 @@ static uint32_t virtio_mem_thp_size(void)
return thp_size;
}
+ /* No THP -> no restrictions. */
+ if (!g_file_test(HPAGE_PATH, G_FILE_TEST_EXISTS)) {
+ thp_size = VIRTIO_MEM_MIN_BLOCK_SIZE;
+ return thp_size;
+ }
+
/*
* Try to probe the actual THP size, fallback to (sane but eventually
* incorrect) default sizes.
@@ -883,6 +890,9 @@ static uint64_t virtio_mem_get_features(VirtIODevice *vdev, uint64_t features,
if (vmem->unplugged_inaccessible == ON_OFF_AUTO_ON) {
virtio_add_feature(&features, VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE);
}
+ if (qemu_wakeup_suspend_enabled()) {
+ virtio_add_feature(&features, VIRTIO_MEM_F_PERSISTENT_SUSPEND);
+ }
return features;
}
@@ -895,18 +905,6 @@ static int virtio_mem_validate_features(VirtIODevice *vdev)
return 0;
}
-static void virtio_mem_system_reset(void *opaque)
-{
- VirtIOMEM *vmem = VIRTIO_MEM(opaque);
-
- /*
- * During usual resets, we will unplug all memory and shrink the usable
- * region size. This is, however, not possible in all scenarios. Then,
- * the guest has to deal with this manually (VIRTIO_MEM_REQ_UNPLUG_ALL).
- */
- virtio_mem_unplug_all(vmem);
-}
-
static void virtio_mem_prepare_mr(VirtIOMEM *vmem)
{
const uint64_t region_size = memory_region_size(&vmem->memdev->mr);
@@ -1123,7 +1121,7 @@ static void virtio_mem_device_realize(DeviceState *dev, Error **errp)
vmstate_register_any(VMSTATE_IF(vmem),
&vmstate_virtio_mem_device_early, vmem);
}
- qemu_register_reset(virtio_mem_system_reset, vmem);
+ qemu_register_resettable(OBJECT(vmem));
/*
* Set ourselves as RamDiscardManager before the plug handler maps the
@@ -1143,7 +1141,7 @@ static void virtio_mem_device_unrealize(DeviceState *dev)
* found via an address space anymore. Unset ourselves.
*/
memory_region_set_ram_discard_manager(&vmem->memdev->mr, NULL);
- qemu_unregister_reset(virtio_mem_system_reset, vmem);
+ qemu_unregister_resettable(OBJECT(vmem));
if (vmem->early_migration) {
vmstate_unregister(VMSTATE_IF(vmem), &vmstate_virtio_mem_device_early,
vmem);
@@ -1843,12 +1841,38 @@ static void virtio_mem_unplug_request_check(VirtIOMEM *vmem, Error **errp)
}
}
+static ResettableState *virtio_mem_get_reset_state(Object *obj)
+{
+ VirtIOMEM *vmem = VIRTIO_MEM(obj);
+ return &vmem->reset_state;
+}
+
+static void virtio_mem_system_reset_hold(Object *obj, ResetType type)
+{
+ VirtIOMEM *vmem = VIRTIO_MEM(obj);
+
+ /*
+ * When waking up from standby/suspend-to-ram, do not unplug any memory.
+ */
+ if (type == RESET_TYPE_WAKEUP) {
+ return;
+ }
+
+ /*
+ * During usual resets, we will unplug all memory and shrink the usable
+ * region size. This is, however, not possible in all scenarios. Then,
+ * the guest has to deal with this manually (VIRTIO_MEM_REQ_UNPLUG_ALL).
+ */
+ virtio_mem_unplug_all(vmem);
+}
+
static void virtio_mem_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
VirtIOMEMClass *vmc = VIRTIO_MEM_CLASS(klass);
RamDiscardManagerClass *rdmc = RAM_DISCARD_MANAGER_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
device_class_set_props(dc, virtio_mem_properties);
dc->vmsd = &vmstate_virtio_mem;
@@ -1875,6 +1899,9 @@ static void virtio_mem_class_init(ObjectClass *klass, void *data)
rdmc->replay_discarded = virtio_mem_rdm_replay_discarded;
rdmc->register_listener = virtio_mem_rdm_register_listener;
rdmc->unregister_listener = virtio_mem_rdm_unregister_listener;
+
+ rc->get_state = virtio_mem_get_reset_state;
+ rc->phases.hold = virtio_mem_system_reset_hold;
}
static const TypeInfo virtio_mem_info = {
diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c
index 320428a..e3366fe 100644
--- a/hw/virtio/virtio-mmio.c
+++ b/hw/virtio/virtio-mmio.c
@@ -790,7 +790,7 @@ static void virtio_mmio_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = virtio_mmio_realizefn;
- dc->reset = virtio_mmio_reset;
+ device_class_set_legacy_reset(dc, virtio_mmio_reset);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
device_class_set_props(dc, virtio_mmio_properties);
}
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 9534730..4d832fe 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -615,8 +615,12 @@ static MemoryRegion *virtio_address_space_lookup(VirtIOPCIProxy *proxy,
reg = &proxy->regs[i];
if (*off >= reg->offset &&
*off + len <= reg->offset + reg->size) {
- *off -= reg->offset;
- return &reg->mr;
+ MemoryRegionSection mrs = memory_region_find(&reg->mr,
+ *off - reg->offset, len);
+ assert(mrs.mr);
+ *off = mrs.offset_within_region;
+ memory_region_unref(mrs.mr);
+ return mrs.mr;
}
}
@@ -866,6 +870,9 @@ static int virtio_pci_get_notifier(VirtIOPCIProxy *proxy, int queue_no,
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
VirtQueue *vq;
+ if (!proxy->vector_irqfd && vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)
+ return -1;
+
if (queue_no == VIRTIO_CONFIG_IRQ_IDX) {
*n = virtio_config_get_guest_notifier(vdev);
*vector = vdev->config_vector;
diff --git a/hw/virtio/virtio-qmp.c b/hw/virtio/virtio-qmp.c
index 1dd96ed..cccc6fe 100644
--- a/hw/virtio/virtio-qmp.c
+++ b/hw/virtio/virtio-qmp.c
@@ -450,6 +450,9 @@ static const qmp_virtio_feature_map_t virtio_mem_feature_map[] = {
FEATURE_ENTRY(VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE, \
"VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE: Unplugged memory cannot be "
"accessed"),
+ FEATURE_ENTRY(VIRTIO_MEM_F_PERSISTENT_SUSPEND, \
+ "VIRTIO_MEM_F_PERSISTENT_SUSPND: Plugged memory will remain "
+ "plugged when suspending+resuming"),
{ -1, "" }
};
#endif
diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c
index f74efff..7cf31da 100644
--- a/hw/virtio/virtio-rng.c
+++ b/hw/virtio/virtio-rng.c
@@ -184,8 +184,9 @@ static void virtio_rng_device_realize(DeviceState *dev, Error **errp)
/* Workaround: Property parsing does not enforce unsigned integers,
* So this is a hack to reject such numbers. */
- if (vrng->conf.max_bytes > INT64_MAX) {
- error_setg(errp, "'max-bytes' parameter must be non-negative, "
+ if (vrng->conf.max_bytes == 0 ||
+ vrng->conf.max_bytes > INT64_MAX) {
+ error_setg(errp, "'max-bytes' parameter must be positive, "
"and less than 2^63");
return;
}
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 583a224..a26f189 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -744,6 +744,60 @@ int virtio_queue_empty(VirtQueue *vq)
}
}
+static bool virtio_queue_split_poll(VirtQueue *vq, unsigned shadow_idx)
+{
+ if (unlikely(!vq->vring.avail)) {
+ return false;
+ }
+
+ return (uint16_t)shadow_idx != vring_avail_idx(vq);
+}
+
+static bool virtio_queue_packed_poll(VirtQueue *vq, unsigned shadow_idx)
+{
+ VRingPackedDesc desc;
+ VRingMemoryRegionCaches *caches;
+
+ if (unlikely(!vq->vring.desc)) {
+ return false;
+ }
+
+ caches = vring_get_region_caches(vq);
+ if (!caches) {
+ return false;
+ }
+
+ vring_packed_desc_read(vq->vdev, &desc, &caches->desc,
+ shadow_idx, true);
+
+ return is_desc_avail(desc.flags, vq->shadow_avail_wrap_counter);
+}
+
+static bool virtio_queue_poll(VirtQueue *vq, unsigned shadow_idx)
+{
+ if (virtio_device_disabled(vq->vdev)) {
+ return false;
+ }
+
+ if (virtio_vdev_has_feature(vq->vdev, VIRTIO_F_RING_PACKED)) {
+ return virtio_queue_packed_poll(vq, shadow_idx);
+ } else {
+ return virtio_queue_split_poll(vq, shadow_idx);
+ }
+}
+
+bool virtio_queue_enable_notification_and_check(VirtQueue *vq,
+ int opaque)
+{
+ virtio_queue_set_notification(vq, 1);
+
+ if (opaque >= 0) {
+ return virtio_queue_poll(vq, (unsigned)opaque);
+ } else {
+ return false;
+ }
+}
+
static void virtqueue_unmap_sg(VirtQueue *vq, const VirtQueueElement *elem,
unsigned int len)
{
@@ -872,6 +926,46 @@ static void virtqueue_packed_fill(VirtQueue *vq, const VirtQueueElement *elem,
vq->used_elems[idx].ndescs = elem->ndescs;
}
+static void virtqueue_ordered_fill(VirtQueue *vq, const VirtQueueElement *elem,
+ unsigned int len)
+{
+ unsigned int i, steps, max_steps;
+
+ i = vq->used_idx % vq->vring.num;
+ steps = 0;
+ /*
+ * We shouldn't need to increase 'i' by more than the distance
+ * between used_idx and last_avail_idx.
+ */
+ max_steps = (vq->last_avail_idx - vq->used_idx) % vq->vring.num;
+
+ /* Search for element in vq->used_elems */
+ while (steps <= max_steps) {
+ /* Found element, set length and mark as filled */
+ if (vq->used_elems[i].index == elem->index) {
+ vq->used_elems[i].len = len;
+ vq->used_elems[i].in_order_filled = true;
+ break;
+ }
+
+ i += vq->used_elems[i].ndescs;
+ steps += vq->used_elems[i].ndescs;
+
+ if (i >= vq->vring.num) {
+ i -= vq->vring.num;
+ }
+ }
+
+ /*
+ * We should be able to find a matching VirtQueueElement in
+ * used_elems. If we don't, this is an error.
+ */
+ if (steps >= max_steps) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: %s cannot fill buffer id %u\n",
+ __func__, vq->vdev->name, elem->index);
+ }
+}
+
static void virtqueue_packed_fill_desc(VirtQueue *vq,
const VirtQueueElement *elem,
unsigned int idx,
@@ -922,7 +1016,9 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
return;
}
- if (virtio_vdev_has_feature(vq->vdev, VIRTIO_F_RING_PACKED)) {
+ if (virtio_vdev_has_feature(vq->vdev, VIRTIO_F_IN_ORDER)) {
+ virtqueue_ordered_fill(vq, elem, len);
+ } else if (virtio_vdev_has_feature(vq->vdev, VIRTIO_F_RING_PACKED)) {
virtqueue_packed_fill(vq, elem, len, idx);
} else {
virtqueue_split_fill(vq, elem, len, idx);
@@ -981,6 +1077,73 @@ static void virtqueue_packed_flush(VirtQueue *vq, unsigned int count)
}
}
+static void virtqueue_ordered_flush(VirtQueue *vq)
+{
+ unsigned int i = vq->used_idx % vq->vring.num;
+ unsigned int ndescs = 0;
+ uint16_t old = vq->used_idx;
+ uint16_t new;
+ bool packed;
+ VRingUsedElem uelem;
+
+ packed = virtio_vdev_has_feature(vq->vdev, VIRTIO_F_RING_PACKED);
+
+ if (packed) {
+ if (unlikely(!vq->vring.desc)) {
+ return;
+ }
+ } else if (unlikely(!vq->vring.used)) {
+ return;
+ }
+
+ /* First expected in-order element isn't ready, nothing to do */
+ if (!vq->used_elems[i].in_order_filled) {
+ return;
+ }
+
+ /* Search for filled elements in-order */
+ while (vq->used_elems[i].in_order_filled) {
+ /*
+ * First entry for packed VQs is written last so the guest
+ * doesn't see invalid descriptors.
+ */
+ if (packed && i != vq->used_idx) {
+ virtqueue_packed_fill_desc(vq, &vq->used_elems[i], ndescs, false);
+ } else if (!packed) {
+ uelem.id = vq->used_elems[i].index;
+ uelem.len = vq->used_elems[i].len;
+ vring_used_write(vq, &uelem, i);
+ }
+
+ vq->used_elems[i].in_order_filled = false;
+ ndescs += vq->used_elems[i].ndescs;
+ i += vq->used_elems[i].ndescs;
+ if (i >= vq->vring.num) {
+ i -= vq->vring.num;
+ }
+ }
+
+ if (packed) {
+ virtqueue_packed_fill_desc(vq, &vq->used_elems[vq->used_idx], 0, true);
+ vq->used_idx += ndescs;
+ if (vq->used_idx >= vq->vring.num) {
+ vq->used_idx -= vq->vring.num;
+ vq->used_wrap_counter ^= 1;
+ vq->signalled_used_valid = false;
+ }
+ } else {
+ /* Make sure buffer is written before we update index. */
+ smp_wmb();
+ new = old + ndescs;
+ vring_used_idx_set(vq, new);
+ if (unlikely((int16_t)(new - vq->signalled_used) <
+ (uint16_t)(new - old))) {
+ vq->signalled_used_valid = false;
+ }
+ }
+ vq->inuse -= ndescs;
+}
+
void virtqueue_flush(VirtQueue *vq, unsigned int count)
{
if (virtio_device_disabled(vq->vdev)) {
@@ -988,7 +1151,9 @@ void virtqueue_flush(VirtQueue *vq, unsigned int count)
return;
}
- if (virtio_vdev_has_feature(vq->vdev, VIRTIO_F_RING_PACKED)) {
+ if (virtio_vdev_has_feature(vq->vdev, VIRTIO_F_IN_ORDER)) {
+ virtqueue_ordered_flush(vq);
+ } else if (virtio_vdev_has_feature(vq->vdev, VIRTIO_F_RING_PACKED)) {
virtqueue_packed_flush(vq, count);
} else {
virtqueue_split_flush(vq, count);
@@ -1331,9 +1496,9 @@ err:
goto done;
}
-void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
- unsigned int *out_bytes,
- unsigned max_in_bytes, unsigned max_out_bytes)
+int virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
+ unsigned int *out_bytes, unsigned max_in_bytes,
+ unsigned max_out_bytes)
{
uint16_t desc_size;
VRingMemoryRegionCaches *caches;
@@ -1366,7 +1531,7 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
caches);
}
- return;
+ return (int)vq->shadow_avail_idx;
err:
if (in_bytes) {
*in_bytes = 0;
@@ -1374,6 +1539,8 @@ err:
if (out_bytes) {
*out_bytes = 0;
}
+
+ return -1;
}
int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes,
@@ -1505,7 +1672,7 @@ static void *virtqueue_alloc_element(size_t sz, unsigned out_num, unsigned in_nu
static void *virtqueue_split_pop(VirtQueue *vq, size_t sz)
{
- unsigned int i, head, max;
+ unsigned int i, head, max, idx;
VRingMemoryRegionCaches *caches;
MemoryRegionCache indirect_desc_cache;
MemoryRegionCache *desc_cache;
@@ -1629,6 +1796,13 @@ static void *virtqueue_split_pop(VirtQueue *vq, size_t sz)
elem->in_sg[i] = iov[out_num + i];
}
+ if (virtio_vdev_has_feature(vdev, VIRTIO_F_IN_ORDER)) {
+ idx = (vq->last_avail_idx - 1) % vq->vring.num;
+ vq->used_elems[idx].index = elem->index;
+ vq->used_elems[idx].len = elem->len;
+ vq->used_elems[idx].ndescs = elem->ndescs;
+ }
+
vq->inuse++;
trace_virtqueue_pop(vq, elem, elem->in_num, elem->out_num);
@@ -1762,6 +1936,13 @@ static void *virtqueue_packed_pop(VirtQueue *vq, size_t sz)
elem->index = id;
elem->ndescs = (desc_cache == &indirect_desc_cache) ? 1 : elem_entries;
+
+ if (virtio_vdev_has_feature(vdev, VIRTIO_F_IN_ORDER)) {
+ vq->used_elems[vq->last_avail_idx].index = elem->index;
+ vq->used_elems[vq->last_avail_idx].len = elem->len;
+ vq->used_elems[vq->last_avail_idx].ndescs = elem->ndescs;
+ }
+
vq->last_avail_idx += elem->ndescs;
vq->inuse += elem->ndescs;
@@ -2150,8 +2331,12 @@ void virtio_reset(void *opaque)
vdev->device_endian = virtio_default_endian();
}
- if (vdev->vhost_started && k->get_vhost) {
- vhost_reset_device(k->get_vhost(vdev));
+ if (k->get_vhost) {
+ struct vhost_dev *hdev = k->get_vhost(vdev);
+ /* Only reset when vhost back-end is connected */
+ if (hdev && hdev->vhost_ops) {
+ vhost_reset_device(hdev);
+ }
}
if (k->reset) {
@@ -3484,7 +3669,7 @@ static void virtio_queue_packed_update_used_idx(VirtIODevice *vdev, int n)
return;
}
-static void virtio_split_packed_update_used_idx(VirtIODevice *vdev, int n)
+static void virtio_queue_split_update_used_idx(VirtIODevice *vdev, int n)
{
RCU_READ_LOCK_GUARD();
if (vdev->vq[n].vring.desc) {
@@ -3497,7 +3682,7 @@ void virtio_queue_update_used_idx(VirtIODevice *vdev, int n)
if (virtio_vdev_has_feature(vdev, VIRTIO_F_RING_PACKED)) {
return virtio_queue_packed_update_used_idx(vdev, n);
} else {
- return virtio_split_packed_update_used_idx(vdev, n);
+ return virtio_queue_split_update_used_idx(vdev, n);
}
}
diff --git a/hw/watchdog/cmsdk-apb-watchdog.c b/hw/watchdog/cmsdk-apb-watchdog.c
index 3091e5c..7ad46f9 100644
--- a/hw/watchdog/cmsdk-apb-watchdog.c
+++ b/hw/watchdog/cmsdk-apb-watchdog.c
@@ -380,7 +380,7 @@ static void cmsdk_apb_watchdog_class_init(ObjectClass *klass, void *data)
dc->realize = cmsdk_apb_watchdog_realize;
dc->vmsd = &cmsdk_apb_watchdog_vmstate;
- dc->reset = cmsdk_apb_watchdog_reset;
+ device_class_set_legacy_reset(dc, cmsdk_apb_watchdog_reset);
}
static const TypeInfo cmsdk_apb_watchdog_info = {
diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c
index d437535..80f9b36 100644
--- a/hw/watchdog/sbsa_gwdt.c
+++ b/hw/watchdog/sbsa_gwdt.c
@@ -278,7 +278,7 @@ static void wdt_sbsa_gwdt_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = wdt_sbsa_gwdt_realize;
- dc->reset = wdt_sbsa_gwdt_reset;
+ device_class_set_legacy_reset(dc, wdt_sbsa_gwdt_reset);
dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_WATCHDOG, dc->categories);
dc->vmsd = &vmstate_sbsa_gwdt;
diff --git a/hw/watchdog/watchdog.c b/hw/watchdog/watchdog.c
index 9550461..d0ce3c4 100644
--- a/hw/watchdog/watchdog.c
+++ b/hw/watchdog/watchdog.c
@@ -85,7 +85,7 @@ void watchdog_perform_action(void)
break;
default:
- assert(0);
+ g_assert_not_reached();
}
}
diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c
index 75685c5..39c3f36 100644
--- a/hw/watchdog/wdt_aspeed.c
+++ b/hw/watchdog/wdt_aspeed.c
@@ -300,7 +300,7 @@ static void aspeed_wdt_class_init(ObjectClass *klass, void *data)
dc->desc = "ASPEED Watchdog Controller";
dc->realize = aspeed_wdt_realize;
- dc->reset = aspeed_wdt_reset;
+ device_class_set_legacy_reset(dc, aspeed_wdt_reset);
set_bit(DEVICE_CATEGORY_WATCHDOG, dc->categories);
dc->vmsd = &vmstate_aspeed_wdt;
device_class_set_props(dc, aspeed_wdt_properties);
diff --git a/hw/watchdog/wdt_diag288.c b/hw/watchdog/wdt_diag288.c
index 1b73b16..040d20f 100644
--- a/hw/watchdog/wdt_diag288.c
+++ b/hw/watchdog/wdt_diag288.c
@@ -115,7 +115,7 @@ static void wdt_diag288_class_init(ObjectClass *klass, void *data)
dc->realize = wdt_diag288_realize;
dc->unrealize = wdt_diag288_unrealize;
- dc->reset = wdt_diag288_reset;
+ device_class_set_legacy_reset(dc, wdt_diag288_reset);
dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_WATCHDOG, dc->categories);
dc->vmsd = &vmstate_diag288;
diff --git a/hw/watchdog/wdt_i6300esb.c b/hw/watchdog/wdt_i6300esb.c
index 8bce050..9427abf 100644
--- a/hw/watchdog/wdt_i6300esb.c
+++ b/hw/watchdog/wdt_i6300esb.c
@@ -469,7 +469,7 @@ static void i6300esb_class_init(ObjectClass *klass, void *data)
k->vendor_id = PCI_VENDOR_ID_INTEL;
k->device_id = PCI_DEVICE_ID_INTEL_ESB_9;
k->class_id = PCI_CLASS_SYSTEM_OTHER;
- dc->reset = i6300esb_reset;
+ device_class_set_legacy_reset(dc, i6300esb_reset);
dc->vmsd = &vmstate_i6300esb;
set_bit(DEVICE_CATEGORY_WATCHDOG, dc->categories);
dc->desc = "Intel 6300ESB";
diff --git a/hw/watchdog/wdt_ib700.c b/hw/watchdog/wdt_ib700.c
index eea8da6..17c8289 100644
--- a/hw/watchdog/wdt_ib700.c
+++ b/hw/watchdog/wdt_ib700.c
@@ -133,7 +133,7 @@ static void wdt_ib700_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = wdt_ib700_realize;
- dc->reset = wdt_ib700_reset;
+ device_class_set_legacy_reset(dc, wdt_ib700_reset);
dc->vmsd = &vmstate_ib700;
set_bit(DEVICE_CATEGORY_WATCHDOG, dc->categories);
dc->desc = "iBASE 700";
diff --git a/hw/watchdog/wdt_imx2.c b/hw/watchdog/wdt_imx2.c
index 6452fc4..be63d42 100644
--- a/hw/watchdog/wdt_imx2.c
+++ b/hw/watchdog/wdt_imx2.c
@@ -294,7 +294,7 @@ static void imx2_wdt_class_init(ObjectClass *klass, void *data)
device_class_set_props(dc, imx2_wdt_properties);
dc->realize = imx2_wdt_realize;
- dc->reset = imx2_wdt_reset;
+ device_class_set_legacy_reset(dc, imx2_wdt_reset);
dc->vmsd = &vmstate_imx2_wdt;
dc->desc = "i.MX2 watchdog timer";
set_bit(DEVICE_CATEGORY_WATCHDOG, dc->categories);
diff --git a/hw/xen/meson.build b/hw/xen/meson.build
index d887fa9..4a486e3 100644
--- a/hw/xen/meson.build
+++ b/hw/xen/meson.build
@@ -15,6 +15,7 @@ xen_specific_ss = ss.source_set()
xen_specific_ss.add(files(
'xen-mapcache.c',
'xen-hvm-common.c',
+ 'xen-pvh-common.c',
))
if have_xen_pci_passthrough
xen_specific_ss.add(files(
diff --git a/hw/xen/trace-events b/hw/xen/trace-events
index d1b27f6..a07fe41 100644
--- a/hw/xen/trace-events
+++ b/hw/xen/trace-events
@@ -64,6 +64,10 @@ destroy_hvm_domain_cannot_acquire_handle(void) "Cannot acquire xenctrl handle"
destroy_hvm_domain_failed_action(const char *action, int sts, char *errno_s) "xc_domain_shutdown failed to issue %s, sts %d, %s"
destroy_hvm_domain_action(int xen_domid, const char *action) "Issued domain %d %s"
+# xen-pvh-common.c
+xen_create_virtio_mmio_devices(int i, int irq, uint64_t base) "Created virtio-mmio device %d: irq %d base 0x%"PRIx64
+xen_enable_tpm(uint64_t addr) "Connected tpmdev at address 0x%"PRIx64
+
# xen-mapcache.c
xen_map_cache(uint64_t phys_addr) "want 0x%"PRIx64
xen_remap_bucket(uint64_t index) "index 0x%"PRIx64
diff --git a/hw/xen/xen-hvm-common.c b/hw/xen/xen-hvm-common.c
index 3a9d6f9..7ffbbfe 100644
--- a/hw/xen/xen-hvm-common.c
+++ b/hw/xen/xen-hvm-common.c
@@ -667,6 +667,8 @@ static int xen_map_ioreq_server(XenIOState *state)
xen_pfn_t ioreq_pfn;
xen_pfn_t bufioreq_pfn;
evtchn_port_t bufioreq_evtchn;
+ unsigned long num_frames = 1;
+ unsigned long frame = 1;
int rc;
/*
@@ -675,65 +677,85 @@ 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);
+
+ if (state->has_bufioreq) {
+ frame = 0;
+ num_frames = 2;
+ }
state->fres = xenforeignmemory_map_resource(xen_fmem, xen_domid,
XENMEM_resource_ioreq_server,
- state->ioservid, 0, 2,
+ state->ioservid,
+ frame, num_frames,
&addr,
PROT_READ | PROT_WRITE, 0);
if (state->fres != NULL) {
trace_xen_map_resource_ioreq(state->ioservid, addr);
- state->buffered_io_page = addr;
- state->shared_page = addr + XC_PAGE_SIZE;
+ state->shared_page = addr;
+ if (state->has_bufioreq) {
+ state->buffered_io_page = addr;
+ state->shared_page = addr + XC_PAGE_SIZE;
+ }
} else if (errno != EOPNOTSUPP) {
error_report("failed to map ioreq server resources: error %d handle=%p",
errno, xen_xc);
return -1;
}
- rc = xen_get_ioreq_server_info(xen_domid, state->ioservid,
- (state->shared_page == NULL) ?
- &ioreq_pfn : NULL,
- (state->buffered_io_page == NULL) ?
- &bufioreq_pfn : NULL,
- &bufioreq_evtchn);
- if (rc < 0) {
- error_report("failed to get ioreq server info: error %d handle=%p",
- errno, xen_xc);
- return rc;
- }
+ /*
+ * If we fail to map the shared page with xenforeignmemory_map_resource()
+ * or if we're using buffered ioreqs, we need xen_get_ioreq_server_info()
+ * to provide the the addresses to map the shared page and/or to get the
+ * event-channel port for buffered ioreqs.
+ */
+ if (state->shared_page == NULL || state->has_bufioreq) {
+ rc = xen_get_ioreq_server_info(xen_domid, state->ioservid,
+ (state->shared_page == NULL) ?
+ &ioreq_pfn : NULL,
+ (state->has_bufioreq &&
+ state->buffered_io_page == NULL) ?
+ &bufioreq_pfn : NULL,
+ &bufioreq_evtchn);
+ if (rc < 0) {
+ error_report("failed to get ioreq server info: error %d handle=%p",
+ errno, xen_xc);
+ return rc;
+ }
- if (state->shared_page == NULL) {
- trace_xen_map_ioreq_server_shared_page(ioreq_pfn);
+ if (state->shared_page == NULL) {
+ trace_xen_map_ioreq_server_shared_page(ioreq_pfn);
- state->shared_page = xenforeignmemory_map(xen_fmem, xen_domid,
- PROT_READ | PROT_WRITE,
- 1, &ioreq_pfn, NULL);
+ state->shared_page = xenforeignmemory_map(xen_fmem, xen_domid,
+ PROT_READ | PROT_WRITE,
+ 1, &ioreq_pfn, NULL);
+ }
if (state->shared_page == NULL) {
error_report("map shared IO page returned error %d handle=%p",
errno, xen_xc);
}
- }
- if (state->buffered_io_page == NULL) {
- trace_xen_map_ioreq_server_buffered_io_page(bufioreq_pfn);
+ if (state->has_bufioreq && state->buffered_io_page == NULL) {
+ trace_xen_map_ioreq_server_buffered_io_page(bufioreq_pfn);
- state->buffered_io_page = xenforeignmemory_map(xen_fmem, xen_domid,
- PROT_READ | PROT_WRITE,
- 1, &bufioreq_pfn,
- NULL);
- if (state->buffered_io_page == NULL) {
- error_report("map buffered IO page returned error %d", errno);
- return -1;
+ state->buffered_io_page = xenforeignmemory_map(xen_fmem, xen_domid,
+ PROT_READ | PROT_WRITE,
+ 1, &bufioreq_pfn,
+ NULL);
+ if (state->buffered_io_page == NULL) {
+ error_report("map buffered IO page returned error %d", errno);
+ return -1;
+ }
}
}
- if (state->shared_page == NULL || state->buffered_io_page == NULL) {
+ if (state->shared_page == NULL ||
+ (state->has_bufioreq && state->buffered_io_page == NULL)) {
return -1;
}
- trace_xen_map_ioreq_server_buffered_io_evtchn(bufioreq_evtchn);
-
- state->bufioreq_remote_port = bufioreq_evtchn;
+ if (state->has_bufioreq) {
+ trace_xen_map_ioreq_server_buffered_io_evtchn(bufioreq_evtchn);
+ state->bufioreq_remote_port = bufioreq_evtchn;
+ }
return 0;
}
@@ -830,14 +852,15 @@ static void xen_do_ioreq_register(XenIOState *state,
state->ioreq_local_port[i] = rc;
}
- rc = qemu_xen_evtchn_bind_interdomain(state->xce_handle, xen_domid,
- state->bufioreq_remote_port);
- if (rc == -1) {
- error_report("buffered evtchn bind error %d", errno);
- goto err;
+ if (state->has_bufioreq) {
+ rc = qemu_xen_evtchn_bind_interdomain(state->xce_handle, xen_domid,
+ state->bufioreq_remote_port);
+ if (rc == -1) {
+ error_report("buffered evtchn bind error %d", errno);
+ goto err;
+ }
+ state->bufioreq_local_port = rc;
}
- state->bufioreq_local_port = rc;
-
/* Init RAM management */
#ifdef XEN_COMPAT_PHYSMAP
xen_map_cache_init(xen_phys_offset_to_gaddr, state);
@@ -865,6 +888,7 @@ err:
}
void xen_register_ioreq(XenIOState *state, unsigned int max_cpus,
+ uint8_t handle_bufioreq,
const MemoryListener *xen_memory_listener)
{
int rc;
@@ -883,7 +907,8 @@ void xen_register_ioreq(XenIOState *state, unsigned int max_cpus,
goto err;
}
- rc = xen_create_ioreq_server(xen_domid, &state->ioservid);
+ state->has_bufioreq = handle_bufioreq != HVM_IOREQSRV_BUFIOREQ_OFF;
+ rc = xen_create_ioreq_server(xen_domid, handle_bufioreq, &state->ioservid);
if (!rc) {
xen_do_ioreq_register(state, max_cpus, xen_memory_listener);
} else {
diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c
index 5514184..e8e1ee4 100644
--- a/hw/xen/xen-legacy-backend.c
+++ b/hw/xen/xen-legacy-backend.c
@@ -147,24 +147,6 @@ void xen_be_unmap_grant_refs(struct XenLegacyDevice *xendev, void *ptr,
}
}
-int xen_be_copy_grant_refs(struct XenLegacyDevice *xendev,
- bool to_domain,
- XenGrantCopySegment segs[],
- unsigned int nr_segs)
-{
- int rc;
-
- assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV);
-
- rc = qemu_xen_gnttab_grant_copy(xendev->gnttabdev, to_domain, xen_domid,
- segs, nr_segs, NULL);
- if (rc) {
- xen_pv_printf(xendev, 0, "xengnttab_grant_copy failed: %s\n",
- strerror(-rc));
- }
- return rc;
-}
-
/*
* get xen backend device, allocate a new one if it doesn't exist.
*/
diff --git a/hw/xen/xen-pvh-common.c b/hw/xen/xen-pvh-common.c
new file mode 100644
index 0000000..218ac85
--- /dev/null
+++ b/hw/xen/xen-pvh-common.c
@@ -0,0 +1,400 @@
+/*
+ * QEMU Xen PVH machine - common code.
+ *
+ * Copyright (c) 2024 Advanced Micro Devices, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "qapi/visitor.h"
+#include "hw/boards.h"
+#include "hw/irq.h"
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/tpm.h"
+#include "sysemu/tpm_backend.h"
+#include "hw/xen/xen-pvh-common.h"
+#include "trace.h"
+
+static const MemoryListener xen_memory_listener = {
+ .region_add = xen_region_add,
+ .region_del = xen_region_del,
+ .log_start = NULL,
+ .log_stop = NULL,
+ .log_sync = NULL,
+ .log_global_start = NULL,
+ .log_global_stop = NULL,
+ .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
+};
+
+static void xen_pvh_init_ram(XenPVHMachineState *s,
+ MemoryRegion *sysmem)
+{
+ MachineState *ms = MACHINE(s);
+ ram_addr_t block_len, ram_size[2];
+
+ if (ms->ram_size <= s->cfg.ram_low.size) {
+ ram_size[0] = ms->ram_size;
+ ram_size[1] = 0;
+ block_len = s->cfg.ram_low.base + ram_size[0];
+ } else {
+ ram_size[0] = s->cfg.ram_low.size;
+ ram_size[1] = ms->ram_size - s->cfg.ram_low.size;
+ block_len = s->cfg.ram_high.base + ram_size[1];
+ }
+
+ memory_region_init_ram(&xen_memory, NULL, "xen.ram", block_len,
+ &error_fatal);
+
+ memory_region_init_alias(&s->ram.low, NULL, "xen.ram.lo", &xen_memory,
+ s->cfg.ram_low.base, ram_size[0]);
+ memory_region_add_subregion(sysmem, s->cfg.ram_low.base, &s->ram.low);
+ if (ram_size[1] > 0) {
+ memory_region_init_alias(&s->ram.high, NULL, "xen.ram.hi", &xen_memory,
+ s->cfg.ram_high.base, ram_size[1]);
+ memory_region_add_subregion(sysmem, s->cfg.ram_high.base, &s->ram.high);
+ }
+
+ /* Setup support for grants. */
+ memory_region_init_ram(&xen_grants, NULL, "xen.grants", block_len,
+ &error_fatal);
+ memory_region_add_subregion(sysmem, XEN_GRANT_ADDR_OFF, &xen_grants);
+}
+
+static void xen_set_irq(void *opaque, int irq, int level)
+{
+ if (xendevicemodel_set_irq_level(xen_dmod, xen_domid, irq, level)) {
+ error_report("xendevicemodel_set_irq_level failed");
+ }
+}
+
+static void xen_create_virtio_mmio_devices(XenPVHMachineState *s)
+{
+ int i;
+
+ /*
+ * We create the transports in reverse order. Since qbus_realize()
+ * prepends (not appends) new child buses, the decrementing loop below will
+ * create a list of virtio-mmio buses with increasing base addresses.
+ *
+ * When a -device option is processed from the command line,
+ * qbus_find_recursive() picks the next free virtio-mmio bus in forwards
+ * order.
+ *
+ * This is what the Xen tools expect.
+ */
+ for (i = s->cfg.virtio_mmio_num - 1; i >= 0; i--) {
+ hwaddr base = s->cfg.virtio_mmio.base + i * s->cfg.virtio_mmio.size;
+ qemu_irq irq = qemu_allocate_irq(xen_set_irq, NULL,
+ s->cfg.virtio_mmio_irq_base + i);
+
+ sysbus_create_simple("virtio-mmio", base, irq);
+
+ trace_xen_create_virtio_mmio_devices(i,
+ s->cfg.virtio_mmio_irq_base + i,
+ base);
+ }
+}
+
+#ifdef CONFIG_TPM
+static void xen_enable_tpm(XenPVHMachineState *s)
+{
+ Error *errp = NULL;
+ DeviceState *dev;
+ SysBusDevice *busdev;
+
+ TPMBackend *be = qemu_find_tpm_be("tpm0");
+ if (be == NULL) {
+ error_report("Couldn't find tmp0 backend");
+ return;
+ }
+ dev = qdev_new(TYPE_TPM_TIS_SYSBUS);
+ object_property_set_link(OBJECT(dev), "tpmdev", OBJECT(be), &errp);
+ object_property_set_str(OBJECT(dev), "tpmdev", be->id, &errp);
+ busdev = SYS_BUS_DEVICE(dev);
+ sysbus_realize_and_unref(busdev, &error_fatal);
+ sysbus_mmio_map(busdev, 0, s->cfg.tpm.base);
+
+ trace_xen_enable_tpm(s->cfg.tpm.base);
+}
+#endif
+
+/*
+ * We use the GPEX PCIe controller with its internal INTX PCI interrupt
+ * swizzling. This swizzling is emulated in QEMU and routes all INTX
+ * interrupts from endpoints down to only 4 INTX interrupts.
+ * See include/hw/pci/pci.h : pci_swizzle()
+ */
+static inline void xenpvh_gpex_init(XenPVHMachineState *s,
+ XenPVHMachineClass *xpc,
+ MemoryRegion *sysmem)
+{
+ MemoryRegion *ecam_reg;
+ MemoryRegion *mmio_reg;
+ DeviceState *dev;
+ int i;
+
+ object_initialize_child(OBJECT(s), "gpex", &s->pci.gpex,
+ TYPE_GPEX_HOST);
+ dev = DEVICE(&s->pci.gpex);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
+ ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
+ memory_region_add_subregion(sysmem, s->cfg.pci_ecam.base, ecam_reg);
+
+ mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
+
+ if (s->cfg.pci_mmio.size) {
+ memory_region_init_alias(&s->pci.mmio_alias, OBJECT(dev), "pcie-mmio",
+ mmio_reg,
+ s->cfg.pci_mmio.base, s->cfg.pci_mmio.size);
+ memory_region_add_subregion(sysmem, s->cfg.pci_mmio.base,
+ &s->pci.mmio_alias);
+ }
+
+ if (s->cfg.pci_mmio_high.size) {
+ memory_region_init_alias(&s->pci.mmio_high_alias, OBJECT(dev),
+ "pcie-mmio-high",
+ mmio_reg, s->cfg.pci_mmio_high.base, s->cfg.pci_mmio_high.size);
+ memory_region_add_subregion(sysmem, s->cfg.pci_mmio_high.base,
+ &s->pci.mmio_high_alias);
+ }
+
+ /*
+ * PVH implementations with PCI enabled must provide set_pci_intx_irq()
+ * and optionally an implementation of set_pci_link_route().
+ */
+ assert(xpc->set_pci_intx_irq);
+
+ for (i = 0; i < GPEX_NUM_IRQS; i++) {
+ qemu_irq irq = qemu_allocate_irq(xpc->set_pci_intx_irq, s, i);
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
+ gpex_set_irq_num(GPEX_HOST(dev), i, s->cfg.pci_intx_irq_base + i);
+ if (xpc->set_pci_link_route) {
+ xpc->set_pci_link_route(i, s->cfg.pci_intx_irq_base + i);
+ }
+ }
+}
+
+static void xen_pvh_init(MachineState *ms)
+{
+ XenPVHMachineState *s = XEN_PVH_MACHINE(ms);
+ XenPVHMachineClass *xpc = XEN_PVH_MACHINE_GET_CLASS(s);
+ MemoryRegion *sysmem = get_system_memory();
+
+ if (ms->ram_size == 0) {
+ warn_report("%s: ram size not specified. QEMU machine started"
+ " without IOREQ (no emulated devices including virtio)",
+ MACHINE_CLASS(object_get_class(OBJECT(ms)))->desc);
+ return;
+ }
+
+ xen_pvh_init_ram(s, sysmem);
+ xen_register_ioreq(&s->ioreq, ms->smp.max_cpus,
+ xpc->handle_bufioreq,
+ &xen_memory_listener);
+
+ if (s->cfg.virtio_mmio_num) {
+ xen_create_virtio_mmio_devices(s);
+ }
+
+#ifdef CONFIG_TPM
+ if (xpc->has_tpm) {
+ if (s->cfg.tpm.base) {
+ xen_enable_tpm(s);
+ } else {
+ warn_report("tpm-base-addr is not set. TPM will not be enabled");
+ }
+ }
+#endif
+
+ /* Non-zero pci-ecam-size enables PCI. */
+ if (s->cfg.pci_ecam.size) {
+ if (s->cfg.pci_ecam.size != 256 * MiB) {
+ error_report("pci-ecam-size only supports values 0 or 0x10000000");
+ exit(EXIT_FAILURE);
+ }
+ if (!s->cfg.pci_intx_irq_base) {
+ error_report("PCI enabled but pci-intx-irq-base not set");
+ exit(EXIT_FAILURE);
+ }
+
+ xenpvh_gpex_init(s, xpc, sysmem);
+ }
+
+ /* Call the implementation specific init. */
+ if (xpc->init) {
+ xpc->init(ms);
+ }
+}
+
+#define XEN_PVH_PROP_MEMMAP_SETTER(n, f) \
+static void xen_pvh_set_ ## n ## _ ## f(Object *obj, Visitor *v, \
+ const char *name, void *opaque, \
+ Error **errp) \
+{ \
+ XenPVHMachineState *xp = XEN_PVH_MACHINE(obj); \
+ uint64_t value; \
+ \
+ if (!visit_type_size(v, name, &value, errp)) { \
+ return; \
+ } \
+ xp->cfg.n.f = value; \
+}
+
+#define XEN_PVH_PROP_MEMMAP_GETTER(n, f) \
+static void xen_pvh_get_ ## n ## _ ## f(Object *obj, Visitor *v, \
+ const char *name, void *opaque, \
+ Error **errp) \
+{ \
+ XenPVHMachineState *xp = XEN_PVH_MACHINE(obj); \
+ uint64_t value = xp->cfg.n.f; \
+ \
+ visit_type_uint64(v, name, &value, errp); \
+}
+
+#define XEN_PVH_PROP_MEMMAP_BASE(n) \
+ XEN_PVH_PROP_MEMMAP_SETTER(n, base) \
+ XEN_PVH_PROP_MEMMAP_GETTER(n, base) \
+
+#define XEN_PVH_PROP_MEMMAP_SIZE(n) \
+ XEN_PVH_PROP_MEMMAP_SETTER(n, size) \
+ XEN_PVH_PROP_MEMMAP_GETTER(n, size)
+
+#define XEN_PVH_PROP_MEMMAP(n) \
+ XEN_PVH_PROP_MEMMAP_BASE(n) \
+ XEN_PVH_PROP_MEMMAP_SIZE(n)
+
+XEN_PVH_PROP_MEMMAP(ram_low)
+XEN_PVH_PROP_MEMMAP(ram_high)
+/* TPM only has a base-addr option. */
+XEN_PVH_PROP_MEMMAP_BASE(tpm)
+XEN_PVH_PROP_MEMMAP(virtio_mmio)
+XEN_PVH_PROP_MEMMAP(pci_ecam)
+XEN_PVH_PROP_MEMMAP(pci_mmio)
+XEN_PVH_PROP_MEMMAP(pci_mmio_high)
+
+static void xen_pvh_set_pci_intx_irq_base(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ XenPVHMachineState *xp = XEN_PVH_MACHINE(obj);
+ uint32_t value;
+
+ if (!visit_type_uint32(v, name, &value, errp)) {
+ return;
+ }
+
+ xp->cfg.pci_intx_irq_base = value;
+}
+
+static void xen_pvh_get_pci_intx_irq_base(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ XenPVHMachineState *xp = XEN_PVH_MACHINE(obj);
+ uint32_t value = xp->cfg.pci_intx_irq_base;
+
+ visit_type_uint32(v, name, &value, errp);
+}
+
+void xen_pvh_class_setup_common_props(XenPVHMachineClass *xpc)
+{
+ ObjectClass *oc = OBJECT_CLASS(xpc);
+ MachineClass *mc = MACHINE_CLASS(xpc);
+
+#define OC_MEMMAP_PROP_BASE(c, prop_name, name) \
+do { \
+ object_class_property_add(c, prop_name "-base", "uint64_t", \
+ xen_pvh_get_ ## name ## _base, \
+ xen_pvh_set_ ## name ## _base, NULL, NULL); \
+ object_class_property_set_description(oc, prop_name "-base", \
+ "Set base address for " prop_name); \
+} while (0)
+
+#define OC_MEMMAP_PROP_SIZE(c, prop_name, name) \
+do { \
+ object_class_property_add(c, prop_name "-size", "uint64_t", \
+ xen_pvh_get_ ## name ## _size, \
+ xen_pvh_set_ ## name ## _size, NULL, NULL); \
+ object_class_property_set_description(oc, prop_name "-size", \
+ "Set memory range size for " prop_name); \
+} while (0)
+
+#define OC_MEMMAP_PROP(c, prop_name, name) \
+do { \
+ OC_MEMMAP_PROP_BASE(c, prop_name, name); \
+ OC_MEMMAP_PROP_SIZE(c, prop_name, name); \
+} while (0)
+
+ /*
+ * We provide memmap properties to allow Xen to move things to other
+ * addresses for example when users need to accomodate the memory-map
+ * for 1:1 mapped devices/memory.
+ */
+ OC_MEMMAP_PROP(oc, "ram-low", ram_low);
+ OC_MEMMAP_PROP(oc, "ram-high", ram_high);
+
+ if (xpc->has_virtio_mmio) {
+ OC_MEMMAP_PROP(oc, "virtio-mmio", virtio_mmio);
+ }
+
+ if (xpc->has_pci) {
+ OC_MEMMAP_PROP(oc, "pci-ecam", pci_ecam);
+ OC_MEMMAP_PROP(oc, "pci-mmio", pci_mmio);
+ OC_MEMMAP_PROP(oc, "pci-mmio-high", pci_mmio_high);
+
+ object_class_property_add(oc, "pci-intx-irq-base", "uint32_t",
+ xen_pvh_get_pci_intx_irq_base,
+ xen_pvh_set_pci_intx_irq_base,
+ NULL, NULL);
+ object_class_property_set_description(oc, "pci-intx-irq-base",
+ "Set PCI INTX interrupt base line.");
+ }
+
+#ifdef CONFIG_TPM
+ if (xpc->has_tpm) {
+ object_class_property_add(oc, "tpm-base-addr", "uint64_t",
+ xen_pvh_get_tpm_base,
+ xen_pvh_set_tpm_base,
+ NULL, NULL);
+ object_class_property_set_description(oc, "tpm-base-addr",
+ "Set Base address for TPM device.");
+
+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
+ }
+#endif
+}
+
+static void xen_pvh_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->init = xen_pvh_init;
+
+ mc->desc = "Xen PVH machine";
+ mc->max_cpus = 1;
+ mc->default_machine_opts = "accel=xen";
+ /* Set to zero to make sure that the real ram size is passed. */
+ mc->default_ram_size = 0;
+}
+
+static const TypeInfo xen_pvh_info = {
+ .name = TYPE_XEN_PVH_MACHINE,
+ .parent = TYPE_MACHINE,
+ .abstract = true,
+ .instance_size = sizeof(XenPVHMachineState),
+ .class_size = sizeof(XenPVHMachineClass),
+ .class_init = xen_pvh_class_init,
+};
+
+static void xen_pvh_register_types(void)
+{
+ type_register_static(&xen_pvh_info);
+}
+
+type_init(xen_pvh_register_types);
diff --git a/hw/xen/xen_devconfig.c b/hw/xen/xen_devconfig.c
index 2150869..45ae134 100644
--- a/hw/xen/xen_devconfig.c
+++ b/hw/xen/xen_devconfig.c
@@ -66,11 +66,3 @@ int xen_config_dev_vkbd(int vdev)
xen_config_dev_dirs("vkbd", "vkbd", vdev, fe, be, sizeof(fe));
return xen_config_dev_all(fe, be);
}
-
-int xen_config_dev_console(int vdev)
-{
- char fe[256], be[256];
-
- xen_config_dev_dirs("console", "console", vdev, fe, be, sizeof(fe));
- return xen_config_dev_all(fe, be);
-}
diff --git a/hw/xtensa/Kconfig b/hw/xtensa/Kconfig
index fc5c785..1f0492d 100644
--- a/hw/xtensa/Kconfig
+++ b/hw/xtensa/Kconfig
@@ -18,4 +18,4 @@ config XTENSA_XTFPGA
select DEVICE_TREE
select OPENCORES_ETH
select PFLASH_CFI01
- select SERIAL
+ select SERIAL_MM
diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c
index 955e886..398e625 100644
--- a/hw/xtensa/xtfpga.c
+++ b/hw/xtensa/xtfpga.c
@@ -35,7 +35,7 @@
#include "hw/qdev-properties.h"
#include "elf.h"
#include "exec/memory.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "net/net.h"
#include "hw/sysbus.h"
#include "hw/block/flash.h"
@@ -415,8 +415,7 @@ static void xtfpga_init(const XtfpgaBoardDesc *board, MachineState *machine)
}
}
if (entry_point != env->pc) {
- uint8_t boot[] = {
-#if TARGET_BIG_ENDIAN
+ uint8_t boot_be[] = {
0x60, 0x00, 0x08, /* j 1f */
0x00, /* .literal_position */
0x00, 0x00, 0x00, 0x00, /* .literal entry_pc */
@@ -425,7 +424,8 @@ static void xtfpga_init(const XtfpgaBoardDesc *board, MachineState *machine)
0x10, 0xff, 0xfe, /* l32r a0, entry_pc */
0x12, 0xff, 0xfe, /* l32r a2, entry_a2 */
0x0a, 0x00, 0x00, /* jx a0 */
-#else
+ };
+ uint8_t boot_le[] = {
0x06, 0x02, 0x00, /* j 1f */
0x00, /* .literal_position */
0x00, 0x00, 0x00, 0x00, /* .literal entry_pc */
@@ -434,14 +434,16 @@ static void xtfpga_init(const XtfpgaBoardDesc *board, MachineState *machine)
0x01, 0xfe, 0xff, /* l32r a0, entry_pc */
0x21, 0xfe, 0xff, /* l32r a2, entry_a2 */
0xa0, 0x00, 0x00, /* jx a0 */
-#endif
};
+ const size_t boot_sz = TARGET_BIG_ENDIAN ? sizeof(boot_be)
+ : sizeof(boot_le);
+ uint8_t *boot = TARGET_BIG_ENDIAN ? boot_be : boot_le;
uint32_t entry_pc = tswap32(entry_point);
uint32_t entry_a2 = tswap32(tagptr);
memcpy(boot + 4, &entry_pc, sizeof(entry_pc));
memcpy(boot + 8, &entry_a2, sizeof(entry_a2));
- cpu_physical_memory_write(env->pc, boot, sizeof(boot));
+ cpu_physical_memory_write(env->pc, boot, boot_sz);
}
} else {
if (flash) {
diff --git a/include/block/aio.h b/include/block/aio.h
index 4ee8193..43883a8 100644
--- a/include/block/aio.h
+++ b/include/block/aio.h
@@ -20,6 +20,7 @@
#include "qemu/coroutine-core.h"
#include "qemu/queue.h"
#include "qemu/event_notifier.h"
+#include "qemu/lockcnt.h"
#include "qemu/thread.h"
#include "qemu/timer.h"
#include "block/graph-lock.h"
diff --git a/include/block/aio_task.h b/include/block/aio_task.h
index 18a9c41..c81d637 100644
--- a/include/block/aio_task.h
+++ b/include/block/aio_task.h
@@ -40,8 +40,6 @@ void aio_task_pool_free(AioTaskPool *);
/* error code of failed task or 0 if all is OK */
int aio_task_pool_status(AioTaskPool *pool);
-bool aio_task_pool_empty(AioTaskPool *pool);
-
/* User provides filled @task, however task->pool will be set automatically */
void coroutine_fn aio_task_pool_start_task(AioTaskPool *pool, AioTask *task);
diff --git a/include/block/block-copy.h b/include/block/block-copy.h
index bdc703b..dd5cc82 100644
--- a/include/block/block-copy.h
+++ b/include/block/block-copy.h
@@ -28,6 +28,7 @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
BlockDriverState *copy_bitmap_bs,
const BdrvDirtyBitmap *bitmap,
bool discard_source,
+ uint64_t min_cluster_size,
Error **errp);
/* Function should be called prior any actual copy request */
diff --git a/include/block/graph-lock.h b/include/block/graph-lock.h
index d7545e8..dc8d949 100644
--- a/include/block/graph-lock.h
+++ b/include/block/graph-lock.h
@@ -209,31 +209,38 @@ typedef struct GraphLockable { } GraphLockable;
* unlocked. TSA_ASSERT_SHARED() makes sure that the following calls know that
* we hold the lock while unlocking is left unchecked.
*/
-static inline GraphLockable * TSA_ASSERT_SHARED(graph_lock) TSA_NO_TSA coroutine_fn
+static inline GraphLockable * TSA_ACQUIRE_SHARED(graph_lock) coroutine_fn
graph_lockable_auto_lock(GraphLockable *x)
{
bdrv_graph_co_rdlock();
return x;
}
-static inline void TSA_NO_TSA coroutine_fn
-graph_lockable_auto_unlock(GraphLockable *x)
+static inline void TSA_RELEASE_SHARED(graph_lock) coroutine_fn
+graph_lockable_auto_unlock(GraphLockable **x)
{
bdrv_graph_co_rdunlock();
}
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(GraphLockable, graph_lockable_auto_unlock)
+#define GRAPH_AUTO_UNLOCK __attribute__((cleanup(graph_lockable_auto_unlock)))
+/*
+ * @var is only used to break the loop after the first iteration.
+ * @unlock_var can't be unlocked and then set to NULL because TSA wants the lock
+ * to be held at the start of every iteration of the loop.
+ */
#define WITH_GRAPH_RDLOCK_GUARD_(var) \
- for (g_autoptr(GraphLockable) var = graph_lockable_auto_lock(GML_OBJ_()); \
+ for (GraphLockable *unlock_var GRAPH_AUTO_UNLOCK = \
+ graph_lockable_auto_lock(GML_OBJ_()), \
+ *var = unlock_var; \
var; \
- graph_lockable_auto_unlock(var), var = NULL)
+ var = NULL)
#define WITH_GRAPH_RDLOCK_GUARD() \
WITH_GRAPH_RDLOCK_GUARD_(glue(graph_lockable_auto, __COUNTER__))
#define GRAPH_RDLOCK_GUARD(x) \
- g_autoptr(GraphLockable) \
+ GraphLockable * GRAPH_AUTO_UNLOCK \
glue(graph_lockable_auto, __COUNTER__) G_GNUC_UNUSED = \
graph_lockable_auto_lock(GML_OBJ_())
diff --git a/include/block/nbd.h b/include/block/nbd.h
index 4e7bd63..d4f8b21 100644
--- a/include/block/nbd.h
+++ b/include/block/nbd.h
@@ -33,6 +33,19 @@ typedef struct NBDMetaContexts NBDMetaContexts;
extern const BlockExportDriver blk_exp_nbd;
+/*
+ * NBD_DEFAULT_HANDSHAKE_MAX_SECS: Number of seconds in which client must
+ * succeed at NBD_OPT_GO before being forcefully dropped as too slow.
+ */
+#define NBD_DEFAULT_HANDSHAKE_MAX_SECS 10
+
+/*
+ * NBD_DEFAULT_MAX_CONNECTIONS: Number of client sockets to allow at
+ * once; must be large enough to allow a MULTI_CONN-aware client like
+ * nbdcopy to create its typical number of 8-16 sockets.
+ */
+#define NBD_DEFAULT_MAX_CONNECTIONS 100
+
/* Handshake phase structs - this struct is passed on the wire */
typedef struct NBDOption {
@@ -403,9 +416,12 @@ AioContext *nbd_export_aio_context(NBDExport *exp);
NBDExport *nbd_export_find(const char *name);
void nbd_client_new(QIOChannelSocket *sioc,
+ uint32_t handshake_max_secs,
QCryptoTLSCreds *tlscreds,
const char *tlsauthz,
- void (*close_fn)(NBDClient *, bool));
+ void (*close_fn)(NBDClient *, bool),
+ void *owner);
+void *nbd_client_owner(NBDClient *client);
void nbd_client_get(NBDClient *client);
void nbd_client_put(NBDClient *client);
diff --git a/include/block/nvme.h b/include/block/nvme.h
index 7c77d38..a37be0d 100644
--- a/include/block/nvme.h
+++ b/include/block/nvme.h
@@ -799,6 +799,8 @@ typedef struct QEMU_PACKED NvmeDsmRange {
enum {
NVME_COPY_FORMAT_0 = 0x0,
NVME_COPY_FORMAT_1 = 0x1,
+ NVME_COPY_FORMAT_2 = 0x2,
+ NVME_COPY_FORMAT_3 = 0x3,
};
typedef struct QEMU_PACKED NvmeCopyCmd {
@@ -820,25 +822,30 @@ typedef struct QEMU_PACKED NvmeCopyCmd {
uint16_t appmask;
} NvmeCopyCmd;
-typedef struct QEMU_PACKED NvmeCopySourceRangeFormat0 {
- uint8_t rsvd0[8];
+typedef struct QEMU_PACKED NvmeCopySourceRangeFormat0_2 {
+ uint32_t sparams;
+ uint8_t rsvd4[4];
uint64_t slba;
uint16_t nlb;
- uint8_t rsvd18[6];
+ uint8_t rsvd18[4];
+ uint16_t sopt;
uint32_t reftag;
uint16_t apptag;
uint16_t appmask;
-} NvmeCopySourceRangeFormat0;
+} NvmeCopySourceRangeFormat0_2;
-typedef struct QEMU_PACKED NvmeCopySourceRangeFormat1 {
- uint8_t rsvd0[8];
+typedef struct QEMU_PACKED NvmeCopySourceRangeFormat1_3 {
+ uint32_t sparams;
+ uint8_t rsvd4[4];
uint64_t slba;
uint16_t nlb;
- uint8_t rsvd18[8];
+ uint8_t rsvd18[4];
+ uint16_t sopt;
+ uint8_t rsvd24[2];
uint8_t sr[10];
uint16_t apptag;
uint16_t appmask;
-} NvmeCopySourceRangeFormat1;
+} NvmeCopySourceRangeFormat1_3;
enum NvmeAsyncEventRequest {
NVME_AER_TYPE_ERROR = 0,
@@ -937,6 +944,8 @@ enum NvmeStatusCodes {
NVME_INVALID_PROT_INFO = 0x0181,
NVME_WRITE_TO_RO = 0x0182,
NVME_CMD_SIZE_LIMIT = 0x0183,
+ NVME_CMD_INCOMP_NS_OR_FMT = 0x0185,
+ NVME_CMD_OVERLAP_IO_RANGE = 0x0187,
NVME_INVALID_ZONE_OP = 0x01b6,
NVME_NOZRWA = 0x01b7,
NVME_ZONE_BOUNDARY_ERROR = 0x01b8,
@@ -1173,6 +1182,7 @@ enum NvmeIdCtrlOaes {
enum NvmeIdCtrlCtratt {
NVME_CTRATT_ENDGRPS = 1 << 4,
NVME_CTRATT_ELBAS = 1 << 15,
+ NVME_CTRATT_MEM = 1 << 16,
NVME_CTRATT_FDPS = 1 << 19,
};
@@ -1195,11 +1205,15 @@ enum NvmeIdCtrlOncs {
NVME_ONCS_TIMESTAMP = 1 << 6,
NVME_ONCS_VERIFY = 1 << 7,
NVME_ONCS_COPY = 1 << 8,
+ NVME_ONCS_NVMCSA = 1 << 9,
+ NVME_ONCS_NVMAFC = 1 << 10,
};
enum NvmeIdCtrlOcfs {
NVME_OCFS_COPY_FORMAT_0 = 1 << NVME_COPY_FORMAT_0,
NVME_OCFS_COPY_FORMAT_1 = 1 << NVME_COPY_FORMAT_1,
+ NVME_OCFS_COPY_FORMAT_2 = 1 << NVME_COPY_FORMAT_2,
+ NVME_OCFS_COPY_FORMAT_3 = 1 << NVME_COPY_FORMAT_3,
};
enum NvmeIdctrlVwc {
@@ -1272,6 +1286,8 @@ enum NvmeNsAttachmentOperation {
#define NVME_ERR_REC_TLER(err_rec) (err_rec & 0xffff)
#define NVME_ERR_REC_DULBE(err_rec) (err_rec & 0x10000)
+#define NVME_ID_CTRL_CTRATT_MEM(ctratt) (ctratt & NVME_CTRATT_MEM)
+
enum NvmeFeatureIds {
NVME_ARBITRATION = 0x1,
NVME_POWER_MANAGEMENT = 0x2,
@@ -1333,7 +1349,9 @@ typedef struct NvmeHostBehaviorSupport {
uint8_t acre;
uint8_t etdas;
uint8_t lbafee;
- uint8_t rsvd3[509];
+ uint8_t rsvd3;
+ uint16_t cdfe;
+ uint8_t rsvd6[506];
} NvmeHostBehaviorSupport;
typedef struct QEMU_PACKED NvmeLBAF {
@@ -1833,8 +1851,8 @@ static inline void _nvme_check_size(void)
QEMU_BUILD_BUG_ON(sizeof(NvmeZonedResult) != 8);
QEMU_BUILD_BUG_ON(sizeof(NvmeCqe) != 16);
QEMU_BUILD_BUG_ON(sizeof(NvmeDsmRange) != 16);
- QEMU_BUILD_BUG_ON(sizeof(NvmeCopySourceRangeFormat0) != 32);
- QEMU_BUILD_BUG_ON(sizeof(NvmeCopySourceRangeFormat1) != 40);
+ QEMU_BUILD_BUG_ON(sizeof(NvmeCopySourceRangeFormat0_2) != 32);
+ QEMU_BUILD_BUG_ON(sizeof(NvmeCopySourceRangeFormat1_3) != 40);
QEMU_BUILD_BUG_ON(sizeof(NvmeCmd) != 64);
QEMU_BUILD_BUG_ON(sizeof(NvmeDeleteQ) != 64);
QEMU_BUILD_BUG_ON(sizeof(NvmeCreateCq) != 64);
diff --git a/include/block/ufs.h b/include/block/ufs.h
index 92da7a8..57f5ea3 100644
--- a/include/block/ufs.h
+++ b/include/block/ufs.h
@@ -764,6 +764,12 @@ typedef struct QEMU_PACKED UtpTaskReqDesc {
#define UFS_WB_EXCEED_LIFETIME 0x0B
/*
+ * The range of valid value of Active ICC attritbute
+ * is from 0x00 to 0x0F.
+ */
+#define UFS_QUERY_ATTR_ACTIVE_ICC_MAXVALUE 0x0F
+
+/*
* In UFS Spec, the Extra Header Segment (EHS) starts from byte 32 in UPIU
* request/response packet
*/
diff --git a/include/chardev/char-fe.h b/include/chardev/char-fe.h
index ecef182..8ef05b3 100644
--- a/include/chardev/char-fe.h
+++ b/include/chardev/char-fe.h
@@ -20,7 +20,7 @@ struct CharBackend {
IOReadHandler *chr_read;
BackendChangeHandler *chr_be_change;
void *opaque;
- int tag;
+ unsigned int tag;
bool fe_is_open;
};
@@ -228,6 +228,7 @@ guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
* is thread-safe.
*
* Returns: the number of bytes consumed (0 if no associated Chardev)
+ * or -1 on error.
*/
int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len);
@@ -242,6 +243,7 @@ int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len);
* attempted to be written. This function is thread-safe.
*
* Returns: the number of bytes consumed (0 if no associated Chardev)
+ * or -1 on error.
*/
int qemu_chr_fe_write_all(CharBackend *be, const uint8_t *buf, int len);
@@ -253,6 +255,7 @@ int qemu_chr_fe_write_all(CharBackend *be, const uint8_t *buf, int len);
* Read data to a buffer from the back end.
*
* Returns: the number of bytes read (0 if no associated Chardev)
+ * or -1 on error.
*/
int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len);
diff --git a/include/chardev/char-socket.h b/include/chardev/char-socket.h
index 0708ca6..d6d13ad 100644
--- a/include/chardev/char-socket.h
+++ b/include/chardev/char-socket.h
@@ -74,7 +74,7 @@ struct SocketChardev {
bool is_websock;
GSource *reconnect_timer;
- int64_t reconnect_time;
+ int64_t reconnect_time_ms;
bool connect_err_reported;
QIOTask *connect_task;
diff --git a/include/crypto/afsplit.h b/include/crypto/afsplit.h
index 4894d64..06f28fe 100644
--- a/include/crypto/afsplit.h
+++ b/include/crypto/afsplit.h
@@ -46,7 +46,7 @@
*
* splitkey = g_new0(uint8_t, nkey * stripes);
*
- * if (qcrypto_afsplit_encode(QCRYPTO_HASH_ALG_SHA256,
+ * if (qcrypto_afsplit_encode(QCRYPTO_HASH_ALGO_SHA256,
* nkey, stripes,
* masterkey, splitkey, errp) < 0) {
* g_free(splitkey);
@@ -71,7 +71,7 @@
*
* masterkey = g_new0(uint8_t, nkey);
*
- * if (qcrypto_afsplit_decode(QCRYPTO_HASH_ALG_SHA256,
+ * if (qcrypto_afsplit_decode(QCRYPTO_HASH_ALGO_SHA256,
* nkey, stripes,
* splitkey, masterkey, errp) < 0) {
* g_free(splitkey);
@@ -102,7 +102,7 @@
*
* Returns: 0 on success, -1 on error;
*/
-int qcrypto_afsplit_encode(QCryptoHashAlgorithm hash,
+int qcrypto_afsplit_encode(QCryptoHashAlgo hash,
size_t blocklen,
uint32_t stripes,
const uint8_t *in,
@@ -124,7 +124,7 @@ int qcrypto_afsplit_encode(QCryptoHashAlgorithm hash,
*
* Returns: 0 on success, -1 on error;
*/
-int qcrypto_afsplit_decode(QCryptoHashAlgorithm hash,
+int qcrypto_afsplit_decode(QCryptoHashAlgo hash,
size_t blocklen,
uint32_t stripes,
const uint8_t *in,
diff --git a/include/crypto/block.h b/include/crypto/block.h
index 5b5d039..b013d27 100644
--- a/include/crypto/block.h
+++ b/include/crypto/block.h
@@ -287,7 +287,7 @@ QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block);
*
* Returns: the hash algorithm
*/
-QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block);
+QCryptoHashAlgo qcrypto_block_get_kdf_hash(QCryptoBlock *block);
/**
* qcrypto_block_get_payload_offset:
diff --git a/include/crypto/cipher.h b/include/crypto/cipher.h
index 083e12a..9293931 100644
--- a/include/crypto/cipher.h
+++ b/include/crypto/cipher.h
@@ -26,7 +26,7 @@
typedef struct QCryptoCipher QCryptoCipher;
typedef struct QCryptoCipherDriver QCryptoCipherDriver;
-/* See also "QCryptoCipherAlgorithm" and "QCryptoCipherMode"
+/* See also "QCryptoCipherAlgo" and "QCryptoCipherMode"
* enums defined in qapi/crypto.json */
/**
@@ -50,12 +50,12 @@ typedef struct QCryptoCipherDriver QCryptoCipherDriver;
* size_t keylen = 16;
* uint8_t iv = ....;
*
- * if (!qcrypto_cipher_supports(QCRYPTO_CIPHER_ALG_AES_128)) {
+ * if (!qcrypto_cipher_supports(QCRYPTO_CIPHER_ALGO_AES_128)) {
* error_report(errp, "Feature <blah> requires AES cipher support");
* return -1;
* }
*
- * cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_128,
+ * cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALGO_AES_128,
* QCRYPTO_CIPHER_MODE_CBC,
* key, keylen,
* errp);
@@ -78,7 +78,7 @@ typedef struct QCryptoCipherDriver QCryptoCipherDriver;
*/
struct QCryptoCipher {
- QCryptoCipherAlgorithm alg;
+ QCryptoCipherAlgo alg;
QCryptoCipherMode mode;
const QCryptoCipherDriver *driver;
};
@@ -93,7 +93,7 @@ struct QCryptoCipher {
*
* Returns: true if the algorithm is supported, false otherwise
*/
-bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
+bool qcrypto_cipher_supports(QCryptoCipherAlgo alg,
QCryptoCipherMode mode);
/**
@@ -106,7 +106,7 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
*
* Returns: the block size in bytes
*/
-size_t qcrypto_cipher_get_block_len(QCryptoCipherAlgorithm alg);
+size_t qcrypto_cipher_get_block_len(QCryptoCipherAlgo alg);
/**
@@ -117,7 +117,7 @@ size_t qcrypto_cipher_get_block_len(QCryptoCipherAlgorithm alg);
*
* Returns: the key size in bytes
*/
-size_t qcrypto_cipher_get_key_len(QCryptoCipherAlgorithm alg);
+size_t qcrypto_cipher_get_key_len(QCryptoCipherAlgo alg);
/**
@@ -130,7 +130,7 @@ size_t qcrypto_cipher_get_key_len(QCryptoCipherAlgorithm alg);
*
* Returns: the IV size in bytes, or 0 if no IV is permitted
*/
-size_t qcrypto_cipher_get_iv_len(QCryptoCipherAlgorithm alg,
+size_t qcrypto_cipher_get_iv_len(QCryptoCipherAlgo alg,
QCryptoCipherMode mode);
@@ -156,7 +156,7 @@ size_t qcrypto_cipher_get_iv_len(QCryptoCipherAlgorithm alg,
*
* Returns: a new cipher object, or NULL on error
*/
-QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
+QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgo alg,
QCryptoCipherMode mode,
const uint8_t *key, size_t nkey,
Error **errp);
diff --git a/include/crypto/hash.h b/include/crypto/hash.h
index 54d87aa..712cac7 100644
--- a/include/crypto/hash.h
+++ b/include/crypto/hash.h
@@ -1,6 +1,7 @@
/*
* QEMU Crypto hash algorithms
*
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
* Copyright (c) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
@@ -23,7 +24,22 @@
#include "qapi/qapi-types-crypto.h"
-/* See also "QCryptoHashAlgorithm" defined in qapi/crypto.json */
+#define QCRYPTO_HASH_DIGEST_LEN_MD5 16
+#define QCRYPTO_HASH_DIGEST_LEN_SHA1 20
+#define QCRYPTO_HASH_DIGEST_LEN_SHA224 28
+#define QCRYPTO_HASH_DIGEST_LEN_SHA256 32
+#define QCRYPTO_HASH_DIGEST_LEN_SHA384 48
+#define QCRYPTO_HASH_DIGEST_LEN_SHA512 64
+#define QCRYPTO_HASH_DIGEST_LEN_RIPEMD160 20
+
+/* See also "QCryptoHashAlgo" defined in qapi/crypto.json */
+
+typedef struct QCryptoHash QCryptoHash;
+struct QCryptoHash {
+ QCryptoHashAlgo alg;
+ void *opaque;
+ void *driver;
+};
/**
* qcrypto_hash_supports:
@@ -34,7 +50,7 @@
*
* Returns: true if the algorithm is supported, false otherwise
*/
-gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg);
+gboolean qcrypto_hash_supports(QCryptoHashAlgo alg);
/**
@@ -45,7 +61,7 @@ gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg);
*
* Returns: the digest length in bytes
*/
-size_t qcrypto_hash_digest_len(QCryptoHashAlgorithm alg);
+size_t qcrypto_hash_digest_len(QCryptoHashAlgo alg);
/**
* qcrypto_hash_bytesv:
@@ -57,15 +73,22 @@ size_t qcrypto_hash_digest_len(QCryptoHashAlgorithm alg);
* @errp: pointer to a NULL-initialized error object
*
* Computes the hash across all the memory regions
- * present in @iov. The @result pointer will be
- * filled with raw bytes representing the computed
- * hash, which will have length @resultlen. The
- * memory pointer in @result must be released
- * with a call to g_free() when no longer required.
+ * present in @iov.
+ *
+ * If @result_len is set to a non-zero value by the caller, then
+ * @result must hold a pointer that is @result_len in size, and
+ * @result_len match the size of the hash output. The digest will
+ * be written into @result.
+ *
+ * If @result_len is set to zero, then this function will allocate
+ * a buffer to hold the hash output digest, storing a pointer to
+ * the buffer in @result, and setting @result_len to its size.
+ * The memory referenced in @result must be released with a call
+ * to g_free() when no longer required by the caller.
*
* Returns: 0 on success, -1 on error
*/
-int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg,
+int qcrypto_hash_bytesv(QCryptoHashAlgo alg,
const struct iovec *iov,
size_t niov,
uint8_t **result,
@@ -82,15 +105,22 @@ int qcrypto_hash_bytesv(QCryptoHashAlgorithm alg,
* @errp: pointer to a NULL-initialized error object
*
* Computes the hash across all the memory region
- * @buf of length @len. The @result pointer will be
- * filled with raw bytes representing the computed
- * hash, which will have length @resultlen. The
- * memory pointer in @result must be released
- * with a call to g_free() when no longer required.
+ * @buf of length @len.
+ *
+ * If @result_len is set to a non-zero value by the caller, then
+ * @result must hold a pointer that is @result_len in size, and
+ * @result_len match the size of the hash output. The digest will
+ * be written into @result.
+ *
+ * If @result_len is set to zero, then this function will allocate
+ * a buffer to hold the hash output digest, storing a pointer to
+ * the buffer in @result, and setting @result_len to its size.
+ * The memory referenced in @result must be released with a call
+ * to g_free() when no longer required by the caller.
*
* Returns: 0 on success, -1 on error
*/
-int qcrypto_hash_bytes(QCryptoHashAlgorithm alg,
+int qcrypto_hash_bytes(QCryptoHashAlgo alg,
const char *buf,
size_t len,
uint8_t **result,
@@ -114,13 +144,133 @@ int qcrypto_hash_bytes(QCryptoHashAlgorithm alg,
*
* Returns: 0 on success, -1 on error
*/
-int qcrypto_hash_digestv(QCryptoHashAlgorithm alg,
+int qcrypto_hash_digestv(QCryptoHashAlgo alg,
const struct iovec *iov,
size_t niov,
char **digest,
Error **errp);
/**
+ * qcrypto_hash_updatev:
+ * @hash: hash object from qcrypto_hash_new
+ * @iov: the array of memory regions to hash
+ * @niov: the length of @iov
+ * @errp: pointer to a NULL-initialized error object
+ *
+ * Updates the given hash object with all the memory regions
+ * present in @iov.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int qcrypto_hash_updatev(QCryptoHash *hash,
+ const struct iovec *iov,
+ size_t niov,
+ Error **errp);
+/**
+ * qcrypto_hash_update:
+ * @hash: hash object from qcrypto_hash_new
+ * @buf: the memory region to hash
+ * @len: the length of @buf
+ * @errp: pointer to a NULL-initialized error object
+ *
+ * Updates the given hash object with the data from
+ * the given buffer.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int qcrypto_hash_update(QCryptoHash *hash,
+ const char *buf,
+ size_t len,
+ Error **errp);
+
+/**
+ * qcrypto_hash_finalize_digest:
+ * @hash: the hash object to finalize
+ * @digest: pointer to hold output hash
+ * @errp: pointer to a NULL-initialized error object
+ *
+ * Computes the hash from the given hash object. Hash object
+ * is expected to have its data updated from the qcrypto_hash_update function.
+ * The @digest pointer will be filled with the printable hex digest of the
+ * computed hash, which will be terminated by '\0'. The memory pointer
+ * in @digest must be released with a call to g_free() when
+ * no longer required.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int qcrypto_hash_finalize_digest(QCryptoHash *hash,
+ char **digest,
+ Error **errp);
+
+/**
+ * qcrypto_hash_finalize_base64:
+ * @hash_ctx: hash object to finalize
+ * @base64: pointer to store the hash result in
+ * @errp: pointer to a NULL-initialized error object
+ *
+ * Computes the hash from the given hash object. Hash object
+ * is expected to have it's data updated from the qcrypto_hash_update function.
+ * The @base64 pointer will be filled with the base64 encoding of the computed
+ * hash, which will be terminated by '\0'. The memory pointer in @base64
+ * must be released with a call to g_free() when no longer required.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int qcrypto_hash_finalize_base64(QCryptoHash *hash,
+ char **base64,
+ Error **errp);
+
+/**
+ * qcrypto_hash_finalize_bytes:
+ * @hash_ctx: hash object to finalize
+ * @result: pointer to store the hash result in
+ * @result_len: Pointer to store the length of the result in
+ * @errp: pointer to a NULL-initialized error object
+ *
+ * Computes the hash from the given hash object. Hash object
+ * is expected to have it's data updated from the qcrypto_hash_update function.
+ *
+ * If @result_len is set to a non-zero value by the caller, then
+ * @result must hold a pointer that is @result_len in size, and
+ * @result_len match the size of the hash output. The digest will
+ * be written into @result.
+ *
+ * If @result_len is set to zero, then this function will allocate
+ * a buffer to hold the hash output digest, storing a pointer to
+ * the buffer in @result, and setting @result_len to its size.
+ * The memory referenced in @result must be released with a call
+ * to g_free() when no longer required by the caller.
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int qcrypto_hash_finalize_bytes(QCryptoHash *hash,
+ uint8_t **result,
+ size_t *result_len,
+ Error **errp);
+
+/**
+ * qcrypto_hash_new:
+ * @alg: the hash algorithm
+ * @errp: pointer to a NULL-initialized error object
+ *
+ * Creates a new hashing context for the chosen algorithm for
+ * usage with qcrypto_hash_update.
+ *
+ * Returns: New hash object with the given algorithm, or NULL on error.
+ */
+QCryptoHash *qcrypto_hash_new(QCryptoHashAlgo alg, Error **errp);
+
+/**
+ * qcrypto_hash_free:
+ * @hash: hash object to free
+ *
+ * Frees a hashing context for the chosen algorithm.
+ */
+void qcrypto_hash_free(QCryptoHash *hash);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoHash, qcrypto_hash_free)
+
+/**
* qcrypto_hash_digest:
* @alg: the hash algorithm
* @buf: the memory region to hash
@@ -137,7 +287,7 @@ int qcrypto_hash_digestv(QCryptoHashAlgorithm alg,
*
* Returns: 0 on success, -1 on error
*/
-int qcrypto_hash_digest(QCryptoHashAlgorithm alg,
+int qcrypto_hash_digest(QCryptoHashAlgo alg,
const char *buf,
size_t len,
char **digest,
@@ -160,7 +310,7 @@ int qcrypto_hash_digest(QCryptoHashAlgorithm alg,
*
* Returns: 0 on success, -1 on error
*/
-int qcrypto_hash_base64v(QCryptoHashAlgorithm alg,
+int qcrypto_hash_base64v(QCryptoHashAlgo alg,
const struct iovec *iov,
size_t niov,
char **base64,
@@ -183,7 +333,7 @@ int qcrypto_hash_base64v(QCryptoHashAlgorithm alg,
*
* Returns: 0 on success, -1 on error
*/
-int qcrypto_hash_base64(QCryptoHashAlgorithm alg,
+int qcrypto_hash_base64(QCryptoHashAlgo alg,
const char *buf,
size_t len,
char **base64,
diff --git a/include/crypto/hmac.h b/include/crypto/hmac.h
index ad4d778..da8a1e3 100644
--- a/include/crypto/hmac.h
+++ b/include/crypto/hmac.h
@@ -16,7 +16,7 @@
typedef struct QCryptoHmac QCryptoHmac;
struct QCryptoHmac {
- QCryptoHashAlgorithm alg;
+ QCryptoHashAlgo alg;
void *opaque;
void *driver;
};
@@ -31,7 +31,7 @@ struct QCryptoHmac {
* Returns:
* true if the algorithm is supported, false otherwise
*/
-bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg);
+bool qcrypto_hmac_supports(QCryptoHashAlgo alg);
/**
* qcrypto_hmac_new:
@@ -52,7 +52,7 @@ bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg);
* Returns:
* a new hmac object, or NULL on error
*/
-QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgorithm alg,
+QCryptoHmac *qcrypto_hmac_new(QCryptoHashAlgo alg,
const uint8_t *key, size_t nkey,
Error **errp);
@@ -77,11 +77,18 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoHmac, qcrypto_hmac_free)
* @errp: pointer to a NULL-initialized error object
*
* Computes the hmac across all the memory regions
- * present in @iov. The @result pointer will be
- * filled with raw bytes representing the computed
- * hmac, which will have length @resultlen. The
- * memory pointer in @result must be released
- * with a call to g_free() when no longer required.
+ * present in @iov.
+ *
+ * If @result_len is set to a non-zero value by the caller, then
+ * @result must hold a pointer that is @result_len in size, and
+ * @result_len match the size of the hash output. The digest will
+ * be written into @result.
+ *
+ * If @result_len is set to zero, then this function will allocate
+ * a buffer to hold the hash output digest, storing a pointer to
+ * the buffer in @result, and setting @result_len to its size.
+ * The memory referenced in @result must be released with a call
+ * to g_free() when no longer required by the caller.
*
* Returns:
* 0 on success, -1 on error
@@ -103,11 +110,18 @@ int qcrypto_hmac_bytesv(QCryptoHmac *hmac,
* @errp: pointer to a NULL-initialized error object
*
* Computes the hmac across all the memory region
- * @buf of length @len. The @result pointer will be
- * filled with raw bytes representing the computed
- * hmac, which will have length @resultlen. The
- * memory pointer in @result must be released
- * with a call to g_free() when no longer required.
+ * @buf of length @len.
+ *
+ * If @result_len is set to a non-zero value by the caller, then
+ * @result must hold a pointer that is @result_len in size, and
+ * @result_len match the size of the hash output. The digest will
+ * be written into @result.
+ *
+ * If @result_len is set to zero, then this function will allocate
+ * a buffer to hold the hash output digest, storing a pointer to
+ * the buffer in @result, and setting @result_len to its size.
+ * The memory referenced in @result must be released with a call
+ * to g_free() when no longer required by the caller.
*
* Returns:
* 0 on success, -1 on error
diff --git a/include/crypto/ivgen.h b/include/crypto/ivgen.h
index a09d573..bfa5d28 100644
--- a/include/crypto/ivgen.h
+++ b/include/crypto/ivgen.h
@@ -44,22 +44,22 @@
*
* g_assert((ndata % 512) == 0);
*
- * QCryptoIVGen *ivgen = qcrypto_ivgen_new(QCRYPTO_IVGEN_ALG_ESSIV,
- * QCRYPTO_CIPHER_ALG_AES_128,
- * QCRYPTO_HASH_ALG_SHA256,
+ * QCryptoIVGen *ivgen = qcrypto_ivgen_new(QCRYPTO_IV_GEN_ALGO_ESSIV,
+ * QCRYPTO_CIPHER_ALGO_AES_128,
+ * QCRYPTO_HASH_ALGO_SHA256,
* key, nkey, errp);
* if (!ivgen) {
* return -1;
* }
*
- * QCryptoCipher *cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_128,
+ * QCryptoCipher *cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALGO_AES_128,
* QCRYPTO_CIPHER_MODE_CBC,
* key, nkey, errp);
* if (!cipher) {
* goto error;
* }
*
- * niv = qcrypto_cipher_get_iv_len(QCRYPTO_CIPHER_ALG_AES_128,
+ * niv = qcrypto_cipher_get_iv_len(QCRYPTO_CIPHER_ALGO_AES_128,
* QCRYPTO_CIPHER_MODE_CBC);
* iv = g_new0(uint8_t, niv);
*
@@ -97,7 +97,7 @@
typedef struct QCryptoIVGen QCryptoIVGen;
-/* See also QCryptoIVGenAlgorithm enum in qapi/crypto.json */
+/* See also QCryptoIVGenAlgo enum in qapi/crypto.json */
/**
@@ -113,19 +113,19 @@ typedef struct QCryptoIVGen QCryptoIVGen;
* are required or not depends on the choice of @alg
* requested.
*
- * - QCRYPTO_IVGEN_ALG_PLAIN
+ * - QCRYPTO_IV_GEN_ALGO_PLAIN
*
* The IVs are generated by the 32-bit truncated sector
* number. This should never be used for block devices
* that are larger than 2^32 sectors in size.
* All the other parameters are unused.
*
- * - QCRYPTO_IVGEN_ALG_PLAIN64
+ * - QCRYPTO_IV_GEN_ALGO_PLAIN64
*
* The IVs are generated by the 64-bit sector number.
* All the other parameters are unused.
*
- * - QCRYPTO_IVGEN_ALG_ESSIV:
+ * - QCRYPTO_IV_GEN_ALGO_ESSIV:
*
* The IVs are generated by encrypting the 64-bit sector
* number with a hash of an encryption key. The @cipheralg,
@@ -133,9 +133,9 @@ typedef struct QCryptoIVGen QCryptoIVGen;
*
* Returns: a new IV generator, or NULL on error
*/
-QCryptoIVGen *qcrypto_ivgen_new(QCryptoIVGenAlgorithm alg,
- QCryptoCipherAlgorithm cipheralg,
- QCryptoHashAlgorithm hash,
+QCryptoIVGen *qcrypto_ivgen_new(QCryptoIVGenAlgo alg,
+ QCryptoCipherAlgo cipheralg,
+ QCryptoHashAlgo hash,
const uint8_t *key, size_t nkey,
Error **errp);
@@ -167,7 +167,7 @@ int qcrypto_ivgen_calculate(QCryptoIVGen *ivgen,
*
* Returns: the IV generator algorithm
*/
-QCryptoIVGenAlgorithm qcrypto_ivgen_get_algorithm(QCryptoIVGen *ivgen);
+QCryptoIVGenAlgo qcrypto_ivgen_get_algorithm(QCryptoIVGen *ivgen);
/**
@@ -179,7 +179,7 @@ QCryptoIVGenAlgorithm qcrypto_ivgen_get_algorithm(QCryptoIVGen *ivgen);
*
* Returns: the cipher algorithm
*/
-QCryptoCipherAlgorithm qcrypto_ivgen_get_cipher(QCryptoIVGen *ivgen);
+QCryptoCipherAlgo qcrypto_ivgen_get_cipher(QCryptoIVGen *ivgen);
/**
@@ -191,7 +191,7 @@ QCryptoCipherAlgorithm qcrypto_ivgen_get_cipher(QCryptoIVGen *ivgen);
*
* Returns: the hash algorithm
*/
-QCryptoHashAlgorithm qcrypto_ivgen_get_hash(QCryptoIVGen *ivgen);
+QCryptoHashAlgo qcrypto_ivgen_get_hash(QCryptoIVGen *ivgen);
/**
diff --git a/include/crypto/pbkdf.h b/include/crypto/pbkdf.h
index 2c31a44..cf59fce 100644
--- a/include/crypto/pbkdf.h
+++ b/include/crypto/pbkdf.h
@@ -38,7 +38,7 @@
* ....
*
* char *password = "a-typical-awful-user-password";
- * size_t nkey = qcrypto_cipher_get_key_len(QCRYPTO_CIPHER_ALG_AES_128);
+ * size_t nkey = qcrypto_cipher_get_key_len(QCRYPTO_CIPHER_ALGO_AES_128);
* uint8_t *salt = g_new0(uint8_t, nkey);
* uint8_t *key = g_new0(uint8_t, nkey);
* int iterations;
@@ -50,7 +50,7 @@
* return -1;
* }
*
- * iterations = qcrypto_pbkdf2_count_iters(QCRYPTO_HASH_ALG_SHA256,
+ * iterations = qcrypto_pbkdf2_count_iters(QCRYPTO_HASH_ALGO_SHA256,
* (const uint8_t *)password,
* strlen(password),
* salt, nkey, errp);
@@ -60,7 +60,7 @@
* return -1;
* }
*
- * if (qcrypto_pbkdf2(QCRYPTO_HASH_ALG_SHA256,
+ * if (qcrypto_pbkdf2(QCRYPTO_HASH_ALGO_SHA256,
* (const uint8_t *)password, strlen(password),
* salt, nkey, iterations, key, nkey, errp) < 0) {
* g_free(key);
@@ -70,7 +70,7 @@
*
* g_free(salt);
*
- * cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALG_AES_128,
+ * cipher = qcrypto_cipher_new(QCRYPTO_CIPHER_ALGO_AES_128,
* QCRYPTO_CIPHER_MODE_ECB,
* key, nkey, errp);
* g_free(key);
@@ -92,7 +92,7 @@
*
* Returns true if supported, false otherwise
*/
-bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash);
+bool qcrypto_pbkdf2_supports(QCryptoHashAlgo hash);
/**
@@ -119,7 +119,7 @@ bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash);
*
* Returns: 0 on success, -1 on error
*/
-int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
+int qcrypto_pbkdf2(QCryptoHashAlgo hash,
const uint8_t *key, size_t nkey,
const uint8_t *salt, size_t nsalt,
uint64_t iterations,
@@ -147,7 +147,7 @@ int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
*
* Returns: number of iterations in 1 second, -1 on error
*/
-uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
+uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgo hash,
const uint8_t *key, size_t nkey,
const uint8_t *salt, size_t nsalt,
size_t nout,
diff --git a/include/crypto/tlssession.h b/include/crypto/tlssession.h
index 571049b..f694a5c 100644
--- a/include/crypto/tlssession.h
+++ b/include/crypto/tlssession.h
@@ -107,6 +107,7 @@
typedef struct QCryptoTLSSession QCryptoTLSSession;
+#define QCRYPTO_TLS_SESSION_ERR_BLOCK -2
/**
* qcrypto_tls_session_new:
@@ -177,12 +178,18 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSSession, qcrypto_tls_session_free)
int qcrypto_tls_session_check_credentials(QCryptoTLSSession *sess,
Error **errp);
+/*
+ * These must return QCRYPTO_TLS_SESSION_ERR_BLOCK if the I/O
+ * would block, but on other errors, must fill 'errp'
+ */
typedef ssize_t (*QCryptoTLSSessionWriteFunc)(const char *buf,
size_t len,
- void *opaque);
+ void *opaque,
+ Error **errp);
typedef ssize_t (*QCryptoTLSSessionReadFunc)(char *buf,
size_t len,
- void *opaque);
+ void *opaque,
+ Error **errp);
/**
* qcrypto_tls_session_set_callbacks:
@@ -212,6 +219,7 @@ void qcrypto_tls_session_set_callbacks(QCryptoTLSSession *sess,
* @sess: the TLS session object
* @buf: the plain text to send
* @len: the length of @buf
+ * @errp: pointer to hold returned error object
*
* Encrypt @len bytes of the data in @buf and send
* it to the remote peer using the callback previously
@@ -221,32 +229,45 @@ void qcrypto_tls_session_set_callbacks(QCryptoTLSSession *sess,
* qcrypto_tls_session_get_handshake_status() returns
* QCRYPTO_TLS_HANDSHAKE_COMPLETE
*
- * Returns: the number of bytes sent, or -1 on error
+ * Returns: the number of bytes sent,
+ * or QCRYPTO_TLS_SESSION_ERR_BLOCK if the write would block,
+ * or -1 on error.
*/
ssize_t qcrypto_tls_session_write(QCryptoTLSSession *sess,
const char *buf,
- size_t len);
+ size_t len,
+ Error **errp);
/**
* qcrypto_tls_session_read:
* @sess: the TLS session object
* @buf: to fill with plain text received
* @len: the length of @buf
+ * @gracefulTermination: treat premature termination as graceful EOF
+ * @errp: pointer to hold returned error object
*
* Receive up to @len bytes of data from the remote peer
* using the callback previously registered with
* qcrypto_tls_session_set_callbacks(), decrypt it and
* store it in @buf.
*
+ * If @gracefulTermination is true, then a premature termination
+ * of the TLS session will be treated as indicating EOF, as
+ * opposed to an error.
+ *
* It is an error to call this before
* qcrypto_tls_session_get_handshake_status() returns
* QCRYPTO_TLS_HANDSHAKE_COMPLETE
*
- * Returns: the number of bytes received, or -1 on error
+ * Returns: the number of bytes received,
+ * or QCRYPTO_TLS_SESSION_ERR_BLOCK if the receive would block,
+ * or -1 on error.
*/
ssize_t qcrypto_tls_session_read(QCryptoTLSSession *sess,
char *buf,
- size_t len);
+ size_t len,
+ bool gracefulTermination,
+ Error **errp);
/**
* qcrypto_tls_session_check_pending:
diff --git a/include/crypto/x509-utils.h b/include/crypto/x509-utils.h
new file mode 100644
index 0000000..1e99661
--- /dev/null
+++ b/include/crypto/x509-utils.h
@@ -0,0 +1,22 @@
+/*
+ * X.509 certificate related helpers
+ *
+ * Copyright (c) 2024 Dorjoy Chowdhury <dorjoychy111@gmail.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#ifndef QCRYPTO_X509_UTILS_H
+#define QCRYPTO_X509_UTILS_H
+
+#include "crypto/hash.h"
+
+int qcrypto_get_x509_cert_fingerprint(uint8_t *cert, size_t size,
+ QCryptoHashAlgo hash,
+ uint8_t *result,
+ size_t *resultlen,
+ Error **errp);
+
+#endif
diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h
index a1d26ce..3b50ecf 100644
--- a/include/disas/dis-asm.h
+++ b/include/disas/dis-asm.h
@@ -232,10 +232,6 @@ enum bfd_architecture
#define bfd_mach_avrxmega5 105
#define bfd_mach_avrxmega6 106
#define bfd_mach_avrxmega7 107
- bfd_arch_cris, /* Axis CRIS */
-#define bfd_mach_cris_v0_v10 255
-#define bfd_mach_cris_v32 32
-#define bfd_mach_cris_v10_v32 1032
bfd_arch_microblaze, /* Xilinx MicroBlaze. */
bfd_arch_moxie, /* The Moxie core. */
bfd_arch_ia64, /* HP/Intel ia64 */
@@ -448,8 +444,6 @@ int print_insn_w65 (bfd_vma, disassemble_info*);
int print_insn_d10v (bfd_vma, disassemble_info*);
int print_insn_v850 (bfd_vma, disassemble_info*);
int print_insn_tic30 (bfd_vma, disassemble_info*);
-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_xtensa (bfd_vma, disassemble_info*);
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
index 6f09b86..45e6676 100644
--- a/include/exec/cpu-all.h
+++ b/include/exec/cpu-all.h
@@ -166,7 +166,20 @@ typedef int (*walk_memory_regions_fn)(void *, target_ulong,
int walk_memory_regions(void *, walk_memory_regions_fn);
int page_get_flags(target_ulong address);
+
+/**
+ * page_set_flags:
+ * @start: first byte of range
+ * @last: last byte of range
+ * @flags: flags to set
+ * Context: holding mmap lock
+ *
+ * Modify the flags of a page and invalidate the code if necessary.
+ * The flag PAGE_WRITE_ORG is positioned automatically depending
+ * on PAGE_WRITE. The mmap_lock should already be held.
+ */
void page_set_flags(target_ulong start, target_ulong last, int flags);
+
void page_reset_target_data(target_ulong start, target_ulong last);
/**
diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h
index 815342d..638dc80 100644
--- a/include/exec/cpu-common.h
+++ b/include/exec/cpu-common.h
@@ -35,6 +35,8 @@ void cpu_list_lock(void);
void cpu_list_unlock(void);
unsigned int cpu_list_generation_id_get(void);
+int cpu_get_free_index(void);
+
void tcg_iommu_init_notifier_list(CPUState *cpu);
void tcg_iommu_free_notifier_list(CPUState *cpu);
@@ -129,6 +131,14 @@ size_t qemu_ram_pagesize_largest(void);
*/
void cpu_address_space_init(CPUState *cpu, int asidx,
const char *prefix, MemoryRegion *mr);
+/**
+ * cpu_address_space_destroy:
+ * @cpu: CPU for which address space needs to be destroyed
+ * @asidx: integer index of this address space
+ *
+ * Note that with KVM only one address space is supported.
+ */
+void cpu_address_space_destroy(CPUState *cpu, int asidx);
void cpu_physical_memory_rw(hwaddr addr, void *buf,
hwaddr len, bool is_write);
@@ -229,6 +239,17 @@ static inline ArchCPU *env_archcpu(CPUArchState *env)
}
/**
+ * env_cpu_const(env)
+ * @env: The architecture environment
+ *
+ * Return the CPUState associated with the environment.
+ */
+static inline const CPUState *env_cpu_const(const CPUArchState *env)
+{
+ return (void *)env - sizeof(CPUState);
+}
+
+/**
* env_cpu(env)
* @env: The architecture environment
*
@@ -236,7 +257,7 @@ static inline ArchCPU *env_archcpu(CPUArchState *env)
*/
static inline CPUState *env_cpu(CPUArchState *env)
{
- return (void *)env - sizeof(CPUState);
+ return (CPUState *)env_cpu_const(env);
}
#ifndef CONFIG_USER_ONLY
diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h
index 71009f8..dac12bd 100644
--- a/include/exec/cpu_ldst.h
+++ b/include/exec/cpu_ldst.h
@@ -379,4 +379,38 @@ void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr,
MMUAccessType access_type, int mmu_idx);
#endif
+/*
+ * For user-only, helpers that use guest to host address translation
+ * must protect the actual host memory access by recording 'retaddr'
+ * for the signal handler. This is required for a race condition in
+ * which another thread unmaps the page between a probe and the
+ * actual access.
+ */
+#ifdef CONFIG_USER_ONLY
+extern __thread uintptr_t helper_retaddr;
+
+static inline void set_helper_retaddr(uintptr_t ra)
+{
+ helper_retaddr = ra;
+ /*
+ * Ensure that this write is visible to the SIGSEGV handler that
+ * may be invoked due to a subsequent invalid memory operation.
+ */
+ signal_barrier();
+}
+
+static inline void clear_helper_retaddr(void)
+{
+ /*
+ * Ensure that previous memory operations have succeeded before
+ * removing the data visible to the signal handler.
+ */
+ signal_barrier();
+ helper_retaddr = 0;
+}
+#else
+#define set_helper_retaddr(ra) do { } while (0)
+#define clear_helper_retaddr() do { } while (0)
+#endif
+
#endif /* CPU_LDST_H */
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index b6b46ad..2e4c4cc 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -301,6 +301,9 @@ static inline void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState *cpu,
{
}
#endif
+
+#if defined(CONFIG_TCG)
+
/**
* probe_access:
* @env: CPUArchState
@@ -357,6 +360,7 @@ int probe_access_flags(CPUArchState *env, vaddr addr, int size,
bool nonfault, void **phost, uintptr_t retaddr);
#ifndef CONFIG_USER_ONLY
+
/**
* probe_access_full:
* Like probe_access_flags, except also return into @pfull.
@@ -364,6 +368,13 @@ int probe_access_flags(CPUArchState *env, vaddr addr, int size,
* The CPUTLBEntryFull structure returned via @pfull is transient
* and must be consumed or copied immediately, before any further
* access or changes to TLB @mmu_idx.
+ *
+ * This function will not fault if @nonfault is set, but will
+ * return TLB_INVALID_MASK if the page is not mapped, or is not
+ * accessible with @access_type.
+ *
+ * This function will return TLB_MMIO in order to force the access
+ * to be handled out-of-line if plugins wish to instrument the access.
*/
int probe_access_full(CPUArchState *env, vaddr addr, int size,
MMUAccessType access_type, int mmu_idx,
@@ -371,28 +382,21 @@ int probe_access_full(CPUArchState *env, vaddr addr, int size,
CPUTLBEntryFull **pfull, uintptr_t retaddr);
/**
- * probe_access_mmu() - Like probe_access_full except cannot fault and
- * doesn't trigger instrumentation.
- *
- * @env: CPUArchState
- * @vaddr: virtual address to probe
- * @size: size of the probe
- * @access_type: read, write or execute permission
- * @mmu_idx: softmmu index
- * @phost: ptr to return value host address or NULL
- * @pfull: ptr to return value CPUTLBEntryFull structure or NULL
- *
- * The CPUTLBEntryFull structure returned via @pfull is transient
- * and must be consumed or copied immediately, before any further
- * access or changes to TLB @mmu_idx.
- *
- * Returns: TLB flags as per probe_access_flags()
+ * probe_access_full_mmu:
+ * Like probe_access_full, except:
+ *
+ * This function is intended to be used for page table accesses by
+ * the target mmu itself. Since such page walking happens while
+ * handling another potential mmu fault, this function never raises
+ * exceptions (akin to @nonfault true for probe_access_full).
+ * Likewise this function does not trigger plugin instrumentation.
*/
int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size,
MMUAccessType access_type, int mmu_idx,
void **phost, CPUTLBEntryFull **pfull);
-#endif
+#endif /* !CONFIG_USER_ONLY */
+#endif /* CONFIG_TCG */
static inline tb_page_addr_t tb_page_addr0(const TranslationBlock *tb)
{
diff --git a/include/exec/gdbstub.h b/include/exec/gdbstub.h
index 1bd2c4e..d73f424 100644
--- a/include/exec/gdbstub.h
+++ b/include/exec/gdbstub.h
@@ -41,6 +41,12 @@ void gdb_register_coprocessor(CPUState *cpu,
const GDBFeature *feature, int g_pos);
/**
+ * gdb_unregister_coprocessor_all() - unregisters supplemental set of registers
+ * @cpu - the CPU associated with registers
+ */
+void gdb_unregister_coprocessor_all(CPUState *cpu);
+
+/**
* gdbserver_start: start the gdb server
* @port_or_device: connection spec for gdb
*
diff --git a/include/exec/memop.h b/include/exec/memop.h
index f881fe7..acdb40a 100644
--- a/include/exec/memop.h
+++ b/include/exec/memop.h
@@ -164,10 +164,51 @@ static inline MemOp size_memop(unsigned size)
return (MemOp)ctz32(size);
}
-/* Big endianness from MemOp. */
-static inline bool memop_big_endian(MemOp op)
+/**
+ * memop_alignment_bits:
+ * @memop: MemOp value
+ *
+ * Extract the alignment size from the memop.
+ */
+static inline unsigned memop_alignment_bits(MemOp memop)
+{
+ unsigned a = memop & MO_AMASK;
+
+ if (a == MO_UNALN) {
+ /* No alignment required. */
+ a = 0;
+ } else if (a == MO_ALIGN) {
+ /* A natural alignment requirement. */
+ a = memop & MO_SIZE;
+ } else {
+ /* A specific alignment requirement. */
+ a = a >> MO_ASHIFT;
+ }
+ return a;
+}
+
+/*
+ * memop_atomicity_bits:
+ * @memop: MemOp value
+ *
+ * Extract the atomicity size from the memop.
+ */
+static inline unsigned memop_atomicity_bits(MemOp memop)
{
- return (op & MO_BSWAP) == MO_BE;
+ unsigned size = memop & MO_SIZE;
+
+ switch (memop & MO_ATOM_MASK) {
+ case MO_ATOM_NONE:
+ size = MO_8;
+ break;
+ case MO_ATOM_IFALIGN_PAIR:
+ case MO_ATOM_WITHIN16_PAIR:
+ size = size ? size - 1 : 0;
+ break;
+ default:
+ break;
+ }
+ return size;
}
#endif
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 02f7528..e5e865d 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -1084,13 +1084,7 @@ typedef struct AddressSpaceMapClient {
QLIST_ENTRY(AddressSpaceMapClient) link;
} AddressSpaceMapClient;
-typedef struct {
- MemoryRegion *mr;
- void *buffer;
- hwaddr addr;
- hwaddr len;
- bool in_use;
-} BounceBuffer;
+#define DEFAULT_MAX_BOUNCE_BUFFER_SIZE (4096)
/**
* struct AddressSpace: describes a mapping of addresses to #MemoryRegion objects
@@ -1110,8 +1104,10 @@ struct AddressSpace {
QTAILQ_HEAD(, MemoryListener) listeners;
QTAILQ_ENTRY(AddressSpace) address_spaces_link;
- /* Bounce buffer to use for this address space. */
- BounceBuffer bounce;
+ /* Maximum DMA bounce buffer size used for indirect memory map requests */
+ size_t max_bounce_buffer_size;
+ /* Total size of bounce buffers currently allocated, atomically accessed */
+ size_t bounce_buffer_size;
/* List of callbacks to invoke when buffers free up */
QemuMutex map_client_list_lock;
QLIST_HEAD(, AddressSpaceMapClient) map_client_list;
@@ -1852,7 +1848,7 @@ void memory_region_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n);
* memory_region_unregister_iommu_notifier: unregister a notifier for
* changes to IOMMU translation entries.
*
- * @mr: the memory region which was observed and for which notity_stopped()
+ * @mr: the memory region which was observed and for which notify_stopped()
* needs to be called
* @n: the notifier to be removed.
*/
diff --git a/include/exec/poison.h b/include/exec/poison.h
index 792a83f..f4283f6 100644
--- a/include/exec/poison.h
+++ b/include/exec/poison.h
@@ -11,7 +11,6 @@
#pragma GCC poison TARGET_AARCH64
#pragma GCC poison TARGET_ALPHA
#pragma GCC poison TARGET_ARM
-#pragma GCC poison TARGET_CRIS
#pragma GCC poison TARGET_HEXAGON
#pragma GCC poison TARGET_HPPA
#pragma GCC poison TARGET_LOONGARCH64
@@ -64,7 +63,6 @@
#pragma GCC poison CPU_INTERRUPT_TGT_INT_2
#pragma GCC poison CONFIG_ALPHA_DIS
-#pragma GCC poison CONFIG_CRIS_DIS
#pragma GCC poison CONFIG_HPPA_DIS
#pragma GCC poison CONFIG_I386_DIS
#pragma GCC poison CONFIG_HEXAGON_DIS
diff --git a/include/exec/ramlist.h b/include/exec/ramlist.h
index 2ad2a81..d9cfe53 100644
--- a/include/exec/ramlist.h
+++ b/include/exec/ramlist.h
@@ -50,6 +50,7 @@ typedef struct RAMList {
/* RCU-enabled, writes protected by the ramlist lock. */
QLIST_HEAD(, RAMBlock) blocks;
DirtyMemoryBlocks *dirty_memory[DIRTY_MEMORY_NUM];
+ unsigned int num_dirty_blocks;
uint32_t version;
QLIST_HEAD(, RAMBlockNotifier) ramblock_notifiers;
} RAMList;
diff --git a/include/exec/translator.h b/include/exec/translator.h
index 25004df..d8dcb77 100644
--- a/include/exec/translator.h
+++ b/include/exec/translator.h
@@ -71,7 +71,6 @@ typedef enum DisasJumpType {
* @is_jmp: What instruction to disassemble next.
* @num_insns: Number of translated instructions (including current).
* @max_insns: Maximum number of instructions to be translated in this TB.
- * @singlestep_enabled: "Hardware" single stepping enabled.
* @plugin_enabled: TCG plugin enabled in this TB.
* @fake_insn: True if translator_fake_ldb used.
* @insn_start: The last op emitted by the insn_start hook,
@@ -86,7 +85,6 @@ struct DisasContextBase {
DisasJumpType is_jmp;
int num_insns;
int max_insns;
- bool singlestep_enabled;
bool plugin_enabled;
bool fake_insn;
struct TCGOp *insn_start;
diff --git a/include/exec/tswap.h b/include/exec/tswap.h
index b7a4191..ecd4fae 100644
--- a/include/exec/tswap.h
+++ b/include/exec/tswap.h
@@ -28,7 +28,7 @@ bool target_words_bigendian(void);
#ifdef COMPILING_PER_TARGET
#define target_needs_bswap() (HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN)
#else
-#define target_needs_bswap() (target_words_bigendian() != HOST_BIG_ENDIAN)
+#define target_needs_bswap() (HOST_BIG_ENDIAN != target_words_bigendian())
#endif /* COMPILING_PER_TARGET */
static inline uint16_t tswap16(uint16_t s)
diff --git a/include/gdbstub/commands.h b/include/gdbstub/commands.h
index f3058f9..40f0514 100644
--- a/include/gdbstub/commands.h
+++ b/include/gdbstub/commands.h
@@ -74,23 +74,28 @@ int gdb_put_packet(const char *buf);
/**
* gdb_extend_query_table() - Extend query table.
- * @table: The table with the additional query packet handlers.
- * @size: The number of handlers to be added.
+ * @table: GPtrArray of GdbCmdParseEntry entries.
+ *
+ * The caller should free @table afterwards
*/
-void gdb_extend_query_table(GdbCmdParseEntry *table, int size);
+void gdb_extend_query_table(GPtrArray *table);
/**
* gdb_extend_set_table() - Extend set table.
- * @table: The table with the additional set packet handlers.
- * @size: The number of handlers to be added.
+ * @table: GPtrArray of GdbCmdParseEntry entries.
+ *
+ * The caller should free @table afterwards
*/
-void gdb_extend_set_table(GdbCmdParseEntry *table, int size);
+void gdb_extend_set_table(GPtrArray *table);
/**
* gdb_extend_qsupported_features() - Extend the qSupported features string.
* @qsupported_features: The additional qSupported feature(s) string. The string
* should start with a semicolon and, if there are more than one feature, the
- * features should be separate by a semiocolon.
+ * features should be separate by a semicolon.
+ *
+ * The caller should free @qsupported_features afterwards if
+ * dynamically allocated.
*/
void gdb_extend_qsupported_features(char *qsupported_features);
diff --git a/include/gdbstub/helpers.h b/include/gdbstub/helpers.h
index 26140ef..6f7cc48 100644
--- a/include/gdbstub/helpers.h
+++ b/include/gdbstub/helpers.h
@@ -95,9 +95,13 @@ static inline uint8_t *gdb_get_reg_ptr(GByteArray *buf, int len)
#if TARGET_LONG_BITS == 64
#define gdb_get_regl(buf, val) gdb_get_reg64(buf, val)
#define ldtul_p(addr) ldq_p(addr)
+#define ldtul_le_p(addr) ldq_le_p(addr)
+#define ldtul_be_p(addr) ldq_be_p(addr)
#else
#define gdb_get_regl(buf, val) gdb_get_reg32(buf, val)
#define ldtul_p(addr) ldl_p(addr)
+#define ldtul_le_p(addr) ldl_le_p(addr)
+#define ldtul_be_p(addr) ldl_be_p(addr)
#endif
#endif /* _GDBSTUB_HELPERS_H_ */
diff --git a/include/gdbstub/syscalls.h b/include/gdbstub/syscalls.h
index 54ff724..d63228e 100644
--- a/include/gdbstub/syscalls.h
+++ b/include/gdbstub/syscalls.h
@@ -3,7 +3,7 @@
*
* Copyright (c) 2023 Linaro Ltd
*
- * SPDX-License-Identifier: LGPL-2.0+
+ * SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef _SYSCALLS_H_
diff --git a/include/gdbstub/user.h b/include/gdbstub/user.h
index 3b8358e..654986d 100644
--- a/include/gdbstub/user.h
+++ b/include/gdbstub/user.h
@@ -3,7 +3,7 @@
*
* Copyright (c) 2022 Linaro Ltd
*
- * SPDX-License-Identifier: LGPL-2.0+
+ * SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef GDBSTUB_USER_H
diff --git a/include/hw/acpi/cpu.h b/include/hw/acpi/cpu.h
index e6e1a9e..32654dc 100644
--- a/include/hw/acpi/cpu.h
+++ b/include/hw/acpi/cpu.h
@@ -19,6 +19,8 @@
#include "hw/boards.h"
#include "hw/hotplug.h"
+#define ACPI_CPU_HOTPLUG_REG_LEN 12
+
typedef struct AcpiCpuStatus {
CPUState *cpu;
uint64_t arch_id;
@@ -61,9 +63,10 @@ typedef void (*build_madt_cpu_fn)(int uid, const CPUArchIdList *apic_ids,
GArray *entry, bool force_enabled);
void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
- build_madt_cpu_fn build_madt_cpu, hwaddr io_base,
+ build_madt_cpu_fn build_madt_cpu, hwaddr base_addr,
const char *res_root,
- const char *event_handler_method);
+ const char *event_handler_method,
+ AmlRegionSpace rs);
void acpi_cpu_ospm_status(CPUHotplugState *cpu_st, ACPIOSTInfoList ***list);
diff --git a/include/hw/acpi/generic_event_device.h b/include/hw/acpi/generic_event_device.h
index ba84ce0..d2dac87 100644
--- a/include/hw/acpi/generic_event_device.h
+++ b/include/hw/acpi/generic_event_device.h
@@ -62,6 +62,7 @@
#include "hw/sysbus.h"
#include "hw/acpi/memory_hotplug.h"
#include "hw/acpi/ghes.h"
+#include "hw/acpi/cpu.h"
#include "qom/object.h"
#define ACPI_POWER_BUTTON_DEVICE "PWRB"
@@ -80,12 +81,16 @@ OBJECT_DECLARE_SIMPLE_TYPE(AcpiGedState, ACPI_GED)
/* ACPI_GED_REG_RESET value for reset*/
#define ACPI_GED_RESET_VALUE 0x42
-/* ACPI_GED_REG_SLEEP_CTL.SLP_TYP value for S5 (aka poweroff) */
-#define ACPI_GED_SLP_TYP_S5 0x05
+/* [ACPI 5.0 Chapter 4.8.3.7] Sleep Control and Status Register */
+#define ACPI_GED_SLP_TYP_POS 0x2 /* SLP_TYPx Bit Offset */
+#define ACPI_GED_SLP_TYP_MASK 0x07 /* SLP_TYPx 3-bit mask */
+#define ACPI_GED_SLP_TYP_S5 0x05 /* System _S5 State (Soft Off) */
+#define ACPI_GED_SLP_EN 0x20 /* SLP_EN write-only bit */
#define GED_DEVICE "GED"
#define AML_GED_EVT_REG "EREG"
#define AML_GED_EVT_SEL "ESEL"
+#define AML_GED_EVT_CPU_SCAN_METHOD "\\_SB.GED.CSCN"
/*
* Platforms need to specify the GED event bitmap
@@ -95,6 +100,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(AcpiGedState, ACPI_GED)
#define ACPI_GED_MEM_HOTPLUG_EVT 0x1
#define ACPI_GED_PWR_DOWN_EVT 0x2
#define ACPI_GED_NVDIMM_HOTPLUG_EVT 0x4
+#define ACPI_GED_CPU_HOTPLUG_EVT 0x8
typedef struct GEDState {
MemoryRegion evt;
@@ -106,6 +112,8 @@ struct AcpiGedState {
SysBusDevice parent_obj;
MemHotplugState memhp_state;
MemoryRegion container_memhp;
+ CPUHotplugState cpuhp_state;
+ MemoryRegion container_cpuhp;
GEDState ged_state;
uint32_t ged_event_bitmap;
qemu_irq irq;
diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h
index 2faf7f0..245fe08 100644
--- a/include/hw/acpi/ich9.h
+++ b/include/hw/acpi/ich9.h
@@ -46,6 +46,7 @@ typedef struct ICH9LPCPMRegs {
uint32_t smi_en;
uint32_t smi_en_wmask;
uint32_t smi_sts;
+ uint32_t smi_sts_wmask;
qemu_irq irq; /* SCI */
@@ -68,6 +69,11 @@ typedef struct ICH9LPCPMRegs {
bool smm_compat;
bool enable_tco;
TCOIORegs tco_regs;
+
+ bool swsmi_timer_enabled;
+ bool periodic_timer_enabled;
+ QEMUTimer *swsmi_timer;
+ QEMUTimer *periodic_timer;
} ICH9LPCPMRegs;
#define ACPI_PM_PROP_TCO_ENABLED "enable_tco"
diff --git a/include/hw/acpi/ich9_timer.h b/include/hw/acpi/ich9_timer.h
new file mode 100644
index 0000000..5112df4
--- /dev/null
+++ b/include/hw/acpi/ich9_timer.h
@@ -0,0 +1,23 @@
+/*
+ * QEMU ICH9 Timer emulation
+ *
+ * Copyright (c) 2024 Dominic Prinz <git@dprinz.de>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef HW_ACPI_ICH9_TIMER_H
+#define HW_ACPI_ICH9_TIMER_H
+
+#include "hw/acpi/ich9.h"
+
+void ich9_pm_update_swsmi_timer(ICH9LPCPMRegs *pm, bool enable);
+
+void ich9_pm_swsmi_timer_init(ICH9LPCPMRegs *pm);
+
+void ich9_pm_update_periodic_timer(ICH9LPCPMRegs *pm, bool enable);
+
+void ich9_pm_periodic_timer_init(ICH9LPCPMRegs *pm);
+
+#endif
diff --git a/include/hw/adc/aspeed_adc.h b/include/hw/adc/aspeed_adc.h
index ff1d06e..f502f19 100644
--- a/include/hw/adc/aspeed_adc.h
+++ b/include/hw/adc/aspeed_adc.h
@@ -18,6 +18,7 @@
#define TYPE_ASPEED_2500_ADC TYPE_ASPEED_ADC "-ast2500"
#define TYPE_ASPEED_2600_ADC TYPE_ASPEED_ADC "-ast2600"
#define TYPE_ASPEED_1030_ADC TYPE_ASPEED_ADC "-ast1030"
+#define TYPE_ASPEED_2700_ADC TYPE_ASPEED_ADC "-ast2700"
OBJECT_DECLARE_TYPE(AspeedADCState, AspeedADCClass, ASPEED_ADC)
#define TYPE_ASPEED_ADC_ENGINE "aspeed.adc.engine"
diff --git a/include/hw/adc/max111x.h b/include/hw/adc/max111x.h
deleted file mode 100644
index beff59c..0000000
--- a/include/hw/adc/max111x.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Maxim MAX1110/1111 ADC chip emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPLv2.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-#ifndef HW_MISC_MAX111X_H
-#define HW_MISC_MAX111X_H
-
-#include "hw/ssi/ssi.h"
-#include "qom/object.h"
-
-/*
- * This is a model of the Maxim MAX1110/1111 ADC chip, which for QEMU
- * is an SSI slave device. It has either 4 (max1110) or 8 (max1111)
- * 8-bit ADC channels.
- *
- * QEMU interface:
- * + GPIO inputs 0..3 (for max1110) or 0..7 (for max1111): set the value
- * of each ADC input, as an unsigned 8-bit value
- * + GPIO output 0: interrupt line
- * + Properties "input0" to "input3" (max1110) or "input0" to "input7"
- * (max1111): initial reset values for ADC inputs.
- *
- * Known bugs:
- * + the interrupt line is not correctly implemented, and will never
- * be lowered once it has been asserted.
- */
-struct MAX111xState {
- SSIPeripheral parent_obj;
-
- qemu_irq interrupt;
- /* Values of inputs at system reset (settable by QOM property) */
- uint8_t reset_input[8];
-
- uint8_t tb1, rb2, rb3;
- int cycle;
-
- uint8_t input[8];
- int inputs, com;
-};
-
-#define TYPE_MAX_111X "max111x"
-
-OBJECT_DECLARE_SIMPLE_TYPE(MAX111xState, MAX_111X)
-
-#define TYPE_MAX_1110 "max1110"
-#define TYPE_MAX_1111 "max1111"
-
-#endif
diff --git a/include/hw/arm/allwinner-a10.h b/include/hw/arm/allwinner-a10.h
index 67a9a17..e5815b0 100644
--- a/include/hw/arm/allwinner-a10.h
+++ b/include/hw/arm/allwinner-a10.h
@@ -12,6 +12,7 @@
#include "hw/misc/allwinner-a10-ccm.h"
#include "hw/misc/allwinner-a10-dramc.h"
#include "hw/i2c/allwinner-i2c.h"
+#include "hw/ssi/allwinner-a10-spi.h"
#include "hw/watchdog/allwinner-wdt.h"
#include "sysemu/block-backend.h"
@@ -40,6 +41,7 @@ struct AwA10State {
AllwinnerAHCIState sata;
AwSdHostState mmc0;
AWI2CState i2c0;
+ AWA10SPIState spi0;
AwRtcState rtc;
AwWdtState wdt;
MemoryRegion sram_a;
diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h
index 849ba37..689f52d 100644
--- a/include/hw/arm/aspeed_soc.h
+++ b/include/hw/arm/aspeed_soc.h
@@ -39,7 +39,7 @@
#include "hw/misc/unimp.h"
#include "hw/misc/aspeed_peci.h"
#include "hw/fsi/aspeed_apb2opb.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#include "hw/intc/arm_gicv3.h"
#define ASPEED_SPIS_NUM 2
@@ -164,6 +164,7 @@ struct AspeedSoCClass {
const hwaddr *memmap;
uint32_t num_cpus;
qemu_irq (*get_irq)(AspeedSoCState *s, int dev);
+ bool (*boot_from_emmc)(AspeedSoCState *s);
};
const char *aspeed_soc_cpu_type(AspeedSoCClass *sc);
diff --git a/include/hw/arm/omap.h b/include/hw/arm/omap.h
index 40ee8ea..420ed1d 100644
--- a/include/hw/arm/omap.h
+++ b/include/hw/arm/omap.h
@@ -21,13 +21,11 @@
#define HW_ARM_OMAP_H
#include "exec/memory.h"
-#include "hw/input/tsc2xxx.h"
#include "target/arm/cpu-qom.h"
#include "qemu/log.h"
#include "qom/object.h"
# define OMAP_EMIFS_BASE 0x00000000
-# define OMAP2_Q0_BASE 0x00000000
# define OMAP_CS0_BASE 0x00000000
# define OMAP_CS1_BASE 0x04000000
# define OMAP_CS2_BASE 0x08000000
@@ -35,20 +33,12 @@
# define OMAP_EMIFF_BASE 0x10000000
# define OMAP_IMIF_BASE 0x20000000
# define OMAP_LOCALBUS_BASE 0x30000000
-# define OMAP2_Q1_BASE 0x40000000
-# define OMAP2_L4_BASE 0x48000000
-# define OMAP2_SRAM_BASE 0x40200000
-# define OMAP2_L3_BASE 0x68000000
-# define OMAP2_Q2_BASE 0x80000000
-# define OMAP2_Q3_BASE 0xc0000000
# define OMAP_MPUI_BASE 0xe1000000
# define OMAP730_SRAM_SIZE 0x00032000
# define OMAP15XX_SRAM_SIZE 0x00030000
# define OMAP16XX_SRAM_SIZE 0x00004000
# define OMAP1611_SRAM_SIZE 0x0003e800
-# define OMAP242X_SRAM_SIZE 0x000a0000
-# define OMAP243X_SRAM_SIZE 0x00010000
# define OMAP_CS0_SIZE 0x04000000
# define OMAP_CS1_SIZE 0x04000000
# define OMAP_CS2_SIZE 0x04000000
@@ -69,7 +59,7 @@ int64_t omap_clk_getrate(omap_clk clk);
void omap_clk_reparent(omap_clk clk, omap_clk parent);
/* omap_intc.c */
-#define TYPE_OMAP_INTC "common-omap-intc"
+#define TYPE_OMAP_INTC "omap-intc"
typedef struct OMAPIntcState OMAPIntcState;
DECLARE_INSTANCE_CHECKER(OMAPIntcState, OMAP_INTC, TYPE_OMAP_INTC)
@@ -106,71 +96,9 @@ typedef struct Omap1GpioState Omap1GpioState;
DECLARE_INSTANCE_CHECKER(Omap1GpioState, OMAP1_GPIO,
TYPE_OMAP1_GPIO)
-#define TYPE_OMAP2_GPIO "omap2-gpio"
-typedef struct Omap2GpioState Omap2GpioState;
-DECLARE_INSTANCE_CHECKER(Omap2GpioState, OMAP2_GPIO,
- TYPE_OMAP2_GPIO)
-
/* TODO: clock framework (see above) */
void omap_gpio_set_clk(Omap1GpioState *gpio, omap_clk clk);
-void omap2_gpio_set_iclk(Omap2GpioState *gpio, omap_clk clk);
-void omap2_gpio_set_fclk(Omap2GpioState *gpio, uint8_t i, omap_clk clk);
-
-/* OMAP2 l4 Interconnect */
-struct omap_l4_s;
-struct omap_l4_region_s {
- hwaddr offset;
- size_t size;
- int access;
-};
-struct omap_l4_agent_info_s {
- int ta;
- int region;
- int regions;
- int ta_region;
-};
-struct omap_target_agent_s {
- MemoryRegion iomem;
- struct omap_l4_s *bus;
- int regions;
- const struct omap_l4_region_s *start;
- hwaddr base;
- uint32_t component;
- uint32_t control;
- uint32_t status;
-};
-struct omap_l4_s *omap_l4_init(MemoryRegion *address_space,
- hwaddr base, int ta_num);
-
-struct omap_target_agent_s;
-struct omap_target_agent_s *omap_l4ta_get(
- struct omap_l4_s *bus,
- const struct omap_l4_region_s *regions,
- const struct omap_l4_agent_info_s *agents,
- int cs);
-hwaddr omap_l4_attach(struct omap_target_agent_s *ta,
- int region, MemoryRegion *mr);
-hwaddr omap_l4_region_base(struct omap_target_agent_s *ta,
- int region);
-hwaddr omap_l4_region_size(struct omap_target_agent_s *ta,
- int region);
-
-/* OMAP2 SDRAM controller */
-struct omap_sdrc_s;
-struct omap_sdrc_s *omap_sdrc_init(MemoryRegion *sysmem,
- hwaddr base);
-void omap_sdrc_reset(struct omap_sdrc_s *s);
-
-/* OMAP2 general purpose memory controller */
-struct omap_gpmc_s;
-struct omap_gpmc_s *omap_gpmc_init(struct omap_mpu_state_s *mpu,
- hwaddr base,
- qemu_irq irq, qemu_irq drq);
-void omap_gpmc_reset(struct omap_gpmc_s *s);
-void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, MemoryRegion *iomem);
-void omap_gpmc_attach_nand(struct omap_gpmc_s *s, int cs, DeviceState *nand);
-
/*
* Common IRQ numbers for level 1 interrupt handler
* See /usr/include/asm-arm/arch-omap/irqs.h in Linux.
@@ -398,93 +326,11 @@ void omap_gpmc_attach_nand(struct omap_gpmc_s *s, int cs, DeviceState *nand);
# define OMAP_INT_730_DMA_CH15 62
# define OMAP_INT_730_NAND 63
-/*
- * OMAP-24xx common IRQ numbers
- */
-# define OMAP_INT_24XX_STI 4
-# define OMAP_INT_24XX_SYS_NIRQ 7
-# define OMAP_INT_24XX_L3_IRQ 10
-# define OMAP_INT_24XX_PRCM_MPU_IRQ 11
-# define OMAP_INT_24XX_SDMA_IRQ0 12
-# define OMAP_INT_24XX_SDMA_IRQ1 13
-# define OMAP_INT_24XX_SDMA_IRQ2 14
-# define OMAP_INT_24XX_SDMA_IRQ3 15
-# define OMAP_INT_243X_MCBSP2_IRQ 16
-# define OMAP_INT_243X_MCBSP3_IRQ 17
-# define OMAP_INT_243X_MCBSP4_IRQ 18
-# define OMAP_INT_243X_MCBSP5_IRQ 19
-# define OMAP_INT_24XX_GPMC_IRQ 20
-# define OMAP_INT_24XX_GUFFAW_IRQ 21
-# define OMAP_INT_24XX_IVA_IRQ 22
-# define OMAP_INT_24XX_EAC_IRQ 23
-# define OMAP_INT_24XX_CAM_IRQ 24
-# define OMAP_INT_24XX_DSS_IRQ 25
-# define OMAP_INT_24XX_MAIL_U0_MPU 26
-# define OMAP_INT_24XX_DSP_UMA 27
-# define OMAP_INT_24XX_DSP_MMU 28
-# define OMAP_INT_24XX_GPIO_BANK1 29
-# define OMAP_INT_24XX_GPIO_BANK2 30
-# define OMAP_INT_24XX_GPIO_BANK3 31
-# define OMAP_INT_24XX_GPIO_BANK4 32
-# define OMAP_INT_243X_GPIO_BANK5 33
-# define OMAP_INT_24XX_MAIL_U3_MPU 34
-# define OMAP_INT_24XX_WDT3 35
-# define OMAP_INT_24XX_WDT4 36
-# define OMAP_INT_24XX_GPTIMER1 37
-# define OMAP_INT_24XX_GPTIMER2 38
-# define OMAP_INT_24XX_GPTIMER3 39
-# define OMAP_INT_24XX_GPTIMER4 40
-# define OMAP_INT_24XX_GPTIMER5 41
-# define OMAP_INT_24XX_GPTIMER6 42
-# define OMAP_INT_24XX_GPTIMER7 43
-# define OMAP_INT_24XX_GPTIMER8 44
-# define OMAP_INT_24XX_GPTIMER9 45
-# define OMAP_INT_24XX_GPTIMER10 46
-# define OMAP_INT_24XX_GPTIMER11 47
-# define OMAP_INT_24XX_GPTIMER12 48
-# define OMAP_INT_24XX_PKA_IRQ 50
-# define OMAP_INT_24XX_SHA1MD5_IRQ 51
-# define OMAP_INT_24XX_RNG_IRQ 52
-# define OMAP_INT_24XX_MG_IRQ 53
-# define OMAP_INT_24XX_I2C1_IRQ 56
-# define OMAP_INT_24XX_I2C2_IRQ 57
-# define OMAP_INT_24XX_MCBSP1_IRQ_TX 59
-# define OMAP_INT_24XX_MCBSP1_IRQ_RX 60
-# define OMAP_INT_24XX_MCBSP2_IRQ_TX 62
-# define OMAP_INT_24XX_MCBSP2_IRQ_RX 63
-# define OMAP_INT_243X_MCBSP1_IRQ 64
-# define OMAP_INT_24XX_MCSPI1_IRQ 65
-# define OMAP_INT_24XX_MCSPI2_IRQ 66
-# define OMAP_INT_24XX_SSI1_IRQ0 67
-# define OMAP_INT_24XX_SSI1_IRQ1 68
-# define OMAP_INT_24XX_SSI2_IRQ0 69
-# define OMAP_INT_24XX_SSI2_IRQ1 70
-# define OMAP_INT_24XX_SSI_GDD_IRQ 71
-# define OMAP_INT_24XX_UART1_IRQ 72
-# define OMAP_INT_24XX_UART2_IRQ 73
-# define OMAP_INT_24XX_UART3_IRQ 74
-# define OMAP_INT_24XX_USB_IRQ_GEN 75
-# define OMAP_INT_24XX_USB_IRQ_NISO 76
-# define OMAP_INT_24XX_USB_IRQ_ISO 77
-# define OMAP_INT_24XX_USB_IRQ_HGEN 78
-# define OMAP_INT_24XX_USB_IRQ_HSOF 79
-# define OMAP_INT_24XX_USB_IRQ_OTG 80
-# define OMAP_INT_24XX_VLYNQ_IRQ 81
-# define OMAP_INT_24XX_MMC_IRQ 83
-# define OMAP_INT_24XX_MS_IRQ 84
-# define OMAP_INT_24XX_FAC_IRQ 85
-# define OMAP_INT_24XX_MCSPI3_IRQ 91
-# define OMAP_INT_243X_HS_USB_MC 92
-# define OMAP_INT_243X_HS_USB_DMA 93
-# define OMAP_INT_243X_CARKIT 94
-# define OMAP_INT_34XX_GPTIMER12 95
-
/* omap_dma.c */
enum omap_dma_model {
omap_dma_3_0,
omap_dma_3_1,
omap_dma_3_2,
- omap_dma_4,
};
struct soc_dma_s;
@@ -632,97 +478,11 @@ struct omap_dma_lcd_channel_s {
# define OMAP_DMA_MMC2_RX 55
# define OMAP_DMA_CRYPTO_DES_OUT 56
-/*
- * DMA request numbers for the OMAP2
- */
-# define OMAP24XX_DMA_NO_DEVICE 0
-# define OMAP24XX_DMA_XTI_DMA 1 /* Not in OMAP2420 */
-# define OMAP24XX_DMA_EXT_DMAREQ0 2
-# define OMAP24XX_DMA_EXT_DMAREQ1 3
-# define OMAP24XX_DMA_GPMC 4
-# define OMAP24XX_DMA_GFX 5 /* Not in OMAP2420 */
-# define OMAP24XX_DMA_DSS 6
-# define OMAP24XX_DMA_VLYNQ_TX 7 /* Not in OMAP2420 */
-# define OMAP24XX_DMA_CWT 8 /* Not in OMAP2420 */
-# define OMAP24XX_DMA_AES_TX 9 /* Not in OMAP2420 */
-# define OMAP24XX_DMA_AES_RX 10 /* Not in OMAP2420 */
-# define OMAP24XX_DMA_DES_TX 11 /* Not in OMAP2420 */
-# define OMAP24XX_DMA_DES_RX 12 /* Not in OMAP2420 */
-# define OMAP24XX_DMA_SHA1MD5_RX 13 /* Not in OMAP2420 */
-# define OMAP24XX_DMA_EXT_DMAREQ2 14
-# define OMAP24XX_DMA_EXT_DMAREQ3 15
-# define OMAP24XX_DMA_EXT_DMAREQ4 16
-# define OMAP24XX_DMA_EAC_AC_RD 17
-# define OMAP24XX_DMA_EAC_AC_WR 18
-# define OMAP24XX_DMA_EAC_MD_UL_RD 19
-# define OMAP24XX_DMA_EAC_MD_UL_WR 20
-# define OMAP24XX_DMA_EAC_MD_DL_RD 21
-# define OMAP24XX_DMA_EAC_MD_DL_WR 22
-# define OMAP24XX_DMA_EAC_BT_UL_RD 23
-# define OMAP24XX_DMA_EAC_BT_UL_WR 24
-# define OMAP24XX_DMA_EAC_BT_DL_RD 25
-# define OMAP24XX_DMA_EAC_BT_DL_WR 26
-# define OMAP24XX_DMA_I2C1_TX 27
-# define OMAP24XX_DMA_I2C1_RX 28
-# define OMAP24XX_DMA_I2C2_TX 29
-# define OMAP24XX_DMA_I2C2_RX 30
-# define OMAP24XX_DMA_MCBSP1_TX 31
-# define OMAP24XX_DMA_MCBSP1_RX 32
-# define OMAP24XX_DMA_MCBSP2_TX 33
-# define OMAP24XX_DMA_MCBSP2_RX 34
-# define OMAP24XX_DMA_SPI1_TX0 35
-# define OMAP24XX_DMA_SPI1_RX0 36
-# define OMAP24XX_DMA_SPI1_TX1 37
-# define OMAP24XX_DMA_SPI1_RX1 38
-# define OMAP24XX_DMA_SPI1_TX2 39
-# define OMAP24XX_DMA_SPI1_RX2 40
-# define OMAP24XX_DMA_SPI1_TX3 41
-# define OMAP24XX_DMA_SPI1_RX3 42
-# define OMAP24XX_DMA_SPI2_TX0 43
-# define OMAP24XX_DMA_SPI2_RX0 44
-# define OMAP24XX_DMA_SPI2_TX1 45
-# define OMAP24XX_DMA_SPI2_RX1 46
-
-# define OMAP24XX_DMA_UART1_TX 49
-# define OMAP24XX_DMA_UART1_RX 50
-# define OMAP24XX_DMA_UART2_TX 51
-# define OMAP24XX_DMA_UART2_RX 52
-# define OMAP24XX_DMA_UART3_TX 53
-# define OMAP24XX_DMA_UART3_RX 54
-# define OMAP24XX_DMA_USB_W2FC_TX0 55
-# define OMAP24XX_DMA_USB_W2FC_RX0 56
-# define OMAP24XX_DMA_USB_W2FC_TX1 57
-# define OMAP24XX_DMA_USB_W2FC_RX1 58
-# define OMAP24XX_DMA_USB_W2FC_TX2 59
-# define OMAP24XX_DMA_USB_W2FC_RX2 60
-# define OMAP24XX_DMA_MMC1_TX 61
-# define OMAP24XX_DMA_MMC1_RX 62
-# define OMAP24XX_DMA_MS 63 /* Not in OMAP2420 */
-# define OMAP24XX_DMA_EXT_DMAREQ5 64
-
-/* omap[123].c */
-/* OMAP2 gp timer */
-struct omap_gp_timer_s;
-struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
- qemu_irq irq, omap_clk fclk, omap_clk iclk);
-void omap_gp_timer_reset(struct omap_gp_timer_s *s);
-
-/* OMAP2 sysctimer */
-struct omap_synctimer_s;
-struct omap_synctimer_s *omap_synctimer_init(struct omap_target_agent_s *ta,
- struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk);
-void omap_synctimer_reset(struct omap_synctimer_s *s);
-
struct omap_uart_s;
struct omap_uart_s *omap_uart_init(hwaddr base,
qemu_irq irq, omap_clk fclk, omap_clk iclk,
qemu_irq txdma, qemu_irq rxdma,
const char *label, Chardev *chr);
-struct omap_uart_s *omap2_uart_init(MemoryRegion *sysmem,
- struct omap_target_agent_s *ta,
- qemu_irq irq, omap_clk fclk, omap_clk iclk,
- qemu_irq txdma, qemu_irq rxdma,
- const char *label, Chardev *chr);
void omap_uart_reset(struct omap_uart_s *s);
struct omap_mpuio_s;
@@ -731,17 +491,6 @@ void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler);
void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down);
struct omap_uwire_s;
-void omap_uwire_attach(struct omap_uwire_s *s,
- uWireSlave *slave, int chipselect);
-
-/* OMAP2 spi */
-struct omap_mcspi_s;
-struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
- qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk);
-void omap_mcspi_attach(struct omap_mcspi_s *s,
- uint32_t (*txrx)(void *opaque, uint32_t, int), void *opaque,
- int chipselect);
-void omap_mcspi_reset(struct omap_mcspi_s *s);
struct I2SCodec {
void *opaque;
@@ -770,9 +519,6 @@ struct I2SCodec {
struct omap_mcbsp_s;
void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, I2SCodec *slave);
-void omap_tap_init(struct omap_target_agent_s *ta,
- struct omap_mpu_state_s *mpu);
-
/* omap_lcdc.c */
struct omap_lcd_panel_s;
void omap_lcdc_reset(struct omap_lcd_panel_s *s);
@@ -782,35 +528,13 @@ struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem,
struct omap_dma_lcd_channel_s *dma,
omap_clk clk);
-/* omap_dss.c */
-struct rfbi_chip_s {
- void *opaque;
- void (*write)(void *opaque, int dc, uint16_t value);
- void (*block)(void *opaque, int dc, void *buf, size_t len, int pitch);
- uint16_t (*read)(void *opaque, int dc);
-};
-struct omap_dss_s;
-void omap_dss_reset(struct omap_dss_s *s);
-struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
- MemoryRegion *sysmem,
- hwaddr l3_base,
- qemu_irq irq, qemu_irq drq,
- omap_clk fck1, omap_clk fck2, omap_clk ck54m,
- omap_clk ick1, omap_clk ick2);
-void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip);
-
/* omap_mmc.c */
struct omap_mmc_s;
struct omap_mmc_s *omap_mmc_init(hwaddr base,
MemoryRegion *sysmem,
BlockBackend *blk,
qemu_irq irq, qemu_irq dma[], omap_clk clk);
-struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
- BlockBackend *blk, qemu_irq irq, qemu_irq dma[],
- omap_clk fclk, omap_clk iclk);
void omap_mmc_reset(struct omap_mmc_s *s);
-void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover);
-void omap_mmc_enable(struct omap_mmc_s *s, int enable);
/* omap_i2c.c */
I2CBus *omap_i2c_bus(DeviceState *omap_i2c);
@@ -819,24 +543,11 @@ I2CBus *omap_i2c_bus(DeviceState *omap_i2c);
# define cpu_is_omap1510(cpu) (cpu->mpu_model == omap1510)
# define cpu_is_omap1610(cpu) (cpu->mpu_model == omap1610)
# define cpu_is_omap1710(cpu) (cpu->mpu_model == omap1710)
-# define cpu_is_omap2410(cpu) (cpu->mpu_model == omap2410)
-# define cpu_is_omap2420(cpu) (cpu->mpu_model == omap2420)
-# define cpu_is_omap2430(cpu) (cpu->mpu_model == omap2430)
-# define cpu_is_omap3430(cpu) (cpu->mpu_model == omap3430)
-# define cpu_is_omap3630(cpu) (cpu->mpu_model == omap3630)
# define cpu_is_omap15xx(cpu) \
(cpu_is_omap310(cpu) || cpu_is_omap1510(cpu))
# define cpu_is_omap16xx(cpu) \
(cpu_is_omap1610(cpu) || cpu_is_omap1710(cpu))
-# define cpu_is_omap24xx(cpu) \
- (cpu_is_omap2410(cpu) || cpu_is_omap2420(cpu) || cpu_is_omap2430(cpu))
-
-# define cpu_class_omap1(cpu) \
- (cpu_is_omap15xx(cpu) || cpu_is_omap16xx(cpu))
-# define cpu_class_omap2(cpu) cpu_is_omap24xx(cpu)
-# define cpu_class_omap3(cpu) \
- (cpu_is_omap3430(cpu) || cpu_is_omap3630(cpu))
struct omap_mpu_state_s {
enum omap_mpu_model {
@@ -844,13 +555,6 @@ struct omap_mpu_state_s {
omap1510,
omap1610,
omap1710,
- omap2410,
- omap2420,
- omap2422,
- omap2423,
- omap2430,
- omap3430,
- omap3630,
} mpu_model;
ARMCPU *cpu;
@@ -960,33 +664,12 @@ struct omap_mpu_state_s {
uint16_t dsp_idlect2;
uint16_t dsp_rstct2;
} clkm;
-
- /* OMAP2-only peripherals */
- struct omap_l4_s *l4;
-
- struct omap_gp_timer_s *gptimer[12];
- struct omap_synctimer_s *synctimer;
-
- struct omap_prcm_s *prcm;
- struct omap_sdrc_s *sdrc;
- struct omap_gpmc_s *gpmc;
- struct omap_sysctl_s *sysc;
-
- struct omap_mcspi_s *mcspi[2];
-
- struct omap_dss_s *dss;
-
- struct omap_eac_s *eac;
};
/* omap1.c */
struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *sdram,
const char *core);
-/* omap2.c */
-struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sdram,
- const char *core);
-
uint32_t omap_badwidth_read8(void *opaque, hwaddr addr);
void omap_badwidth_write8(void *opaque, hwaddr addr,
uint32_t value);
@@ -1007,35 +690,6 @@ void omap_mpu_wakeup(void *opaque, int irq, int req);
HWADDR_PRIx "\n", \
__func__, paddr)
-/* OMAP-specific Linux bootloader tags for the ATAG_BOARD area
- * (Board-specific tags are not here)
- */
-#define OMAP_TAG_CLOCK 0x4f01
-#define OMAP_TAG_MMC 0x4f02
-#define OMAP_TAG_SERIAL_CONSOLE 0x4f03
-#define OMAP_TAG_USB 0x4f04
-#define OMAP_TAG_LCD 0x4f05
-#define OMAP_TAG_GPIO_SWITCH 0x4f06
-#define OMAP_TAG_UART 0x4f07
-#define OMAP_TAG_FBMEM 0x4f08
-#define OMAP_TAG_STI_CONSOLE 0x4f09
-#define OMAP_TAG_CAMERA_SENSOR 0x4f0a
-#define OMAP_TAG_PARTITION 0x4f0b
-#define OMAP_TAG_TEA5761 0x4f10
-#define OMAP_TAG_TMP105 0x4f11
-#define OMAP_TAG_BOOT_REASON 0x4f80
-#define OMAP_TAG_FLASH_PART_STR 0x4f81
-#define OMAP_TAG_VERSION_STR 0x4f82
-
-enum {
- OMAP_GPIOSW_TYPE_COVER = 0 << 4,
- OMAP_GPIOSW_TYPE_CONNECTION = 1 << 4,
- OMAP_GPIOSW_TYPE_ACTIVITY = 2 << 4,
-};
-
-#define OMAP_GPIOSW_INVERTED 0x0001
-#define OMAP_GPIOSW_OUTPUT 0x0002
-
# define OMAP_MPUI_REG_MASK 0x000007ff
#endif
diff --git a/include/hw/arm/pxa.h b/include/hw/arm/pxa.h
deleted file mode 100644
index 4c6caee..0000000
--- a/include/hw/arm/pxa.h
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Intel XScale PXA255/270 processor support.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPL v2.
- */
-
-#ifndef PXA_H
-#define PXA_H
-
-#include "exec/memory.h"
-#include "target/arm/cpu-qom.h"
-#include "hw/pcmcia.h"
-#include "qom/object.h"
-
-/* Interrupt numbers */
-# define PXA2XX_PIC_SSP3 0
-# define PXA2XX_PIC_USBH2 2
-# define PXA2XX_PIC_USBH1 3
-# define PXA2XX_PIC_KEYPAD 4
-# define PXA2XX_PIC_PWRI2C 6
-# define PXA25X_PIC_HWUART 7
-# define PXA27X_PIC_OST_4_11 7
-# define PXA2XX_PIC_GPIO_0 8
-# define PXA2XX_PIC_GPIO_1 9
-# define PXA2XX_PIC_GPIO_X 10
-# define PXA2XX_PIC_I2S 13
-# define PXA26X_PIC_ASSP 15
-# define PXA25X_PIC_NSSP 16
-# define PXA27X_PIC_SSP2 16
-# define PXA2XX_PIC_LCD 17
-# define PXA2XX_PIC_I2C 18
-# define PXA2XX_PIC_ICP 19
-# define PXA2XX_PIC_STUART 20
-# define PXA2XX_PIC_BTUART 21
-# define PXA2XX_PIC_FFUART 22
-# define PXA2XX_PIC_MMC 23
-# define PXA2XX_PIC_SSP 24
-# define PXA2XX_PIC_DMA 25
-# define PXA2XX_PIC_OST_0 26
-# define PXA2XX_PIC_RTC1HZ 30
-# define PXA2XX_PIC_RTCALARM 31
-
-/* DMA requests */
-# define PXA2XX_RX_RQ_I2S 2
-# define PXA2XX_TX_RQ_I2S 3
-# define PXA2XX_RX_RQ_BTUART 4
-# define PXA2XX_TX_RQ_BTUART 5
-# define PXA2XX_RX_RQ_FFUART 6
-# define PXA2XX_TX_RQ_FFUART 7
-# define PXA2XX_RX_RQ_SSP1 13
-# define PXA2XX_TX_RQ_SSP1 14
-# define PXA2XX_RX_RQ_SSP2 15
-# define PXA2XX_TX_RQ_SSP2 16
-# define PXA2XX_RX_RQ_ICP 17
-# define PXA2XX_TX_RQ_ICP 18
-# define PXA2XX_RX_RQ_STUART 19
-# define PXA2XX_TX_RQ_STUART 20
-# define PXA2XX_RX_RQ_MMCI 21
-# define PXA2XX_TX_RQ_MMCI 22
-# define PXA2XX_USB_RQ(x) ((x) + 24)
-# define PXA2XX_RX_RQ_SSP3 66
-# define PXA2XX_TX_RQ_SSP3 67
-
-# define PXA2XX_SDRAM_BASE 0xa0000000
-# define PXA2XX_INTERNAL_BASE 0x5c000000
-# define PXA2XX_INTERNAL_SIZE 0x40000
-
-/* pxa2xx_pic.c */
-DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu);
-
-/* pxa2xx_gpio.c */
-DeviceState *pxa2xx_gpio_init(hwaddr base,
- ARMCPU *cpu, DeviceState *pic, int lines);
-void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler);
-
-/* pxa2xx_dma.c */
-DeviceState *pxa255_dma_init(hwaddr base, qemu_irq irq);
-DeviceState *pxa27x_dma_init(hwaddr base, qemu_irq irq);
-
-/* pxa2xx_lcd.c */
-typedef struct PXA2xxLCDState PXA2xxLCDState;
-PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
- hwaddr base, qemu_irq irq);
-void pxa2xx_lcd_vsync_notifier(PXA2xxLCDState *s, qemu_irq handler);
-
-/* pxa2xx_mmci.c */
-#define TYPE_PXA2XX_MMCI "pxa2xx-mmci"
-OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxMMCIState, PXA2XX_MMCI)
-
-PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem,
- hwaddr base,
- qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma);
-void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly,
- qemu_irq coverswitch);
-
-/* pxa2xx_pcmcia.c */
-#define TYPE_PXA2XX_PCMCIA "pxa2xx-pcmcia"
-OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxPCMCIAState, PXA2XX_PCMCIA)
-
-int pxa2xx_pcmcia_attach(void *opaque, PCMCIACardState *card);
-int pxa2xx_pcmcia_detach(void *opaque);
-void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq);
-
-/* pxa2xx_keypad.c */
-struct keymap {
- int8_t column;
- int8_t row;
-};
-typedef struct PXA2xxKeyPadState PXA2xxKeyPadState;
-PXA2xxKeyPadState *pxa27x_keypad_init(MemoryRegion *sysmem,
- hwaddr base,
- qemu_irq irq);
-void pxa27x_register_keypad(PXA2xxKeyPadState *kp,
- const struct keymap *map, int size);
-
-/* pxa2xx.c */
-#define TYPE_PXA2XX_I2C "pxa2xx_i2c"
-OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxI2CState, PXA2XX_I2C)
-
-PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base,
- qemu_irq irq, uint32_t page_size);
-I2CBus *pxa2xx_i2c_bus(PXA2xxI2CState *s);
-
-typedef struct PXA2xxI2SState PXA2xxI2SState;
-
-#define TYPE_PXA2XX_FIR "pxa2xx-fir"
-OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxFIrState, PXA2XX_FIR)
-
-typedef struct {
- ARMCPU *cpu;
- DeviceState *pic;
- qemu_irq reset;
- MemoryRegion sdram;
- MemoryRegion internal;
- MemoryRegion cm_iomem;
- MemoryRegion mm_iomem;
- MemoryRegion pm_iomem;
- DeviceState *dma;
- DeviceState *gpio;
- PXA2xxLCDState *lcd;
- SSIBus **ssp;
- PXA2xxI2CState *i2c[2];
- PXA2xxMMCIState *mmc;
- PXA2xxPCMCIAState *pcmcia[2];
- PXA2xxI2SState *i2s;
- PXA2xxFIrState *fir;
- PXA2xxKeyPadState *kp;
-
- /* Power management */
- hwaddr pm_base;
- uint32_t pm_regs[0x40];
-
- /* Clock management */
- hwaddr cm_base;
- uint32_t cm_regs[4];
- uint32_t clkcfg;
-
- /* Memory management */
- hwaddr mm_base;
- uint32_t mm_regs[0x1a];
-
- /* Performance monitoring */
- uint32_t pmnc;
-} PXA2xxState;
-
-struct PXA2xxI2SState {
- MemoryRegion iomem;
- qemu_irq irq;
- qemu_irq rx_dma;
- qemu_irq tx_dma;
- void (*data_req)(void *, int, int);
-
- uint32_t control[2];
- uint32_t status;
- uint32_t mask;
- uint32_t clk;
-
- int enable;
- int rx_len;
- int tx_len;
- void (*codec_out)(void *, uint32_t);
- uint32_t (*codec_in)(void *);
- void *opaque;
-
- int fifo_len;
- uint32_t fifo[16];
-};
-
-# define PA_FMT "0x%08lx"
-
-PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision);
-PXA2xxState *pxa255_init(unsigned int sdram_size);
-
-#endif /* PXA_H */
diff --git a/include/hw/arm/stm32f405_soc.h b/include/hw/arm/stm32f405_soc.h
index d15c03c..2eeada6 100644
--- a/include/hw/arm/stm32f405_soc.h
+++ b/include/hw/arm/stm32f405_soc.h
@@ -25,6 +25,7 @@
#ifndef HW_ARM_STM32F405_SOC_H
#define HW_ARM_STM32F405_SOC_H
+#include "hw/misc/stm32_rcc.h"
#include "hw/misc/stm32f4xx_syscfg.h"
#include "hw/timer/stm32f2xx_timer.h"
#include "hw/char/stm32f2xx_usart.h"
@@ -55,6 +56,7 @@ struct STM32F405State {
ARMv7MState armv7m;
+ STM32RccState rcc;
STM32F4xxSyscfgState syscfg;
STM32F4xxExtiState exti;
STM32F2XXUsartState usart[STM_NUM_USARTS];
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index ab961bb..aca4f80 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -47,6 +47,9 @@
/* See Linux kernel arch/arm64/include/asm/pvclock-abi.h */
#define PVTIME_SIZE_PER_CPU 64
+/* GPIO pins */
+#define GPIO_PIN_POWER_BUTTON 3
+
enum {
VIRT_FLASH,
VIRT_MEM,
@@ -131,6 +134,7 @@ struct VirtMachineClass {
bool no_cpu_topology;
bool no_tcg_lpa2;
bool no_ns_el2_virt_timer_irq;
+ bool no_nested_smmu;
};
struct VirtMachineState {
diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h
index 025beb5..05ed641 100644
--- a/include/hw/arm/xlnx-versal.h
+++ b/include/hw/arm/xlnx-versal.h
@@ -78,6 +78,7 @@ struct Versal {
struct {
PL011State uart[XLNX_VERSAL_NR_UARTS];
CadenceGEMState gem[XLNX_VERSAL_NR_GEMS];
+ OrIRQState gem_irq_orgate[XLNX_VERSAL_NR_GEMS];
XlnxZDMA adma[XLNX_VERSAL_NR_ADMAS];
VersalUsb2 usb;
CanBusState *canbus[XLNX_VERSAL_NR_CANFD];
diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h
index 48f7948..c137ac5 100644
--- a/include/hw/arm/xlnx-zynqmp.h
+++ b/include/hw/arm/xlnx-zynqmp.h
@@ -116,6 +116,7 @@ struct XlnxZynqMPState {
MemoryRegion mr_unimp[XLNX_ZYNQMP_NUM_UNIMP_AREAS];
CadenceGEMState gem[XLNX_ZYNQMP_NUM_GEMS];
+ OrIRQState gem_irq_orgate[XLNX_ZYNQMP_NUM_GEMS];
CadenceUARTState uart[XLNX_ZYNQMP_NUM_UARTS];
XlnxZynqMPCANState can[XLNX_ZYNQMP_NUM_CAN];
SysbusAHCIState sata;
diff --git a/include/hw/block/flash.h b/include/hw/block/flash.h
index 2b5ccd9..5fd67f5 100644
--- a/include/hw/block/flash.h
+++ b/include/hw/block/flash.h
@@ -62,20 +62,6 @@ uint32_t nand_getbuswidth(DeviceState *dev);
#define NAND_MFR_HYNIX 0xad
#define NAND_MFR_MICRON 0x2c
-/* onenand.c */
-void *onenand_raw_otp(DeviceState *onenand_device);
-
-/* ecc.c */
-typedef struct {
- uint8_t cp; /* Column parity */
- uint16_t lp[2]; /* Line parity */
- uint16_t count;
-} ECCState;
-
-uint8_t ecc_digest(ECCState *s, uint8_t sample);
-void ecc_reset(ECCState *s);
-extern const VMStateDescription vmstate_ecc_state;
-
/* m25p80.c */
#define TYPE_M25P80 "m25p80-generic"
diff --git a/include/hw/boards.h b/include/hw/boards.h
index ef6f18f..5966069 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -10,6 +10,7 @@
#include "qemu/module.h"
#include "qom/object.h"
#include "hw/core/cpu.h"
+#include "hw/resettable.h"
#define TYPE_MACHINE_SUFFIX "-machine"
@@ -215,6 +216,10 @@ typedef struct {
* Return the type of KVM corresponding to the kvm-type string option or
* computed based on other criteria such as the host kernel capabilities.
* kvm-type may be NULL if it is not needed.
+ * @hvf_get_physical_address_range:
+ * Returns the physical address range in bits to use for the HVF virtual
+ * machine based on the current boards memory map. This may be NULL if it
+ * is not needed.
* @numa_mem_supported:
* true if '--numa node.mem' option is supported and false otherwise
* @hotplug_allowed:
@@ -237,6 +242,9 @@ typedef struct {
* purposes only.
* Applies only to default memory backend, i.e., explicit memory backend
* wasn't used.
+ * @smbios_memory_device_size:
+ * Default size of memory device,
+ * SMBIOS 3.1.0 "7.18 Memory Device (Type 17)"
*/
struct MachineClass {
/*< private >*/
@@ -250,9 +258,10 @@ struct MachineClass {
const char *deprecation_reason;
void (*init)(MachineState *state);
- void (*reset)(MachineState *state, ShutdownCause reason);
+ void (*reset)(MachineState *state, ResetType type);
void (*wakeup)(MachineState *state);
int (*kvm_type)(MachineState *machine, const char *arg);
+ int (*hvf_get_physical_address_range)(MachineState *machine);
BlockInterfaceType block_default_type;
int units_per_default_bus;
@@ -304,6 +313,7 @@ struct MachineClass {
const CPUArchIdList *(*possible_cpu_arch_ids)(MachineState *machine);
int64_t (*get_default_cpu_node_id)(const MachineState *ms, int idx);
ram_addr_t (*fixup_ram_size)(ram_addr_t size);
+ uint64_t smbios_memory_device_size;
};
/**
@@ -728,6 +738,9 @@ struct MachineState {
} \
type_init(machine_initfn##_register_types)
+extern GlobalProperty hw_compat_9_1[];
+extern const size_t hw_compat_9_1_len;
+
extern GlobalProperty hw_compat_9_0[];
extern const size_t hw_compat_9_0_len;
diff --git a/include/hw/char/escc.h b/include/hw/char/escc.h
index 5669a5b..8c4c6a7 100644
--- a/include/hw/char/escc.h
+++ b/include/hw/char/escc.h
@@ -46,6 +46,9 @@ typedef struct ESCCChannelState {
uint8_t rx, tx;
QemuInputHandlerState *hs;
char *sunkbd_layout;
+ int sunmouse_dx;
+ int sunmouse_dy;
+ int sunmouse_buttons;
} ESCCChannelState;
struct ESCCState {
diff --git a/include/hw/char/mchp_pfsoc_mmuart.h b/include/hw/char/mchp_pfsoc_mmuart.h
index b0e14ca..a7b8b1b 100644
--- a/include/hw/char/mchp_pfsoc_mmuart.h
+++ b/include/hw/char/mchp_pfsoc_mmuart.h
@@ -29,7 +29,7 @@
#define HW_MCHP_PFSOC_MMUART_H
#include "hw/sysbus.h"
-#include "hw/char/serial.h"
+#include "hw/char/serial-mm.h"
#define MCHP_PFSOC_MMUART_REG_COUNT 13
diff --git a/include/hw/char/pl011.h b/include/hw/char/pl011.h
index d853802..4fcaf3d 100644
--- a/include/hw/char/pl011.h
+++ b/include/hw/char/pl011.h
@@ -32,7 +32,6 @@ struct PL011State {
SysBusDevice parent_obj;
MemoryRegion iomem;
- uint32_t readbuff;
uint32_t flags;
uint32_t lcr;
uint32_t rsr;
diff --git a/include/hw/char/serial-isa.h b/include/hw/char/serial-isa.h
new file mode 100644
index 0000000..8517afa
--- /dev/null
+++ b/include/hw/char/serial-isa.h
@@ -0,0 +1,38 @@
+/*
+ * QEMU ISA 16550A UART emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2008 Citrix Systems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef HW_SERIAL_ISA_H
+#define HW_SERIAL_ISA_H
+
+#include "hw/isa/isa.h"
+
+#define MAX_ISA_SERIAL_PORTS 4
+
+#define TYPE_ISA_SERIAL "isa-serial"
+void serial_hds_isa_init(ISABus *bus, int from, int to);
+void isa_serial_set_iobase(ISADevice *serial, hwaddr iobase);
+void isa_serial_set_enabled(ISADevice *serial, bool enabled);
+
+#endif
diff --git a/include/hw/char/serial-mm.h b/include/hw/char/serial-mm.h
new file mode 100644
index 0000000..62a8489
--- /dev/null
+++ b/include/hw/char/serial-mm.h
@@ -0,0 +1,52 @@
+/*
+ * QEMU 16550A UART emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2008 Citrix Systems, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef HW_SERIAL_MM_H
+#define HW_SERIAL_MM_H
+
+#include "hw/char/serial.h"
+#include "exec/memory.h"
+#include "chardev/char.h"
+#include "hw/sysbus.h"
+#include "qom/object.h"
+
+#define TYPE_SERIAL_MM "serial-mm"
+OBJECT_DECLARE_SIMPLE_TYPE(SerialMM, SERIAL_MM)
+
+struct SerialMM {
+ SysBusDevice parent;
+
+ SerialState serial;
+
+ uint8_t regshift;
+ uint8_t endianness;
+};
+
+SerialMM *serial_mm_init(MemoryRegion *address_space,
+ hwaddr base, int regshift,
+ qemu_irq irq, int baudbase,
+ Chardev *chr, enum device_endian end);
+
+#endif
diff --git a/include/hw/char/serial.h b/include/hw/char/serial.h
index 6e14099..942b372 100644
--- a/include/hw/char/serial.h
+++ b/include/hw/char/serial.h
@@ -29,8 +29,6 @@
#include "chardev/char-fe.h"
#include "exec/memory.h"
#include "qemu/fifo8.h"
-#include "chardev/char.h"
-#include "hw/sysbus.h"
#include "qom/object.h"
#define UART_FIFO_LENGTH 16 /* 16550A Fifo Length */
@@ -81,38 +79,10 @@ struct SerialState {
};
typedef struct SerialState SerialState;
-struct SerialMM {
- SysBusDevice parent;
-
- SerialState serial;
-
- uint8_t regshift;
- uint8_t endianness;
-};
-
extern const VMStateDescription vmstate_serial;
extern const MemoryRegionOps serial_io_ops;
-void serial_set_frequency(SerialState *s, uint32_t frequency);
-
#define TYPE_SERIAL "serial"
OBJECT_DECLARE_SIMPLE_TYPE(SerialState, SERIAL)
-#define TYPE_SERIAL_MM "serial-mm"
-OBJECT_DECLARE_SIMPLE_TYPE(SerialMM, SERIAL_MM)
-
-SerialMM *serial_mm_init(MemoryRegion *address_space,
- hwaddr base, int regshift,
- qemu_irq irq, int baudbase,
- Chardev *chr, enum device_endian end);
-
-/* serial-isa.c */
-
-#define MAX_ISA_SERIAL_PORTS 4
-
-#define TYPE_ISA_SERIAL "isa-serial"
-void serial_hds_isa_init(ISABus *bus, int from, int to);
-void isa_serial_set_iobase(ISADevice *serial, hwaddr iobase);
-void isa_serial_set_enabled(ISADevice *serial, bool enabled);
-
#endif
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index d946161..c3ca0ba 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -33,6 +33,7 @@
#include "qemu/bitmap.h"
#include "qemu/rcu_queue.h"
#include "qemu/queue.h"
+#include "qemu/lockcnt.h"
#include "qemu/thread.h"
#include "qom/object.h"
@@ -205,7 +206,7 @@ struct CPUClass {
* so the layout is not as critical as that of CPUTLBEntry. This is
* also why we don't want to combine the two structs.
*/
-typedef struct CPUTLBEntryFull {
+struct CPUTLBEntryFull {
/*
* @xlat_section contains:
* - in the lower TARGET_PAGE_BITS, a physical section number
@@ -261,7 +262,7 @@ typedef struct CPUTLBEntryFull {
bool guarded;
} arm;
} extra;
-} CPUTLBEntryFull;
+};
/*
* Data elements that are per MMU mode, minus the bits accessed by
@@ -350,6 +351,8 @@ typedef union IcountDecr {
* from CPUArchState, via small negative offsets.
* @can_do_io: True if memory-mapped IO is allowed.
* @plugin_mem_cbs: active plugin memory callbacks
+ * @plugin_mem_value_low: 64 lower bits of latest accessed mem value.
+ * @plugin_mem_value_high: 64 higher bits of latest accessed mem value.
*/
typedef struct CPUNegativeOffsetState {
CPUTLB tlb;
@@ -358,6 +361,8 @@ typedef struct CPUNegativeOffsetState {
* The callback pointer are accessed via TCG (see gen_empty_mem_helper).
*/
GArray *plugin_mem_cbs;
+ uint64_t plugin_mem_value_low;
+ uint64_t plugin_mem_value_high;
#endif
IcountDecr icount_decr;
bool can_do_io;
@@ -496,6 +501,7 @@ struct CPUState {
QSIMPLEQ_HEAD(, qemu_work_item) work_list;
struct CPUAddressSpace *cpu_ases;
+ int cpu_ases_count;
int num_ases;
AddressSpace *as;
MemoryRegion *memory;
diff --git a/include/hw/core/tcg-cpu-ops.h b/include/hw/core/tcg-cpu-ops.h
index 34318cf..663efb9 100644
--- a/include/hw/core/tcg-cpu-ops.h
+++ b/include/hw/core/tcg-cpu-ops.h
@@ -13,6 +13,7 @@
#include "exec/breakpoint.h"
#include "exec/hwaddr.h"
#include "exec/memattrs.h"
+#include "exec/memop.h"
#include "exec/mmu-access-type.h"
#include "exec/vaddr.h"
@@ -132,6 +133,31 @@ struct TCGCPUOps {
*/
bool (*cpu_exec_halt)(CPUState *cpu);
/**
+ * @tlb_fill_align: Handle a softmmu tlb miss
+ * @cpu: cpu context
+ * @out: output page properties
+ * @addr: virtual address
+ * @access_type: read, write or execute
+ * @mmu_idx: mmu context
+ * @memop: memory operation for the access
+ * @size: memory access size, or 0 for whole page
+ * @probe: test only, no fault
+ * @ra: host return address for exception unwind
+ *
+ * If the access is valid, fill in @out and return true.
+ * Otherwise if probe is true, return false.
+ * Otherwise raise an exception and do not return.
+ *
+ * The alignment check for the access is deferred to this hook,
+ * so that the target can determine the priority of any alignment
+ * fault with respect to other potential faults from paging.
+ * Zero may be passed for @memop to skip any alignment check
+ * for non-memory-access operations such as probing.
+ */
+ bool (*tlb_fill_align)(CPUState *cpu, CPUTLBEntryFull *out, vaddr addr,
+ MMUAccessType access_type, int mmu_idx,
+ MemOp memop, int size, bool probe, uintptr_t ra);
+ /**
* @tlb_fill: Handle a softmmu tlb miss
*
* If the access is valid, call tlb_set_page and return true;
diff --git a/include/hw/cris/etraxfs_dma.h b/include/hw/cris/etraxfs_dma.h
deleted file mode 100644
index 095d76b..0000000
--- a/include/hw/cris/etraxfs_dma.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef HW_ETRAXFS_DMA_H
-#define HW_ETRAXFS_DMA_H
-
-#include "exec/hwaddr.h"
-
-struct dma_context_metadata {
- /* data descriptor md */
- uint16_t metadata;
-};
-
-struct etraxfs_dma_client
-{
- /* DMA controller. */
- int channel;
- void *ctrl;
-
- /* client. */
- struct {
- int (*push)(void *opaque, unsigned char *buf,
- int len, bool eop);
- void (*pull)(void *opaque);
- void (*metadata_push)(void *opaque,
- const struct dma_context_metadata *md);
- void *opaque;
- } client;
-};
-
-void *etraxfs_dmac_init(hwaddr base, int nr_channels);
-void etraxfs_dmac_connect(void *opaque, int channel, qemu_irq *line,
- int input);
-void etraxfs_dmac_connect_client(void *opaque, int c,
- struct etraxfs_dma_client *cl);
-int etraxfs_dmac_input(struct etraxfs_dma_client *client,
- void *buf, int len, int eop);
-
-#endif
diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h
index 0a4fcb2..fdd0f4e 100644
--- a/include/hw/cxl/cxl_device.h
+++ b/include/hw/cxl/cxl_device.h
@@ -181,6 +181,21 @@ typedef struct CXLCCI {
uint64_t runtime;
QEMUTimer *timer;
} bg;
+
+ /* firmware update */
+ struct {
+ uint8_t active_slot;
+ uint8_t staged_slot;
+ bool slot[4];
+ uint8_t curr_action;
+ uint8_t curr_slot;
+ /* handle partial transfers */
+ bool transferring;
+ size_t prev_offset;
+ size_t prev_len;
+ time_t last_partxfer;
+ } fw;
+
size_t payload_max;
/* Pointer to device hosting the CCI */
DeviceState *d;
@@ -397,9 +412,14 @@ static inline void __toggle_media(CXLDeviceState *cxl_dstate, int val)
#define cxl_dev_enable_media(cxlds) \
do { __toggle_media((cxlds), 0x1); } while (0)
-static inline bool sanitize_running(CXLCCI *cci)
+static inline bool cxl_dev_media_disabled(CXLDeviceState *cxl_dstate)
+{
+ uint64_t dev_status_reg = cxl_dstate->mbox_reg_state64[R_CXL_MEM_DEV_STS];
+ return FIELD_EX64(dev_status_reg, CXL_MEM_DEV_STS, MEDIA_STATUS) == 0x3;
+}
+static inline bool scan_media_running(CXLCCI *cci)
{
- return !!cci->bg.runtime && cci->bg.opcode == 0x4400;
+ return !!cci->bg.runtime && cci->bg.opcode == 0x4304;
}
typedef struct CXLError {
@@ -422,6 +442,47 @@ typedef struct CXLPoison {
typedef QLIST_HEAD(, CXLPoison) CXLPoisonList;
#define CXL_POISON_LIST_LIMIT 256
+/* CXL memory device patrol scrub control attributes */
+typedef struct CXLMemPatrolScrubReadAttrs {
+ uint8_t scrub_cycle_cap;
+ uint16_t scrub_cycle;
+ uint8_t scrub_flags;
+} QEMU_PACKED CXLMemPatrolScrubReadAttrs;
+
+typedef struct CXLMemPatrolScrubWriteAttrs {
+ uint8_t scrub_cycle_hr;
+ uint8_t scrub_flags;
+} QEMU_PACKED CXLMemPatrolScrubWriteAttrs;
+
+#define CXL_MEMDEV_PS_GET_FEATURE_VERSION 0x01
+#define CXL_MEMDEV_PS_SET_FEATURE_VERSION 0x01
+#define CXL_MEMDEV_PS_SCRUB_CYCLE_CHANGE_CAP_DEFAULT BIT(0)
+#define CXL_MEMDEV_PS_SCRUB_REALTIME_REPORT_CAP_DEFAULT BIT(1)
+#define CXL_MEMDEV_PS_CUR_SCRUB_CYCLE_DEFAULT 12
+#define CXL_MEMDEV_PS_MIN_SCRUB_CYCLE_DEFAULT 1
+#define CXL_MEMDEV_PS_ENABLE_DEFAULT 0
+
+/* CXL memory device DDR5 ECS control attributes */
+typedef struct CXLMemECSReadAttrs {
+ uint8_t ecs_log_cap;
+ uint8_t ecs_cap;
+ uint16_t ecs_config;
+ uint8_t ecs_flags;
+} QEMU_PACKED CXLMemECSReadAttrs;
+
+typedef struct CXLMemECSWriteAttrs {
+ uint8_t ecs_log_cap;
+ uint16_t ecs_config;
+} QEMU_PACKED CXLMemECSWriteAttrs;
+
+#define CXL_ECS_GET_FEATURE_VERSION 0x01
+#define CXL_ECS_SET_FEATURE_VERSION 0x01
+#define CXL_ECS_LOG_ENTRY_TYPE_DEFAULT 0x01
+#define CXL_ECS_REALTIME_REPORT_CAP_DEFAULT 1
+#define CXL_ECS_THRESHOLD_COUNT_DEFAULT 3 /* 3: 256, 4: 1024, 5: 4096 */
+#define CXL_ECS_MODE_DEFAULT 0
+#define CXL_ECS_NUM_MEDIA_FRUS 3 /* Default */
+
#define DCD_MAX_NUM_REGION 8
typedef struct CXLDCExtentRaw {
@@ -459,6 +520,14 @@ typedef struct CXLDCRegion {
unsigned long *blk_bitmap;
} CXLDCRegion;
+typedef struct CXLSetFeatureInfo {
+ QemuUUID uuid;
+ uint8_t data_transfer_flag;
+ bool data_saved_across_reset;
+ uint16_t data_offset;
+ size_t data_size;
+} CXLSetFeatureInfo;
+
struct CXLType3Dev {
/* Private */
PCIDevice parent_obj;
@@ -491,6 +560,19 @@ struct CXLType3Dev {
unsigned int poison_list_cnt;
bool poison_list_overflowed;
uint64_t poison_list_overflow_ts;
+ /* Poison Injection - backup */
+ CXLPoisonList poison_list_bkp;
+ CXLPoisonList scan_media_results;
+ bool scan_media_hasrun;
+
+ CXLSetFeatureInfo set_feat_info;
+
+ /* Patrol scrub control attributes */
+ CXLMemPatrolScrubReadAttrs patrol_scrub_attrs;
+ CXLMemPatrolScrubWriteAttrs patrol_scrub_wr_attrs;
+ /* ECS control attributes */
+ CXLMemECSReadAttrs ecs_attrs[CXL_ECS_NUM_MEDIA_FRUS];
+ CXLMemECSWriteAttrs ecs_wr_attrs[CXL_ECS_NUM_MEDIA_FRUS];
struct dynamic_capacity {
HostMemoryBackend *host_dc;
@@ -554,10 +636,12 @@ CXLRetCode cxl_event_get_records(CXLDeviceState *cxlds, CXLGetEventPayload *pl,
size_t *len);
CXLRetCode cxl_event_clear_records(CXLDeviceState *cxlds,
CXLClearEventPayload *pl);
+void cxl_discard_all_event_records(CXLDeviceState *cxlds);
void cxl_event_irq_assert(CXLType3Dev *ct3d);
void cxl_set_poison_list_overflowed(CXLType3Dev *ct3d);
+void cxl_clear_poison_list_overflowed(CXLType3Dev *ct3d);
CXLDCRegion *cxl_find_dc_region(CXLType3Dev *ct3d, uint64_t dpa, uint64_t len);
diff --git a/include/hw/cxl/cxl_mailbox.h b/include/hw/cxl/cxl_mailbox.h
new file mode 100644
index 0000000..beb0480
--- /dev/null
+++ b/include/hw/cxl/cxl_mailbox.h
@@ -0,0 +1,18 @@
+/*
+ * QEMU CXL Mailbox
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See the
+ * COPYING file in the top-level directory.
+ */
+
+#ifndef CXL_MAILBOX_H
+#define CXL_MAILBOX_H
+
+#define CXL_MBOX_IMMEDIATE_CONFIG_CHANGE (1 << 1)
+#define CXL_MBOX_IMMEDIATE_DATA_CHANGE (1 << 2)
+#define CXL_MBOX_IMMEDIATE_POLICY_CHANGE (1 << 3)
+#define CXL_MBOX_IMMEDIATE_LOG_CHANGE (1 << 4)
+#define CXL_MBOX_SECURITY_STATE_CHANGE (1 << 5)
+#define CXL_MBOX_BACKGROUND_OPERATION (1 << 6)
+
+#endif
diff --git a/include/hw/display/blizzard.h b/include/hw/display/blizzard.h
deleted file mode 100644
index 5b33018..0000000
--- a/include/hw/display/blizzard.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Epson S1D13744/S1D13745 (Blizzard/Hailstorm/Tornado) LCD/TV controller.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#ifndef HW_DISPLAY_BLIZZARD_H
-#define HW_DISPLAY_BLIZZARD_H
-
-
-void *s1d13745_init(qemu_irq gpio_int);
-void s1d13745_write(void *opaque, int dc, uint16_t value);
-void s1d13745_write_block(void *opaque, int dc,
- void *buf, size_t len, int pitch);
-uint16_t s1d13745_read(void *opaque, int dc);
-
-#endif
diff --git a/include/hw/display/tc6393xb.h b/include/hw/display/tc6393xb.h
deleted file mode 100644
index f9263bf..0000000
--- a/include/hw/display/tc6393xb.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Toshiba TC6393XB I/O Controller.
- * Found in Sharp Zaurus SL-6000 (tosa) or some
- * Toshiba e-Series PDAs.
- *
- * Copyright (c) 2007 HervƩ Poussineau
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#ifndef HW_DISPLAY_TC6393XB_H
-#define HW_DISPLAY_TC6393XB_H
-
-typedef struct TC6393xbState TC6393xbState;
-
-TC6393xbState *tc6393xb_init(struct MemoryRegion *sysmem,
- uint32_t base, qemu_irq irq);
-qemu_irq tc6393xb_l3v_get(TC6393xbState *s);
-
-#endif
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 90a12ae..e1e6c54 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -76,6 +76,8 @@ struct AspeedGPIOClass {
uint32_t nr_gpio_sets;
const AspeedGPIOReg *reg_table;
unsigned reg_table_count;
+ uint64_t mem_size;
+ const MemoryRegionOps *reg_ops;
};
struct AspeedGPIOState {
@@ -88,7 +90,7 @@ struct AspeedGPIOState {
qemu_irq irq;
qemu_irq gpios[ASPEED_GPIO_MAX_NR_SETS][ASPEED_GPIOS_PER_SET];
-/* Parallel GPIO Registers */
+ /* Parallel GPIO Registers */
uint32_t debounce_regs[ASPEED_GPIO_NR_DEBOUNCE_REGS];
struct GPIOSets {
uint32_t data_value; /* Reflects pin values */
diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
index a064479..2c4c81b 100644
--- a/include/hw/i2c/aspeed_i2c.h
+++ b/include/hw/i2c/aspeed_i2c.h
@@ -31,12 +31,14 @@
#define TYPE_ASPEED_2500_I2C TYPE_ASPEED_I2C "-ast2500"
#define TYPE_ASPEED_2600_I2C TYPE_ASPEED_I2C "-ast2600"
#define TYPE_ASPEED_1030_I2C TYPE_ASPEED_I2C "-ast1030"
+#define TYPE_ASPEED_2700_I2C TYPE_ASPEED_I2C "-ast2700"
OBJECT_DECLARE_TYPE(AspeedI2CState, AspeedI2CClass, ASPEED_I2C)
#define ASPEED_I2C_NR_BUSSES 16
-#define ASPEED_I2C_MAX_POOL_SIZE 0x800
+#define ASPEED_I2C_SHARE_POOL_SIZE 0x800
+#define ASPEED_I2C_BUS_POOL_SIZE 0x20
#define ASPEED_I2C_OLD_NUM_REG 11
-#define ASPEED_I2C_NEW_NUM_REG 22
+#define ASPEED_I2C_NEW_NUM_REG 28
#define A_I2CD_M_STOP_CMD BIT(5)
#define A_I2CD_M_RX_CMD BIT(3)
@@ -225,6 +227,15 @@ REG32(I2CS_DMA_LEN_STS, 0x4c)
FIELD(I2CS_DMA_LEN_STS, TX_LEN, 0, 13)
REG32(I2CC_DMA_ADDR, 0x50)
REG32(I2CC_DMA_LEN, 0x54)
+/* DMA 64bits */
+REG32(I2CM_DMA_TX_ADDR_HI, 0x60)
+ FIELD(I2CM_DMA_TX_ADDR_HI, ADDR_HI, 0, 7)
+REG32(I2CM_DMA_RX_ADDR_HI, 0x64)
+ FIELD(I2CM_DMA_RX_ADDR_HI, ADDR_HI, 0, 7)
+REG32(I2CS_DMA_TX_ADDR_HI, 0x68)
+ FIELD(I2CS_DMA_TX_ADDR_HI, ADDR_HI, 0, 7)
+REG32(I2CS_DMA_RX_ADDR_HI, 0x6c)
+ FIELD(I2CS_DMA_RX_ADDR_HI, ADDR_HI, 0, 7)
struct AspeedI2CState;
@@ -239,12 +250,15 @@ struct AspeedI2CBus {
I2CSlave *slave;
MemoryRegion mr;
+ MemoryRegion mr_pool;
I2CBus *bus;
uint8_t id;
qemu_irq irq;
uint32_t regs[ASPEED_I2C_NEW_NUM_REG];
+ uint8_t pool[ASPEED_I2C_BUS_POOL_SIZE];
+ uint64_t dma_dram_offset;
};
struct AspeedI2CState {
@@ -257,7 +271,7 @@ struct AspeedI2CState {
uint32_t ctrl_global;
uint32_t new_clk_divider;
MemoryRegion pool_iomem;
- uint8_t pool[ASPEED_I2C_MAX_POOL_SIZE];
+ uint8_t share_pool[ASPEED_I2C_SHARE_POOL_SIZE];
AspeedI2CBus busses[ASPEED_I2C_NR_BUSSES];
MemoryRegion *dram_mr;
@@ -275,15 +289,19 @@ struct AspeedI2CClass {
uint8_t num_busses;
uint8_t reg_size;
+ uint32_t reg_gap_size;
uint8_t gap;
qemu_irq (*bus_get_irq)(AspeedI2CBus *);
uint64_t pool_size;
hwaddr pool_base;
+ uint32_t pool_gap_size;
uint8_t *(*bus_pool_base)(AspeedI2CBus *);
bool check_sram;
bool has_dma;
-
+ bool has_share_pool;
+ uint64_t mem_size;
+ bool has_dma64;
};
static inline bool aspeed_i2c_is_new_mode(AspeedI2CState *s)
@@ -363,14 +381,6 @@ static inline uint32_t aspeed_i2c_bus_dma_len_offset(AspeedI2CBus *bus)
return R_I2CD_DMA_LEN;
}
-static inline uint32_t aspeed_i2c_bus_dma_addr_offset(AspeedI2CBus *bus)
-{
- if (aspeed_i2c_is_new_mode(bus->controller)) {
- return R_I2CC_DMA_ADDR;
- }
- return R_I2CD_DMA_ADDR;
-}
-
static inline bool aspeed_i2c_bus_is_master(AspeedI2CBus *bus)
{
return SHARED_ARRAY_FIELD_EX32(bus->regs, aspeed_i2c_bus_ctrl_offset(bus),
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 4e55d7e..14ee062 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -215,6 +215,9 @@ void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size);
/* sgx.c */
void pc_machine_init_sgx_epc(PCMachineState *pcms);
+extern GlobalProperty pc_compat_9_1[];
+extern const size_t pc_compat_9_1_len;
+
extern GlobalProperty pc_compat_9_0[];
extern const size_t pc_compat_9_0_len;
diff --git a/include/hw/i386/sgx-epc.h b/include/hw/i386/sgx-epc.h
index 3e00efd..41d55da 100644
--- a/include/hw/i386/sgx-epc.h
+++ b/include/hw/i386/sgx-epc.h
@@ -58,6 +58,7 @@ typedef struct SGXEPCState {
int nr_sections;
} SGXEPCState;
+bool check_sgx_support(void);
bool sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size);
void sgx_epc_build_srat(GArray *table_data);
diff --git a/include/hw/input/lm832x.h b/include/hw/input/lm832x.h
deleted file mode 100644
index e0e5d5e..0000000
--- a/include/hw/input/lm832x.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * National Semiconductor LM8322/8323 GPIO keyboard & PWM chips.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef HW_INPUT_LM832X_H
-#define HW_INPUT_LM832X_H
-
-#define TYPE_LM8323 "lm8323"
-
-void lm832x_key_event(DeviceState *dev, int key, int state);
-
-#endif
diff --git a/include/hw/input/tsc2xxx.h b/include/hw/input/tsc2xxx.h
deleted file mode 100644
index 00eca17..0000000
--- a/include/hw/input/tsc2xxx.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * TI touchscreen controller
- *
- * Copyright (c) 2006 Andrzej Zaborowski
- * Copyright (C) 2008 Nokia Corporation
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#ifndef HW_INPUT_TSC2XXX_H
-#define HW_INPUT_TSC2XXX_H
-
-typedef struct MouseTransformInfo {
- /* Touchscreen resolution */
- int x;
- int y;
- /* Calibration values as used/generated by tslib */
- int a[7];
-} MouseTransformInfo;
-
-typedef struct uWireSlave {
- uint16_t (*receive)(void *opaque);
- void (*send)(void *opaque, uint16_t data);
- void *opaque;
-} uWireSlave;
-
-/* tsc210x.c */
-uWireSlave *tsc2102_init(qemu_irq pint);
-uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav);
-I2SCodec *tsc210x_codec(uWireSlave *chip);
-uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len);
-void tsc210x_set_transform(uWireSlave *chip, const MouseTransformInfo *info);
-void tsc210x_key_event(uWireSlave *chip, int key, int down);
-
-/* tsc2005.c */
-void *tsc2005_init(qemu_irq pintdav);
-uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len);
-void tsc2005_set_transform(void *opaque, const MouseTransformInfo *info);
-
-#endif
diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h
index eccc2e0..626a37d 100644
--- a/include/hw/intc/loongarch_extioi.h
+++ b/include/hw/intc/loongarch_extioi.h
@@ -50,7 +50,6 @@
#define EXTIOI_HAS_CPU_ENCODE (3)
#define EXTIOI_VIRT_HAS_FEATURES (BIT(EXTIOI_HAS_VIRT_EXTENSION) \
| BIT(EXTIOI_HAS_ENABLE_OPTION) \
- | BIT(EXTIOI_HAS_INT_ENCODE) \
| BIT(EXTIOI_HAS_CPU_ENCODE))
#define EXTIOI_VIRT_CONFIG (0x4)
#define EXTIOI_ENABLE (1)
diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
new file mode 100644
index 0000000..276b304
--- /dev/null
+++ b/include/hw/intc/loongarch_ipi.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch IPI interrupt header files
+ *
+ * Copyright (C) 2024 Loongson Technology Corporation Limited
+ */
+
+#ifndef HW_LOONGARCH_IPI_H
+#define HW_LOONGARCH_IPI_H
+
+#include "qom/object.h"
+#include "hw/intc/loongson_ipi_common.h"
+
+#define TYPE_LOONGARCH_IPI "loongarch_ipi"
+OBJECT_DECLARE_TYPE(LoongarchIPIState, LoongarchIPIClass, LOONGARCH_IPI)
+
+struct LoongarchIPIState {
+ LoongsonIPICommonState parent_obj;
+};
+
+struct LoongarchIPIClass {
+ LoongsonIPICommonClass parent_class;
+};
+
+#endif
diff --git a/include/hw/intc/loongson_ipi.h b/include/hw/intc/loongson_ipi.h
index 3f795ed..4e517cc 100644
--- a/include/hw/intc/loongson_ipi.h
+++ b/include/hw/intc/loongson_ipi.h
@@ -8,49 +8,24 @@
#ifndef HW_LOONGSON_IPI_H
#define HW_LOONGSON_IPI_H
+#include "qom/object.h"
+#include "hw/intc/loongson_ipi_common.h"
#include "hw/sysbus.h"
-/* Mainy used by iocsr read and write */
-#define SMP_IPI_MAILBOX 0x1000ULL
-#define CORE_STATUS_OFF 0x0
-#define CORE_EN_OFF 0x4
-#define CORE_SET_OFF 0x8
-#define CORE_CLEAR_OFF 0xc
-#define CORE_BUF_20 0x20
-#define CORE_BUF_28 0x28
-#define CORE_BUF_30 0x30
-#define CORE_BUF_38 0x38
-#define IOCSR_IPI_SEND 0x40
-#define IOCSR_MAIL_SEND 0x48
-#define IOCSR_ANY_SEND 0x158
-
-#define MAIL_SEND_ADDR (SMP_IPI_MAILBOX + IOCSR_MAIL_SEND)
-#define MAIL_SEND_OFFSET 0
-#define ANY_SEND_OFFSET (IOCSR_ANY_SEND - IOCSR_MAIL_SEND)
-
-#define IPI_MBX_NUM 4
-
#define TYPE_LOONGSON_IPI "loongson_ipi"
-OBJECT_DECLARE_SIMPLE_TYPE(LoongsonIPI, LOONGSON_IPI)
+OBJECT_DECLARE_TYPE(LoongsonIPIState, LoongsonIPIClass, LOONGSON_IPI)
+
+struct LoongsonIPIClass {
+ LoongsonIPICommonClass parent_class;
+
+ DeviceRealize parent_realize;
+ DeviceUnrealize parent_unrealize;
+};
+
+struct LoongsonIPIState {
+ LoongsonIPICommonState parent_obj;
-typedef struct IPICore {
- LoongsonIPI *ipi;
MemoryRegion *ipi_mmio_mem;
- uint32_t status;
- uint32_t en;
- uint32_t set;
- uint32_t clear;
- /* 64bit buf divide into 2 32bit buf */
- uint32_t buf[IPI_MBX_NUM * 2];
- qemu_irq irq;
-} IPICore;
-
-struct LoongsonIPI {
- SysBusDevice parent_obj;
- MemoryRegion ipi_iocsr_mem;
- MemoryRegion ipi64_iocsr_mem;
- uint32_t num_cpu;
- IPICore *cpu;
};
#endif
diff --git a/include/hw/intc/loongson_ipi_common.h b/include/hw/intc/loongson_ipi_common.h
new file mode 100644
index 0000000..df9d9c5
--- /dev/null
+++ b/include/hw/intc/loongson_ipi_common.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Loongson ipi interrupt header files
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#ifndef HW_LOONGSON_IPI_COMMON_H
+#define HW_LOONGSON_IPI_COMMON_H
+
+#include "qom/object.h"
+#include "hw/sysbus.h"
+#include "exec/memattrs.h"
+
+#define IPI_MBX_NUM 4
+
+#define TYPE_LOONGSON_IPI_COMMON "loongson_ipi_common"
+OBJECT_DECLARE_TYPE(LoongsonIPICommonState,
+ LoongsonIPICommonClass, LOONGSON_IPI_COMMON)
+
+typedef struct IPICore {
+ LoongsonIPICommonState *ipi;
+ uint32_t status;
+ uint32_t en;
+ uint32_t set;
+ uint32_t clear;
+ /* 64bit buf divide into 2 32-bit buf */
+ uint32_t buf[IPI_MBX_NUM * 2];
+ qemu_irq irq;
+} IPICore;
+
+struct LoongsonIPICommonState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion ipi_iocsr_mem;
+ MemoryRegion ipi64_iocsr_mem;
+ uint32_t num_cpu;
+ IPICore *cpu;
+};
+
+struct LoongsonIPICommonClass {
+ SysBusDeviceClass parent_class;
+
+ DeviceRealize parent_realize;
+ DeviceUnrealize parent_unrealize;
+ AddressSpace *(*get_iocsr_as)(CPUState *cpu);
+ CPUState *(*cpu_by_arch_id)(int64_t id);
+};
+
+MemTxResult loongson_ipi_core_readl(void *opaque, hwaddr addr, uint64_t *data,
+ unsigned size, MemTxAttrs attrs);
+MemTxResult loongson_ipi_core_writel(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size, MemTxAttrs attrs);
+
+/* Mainy used by iocsr read and write */
+#define SMP_IPI_MAILBOX 0x1000ULL
+
+#define CORE_STATUS_OFF 0x0
+#define CORE_EN_OFF 0x4
+#define CORE_SET_OFF 0x8
+#define CORE_CLEAR_OFF 0xc
+#define CORE_BUF_20 0x20
+#define CORE_BUF_28 0x28
+#define CORE_BUF_30 0x30
+#define CORE_BUF_38 0x38
+#define IOCSR_IPI_SEND 0x40
+#define IOCSR_MAIL_SEND 0x48
+#define IOCSR_ANY_SEND 0x158
+
+#define MAIL_SEND_ADDR (SMP_IPI_MAILBOX + IOCSR_MAIL_SEND)
+#define MAIL_SEND_OFFSET 0
+#define ANY_SEND_OFFSET (IOCSR_ANY_SEND - IOCSR_MAIL_SEND)
+
+#endif
diff --git a/include/hw/irq.h b/include/hw/irq.h
index 645b73d..c861c1d 100644
--- a/include/hw/irq.h
+++ b/include/hw/irq.h
@@ -1,9 +1,20 @@
#ifndef QEMU_IRQ_H
#define QEMU_IRQ_H
+#include "qom/object.h"
+
/* Generic IRQ/GPIO pin infrastructure. */
#define TYPE_IRQ "irq"
+OBJECT_DECLARE_SIMPLE_TYPE(IRQState, IRQ)
+
+struct IRQState {
+ Object parent_obj;
+
+ qemu_irq_handler handler;
+ void *opaque;
+ int n;
+};
void qemu_set_irq(qemu_irq irq, int level);
@@ -23,6 +34,13 @@ static inline void qemu_irq_pulse(qemu_irq irq)
qemu_set_irq(irq, 0);
}
+/*
+ * Init a single IRQ. The irq is assigned with a handler, an opaque data
+ * and the interrupt number.
+ */
+void qemu_init_irq(IRQState *irq, qemu_irq_handler handler, void *opaque,
+ int n);
+
/* Returns an array of N IRQs. Each IRQ is assigned the argument handler and
* opaque data.
*/
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 8fdfacf..9ba4779 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -8,10 +8,8 @@
#ifndef HW_LOONGARCH_H
#define HW_LOONGARCH_H
-#include "target/loongarch/cpu.h"
#include "hw/boards.h"
#include "qemu/queue.h"
-#include "hw/intc/loongson_ipi.h"
#include "hw/block/flash.h"
#include "hw/loongarch/boot.h"
@@ -20,7 +18,7 @@
#define VIRT_FWCFG_BASE 0x1e020000UL
#define VIRT_BIOS_BASE 0x1c000000UL
#define VIRT_BIOS_SIZE (16 * MiB)
-#define VIRT_FLASH_SECTOR_SIZE (128 * KiB)
+#define VIRT_FLASH_SECTOR_SIZE (256 * KiB)
#define VIRT_FLASH0_BASE VIRT_BIOS_BASE
#define VIRT_FLASH0_SIZE VIRT_BIOS_SIZE
#define VIRT_FLASH1_BASE 0x1d000000UL
diff --git a/include/hw/mips/cps.h b/include/hw/mips/cps.h
index 04d6362..05ef9f7 100644
--- a/include/hw/mips/cps.h
+++ b/include/hw/mips/cps.h
@@ -38,6 +38,7 @@ struct MIPSCPSState {
uint32_t num_vp;
uint32_t num_irq;
char *cpu_type;
+ bool cpu_is_bigendian;
MemoryRegion container;
MIPSGCRState gcr;
diff --git a/include/hw/misc/aspeed_hace.h b/include/hw/misc/aspeed_hace.h
index ecb1b67..4af9919 100644
--- a/include/hw/misc/aspeed_hace.h
+++ b/include/hw/misc/aspeed_hace.h
@@ -1,6 +1,7 @@
/*
* ASPEED Hash and Crypto Engine
*
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
* Copyright (C) 2021 IBM Corp.
*
* SPDX-License-Identifier: GPL-2.0-or-later
@@ -10,6 +11,7 @@
#define ASPEED_HACE_H
#include "hw/sysbus.h"
+#include "crypto/hash.h"
#define TYPE_ASPEED_HACE "aspeed.hace"
#define TYPE_ASPEED_AST2400_HACE TYPE_ASPEED_HACE "-ast2400"
@@ -35,6 +37,8 @@ struct AspeedHACEState {
MemoryRegion *dram_mr;
AddressSpace dram_as;
+
+ QCryptoHash *hash_ctx;
};
diff --git a/include/hw/misc/aspeed_scu.h b/include/hw/misc/aspeed_scu.h
index 58db28d..356be95 100644
--- a/include/hw/misc/aspeed_scu.h
+++ b/include/hw/misc/aspeed_scu.h
@@ -349,6 +349,10 @@ uint32_t aspeed_scu_get_apb_freq(AspeedSCUState *s);
#define SCU_AST2600_H_PLL_BYPASS_EN (0x1 << 24)
#define SCU_AST2600_H_PLL_OFF (0x1 << 23)
+/* STRAP1 SCU500 */
+#define SCU_AST2600_HW_STRAP_BOOT_SRC_EMMC (0x1 << 2)
+#define SCU_AST2600_HW_STRAP_BOOT_SRC_SPI (0x0 << 2)
+
/*
* SCU310 Clock Selection Register Set 4 (for Aspeed AST1030 SOC)
*
diff --git a/include/hw/misc/cbus.h b/include/hw/misc/cbus.h
deleted file mode 100644
index 5334984..0000000
--- a/include/hw/misc/cbus.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * CBUS three-pin bus and the Retu / Betty / Tahvo / Vilma / Avilma /
- * Hinku / Vinku / Ahne / Pihi chips used in various Nokia platforms.
- * Based on reverse-engineering of a linux driver.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#ifndef HW_MISC_CBUS_H
-#define HW_MISC_CBUS_H
-
-
-typedef struct {
- qemu_irq clk;
- qemu_irq dat;
- qemu_irq sel;
-} CBus;
-
-CBus *cbus_init(qemu_irq dat_out);
-void cbus_attach(CBus *bus, void *slave_opaque);
-
-void *retu_init(qemu_irq irq, int vilma);
-void *tahvo_init(qemu_irq irq, int betty);
-
-void retu_key_event(void *retu, int state);
-
-#endif
diff --git a/include/hw/misc/stm32_rcc.h b/include/hw/misc/stm32_rcc.h
new file mode 100644
index 0000000..ffbdf20
--- /dev/null
+++ b/include/hw/misc/stm32_rcc.h
@@ -0,0 +1,91 @@
+/*
+ * STM32 RCC (only reset and enable registers are implemented)
+ *
+ * Copyright (c) 2024 RomƔn CƔrdenas <rcardenas.rod@gmail.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_STM32_RCC_H
+#define HW_STM32_RCC_H
+
+#include "hw/sysbus.h"
+#include "qom/object.h"
+
+#define STM32_RCC_CR 0x00
+#define STM32_RCC_PLL_CFGR 0x04
+#define STM32_RCC_CFGR 0x08
+#define STM32_RCC_CIR 0x0C
+#define STM32_RCC_AHB1_RSTR 0x10
+#define STM32_RCC_AHB2_RSTR 0x14
+#define STM32_RCC_AHB3_RSTR 0x18
+
+#define STM32_RCC_APB1_RSTR 0x20
+#define STM32_RCC_APB2_RSTR 0x24
+
+#define STM32_RCC_AHB1_ENR 0x30
+#define STM32_RCC_AHB2_ENR 0x34
+#define STM32_RCC_AHB3_ENR 0x38
+
+#define STM32_RCC_APB1_ENR 0x40
+#define STM32_RCC_APB2_ENR 0x44
+
+#define STM32_RCC_AHB1_LPENR 0x50
+#define STM32_RCC_AHB2_LPENR 0x54
+#define STM32_RCC_AHB3_LPENR 0x58
+
+#define STM32_RCC_APB1_LPENR 0x60
+#define STM32_RCC_APB2_LPENR 0x64
+
+#define STM32_RCC_BDCR 0x70
+#define STM32_RCC_CSR 0x74
+
+#define STM32_RCC_SSCGR 0x80
+#define STM32_RCC_PLLI2SCFGR 0x84
+#define STM32_RCC_PLLSAI_CFGR 0x88
+#define STM32_RCC_DCKCFGR 0x8C
+#define STM32_RCC_CKGATENR 0x90
+#define STM32_RCC_DCKCFGR2 0x94
+
+#define STM32_RCC_NREGS ((STM32_RCC_DCKCFGR2 >> 2) + 1)
+#define STM32_RCC_PERIPHERAL_SIZE 0x400
+#define STM32_RCC_NIRQS (32 * 5) /* 32 bits per reg, 5 en/rst regs */
+
+#define STM32_RCC_GPIO_IRQ_OFFSET 0
+
+#define TYPE_STM32_RCC "stm32.rcc"
+
+typedef struct STM32RccState STM32RccState;
+
+DECLARE_INSTANCE_CHECKER(STM32RccState, STM32_RCC, TYPE_STM32_RCC)
+
+#define NUM_GPIO_EVENT_IN_LINES 16
+
+struct STM32RccState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion mmio;
+
+ uint32_t regs[STM32_RCC_NREGS];
+
+ qemu_irq enable_irq[STM32_RCC_NIRQS];
+ qemu_irq reset_irq[STM32_RCC_NIRQS];
+};
+
+#endif /* HW_STM32_RCC_H */
diff --git a/include/hw/misc/stm32l4x5_syscfg.h b/include/hw/misc/stm32l4x5_syscfg.h
index 23bb564..c450df2 100644
--- a/include/hw/misc/stm32l4x5_syscfg.h
+++ b/include/hw/misc/stm32l4x5_syscfg.h
@@ -48,6 +48,7 @@ struct Stm32l4x5SyscfgState {
uint32_t swpr2;
qemu_irq gpio_out[GPIO_NUM_PINS];
+ Clock *clk;
};
#endif
diff --git a/include/hw/misc/xlnx-versal-trng.h b/include/hw/misc/xlnx-versal-trng.h
index 0bcef8a..d96f8f9 100644
--- a/include/hw/misc/xlnx-versal-trng.h
+++ b/include/hw/misc/xlnx-versal-trng.h
@@ -50,6 +50,7 @@ typedef struct XlnxVersalTRng {
uint64_t forced_prng_count;
uint64_t tst_seed[2];
+ RegisterInfoArray *reg_array;
uint32_t regs[RMAX_XLNX_VERSAL_TRNG];
RegisterInfo regs_info[RMAX_XLNX_VERSAL_TRNG];
} XlnxVersalTRng;
diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
index d173998..fa42677 100644
--- a/include/hw/nvram/fw_cfg.h
+++ b/include/hw/nvram/fw_cfg.h
@@ -321,7 +321,6 @@ void fw_cfg_add_extra_pci_roots(PCIBus *bus, FWCfgState *s);
FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
AddressSpace *dma_as);
-FWCfgState *fw_cfg_init_io(uint32_t iobase);
FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr);
FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
hwaddr data_addr, uint32_t data_width,
diff --git a/include/hw/nvram/fw_cfg_acpi.h b/include/hw/nvram/fw_cfg_acpi.h
index b39eb04..dfd2a44 100644
--- a/include/hw/nvram/fw_cfg_acpi.h
+++ b/include/hw/nvram/fw_cfg_acpi.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* ACPI support for fw_cfg
*
diff --git a/include/hw/nvram/xlnx-bbram.h b/include/hw/nvram/xlnx-bbram.h
index 6fc13f8..bce8e89 100644
--- a/include/hw/nvram/xlnx-bbram.h
+++ b/include/hw/nvram/xlnx-bbram.h
@@ -47,6 +47,7 @@ struct XlnxBBRam {
bool bbram8_wo;
bool blk_ro;
+ RegisterInfoArray *reg_array;
uint32_t regs[RMAX_XLNX_BBRAM];
RegisterInfo regs_info[RMAX_XLNX_BBRAM];
};
diff --git a/include/hw/nvram/xlnx-versal-efuse.h b/include/hw/nvram/xlnx-versal-efuse.h
index 86e2261..afa4f4f 100644
--- a/include/hw/nvram/xlnx-versal-efuse.h
+++ b/include/hw/nvram/xlnx-versal-efuse.h
@@ -44,6 +44,7 @@ struct XlnxVersalEFuseCtrl {
void *extra_pg0_lock_spec; /* Opaque property */
uint32_t extra_pg0_lock_n16;
+ RegisterInfoArray *reg_array;
uint32_t regs[XLNX_VERSAL_EFUSE_CTRL_R_MAX];
RegisterInfo regs_info[XLNX_VERSAL_EFUSE_CTRL_R_MAX];
};
diff --git a/include/hw/nvram/xlnx-zynqmp-efuse.h b/include/hw/nvram/xlnx-zynqmp-efuse.h
index f5beacc..7fb12df 100644
--- a/include/hw/nvram/xlnx-zynqmp-efuse.h
+++ b/include/hw/nvram/xlnx-zynqmp-efuse.h
@@ -37,6 +37,7 @@ struct XlnxZynqMPEFuse {
qemu_irq irq;
XlnxEFuse *efuse;
+ RegisterInfoArray *reg_array;
uint32_t regs[XLNX_ZYNQMP_EFUSE_R_MAX];
RegisterInfo regs_info[XLNX_ZYNQMP_EFUSE_R_MAX];
};
diff --git a/include/hw/pci-host/designware.h b/include/hw/pci-host/designware.h
index 908f3d9..c484e37 100644
--- a/include/hw/pci-host/designware.h
+++ b/include/hw/pci-host/designware.h
@@ -31,8 +31,6 @@ OBJECT_DECLARE_SIMPLE_TYPE(DesignwarePCIEHost, DESIGNWARE_PCIE_HOST)
#define TYPE_DESIGNWARE_PCIE_ROOT "designware-pcie-root"
OBJECT_DECLARE_SIMPLE_TYPE(DesignwarePCIERoot, DESIGNWARE_PCIE_ROOT)
-struct DesignwarePCIERoot;
-
typedef struct DesignwarePCIEViewport {
DesignwarePCIERoot *root;
diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
index cd7c9ec..79d4ea8 100644
--- a/include/hw/pci-host/ls7a.h
+++ b/include/hw/pci-host/ls7a.h
@@ -36,17 +36,18 @@
#define VIRT_PCH_PIC_IRQ_NUM 32
#define VIRT_GSI_BASE 64
#define VIRT_DEVICE_IRQS 16
+#define VIRT_UART_COUNT 4
#define VIRT_UART_IRQ (VIRT_GSI_BASE + 2)
#define VIRT_UART_BASE 0x1fe001e0
-#define VIRT_UART_SIZE 0X100
-#define VIRT_RTC_IRQ (VIRT_GSI_BASE + 3)
+#define VIRT_UART_SIZE 0x100
+#define VIRT_RTC_IRQ (VIRT_GSI_BASE + 6)
#define VIRT_MISC_REG_BASE (VIRT_PCH_REG_BASE + 0x00080000)
#define VIRT_RTC_REG_BASE (VIRT_MISC_REG_BASE + 0x00050100)
#define VIRT_RTC_LEN 0x100
-#define VIRT_SCI_IRQ (VIRT_GSI_BASE + 4)
+#define VIRT_SCI_IRQ (VIRT_GSI_BASE + 7)
#define VIRT_PLATFORM_BUS_BASEADDRESS 0x16000000
#define VIRT_PLATFORM_BUS_SIZE 0x2000000
#define VIRT_PLATFORM_BUS_NUM_IRQS 2
-#define VIRT_PLATFORM_BUS_IRQ (VIRT_GSI_BASE + 5)
+#define VIRT_PLATFORM_BUS_IRQ (VIRT_GSI_BASE + 8)
#endif
diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h
index 22fadfa..ddafc3f 100644
--- a/include/hw/pci-host/q35.h
+++ b/include/hw/pci-host/q35.h
@@ -181,8 +181,6 @@ struct Q35PCIHost {
#define MCH_PCIE_DEV 1
#define MCH_PCIE_FUNC 0
-uint64_t mch_mcfg_base(void);
-
/*
* Arbitrary but unique BNF number for IOAPIC device.
*
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index 14a869e..eb26cac 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -678,6 +678,6 @@ static inline void pci_irq_pulse(PCIDevice *pci_dev)
}
MSIMessage pci_get_msi_message(PCIDevice *dev, int vector);
-void pci_set_enabled(PCIDevice *pci_dev, bool state);
+void pci_set_power(PCIDevice *pci_dev, bool state);
#endif
diff --git a/include/hw/pci/pci_device.h b/include/hw/pci/pci_device.h
index ca15132..91df40f 100644
--- a/include/hw/pci/pci_device.h
+++ b/include/hw/pci/pci_device.h
@@ -3,6 +3,7 @@
#include "hw/pci/pci.h"
#include "hw/pci/pcie.h"
+#include "hw/pci/pcie_doe.h"
#define TYPE_PCI_DEVICE "pci-device"
typedef struct PCIDeviceClass PCIDeviceClass;
@@ -56,7 +57,7 @@ typedef struct PCIReqIDCache PCIReqIDCache;
struct PCIDevice {
DeviceState qdev;
bool partially_hotplugged;
- bool enabled;
+ bool has_power;
/* PCI config space */
uint8_t *config;
@@ -157,9 +158,18 @@ struct PCIDevice {
MSIVectorReleaseNotifier msix_vector_release_notifier;
MSIVectorPollNotifier msix_vector_poll_notifier;
+ /* SPDM */
+ uint16_t spdm_port;
+
+ /* DOE */
+ DOECap doe_spdm;
+
/* ID of standby device in net_failover pair */
char *failover_pair_id;
uint32_t acpi_index;
+
+ /* Maximum DMA bounce buffer size used for indirect memory map requests */
+ uint32_t max_bounce_buffer_size;
};
static inline int pci_intx(PCIDevice *pci_dev)
@@ -205,21 +215,6 @@ static inline uint16_t pci_get_bdf(PCIDevice *dev)
return PCI_BUILD_BDF(pci_bus_num(pci_get_bus(dev)), dev->devfn);
}
-static inline void pci_set_power(PCIDevice *pci_dev, bool state)
-{
- /*
- * Don't change the enabled state of VFs when powering on/off the device.
- *
- * When powering on, VFs must not be enabled immediately but they must
- * wait until the guest configures SR-IOV.
- * When powering off, their corresponding PFs will be reset and disable
- * VFs.
- */
- if (!pci_is_vf(pci_dev)) {
- pci_set_enabled(pci_dev, state);
- }
-}
-
uint16_t pci_requester_id(PCIDevice *dev);
/* DMA access functions */
diff --git a/include/hw/pci/pcie_doe.h b/include/hw/pci/pcie_doe.h
index 87dc17d..9e1275d 100644
--- a/include/hw/pci/pcie_doe.h
+++ b/include/hw/pci/pcie_doe.h
@@ -46,6 +46,8 @@ REG32(PCI_DOE_CAP_STATUS, 0)
/* PCI-SIG defined Data Object Types - r6.0 Table 6-32 */
#define PCI_SIG_DOE_DISCOVERY 0x00
+#define PCI_SIG_DOE_CMA 0x01
+#define PCI_SIG_DOE_SECURED_CMA 0x02
#define PCI_DOE_DW_SIZE_MAX (1 << 18)
#define PCI_DOE_PROTOCOL_NUM_MAX 256
@@ -106,6 +108,9 @@ struct DOECap {
/* Protocols and its callback response */
DOEProtocol *protocols;
uint16_t protocol_num;
+
+ /* Used for spdm-socket */
+ int spdm_socket;
};
void pcie_doe_init(PCIDevice *pdev, DOECap *doe_cap, uint16_t offset,
diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h
index 90e6cf4..7cd7af8 100644
--- a/include/hw/pci/pcie_port.h
+++ b/include/hw/pci/pcie_port.h
@@ -72,7 +72,6 @@ struct PCIESlot {
};
void pcie_chassis_create(uint8_t chassis_number);
-PCIESlot *pcie_chassis_find_slot(uint8_t chassis, uint16_t slot);
int pcie_chassis_add_slot(struct PCIESlot *slot);
void pcie_chassis_del_slot(PCIESlot *s);
diff --git a/include/hw/pci/pcie_sriov.h b/include/hw/pci/pcie_sriov.h
index c5d2d31..450cbef 100644
--- a/include/hw/pci/pcie_sriov.h
+++ b/include/hw/pci/pcie_sriov.h
@@ -16,7 +16,9 @@
#include "hw/pci/pci.h"
typedef struct PCIESriovPF {
+ uint16_t num_vfs; /* Number of virtual functions created */
uint8_t vf_bar_type[PCI_NUM_REGIONS]; /* Store type for each VF bar */
+ const char *vfname; /* Reference to the device type used for the VFs */
PCIDevice **vf; /* Pointer to an array of num_vfs VF devices */
} PCIESriovPF;
@@ -25,11 +27,10 @@ typedef struct PCIESriovVF {
uint16_t vf_number; /* Logical VF number of this function */
} PCIESriovVF;
-bool pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset,
+void pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset,
const char *vfname, uint16_t vf_dev_id,
uint16_t init_vfs, uint16_t total_vfs,
- uint16_t vf_offset, uint16_t vf_stride,
- Error **errp);
+ uint16_t vf_offset, uint16_t vf_stride);
void pcie_sriov_pf_exit(PCIDevice *dev);
/* Set up a VF bar in the SR/IOV bar area */
@@ -57,8 +58,6 @@ void pcie_sriov_pf_add_sup_pgsize(PCIDevice *dev, uint16_t opt_sup_pgsize);
void pcie_sriov_config_write(PCIDevice *dev, uint32_t address,
uint32_t val, int len);
-void pcie_sriov_pf_post_load(PCIDevice *dev);
-
/* Reset SR/IOV */
void pcie_sriov_pf_reset(PCIDevice *dev);
diff --git a/include/hw/pcmcia.h b/include/hw/pcmcia.h
deleted file mode 100644
index ab26802..0000000
--- a/include/hw/pcmcia.h
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef HW_PCMCIA_H
-#define HW_PCMCIA_H
-
-/* PCMCIA/Cardbus */
-
-#include "hw/qdev-core.h"
-#include "qom/object.h"
-
-typedef struct PCMCIASocket {
- qemu_irq irq;
- bool attached;
-} PCMCIASocket;
-
-#define TYPE_PCMCIA_CARD "pcmcia-card"
-OBJECT_DECLARE_TYPE(PCMCIACardState, PCMCIACardClass, PCMCIA_CARD)
-
-struct PCMCIACardState {
- /*< private >*/
- DeviceState parent_obj;
- /*< public >*/
-
- PCMCIASocket *slot;
-};
-
-struct PCMCIACardClass {
- /*< private >*/
- DeviceClass parent_class;
- /*< public >*/
-
- int (*attach)(PCMCIACardState *state);
- int (*detach)(PCMCIACardState *state);
-
- const uint8_t *cis;
- int cis_len;
-
- /* Only valid if attached */
- uint8_t (*attr_read)(PCMCIACardState *card, uint32_t address);
- void (*attr_write)(PCMCIACardState *card, uint32_t address, uint8_t value);
- uint16_t (*common_read)(PCMCIACardState *card, uint32_t address);
- void (*common_write)(PCMCIACardState *card,
- uint32_t address, uint16_t value);
- uint16_t (*io_read)(PCMCIACardState *card, uint32_t address);
- void (*io_write)(PCMCIACardState *card, uint32_t address, uint16_t value);
-};
-
-#define CISTPL_DEVICE 0x01 /* 5V Device Information Tuple */
-#define CISTPL_NO_LINK 0x14 /* No Link Tuple */
-#define CISTPL_VERS_1 0x15 /* Level 1 Version Tuple */
-#define CISTPL_JEDEC_C 0x18 /* JEDEC ID Tuple */
-#define CISTPL_JEDEC_A 0x19 /* JEDEC ID Tuple */
-#define CISTPL_CONFIG 0x1a /* Configuration Tuple */
-#define CISTPL_CFTABLE_ENTRY 0x1b /* 16-bit PCCard Configuration */
-#define CISTPL_DEVICE_OC 0x1c /* Additional Device Information */
-#define CISTPL_DEVICE_OA 0x1d /* Additional Device Information */
-#define CISTPL_DEVICE_GEO 0x1e /* Additional Device Information */
-#define CISTPL_DEVICE_GEO_A 0x1f /* Additional Device Information */
-#define CISTPL_MANFID 0x20 /* Manufacture ID Tuple */
-#define CISTPL_FUNCID 0x21 /* Function ID Tuple */
-#define CISTPL_FUNCE 0x22 /* Function Extension Tuple */
-#define CISTPL_END 0xff /* Tuple End */
-#define CISTPL_ENDMARK 0xff
-
-/* dscm1xxxx.c */
-PCMCIACardState *dscm1xxxx_init(DriveInfo *bdrv);
-
-#endif
diff --git a/include/hw/ppc/mac_dbdma.h b/include/hw/ppc/mac_dbdma.h
index 4a3f644..c774f6b 100644
--- a/include/hw/ppc/mac_dbdma.h
+++ b/include/hw/ppc/mac_dbdma.h
@@ -44,10 +44,6 @@ struct DBDMA_io {
DBDMA_end dma_end;
/* DMA is in progress, don't start another one */
bool processing;
- /* DMA request */
- void *dma_mem;
- dma_addr_t dma_len;
- DMADirection dir;
};
/*
diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h
index 476b136..fcb6699 100644
--- a/include/hw/ppc/pnv.h
+++ b/include/hw/ppc/pnv.h
@@ -76,6 +76,9 @@ struct PnvMachineClass {
/*< public >*/
const char *compat;
int compat_size;
+ int max_smt_threads;
+ bool has_lpar_per_thread;
+ bool quirk_tb_big_core;
void (*dt_power_mgt)(PnvMachineState *pnv, void *fdt);
void (*i2c_init)(PnvMachineState *pnv);
@@ -100,6 +103,9 @@ struct PnvMachineState {
PnvPnor *pnor;
hwaddr fw_load_addr;
+
+ bool big_core;
+ bool lpar_per_core;
};
PnvChip *pnv_get_chip(PnvMachineState *pnv, uint32_t chip_id);
@@ -108,6 +114,8 @@ PnvChip *pnv_chip_add_phb(PnvChip *chip, PnvPHB *phb);
#define PNV_FDT_ADDR 0x01000000
#define PNV_TIMEBASE_FREQ 512000000ULL
+void pnv_cpu_do_nmi_resume(CPUState *cs);
+
/*
* BMC helpers
*/
diff --git a/include/hw/ppc/pnv_adu.h b/include/hw/ppc/pnv_adu.h
new file mode 100644
index 0000000..f9dbd8c
--- /dev/null
+++ b/include/hw/ppc/pnv_adu.h
@@ -0,0 +1,32 @@
+/*
+ * QEMU PowerPC PowerNV Emulation of some ADU behaviour
+ *
+ * Copyright (c) 2024, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef PPC_PNV_ADU_H
+#define PPC_PNV_ADU_H
+
+#include "hw/ppc/pnv.h"
+#include "hw/ppc/pnv_lpc.h"
+#include "hw/qdev-core.h"
+
+#define TYPE_PNV_ADU "pnv-adu"
+
+OBJECT_DECLARE_TYPE(PnvADU, PnvADUClass, PNV_ADU)
+
+struct PnvADU {
+ DeviceState xd;
+
+ /* LPCMC (LPC Master Controller) access engine */
+ PnvLpcController *lpc;
+ uint64_t lpc_base_reg;
+ uint64_t lpc_cmd_reg;
+ uint64_t lpc_data_reg;
+
+ MemoryRegion xscom_regs;
+};
+
+#endif /* PPC_PNV_ADU_H */
diff --git a/include/hw/ppc/pnv_chip.h b/include/hw/ppc/pnv_chip.h
index a4ed17a..24ce37a 100644
--- a/include/hw/ppc/pnv_chip.h
+++ b/include/hw/ppc/pnv_chip.h
@@ -2,10 +2,12 @@
#define PPC_PNV_CHIP_H
#include "hw/pci-host/pnv_phb4.h"
+#include "hw/ppc/pnv_adu.h"
#include "hw/ppc/pnv_chiptod.h"
#include "hw/ppc/pnv_core.h"
#include "hw/ppc/pnv_homer.h"
#include "hw/ppc/pnv_n1_chiplet.h"
+#include "hw/ssi/pnv_spi.h"
#include "hw/ppc/pnv_lpc.h"
#include "hw/ppc/pnv_occ.h"
#include "hw/ppc/pnv_psi.h"
@@ -26,6 +28,8 @@ struct PnvChip {
uint64_t ram_start;
uint64_t ram_size;
+ bool big_core;
+ bool lpar_per_core;
uint32_t nr_cores;
uint32_t nr_threads;
uint64_t cores_mask;
@@ -77,6 +81,7 @@ struct Pnv9Chip {
PnvChip parent_obj;
/*< public >*/
+ PnvADU adu;
PnvXive xive;
Pnv9Psi psi;
PnvLpcController lpc;
@@ -110,6 +115,7 @@ struct Pnv10Chip {
PnvChip parent_obj;
/*< public >*/
+ PnvADU adu;
PnvXive2 xive;
Pnv9Psi psi;
PnvLpcController lpc;
@@ -118,6 +124,8 @@ struct Pnv10Chip {
PnvSBE sbe;
PnvHomer homer;
PnvN1Chiplet n1_chiplet;
+#define PNV10_CHIP_MAX_PIB_SPIC 6
+ PnvSpi pib_spic[PNV10_CHIP_MAX_PIB_SPIC];
uint32_t nr_quads;
PnvQuad *quads;
@@ -131,6 +139,7 @@ struct Pnv10Chip {
#define PNV10_PIR2FUSEDCORE(pir) (((pir) >> 3) & 0xf)
#define PNV10_PIR2CHIP(pir) (((pir) >> 8) & 0x7f)
+#define PNV10_PIR2THREAD(pir) (((pir) & 0x7f))
struct PnvChipClass {
/*< private >*/
@@ -147,7 +156,9 @@ struct PnvChipClass {
DeviceRealize parent_realize;
- uint32_t (*chip_pir)(PnvChip *chip, uint32_t core_id, uint32_t thread_id);
+ /* Get PIR and TIR values for a CPU thread identified by core/thread id */
+ void (*get_pir_tir)(PnvChip *chip, uint32_t core_id, uint32_t thread_id,
+ uint32_t *pir, uint32_t *tir);
void (*intc_create)(PnvChip *chip, PowerPCCPU *cpu, Error **errp);
void (*intc_reset)(PnvChip *chip, PowerPCCPU *cpu);
void (*intc_destroy)(PnvChip *chip, PowerPCCPU *cpu);
diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
index c6d62fd..d8afb4f 100644
--- a/include/hw/ppc/pnv_core.h
+++ b/include/hw/ppc/pnv_core.h
@@ -25,6 +25,27 @@
#include "hw/ppc/pnv.h"
#include "qom/object.h"
+/* Per-core ChipTOD / TimeBase state */
+typedef struct PnvCoreTODState {
+ /*
+ * POWER10 DD2.0 - big core TFMR drives the state machine on the even
+ * small core. Skiboot has a workaround that targets the even small core
+ * for CHIPTOD_TO_TB ops.
+ */
+ bool big_core_quirk;
+
+ int tb_ready_for_tod; /* core TB ready to receive TOD from chiptod */
+ int tod_sent_to_tb; /* chiptod sent TOD to the core TB */
+
+ /*
+ * "Timers" for async TBST events are simulated by mfTFAC because TFAC
+ * is polled for such events. These are just used to ensure firmware
+ * performs the polling at least a few times.
+ */
+ int tb_state_timer;
+ int tb_sync_pulse_timer;
+} PnvCoreTODState;
+
#define TYPE_PNV_CORE "powernv-cpu-core"
OBJECT_DECLARE_TYPE(PnvCore, PnvCoreClass,
PNV_CORE)
@@ -35,9 +56,15 @@ struct PnvCore {
/*< public >*/
PowerPCCPU **threads;
+ bool big_core;
+ bool lpar_per_core;
uint32_t pir;
uint32_t hwid;
uint64_t hrmor;
+
+ target_ulong scratch[8]; /* SPRC/SPRD indirect SCRATCH registers */
+ PnvCoreTODState tod_state;
+
PnvChip *chip;
MemoryRegion xscom_regs;
@@ -54,6 +81,7 @@ struct PnvCoreClass {
#define PNV_CORE_TYPE_NAME(cpu_model) cpu_model PNV_CORE_TYPE_SUFFIX
typedef struct PnvCPUState {
+ PnvCore *pnv_core;
Object *intc;
} PnvCPUState;
@@ -82,6 +110,9 @@ OBJECT_DECLARE_TYPE(PnvQuad, PnvQuadClass, PNV_QUAD)
struct PnvQuad {
DeviceState parent_obj;
+ bool special_wakeup_done;
+ bool special_wakeup[4];
+
uint32_t quad_id;
MemoryRegion xscom_regs;
MemoryRegion xscom_qme_regs;
diff --git a/include/hw/ppc/pnv_lpc.h b/include/hw/ppc/pnv_lpc.h
index 5d22c45..174add4 100644
--- a/include/hw/ppc/pnv_lpc.h
+++ b/include/hw/ppc/pnv_lpc.h
@@ -23,6 +23,7 @@
#include "exec/memory.h"
#include "hw/ppc/pnv.h"
#include "hw/qdev-core.h"
+#include "hw/isa/isa.h" /* For ISA_NUM_IRQS */
#define TYPE_PNV_LPC "pnv-lpc"
typedef struct PnvLpcClass PnvLpcClass;
@@ -73,6 +74,9 @@ struct PnvLpcController {
uint32_t opb_irq_pol;
uint32_t opb_irq_input;
+ /* LPC device IRQ state */
+ uint32_t lpc_hc_irq_inputs;
+
/* LPC HC registers */
uint32_t lpc_hc_fw_seg_idsel;
uint32_t lpc_hc_fw_rd_acc_size;
@@ -84,8 +88,19 @@ struct PnvLpcController {
/* XSCOM registers */
MemoryRegion xscom_regs;
+ /*
+ * In P8, ISA irqs are combined with internal sources to drive the
+ * LPCHC interrupt output. P9 ISA irqs raise one of 4 lines that
+ * drive PSI SERIRQ irqs, routing according to OPB routing registers.
+ */
+ bool psi_has_serirq;
+
/* PSI to generate interrupts */
- qemu_irq psi_irq;
+ qemu_irq psi_irq_lpchc;
+
+ /* P9 serirq lines and irq routing table */
+ qemu_irq psi_irq_serirq[4];
+ int irq_to_serirq_route[ISA_NUM_IRQS];
};
struct PnvLpcClass {
@@ -94,6 +109,11 @@ struct PnvLpcClass {
DeviceRealize parent_realize;
};
+bool pnv_lpc_opb_read(PnvLpcController *lpc, uint32_t addr,
+ uint8_t *data, int sz);
+bool pnv_lpc_opb_write(PnvLpcController *lpc, uint32_t addr,
+ uint8_t *data, int sz);
+
ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp);
int pnv_dt_lpc(PnvChip *chip, void *fdt, int root_offset,
uint64_t lpcm_addr, uint64_t lpcm_size);
diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h
index 6209e18..648388a 100644
--- a/include/hw/ppc/pnv_xscom.h
+++ b/include/hw/ppc/pnv_xscom.h
@@ -21,9 +21,9 @@
#define PPC_PNV_XSCOM_H
#include "exec/memory.h"
-#include "hw/ppc/pnv.h"
typedef struct PnvXScomInterface PnvXScomInterface;
+typedef struct PnvChip PnvChip;
#define TYPE_PNV_XSCOM_INTERFACE "pnv-xscom-interface"
#define PNV_XSCOM_INTERFACE(obj) \
@@ -82,6 +82,9 @@ struct PnvXScomInterfaceClass {
#define PNV_XSCOM_PBCQ_SPCI_BASE 0x9013c00
#define PNV_XSCOM_PBCQ_SPCI_SIZE 0x5
+#define PNV9_XSCOM_ADU_BASE 0x0090000
+#define PNV9_XSCOM_ADU_SIZE 0x55
+
/*
* Layout of the XSCOM PCB addresses (POWER 9)
*/
@@ -128,6 +131,9 @@ struct PnvXScomInterfaceClass {
#define PNV9_XSCOM_PEC_PCI_STK1 0x140
#define PNV9_XSCOM_PEC_PCI_STK2 0x180
+#define PNV10_XSCOM_ADU_BASE 0x0090000
+#define PNV10_XSCOM_ADU_SIZE 0x55
+
/*
* Layout of the XSCOM PCB addresses (POWER 10)
*/
@@ -194,6 +200,9 @@ struct PnvXScomInterfaceClass {
#define PNV10_XSCOM_PEC_PCI_BASE 0x8010800 /* index goes upwards ... */
#define PNV10_XSCOM_PEC_PCI_SIZE 0x200
+#define PNV10_XSCOM_PIB_SPIC_BASE 0xc0000
+#define PNV10_XSCOM_PIB_SPIC_SIZE 0x20
+
void pnv_xscom_init(PnvChip *chip, uint64_t size, hwaddr addr);
int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset,
uint64_t xscom_base, uint64_t xscom_size,
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index 4aaf23d..f6de3e9 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -1004,6 +1004,7 @@ extern const VMStateDescription vmstate_spapr_cap_large_decr;
extern const VMStateDescription vmstate_spapr_cap_ccf_assist;
extern const VMStateDescription vmstate_spapr_cap_fwnmi;
extern const VMStateDescription vmstate_spapr_cap_rpt_invalidate;
+extern const VMStateDescription vmstate_spapr_cap_ail_mode_3;
extern const VMStateDescription vmstate_spapr_wdt;
static inline uint8_t spapr_get_cap(SpaprMachineState *spapr, int cap)
diff --git a/include/hw/ppc/xive2_regs.h b/include/hw/ppc/xive2_regs.h
index 4e5e17c..4349d00 100644
--- a/include/hw/ppc/xive2_regs.h
+++ b/include/hw/ppc/xive2_regs.h
@@ -97,6 +97,7 @@ typedef struct Xive2End {
uint32_t w6;
#define END2_W6_FORMAT_BIT PPC_BIT32(0)
#define END2_W6_IGNORE PPC_BIT32(1)
+#define END2_W6_CROWD PPC_BIT32(2)
#define END2_W6_VP_BLOCK PPC_BITMASK32(4, 7)
#define END2_W6_VP_OFFSET PPC_BITMASK32(8, 31)
#define END2_W6_VP_OFFSET_GEN1 PPC_BITMASK32(13, 31)
@@ -111,6 +112,8 @@ typedef struct Xive2End {
#define xive2_end_is_notify(end) \
(be32_to_cpu((end)->w0) & END2_W0_UCOND_NOTIFY)
#define xive2_end_is_backlog(end) (be32_to_cpu((end)->w0) & END2_W0_BACKLOG)
+#define xive2_end_is_precluded_escalation(end) \
+ (be32_to_cpu((end)->w0) & END2_W0_PRECL_ESC_CTL)
#define xive2_end_is_escalate(end) \
(be32_to_cpu((end)->w0) & END2_W0_ESCALATE_CTL)
#define xive2_end_is_uncond_escalation(end) \
@@ -123,6 +126,10 @@ typedef struct Xive2End {
(be32_to_cpu((end)->w0) & END2_W0_FIRMWARE1)
#define xive2_end_is_firmware2(end) \
(be32_to_cpu((end)->w0) & END2_W0_FIRMWARE2)
+#define xive2_end_is_ignore(end) \
+ (be32_to_cpu((end)->w6) & END2_W6_IGNORE)
+#define xive2_end_is_crowd(end) \
+ (be32_to_cpu((end)->w6) & END2_W6_CROWD)
static inline uint64_t xive2_end_qaddr(Xive2End *end)
{
@@ -194,6 +201,8 @@ static inline uint32_t xive2_nvp_blk(uint32_t cam_line)
return (cam_line >> XIVE2_NVP_SHIFT) & 0xf;
}
+void xive2_nvp_pic_print_info(Xive2Nvp *nvp, uint32_t nvp_idx, GString *buf);
+
/*
* Notification Virtual Group or Crowd (NVG/NVC)
*/
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 77bfcbd..aa97c34 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -152,14 +152,14 @@ struct DeviceClass {
/* callbacks */
/**
- * @reset: deprecated device reset method pointer
+ * @legacy_reset: deprecated device reset method pointer
*
* Modern code should use the ResettableClass interface to
* implement a multi-phase reset.
*
* TODO: remove once every reset callback is unused
*/
- DeviceReset reset;
+ DeviceReset legacy_reset;
DeviceRealize realize;
DeviceUnrealize unrealize;
@@ -938,22 +938,6 @@ char *qdev_get_own_fw_dev_path_from_handler(BusState *bus, DeviceState *dev);
void device_class_set_props(DeviceClass *dc, Property *props);
/**
- * device_class_set_parent_reset() - legacy set device reset handlers
- * @dc: device class
- * @dev_reset: function pointer to reset handler
- * @parent_reset: function pointer to parents reset handler
- *
- * Modern code should use the ResettableClass interface to
- * implement a multi-phase reset instead.
- *
- * TODO: remove the function when DeviceClass's reset method
- * is not used anymore.
- */
-void device_class_set_parent_reset(DeviceClass *dc,
- DeviceReset dev_reset,
- DeviceReset *parent_reset);
-
-/**
* device_class_set_parent_realize() - set up for chaining realize fns
* @dc: The device class
* @dev_realize: the device realize function
@@ -969,6 +953,19 @@ void device_class_set_parent_realize(DeviceClass *dc,
DeviceRealize dev_realize,
DeviceRealize *parent_realize);
+/**
+ * device_class_set_legacy_reset(): set the DeviceClass::reset method
+ * @dc: The device class
+ * @dev_reset: the reset function
+ *
+ * This function sets the DeviceClass::reset method. This is widely
+ * used in existing code, but new code should prefer to use the
+ * Resettable API as documented in docs/devel/reset.rst.
+ * In addition, devices which need to chain to their parent class's
+ * reset methods or which need to be subclassed must use Resettable.
+ */
+void device_class_set_legacy_reset(DeviceClass *dc,
+ DeviceReset dev_reset);
/**
* device_class_set_parent_unrealize() - set up for chaining unrealize fns
diff --git a/include/hw/qdev-properties-system.h b/include/hw/qdev-properties-system.h
index 438f653..cdcc630 100644
--- a/include/hw/qdev-properties-system.h
+++ b/include/hw/qdev-properties-system.h
@@ -88,7 +88,7 @@ extern const PropertyInfo qdev_prop_iothread_vq_mapping_list;
#define DEFINE_PROP_CPUS390ENTITLEMENT(_n, _s, _f, _d) \
DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_cpus390entitlement, \
- CpuS390Entitlement)
+ S390CpuEntitlement)
#define DEFINE_PROP_IOTHREAD_VQ_MAPPING_LIST(_name, _state, _field) \
DEFINE_PROP(_name, _state, _field, qdev_prop_iothread_vq_mapping_list, \
diff --git a/include/hw/remote/iohub.h b/include/hw/remote/iohub.h
index 6a8444f..09ee6c7 100644
--- a/include/hw/remote/iohub.h
+++ b/include/hw/remote/iohub.h
@@ -37,6 +37,5 @@ void remote_iohub_set_irq(void *opaque, int pirq, int level);
void process_set_irqfd_msg(PCIDevice *pci_dev, MPQemuMsg *msg);
void remote_iohub_init(RemoteIOHubState *iohub);
-void remote_iohub_finalize(RemoteIOHubState *iohub);
#endif
diff --git a/include/hw/resettable.h b/include/hw/resettable.h
index 7e249de..fd862f1 100644
--- a/include/hw/resettable.h
+++ b/include/hw/resettable.h
@@ -29,6 +29,7 @@ typedef struct ResettableState ResettableState;
* Types of reset.
*
* + Cold: reset resulting from a power cycle of the object.
+ * + Wakeup: reset resulting from a wake-up from a suspended state.
*
* TODO: Support has to be added to handle more types. In particular,
* ResettableState structure needs to be expanded.
@@ -36,6 +37,9 @@ typedef struct ResettableState ResettableState;
typedef enum ResetType {
RESET_TYPE_COLD,
RESET_TYPE_SNAPSHOT_LOAD,
+ RESET_TYPE_WAKEUP,
+ RESET_TYPE_S390_CPU_INITIAL,
+ RESET_TYPE_S390_CPU_NORMAL,
} ResetType;
/*
@@ -88,14 +92,6 @@ typedef enum ResetType {
* @get_state: Mandatory method which must return a pointer to a
* ResettableState.
*
- * @get_transitional_function: transitional method to handle Resettable objects
- * not yet fully moved to this interface. It will be removed as soon as it is
- * not needed anymore. This method is optional and may return a pointer to a
- * function to be used instead of the phases. If the method exists and returns
- * a non-NULL function pointer then that function is executed as a replacement
- * of the 'hold' phase method taking the object as argument. The two other phase
- * methods are not executed.
- *
* @child_foreach: Executes a given callback on every Resettable child. Child
* in this context means a child in the qbus tree, so the children of a qbus
* are the devices on it, and the children of a device are all the buses it
@@ -107,8 +103,6 @@ typedef void (*ResettableEnterPhase)(Object *obj, ResetType type);
typedef void (*ResettableHoldPhase)(Object *obj, ResetType type);
typedef void (*ResettableExitPhase)(Object *obj, ResetType type);
typedef ResettableState * (*ResettableGetState)(Object *obj);
-typedef void (*ResettableTrFunction)(Object *obj);
-typedef ResettableTrFunction (*ResettableGetTrFunction)(Object *obj);
typedef void (*ResettableChildCallback)(Object *, void *opaque,
ResetType type);
typedef void (*ResettableChildForeach)(Object *obj,
@@ -128,9 +122,6 @@ struct ResettableClass {
/* State access method */
ResettableGetState get_state;
- /* Transitional method for legacy reset compatibility */
- ResettableGetTrFunction get_transitional_function;
-
/* Hierarchy handling method */
ResettableChildForeach child_foreach;
};
diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h
index a2e4ae9..18bfe9f 100644
--- a/include/hw/riscv/boot.h
+++ b/include/hw/riscv/boot.h
@@ -35,13 +35,13 @@ target_ulong riscv_calc_kernel_start_addr(RISCVHartArrayState *harts,
target_ulong firmware_end_addr);
target_ulong riscv_find_and_load_firmware(MachineState *machine,
const char *default_machine_firmware,
- hwaddr firmware_load_addr,
+ hwaddr *firmware_load_addr,
symbol_fn_t sym_cb);
const char *riscv_default_firmware_name(RISCVHartArrayState *harts);
char *riscv_find_firmware(const char *firmware_filename,
const char *default_machine_firmware);
target_ulong riscv_load_firmware(const char *firmware_filename,
- hwaddr firmware_load_addr,
+ hwaddr *firmware_load_addr,
symbol_fn_t sym_cb);
target_ulong riscv_load_kernel(MachineState *machine,
RISCVHartArrayState *harts,
diff --git a/include/hw/s390x/cpu-topology.h b/include/hw/s390x/cpu-topology.h
index c064f42..9283c94 100644
--- a/include/hw/s390x/cpu-topology.h
+++ b/include/hw/s390x/cpu-topology.h
@@ -37,7 +37,7 @@ typedef struct S390TopologyEntry {
typedef struct S390Topology {
uint8_t *cores_per_socket;
- CpuS390Polarization polarization;
+ S390CpuPolarization polarization;
} S390Topology;
typedef QTAILQ_HEAD(, S390TopologyEntry) S390TopologyList;
@@ -57,7 +57,7 @@ static inline void s390_topology_setup_cpu(MachineState *ms,
static inline void s390_topology_reset(void)
{
/* Unreachable, CPU topology not implemented for TCG */
- assert(false);
+ g_assert_not_reached();
}
#endif
diff --git a/include/hw/s390x/ipl/qipl.h b/include/hw/s390x/ipl/qipl.h
new file mode 100644
index 0000000..6824391
--- /dev/null
+++ b/include/hw/s390x/ipl/qipl.h
@@ -0,0 +1,127 @@
+/*
+ * S/390 boot structures
+ *
+ * Copyright 2024 IBM Corp.
+ * Author(s): Jared Rossi <jrossi@linux.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#ifndef S390X_QIPL_H
+#define S390X_QIPL_H
+
+/* Boot Menu flags */
+#define QIPL_FLAG_BM_OPTS_CMD 0x80
+#define QIPL_FLAG_BM_OPTS_ZIPL 0x40
+
+#define QIPL_ADDRESS 0xcc
+#define LOADPARM_LEN 8
+#define NO_LOADPARM "\0\0\0\0\0\0\0\0"
+
+/*
+ * The QEMU IPL Parameters will be stored at absolute address
+ * 204 (0xcc) which means it is 32-bit word aligned but not
+ * double-word aligned. Placement of 64-bit data fields in this
+ * area must account for their alignment needs.
+ * The total size of the struct must never exceed 28 bytes.
+ */
+struct QemuIplParameters {
+ uint8_t qipl_flags;
+ uint8_t index;
+ uint8_t reserved1[2];
+ uint64_t reserved2;
+ uint32_t boot_menu_timeout;
+ uint8_t reserved3[2];
+ uint16_t chain_len;
+ uint64_t next_iplb;
+} QEMU_PACKED;
+typedef struct QemuIplParameters QemuIplParameters;
+
+struct IPLBlockPVComp {
+ uint64_t tweak_pref;
+ uint64_t addr;
+ uint64_t size;
+} QEMU_PACKED;
+typedef struct IPLBlockPVComp IPLBlockPVComp;
+
+struct IPLBlockPV {
+ uint8_t reserved18[87]; /* 0x18 */
+ uint8_t version; /* 0x6f */
+ uint32_t reserved70; /* 0x70 */
+ uint32_t num_comp; /* 0x74 */
+ uint64_t pv_header_addr; /* 0x78 */
+ uint64_t pv_header_len; /* 0x80 */
+ struct IPLBlockPVComp components[0];
+} QEMU_PACKED;
+typedef struct IPLBlockPV IPLBlockPV;
+
+struct IplBlockCcw {
+ uint8_t reserved0[85];
+ uint8_t ssid;
+ uint16_t devno;
+ uint8_t vm_flags;
+ uint8_t reserved3[3];
+ uint32_t vm_parm_len;
+ uint8_t nss_name[8];
+ uint8_t vm_parm[64];
+ uint8_t reserved4[8];
+} QEMU_PACKED;
+typedef struct IplBlockCcw IplBlockCcw;
+
+struct IplBlockFcp {
+ uint8_t reserved1[305 - 1];
+ uint8_t opt;
+ uint8_t reserved2[3];
+ uint16_t reserved3;
+ uint16_t devno;
+ uint8_t reserved4[4];
+ uint64_t wwpn;
+ uint64_t lun;
+ uint32_t bootprog;
+ uint8_t reserved5[12];
+ uint64_t br_lba;
+ uint32_t scp_data_len;
+ uint8_t reserved6[260];
+ uint8_t scp_data[0];
+} QEMU_PACKED;
+typedef struct IplBlockFcp IplBlockFcp;
+
+struct IplBlockQemuScsi {
+ uint32_t lun;
+ uint16_t target;
+ uint16_t channel;
+ uint8_t reserved0[77];
+ uint8_t ssid;
+ uint16_t devno;
+} QEMU_PACKED;
+typedef struct IplBlockQemuScsi IplBlockQemuScsi;
+
+union IplParameterBlock {
+ struct {
+ uint32_t len;
+ uint8_t reserved0[3];
+ uint8_t version;
+ uint32_t blk0_len;
+ uint8_t pbt;
+ uint8_t flags;
+ uint16_t reserved01;
+ uint8_t loadparm[LOADPARM_LEN];
+ union {
+ IplBlockCcw ccw;
+ IplBlockFcp fcp;
+ IPLBlockPV pv;
+ IplBlockQemuScsi scsi;
+ };
+ } QEMU_PACKED;
+ struct {
+ uint8_t reserved1[110];
+ uint16_t devno;
+ uint8_t reserved2[88];
+ uint8_t reserved_ext[4096 - 200];
+ } QEMU_PACKED;
+} QEMU_PACKED;
+typedef union IplParameterBlock IplParameterBlock;
+
+#endif
diff --git a/include/hw/sh4/sh.h b/include/hw/sh4/sh.h
index ec716cd..c82feef 100644
--- a/include/hw/sh4/sh.h
+++ b/include/hw/sh4/sh.h
@@ -38,29 +38,10 @@ struct SH7750State;
struct SH7750State *sh7750_init(SuperHCPU *cpu, MemoryRegion *sysmem);
-typedef struct {
- /* The callback will be triggered if any of the designated lines change */
- uint16_t portamask_trigger;
- uint16_t portbmask_trigger;
- /* Return 0 if no action was taken */
- int (*port_change_cb) (uint16_t porta, uint16_t portb,
- uint16_t *periph_pdtra,
- uint16_t *periph_portdira,
- uint16_t *periph_pdtrb,
- uint16_t *periph_portdirb);
-} sh7750_io_device;
-
-int sh7750_register_io_device(struct SH7750State *s,
- sh7750_io_device *device);
-
-/* sh_serial.c */
#define TYPE_SH_SERIAL "sh-serial"
#define SH_SERIAL_FEAT_SCIF (1 << 0)
/* sh7750.c */
qemu_irq sh7750_irl(struct SH7750State *s);
-/* tc58128.c */
-int tc58128_init(struct SH7750State *s, const char *zone1, const char *zone2);
-
#endif
diff --git a/include/hw/southbridge/ich9.h b/include/hw/southbridge/ich9.h
index fd01649..6c60017 100644
--- a/include/hw/southbridge/ich9.h
+++ b/include/hw/southbridge/ich9.h
@@ -196,8 +196,12 @@ struct ICH9LPCState {
#define ICH9_PMIO_GPE0_LEN 16
#define ICH9_PMIO_SMI_EN 0x30
#define ICH9_PMIO_SMI_EN_APMC_EN (1 << 5)
+#define ICH9_PMIO_SMI_EN_SWSMI_EN (1 << 6)
#define ICH9_PMIO_SMI_EN_TCO_EN (1 << 13)
+#define ICH9_PMIO_SMI_EN_PERIODIC_EN (1 << 14)
#define ICH9_PMIO_SMI_STS 0x34
+#define ICH9_PMIO_SMI_STS_SWSMI_STS (1 << 6)
+#define ICH9_PMIO_SMI_STS_PERIODIC_STS (1 << 14)
#define ICH9_PMIO_TCO_RLD 0x60
#define ICH9_PMIO_TCO_LEN 32
diff --git a/include/hw/ssi/allwinner-a10-spi.h b/include/hw/ssi/allwinner-a10-spi.h
new file mode 100644
index 0000000..da46e29
--- /dev/null
+++ b/include/hw/ssi/allwinner-a10-spi.h
@@ -0,0 +1,57 @@
+/*
+ * Allwinner SPI Bus Serial Interface registers definition
+ *
+ * Copyright (C) 2024 Strahinja Jankovic. <strahinja.p.jankovic@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 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/>.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef ALLWINNER_A10_SPI_H
+#define ALLWINNER_A10_SPI_H
+
+#include "hw/ssi/ssi.h"
+#include "hw/sysbus.h"
+#include "qemu/fifo8.h"
+#include "qom/object.h"
+
+/** Size of register I/O address space used by SPI device */
+#define AW_A10_SPI_IOSIZE (0x1000)
+
+/** Total number of known registers */
+#define AW_A10_SPI_REGS_NUM (AW_A10_SPI_IOSIZE / sizeof(uint32_t))
+#define AW_A10_SPI_FIFO_SIZE (64)
+#define AW_A10_SPI_CS_LINES_NR (4)
+
+#define TYPE_AW_A10_SPI "allwinner.spi"
+OBJECT_DECLARE_SIMPLE_TYPE(AWA10SPIState, AW_A10_SPI)
+
+struct AWA10SPIState {
+ /*< private >*/
+ SysBusDevice parent_obj;
+
+ /*< public >*/
+ MemoryRegion iomem;
+ SSIBus *bus;
+ qemu_irq irq;
+ qemu_irq cs_lines[AW_A10_SPI_CS_LINES_NR];
+
+ uint32_t regs[AW_A10_SPI_REGS_NUM];
+
+ Fifo8 rx_fifo;
+ Fifo8 tx_fifo;
+};
+
+#endif /* ALLWINNER_A10_SPI_H */
diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h
index 234dca3..25b95e7 100644
--- a/include/hw/ssi/aspeed_smc.h
+++ b/include/hw/ssi/aspeed_smc.h
@@ -82,6 +82,7 @@ struct AspeedSMCState {
uint8_t snoop_index;
uint8_t snoop_dummies;
+ bool unselect;
};
typedef struct AspeedSegments {
diff --git a/include/hw/ssi/pnv_spi.h b/include/hw/ssi/pnv_spi.h
new file mode 100644
index 0000000..8815f67
--- /dev/null
+++ b/include/hw/ssi/pnv_spi.h
@@ -0,0 +1,67 @@
+/*
+ * QEMU PowerPC SPI model
+ *
+ * Copyright (c) 2024, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This model Supports a connection to a single SPI responder.
+ * Introduced for P10 to provide access to SPI seeproms, TPM, flash device
+ * and an ADC controller.
+ *
+ * All SPI function control is mapped into the SPI register space to enable
+ * full control by firmware.
+ *
+ * SPI Controller has sequencer and shift engine. The SPI shift engine
+ * performs serialization and de-serialization according to the control by
+ * the sequencer and according to the setup defined in the configuration
+ * registers and the SPI sequencer implements the main control logic.
+ */
+
+#ifndef PPC_PNV_SPI_H
+#define PPC_PNV_SPI_H
+
+#include "hw/ssi/ssi.h"
+#include "hw/sysbus.h"
+
+#define TYPE_PNV_SPI "pnv-spi"
+OBJECT_DECLARE_SIMPLE_TYPE(PnvSpi, PNV_SPI)
+
+#define PNV_SPI_REG_SIZE 8
+#define PNV_SPI_REGS 7
+
+#define TYPE_PNV_SPI_BUS "pnv-spi-bus"
+typedef struct PnvSpi {
+ SysBusDevice parent_obj;
+
+ SSIBus *ssi_bus;
+ qemu_irq *cs_line;
+ MemoryRegion xscom_spic_regs;
+ /* SPI object number */
+ uint32_t spic_num;
+ uint8_t transfer_len;
+ uint8_t responder_select;
+ /* To verify if shift_n1 happens prior to shift_n2 */
+ bool shift_n1_done;
+ /* Loop counter for branch operation opcode Ex/Fx */
+ uint8_t loop_counter_1;
+ uint8_t loop_counter_2;
+ /* N1/N2_bits specifies the size of the N1/N2 segment of a frame in bits.*/
+ uint8_t N1_bits;
+ uint8_t N2_bits;
+ /* Number of bytes in a payload for the N1/N2 frame segment.*/
+ uint8_t N1_bytes;
+ uint8_t N2_bytes;
+ /* Number of N1/N2 bytes marked for transmit */
+ uint8_t N1_tx;
+ uint8_t N2_tx;
+ /* Number of N1/N2 bytes marked for receive */
+ uint8_t N1_rx;
+ uint8_t N2_rx;
+
+ /* SPI registers */
+ uint64_t regs[PNV_SPI_REGS];
+ uint8_t seq_op[PNV_SPI_REG_SIZE];
+ uint64_t status;
+} PnvSpi;
+#endif /* PPC_PNV_SPI_H */
diff --git a/include/hw/ssi/pnv_spi_regs.h b/include/hw/ssi/pnv_spi_regs.h
new file mode 100644
index 0000000..596e2c1
--- /dev/null
+++ b/include/hw/ssi/pnv_spi_regs.h
@@ -0,0 +1,133 @@
+/*
+ * QEMU PowerPC SPI model
+ *
+ * Copyright (c) 2024, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef PNV_SPI_CONTROLLER_REGS_H
+#define PNV_SPI_CONTROLLER_REGS_H
+
+/*
+ * Macros from target/ppc/cpu.h
+ * These macros are copied from ppc target specific file target/ppc/cpu.h
+ * as target/ppc/cpu.h cannot be included here.
+ */
+#define PPC_BIT(bit) (0x8000000000000000ULL >> (bit))
+#define PPC_BIT8(bit) (0x80 >> (bit))
+#define PPC_BITMASK(bs, be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs))
+#define PPC_BITMASK8(bs, be) ((PPC_BIT8(bs) - PPC_BIT8(be)) | PPC_BIT8(bs))
+#define MASK_TO_LSH(m) (__builtin_ffsll(m) - 1)
+#define GETFIELD(m, v) (((v) & (m)) >> MASK_TO_LSH(m))
+#define SETFIELD(m, v, val) \
+ (((v) & ~(m)) | ((((typeof(v))(val)) << MASK_TO_LSH(m)) & (m)))
+
+/* Error Register */
+#define ERROR_REG 0x00
+
+/* counter_config_reg */
+#define SPI_CTR_CFG_REG 0x01
+#define SPI_CTR_CFG_N1 PPC_BITMASK(0, 7)
+#define SPI_CTR_CFG_N2 PPC_BITMASK(8, 15)
+#define SPI_CTR_CFG_CMP1 PPC_BITMASK(24, 31)
+#define SPI_CTR_CFG_CMP2 PPC_BITMASK(32, 39)
+#define SPI_CTR_CFG_N1_CTRL_B1 PPC_BIT(49)
+#define SPI_CTR_CFG_N1_CTRL_B2 PPC_BIT(50)
+#define SPI_CTR_CFG_N1_CTRL_B3 PPC_BIT(51)
+#define SPI_CTR_CFG_N2_CTRL_B0 PPC_BIT(52)
+#define SPI_CTR_CFG_N2_CTRL_B1 PPC_BIT(53)
+#define SPI_CTR_CFG_N2_CTRL_B2 PPC_BIT(54)
+#define SPI_CTR_CFG_N2_CTRL_B3 PPC_BIT(55)
+
+/* config_reg */
+#define CONFIG_REG1 0x02
+
+/* clock_config_reset_control_ecc_enable_reg */
+#define SPI_CLK_CFG_REG 0x03
+#define SPI_CLK_CFG_HARD_RST 0x0084000000000000;
+#define SPI_CLK_CFG_RST_CTRL PPC_BITMASK(24, 27)
+#define SPI_CLK_CFG_ECC_EN PPC_BIT(28)
+#define SPI_CLK_CFG_ECC_CTRL PPC_BITMASK(29, 30)
+
+/* memory_mapping_reg */
+#define SPI_MM_REG 0x04
+#define SPI_MM_RDR_MATCH_VAL PPC_BITMASK(32, 47)
+#define SPI_MM_RDR_MATCH_MASK PPC_BITMASK(48, 63)
+
+/* transmit_data_reg */
+#define SPI_XMIT_DATA_REG 0x05
+
+/* receive_data_reg */
+#define SPI_RCV_DATA_REG 0x06
+
+/* sequencer_operation_reg */
+#define SPI_SEQ_OP_REG 0x07
+
+/* status_reg */
+#define SPI_STS_REG 0x08
+#define SPI_STS_RDR_FULL PPC_BIT(0)
+#define SPI_STS_RDR_OVERRUN PPC_BIT(1)
+#define SPI_STS_RDR_UNDERRUN PPC_BIT(2)
+#define SPI_STS_TDR_FULL PPC_BIT(4)
+#define SPI_STS_TDR_OVERRUN PPC_BIT(5)
+#define SPI_STS_TDR_UNDERRUN PPC_BIT(6)
+#define SPI_STS_SEQ_FSM PPC_BITMASK(8, 15)
+#define SPI_STS_SHIFTER_FSM PPC_BITMASK(16, 27)
+#define SPI_STS_SEQ_INDEX PPC_BITMASK(28, 31)
+#define SPI_STS_GEN_STATUS_B3 PPC_BIT(35)
+#define SPI_STS_RDR PPC_BITMASK(1, 3)
+#define SPI_STS_TDR PPC_BITMASK(5, 7)
+
+/*
+ * Shifter states
+ *
+ * These are the same values defined for the Shifter FSM field of the
+ * status register. It's a 12 bit field so we will represent it as three
+ * nibbles in the constants.
+ *
+ * These are shifter_fsm values
+ *
+ * Status reg bits 16-27 -> field bits 0-11
+ * bits 0,1,2,5 unused/reserved
+ * bit 4 crc shift in (unused)
+ * bit 8 crc shift out (unused)
+ */
+
+#define FSM_DONE 0x100 /* bit 3 */
+#define FSM_SHIFT_N2 0x020 /* bit 6 */
+#define FSM_WAIT 0x010 /* bit 7 */
+#define FSM_SHIFT_N1 0x004 /* bit 9 */
+#define FSM_START 0x002 /* bit 10 */
+#define FSM_IDLE 0x001 /* bit 11 */
+
+/*
+ * Sequencer states
+ *
+ * These are sequencer_fsm values
+ *
+ * Status reg bits 8-15 -> field bits 0-7
+ * bits 0-3 unused/reserved
+ *
+ */
+#define SEQ_STATE_INDEX_INCREMENT 0x08 /* bit 4 */
+#define SEQ_STATE_EXECUTE 0x04 /* bit 5 */
+#define SEQ_STATE_DECODE 0x02 /* bit 6 */
+#define SEQ_STATE_IDLE 0x01 /* bit 7 */
+
+/*
+ * These are the supported sequencer operations.
+ * Only the upper nibble is significant because for many operations
+ * the lower nibble is a variable specific to the operation.
+ */
+#define SEQ_OP_STOP 0x00
+#define SEQ_OP_SELECT_SLAVE 0x10
+#define SEQ_OP_SHIFT_N1 0x30
+#define SEQ_OP_SHIFT_N2 0x40
+#define SEQ_OP_BRANCH_IFNEQ_RDR 0x60
+#define SEQ_OP_TRANSFER_TDR 0xC0
+#define SEQ_OP_BRANCH_IFNEQ_INC_1 0xE0
+#define SEQ_OP_BRANCH_IFNEQ_INC_2 0xF0
+#define NUM_SEQ_OPS 8
+
+#endif
diff --git a/include/hw/sysbus.h b/include/hw/sysbus.h
index 3cb29a4..c9b1e0e 100644
--- a/include/hw/sysbus.h
+++ b/include/hw/sysbus.h
@@ -82,7 +82,6 @@ qemu_irq sysbus_get_connected_irq(SysBusDevice *dev, int n);
void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr);
void sysbus_mmio_map_overlap(SysBusDevice *dev, int n, hwaddr addr,
int priority);
-void sysbus_mmio_unmap(SysBusDevice *dev, int n);
bool sysbus_realize(SysBusDevice *dev, Error **errp);
bool sysbus_realize_and_unref(SysBusDevice *dev, Error **errp);
diff --git a/include/hw/usb/dwc2-regs.h b/include/hw/usb/dwc2-regs.h
index 0bf3f2a..523b112 100644
--- a/include/hw/usb/dwc2-regs.h
+++ b/include/hw/usb/dwc2-regs.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-3-Clause) */
/*
* Imported from the Linux kernel file drivers/usb/dwc2/hw.h, commit
* a89bae709b3492b478480a2c9734e7e9393b279c ("usb: dwc2: Move
diff --git a/include/hw/usb/hcd-musb.h b/include/hw/usb/hcd-musb.h
deleted file mode 100644
index 4d4b1ec..0000000
--- a/include/hw/usb/hcd-musb.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * "Inventra" High-speed Dual-Role Controller (MUSB-HDRC), Mentor Graphics,
- * USB2.0 OTG compliant core used in various chips.
- *
- * Only host-mode and non-DMA accesses are currently supported.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- */
-
-#ifndef HW_USB_HCD_MUSB_H
-#define HW_USB_HCD_MUSB_H
-
-#include "exec/hwaddr.h"
-
-enum musb_irq_source_e {
- musb_irq_suspend = 0,
- musb_irq_resume,
- musb_irq_rst_babble,
- musb_irq_sof,
- musb_irq_connect,
- musb_irq_disconnect,
- musb_irq_vbus_request,
- musb_irq_vbus_error,
- musb_irq_rx,
- musb_irq_tx,
- musb_set_vbus,
- musb_set_session,
- /* Add new interrupts here */
- musb_irq_max /* total number of interrupts defined */
-};
-
-/* TODO convert hcd-musb to QOM/qdev and remove MUSBReadFunc/MUSBWriteFunc */
-typedef void MUSBWriteFunc(void *opaque, hwaddr addr, uint32_t value);
-typedef uint32_t MUSBReadFunc(void *opaque, hwaddr addr);
-extern MUSBReadFunc * const musb_read[];
-extern MUSBWriteFunc * const musb_write[];
-
-typedef struct MUSBState MUSBState;
-
-MUSBState *musb_init(DeviceState *parent_device, int gpio_base);
-void musb_reset(MUSBState *s);
-uint32_t musb_core_intr_get(MUSBState *s);
-void musb_core_intr_clear(MUSBState *s, uint32_t mask);
-void musb_set_size(MUSBState *s, int epnum, int size, int is_tx);
-
-#endif
diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h
index e8ddf92..fed499b 100644
--- a/include/hw/vfio/vfio-common.h
+++ b/include/hw/vfio/vfio-common.h
@@ -95,10 +95,18 @@ typedef struct VFIOHostDMAWindow {
typedef struct IOMMUFDBackend IOMMUFDBackend;
+typedef struct VFIOIOASHwpt {
+ uint32_t hwpt_id;
+ uint32_t hwpt_flags;
+ QLIST_HEAD(, VFIODevice) device_list;
+ QLIST_ENTRY(VFIOIOASHwpt) next;
+} VFIOIOASHwpt;
+
typedef struct VFIOIOMMUFDContainer {
VFIOContainerBase bcontainer;
IOMMUFDBackend *be;
uint32_t ioas_id;
+ QLIST_HEAD(, VFIOIOASHwpt) hwpt_list;
} VFIOIOMMUFDContainer;
OBJECT_DECLARE_SIMPLE_TYPE(VFIOIOMMUFDContainer, VFIO_IOMMU_IOMMUFD);
@@ -116,6 +124,7 @@ typedef struct VFIODevice {
DeviceState *dev;
int fd;
int type;
+ bool mdev;
bool reset_works;
bool needs_reset;
bool no_mmap;
@@ -129,11 +138,15 @@ typedef struct VFIODevice {
VFIOMigration *migration;
Error *migration_blocker;
OnOffAuto pre_copy_dirty_page_tracking;
+ OnOffAuto device_dirty_page_tracking;
bool dirty_pages_supported;
bool dirty_tracking;
+ bool iommu_dirty_tracking;
HostIOMMUDevice *hiod;
int devid;
IOMMUFDBackend *iommufd;
+ VFIOIOASHwpt *hwpt;
+ QLIST_ENTRY(VFIODevice) hwpt_next;
} VFIODevice;
struct VFIODeviceOps {
@@ -231,6 +244,8 @@ void vfio_region_exit(VFIORegion *region);
void vfio_region_finalize(VFIORegion *region);
void vfio_reset_handler(void *opaque);
struct vfio_device_info *vfio_get_device_info(int fd);
+bool vfio_device_is_mdev(VFIODevice *vbasedev);
+bool vfio_device_hiod_realize(VFIODevice *vbasedev, Error **errp);
bool vfio_attach_device(char *name, VFIODevice *vbasedev,
AddressSpace *as, Error **errp);
void vfio_detach_device(VFIODevice *vbasedev);
diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
index d75faf4..461c168 100644
--- a/include/hw/virtio/vhost.h
+++ b/include/hw/virtio/vhost.h
@@ -171,6 +171,10 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
*/
void vhost_dev_cleanup(struct vhost_dev *hdev);
+void vhost_dev_disable_notifiers_nvqs(struct vhost_dev *hdev,
+ VirtIODevice *vdev,
+ unsigned int nvqs);
+
/**
* vhost_dev_enable_notifiers() - enable event notifiers
* @hdev: common vhost_dev structure
@@ -334,8 +338,6 @@ void vhost_virtqueue_stop(struct vhost_dev *dev, struct VirtIODevice *vdev,
void vhost_dev_reset_inflight(struct vhost_inflight *inflight);
void vhost_dev_free_inflight(struct vhost_inflight *inflight);
-void vhost_dev_save_inflight(struct vhost_inflight *inflight, QEMUFile *f);
-int vhost_dev_load_inflight(struct vhost_inflight *inflight, QEMUFile *f);
int vhost_dev_prepare_inflight(struct vhost_dev *hdev, VirtIODevice *vdev);
int vhost_dev_set_inflight(struct vhost_dev *dev,
struct vhost_inflight *inflight);
diff --git a/include/hw/virtio/virtio-acpi.h b/include/hw/virtio/virtio-acpi.h
index cace2a3..cdfbd94 100644
--- a/include/hw/virtio/virtio-acpi.h
+++ b/include/hw/virtio/virtio-acpi.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* ACPI support for virtio
*/
diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
index 7a59379..553799b 100644
--- a/include/hw/virtio/virtio-gpu.h
+++ b/include/hw/virtio/virtio-gpu.h
@@ -51,9 +51,7 @@ struct virtio_gpu_simple_resource {
unsigned int iov_cnt;
uint32_t scanout_bitmask;
pixman_image_t *image;
-#ifdef WIN32
- HANDLE handle;
-#endif
+ qemu_pixman_shareable share_handle;
uint64_t hostmem;
uint64_t blob_size;
@@ -99,6 +97,7 @@ enum virtio_gpu_base_conf_flags {
VIRTIO_GPU_FLAG_BLOB_ENABLED,
VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED,
VIRTIO_GPU_FLAG_RUTABAGA_ENABLED,
+ VIRTIO_GPU_FLAG_VENUS_ENABLED,
};
#define virtio_gpu_virgl_enabled(_cfg) \
@@ -117,6 +116,8 @@ enum virtio_gpu_base_conf_flags {
(_cfg.flags & (1 << VIRTIO_GPU_FLAG_RUTABAGA_ENABLED))
#define virtio_gpu_hostmem_enabled(_cfg) \
(_cfg.hostmem > 0)
+#define virtio_gpu_venus_enabled(_cfg) \
+ (_cfg.flags & (1 << VIRTIO_GPU_FLAG_VENUS_ENABLED))
struct virtio_gpu_base_conf {
uint32_t max_outputs;
@@ -196,8 +197,6 @@ struct VirtIOGPU {
uint64_t hostmem;
bool processing_cmdq;
- QEMUTimer *fence_poll;
- QEMUTimer *print_stats;
uint32_t inflight;
struct {
@@ -211,6 +210,8 @@ struct VirtIOGPU {
QTAILQ_HEAD(, VGPUDMABuf) bufs;
VGPUDMABuf *primary[VIRTIO_GPU_MAX_SCANOUTS];
} dmabuf;
+
+ GArray *capset_ids;
};
struct VirtIOGPUClass {
@@ -226,11 +227,23 @@ struct VirtIOGPUClass {
Error **errp);
};
+/* VirtIOGPUGL renderer states */
+typedef enum {
+ RS_START, /* starting state */
+ RS_INIT_FAILED, /* failed initialisation */
+ RS_INITED, /* initialised and working */
+ RS_RESET, /* inited and reset pending, moves to start after reset */
+} RenderState;
+
struct VirtIOGPUGL {
struct VirtIOGPU parent_obj;
- bool renderer_inited;
- bool renderer_reset;
+ RenderState renderer_state;
+
+ QEMUTimer *fence_poll;
+ QEMUTimer *print_stats;
+
+ QEMUBH *cmdq_resume_bh;
};
struct VhostUserGPU {
@@ -330,6 +343,13 @@ int virtio_gpu_update_dmabuf(VirtIOGPU *g,
struct virtio_gpu_framebuffer *fb,
struct virtio_gpu_rect *r);
+void virtio_gpu_update_scanout(VirtIOGPU *g,
+ uint32_t scanout_id,
+ struct virtio_gpu_simple_resource *res,
+ struct virtio_gpu_framebuffer *fb,
+ struct virtio_gpu_rect *r);
+void virtio_gpu_disable_scanout(VirtIOGPU *g, int scanout_id);
+
/* virtio-gpu-3d.c */
void virtio_gpu_virgl_process_cmd(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd);
@@ -337,6 +357,6 @@ void virtio_gpu_virgl_fence_poll(VirtIOGPU *g);
void virtio_gpu_virgl_reset_scanout(VirtIOGPU *g);
void virtio_gpu_virgl_reset(VirtIOGPU *g);
int virtio_gpu_virgl_init(VirtIOGPU *g);
-int virtio_gpu_virgl_get_num_capsets(VirtIOGPU *g);
+GArray *virtio_gpu_virgl_get_capsets(VirtIOGPU *g);
#endif
diff --git a/include/hw/virtio/virtio-iommu.h b/include/hw/virtio/virtio-iommu.h
index bdb3da7..7db4210 100644
--- a/include/hw/virtio/virtio-iommu.h
+++ b/include/hw/virtio/virtio-iommu.h
@@ -43,7 +43,6 @@ typedef struct IOMMUDevice {
MemoryRegion bypass_mr; /* The alias of shared memory MR */
GList *resv_regions;
GList *host_resv_ranges;
- bool probe_done;
} IOMMUDevice;
typedef struct IOMMUPciBus {
diff --git a/include/hw/virtio/virtio-mem.h b/include/hw/virtio/virtio-mem.h
index 5f5b02b..a1af144 100644
--- a/include/hw/virtio/virtio-mem.h
+++ b/include/hw/virtio/virtio-mem.h
@@ -14,6 +14,7 @@
#define HW_VIRTIO_MEM_H
#include "standard-headers/linux/virtio_mem.h"
+#include "hw/resettable.h"
#include "hw/virtio/virtio.h"
#include "qapi/qapi-types-misc.h"
#include "sysemu/hostmem.h"
@@ -115,6 +116,9 @@ struct VirtIOMEM {
/* listeners to notify on plug/unplug activity. */
QLIST_HEAD(, RamDiscardListener) rdl_list;
+
+ /* State of the resettable container */
+ ResettableState reset_state;
};
struct VirtIOMEMClass {
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index 7512afb..f526ecc 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -69,6 +69,8 @@ typedef struct VirtQueueElement
unsigned int ndescs;
unsigned int out_num;
unsigned int in_num;
+ /* Element has been processed (VIRTIO_F_IN_ORDER) */
+ bool in_order_filled;
hwaddr *in_addr;
hwaddr *out_addr;
struct iovec *in_sg;
@@ -221,6 +223,7 @@ struct VirtioDeviceClass {
int (*post_load)(VirtIODevice *vdev);
const VMStateDescription *vmsd;
bool (*primary_unplug_pending)(void *opaque);
+ /* May be called even when vdev->vhost_started is false */
struct vhost_dev *(*get_vhost)(VirtIODevice *vdev);
void (*toggle_device_iotlb)(VirtIODevice *vdev);
};
@@ -271,9 +274,13 @@ void qemu_put_virtqueue_element(VirtIODevice *vdev, QEMUFile *f,
VirtQueueElement *elem);
int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes,
unsigned int out_bytes);
-void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
- unsigned int *out_bytes,
- unsigned max_in_bytes, unsigned max_out_bytes);
+/**
+ * Return <0 on error or an opaque >=0 to pass to
+ * virtio_queue_enable_notification_and_check on success.
+ */
+int virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
+ unsigned int *out_bytes, unsigned max_in_bytes,
+ unsigned max_out_bytes);
void virtio_notify_irqfd(VirtIODevice *vdev, VirtQueue *vq);
void virtio_notify(VirtIODevice *vdev, VirtQueue *vq);
@@ -307,6 +314,15 @@ int virtio_queue_ready(VirtQueue *vq);
int virtio_queue_empty(VirtQueue *vq);
+/**
+ * Enable notification and check whether guest has added some
+ * buffers since last call to virtqueue_get_avail_bytes.
+ *
+ * @opaque: value returned from virtqueue_get_avail_bytes
+ */
+bool virtio_queue_enable_notification_and_check(VirtQueue *vq,
+ int opaque);
+
void virtio_queue_set_shadow_avail_idx(VirtQueue *vq, uint16_t idx);
/* Host binding interface. */
@@ -371,7 +387,9 @@ typedef struct VirtIORNGConf VirtIORNGConf;
DEFINE_PROP_BIT64("packed", _state, _field, \
VIRTIO_F_RING_PACKED, false), \
DEFINE_PROP_BIT64("queue_reset", _state, _field, \
- VIRTIO_F_RING_RESET, true)
+ VIRTIO_F_RING_RESET, true), \
+ DEFINE_PROP_BIT64("in_order", _state, _field, \
+ VIRTIO_F_IN_ORDER, false)
hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n);
bool virtio_queue_enabled_legacy(VirtIODevice *vdev, int n);
diff --git a/include/hw/xen/xen-hvm-common.h b/include/hw/xen/xen-hvm-common.h
index 3d79623..0f586c4 100644
--- a/include/hw/xen/xen-hvm-common.h
+++ b/include/hw/xen/xen-hvm-common.h
@@ -81,6 +81,8 @@ typedef struct XenIOState {
QLIST_HEAD(, XenPciDevice) dev_list;
DeviceListener device_listener;
+ bool has_bufioreq;
+
Notifier exit;
} XenIOState;
@@ -95,6 +97,7 @@ void xen_device_unrealize(DeviceListener *listener, DeviceState *dev);
void xen_hvm_change_state_handler(void *opaque, bool running, RunState rstate);
void xen_register_ioreq(XenIOState *state, unsigned int max_cpus,
+ uint8_t handle_bufioreq,
const MemoryListener *xen_memory_listener);
void cpu_ioreq_pio(ioreq_t *req);
diff --git a/include/hw/xen/xen-legacy-backend.h b/include/hw/xen/xen-legacy-backend.h
index 943732b..e198b12 100644
--- a/include/hw/xen/xen-legacy-backend.h
+++ b/include/hw/xen/xen-legacy-backend.h
@@ -50,10 +50,6 @@ void *xen_be_map_grant_refs(struct XenLegacyDevice *xendev, uint32_t *refs,
void xen_be_unmap_grant_refs(struct XenLegacyDevice *xendev, void *ptr,
uint32_t *refs, unsigned int nr_refs);
-int xen_be_copy_grant_refs(struct XenLegacyDevice *xendev,
- bool to_domain, XenGrantCopySegment segs[],
- unsigned int nr_segs);
-
static inline void *xen_be_map_grant_ref(struct XenLegacyDevice *xendev,
uint32_t ref, int prot)
{
@@ -70,6 +66,5 @@ static inline void xen_be_unmap_grant_ref(struct XenLegacyDevice *xendev,
void xen_config_cleanup(void);
int xen_config_dev_vfb(int vdev, const char *type);
int xen_config_dev_vkbd(int vdev);
-int xen_config_dev_console(int vdev);
#endif /* HW_XEN_LEGACY_BACKEND_H */
diff --git a/include/hw/xen/xen-pvh-common.h b/include/hw/xen/xen-pvh-common.h
new file mode 100644
index 0000000..5cdd23c
--- /dev/null
+++ b/include/hw/xen/xen-pvh-common.h
@@ -0,0 +1,91 @@
+/*
+ * QEMU Xen PVH machine - common code.
+ *
+ * Copyright (c) 2024 Advanced Micro Devices, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef XEN_PVH_COMMON_H__
+#define XEN_PVH_COMMON_H__
+
+#include <assert.h>
+#include "hw/sysbus.h"
+#include "hw/hw.h"
+#include "hw/xen/xen-hvm-common.h"
+#include "hw/pci-host/gpex.h"
+
+#define TYPE_XEN_PVH_MACHINE MACHINE_TYPE_NAME("xen-pvh-base")
+OBJECT_DECLARE_TYPE(XenPVHMachineState, XenPVHMachineClass,
+ XEN_PVH_MACHINE)
+
+struct XenPVHMachineClass {
+ MachineClass parent;
+
+ /* PVH implementation specific init. */
+ void (*init)(MachineState *state);
+
+ /*
+ * set_pci_intx_irq - Deliver INTX irqs to the guest.
+ *
+ * @opaque: pointer to XenPVHMachineState.
+ * @irq: IRQ after swizzling, between 0-3.
+ * @level: IRQ level.
+ */
+ void (*set_pci_intx_irq)(void *opaque, int irq, int level);
+
+ /*
+ * set_pci_link_route: - optional implementation call to setup
+ * routing between INTX IRQ (0 - 3) and GSI's.
+ *
+ * @line: line the INTx line (0 => A .. 3 => B)
+ * @irq: GSI
+ */
+ int (*set_pci_link_route)(uint8_t line, uint8_t irq);
+
+ /* Allow implementations to optionally enable buffered ioreqs. */
+ uint8_t handle_bufioreq;
+
+ /*
+ * Each implementation can optionally enable features that it
+ * supports and are known to work.
+ */
+ bool has_pci;
+ bool has_tpm;
+ bool has_virtio_mmio;
+};
+
+struct XenPVHMachineState {
+ /*< private >*/
+ MachineState parent;
+
+ XenIOState ioreq;
+
+ struct {
+ MemoryRegion low;
+ MemoryRegion high;
+ } ram;
+
+ struct {
+ GPEXHost gpex;
+ MemoryRegion mmio_alias;
+ MemoryRegion mmio_high_alias;
+ } pci;
+
+ struct {
+ MemMapEntry ram_low, ram_high;
+ MemMapEntry tpm;
+
+ /* Virtio-mmio */
+ MemMapEntry virtio_mmio;
+ uint32_t virtio_mmio_num;
+ uint32_t virtio_mmio_irq_base;
+
+ /* PCI */
+ MemMapEntry pci_ecam, pci_mmio, pci_mmio_high;
+ uint32_t pci_intx_irq_base;
+ } cfg;
+};
+
+void xen_pvh_class_setup_common_props(XenPVHMachineClass *xpc);
+#endif
diff --git a/include/hw/xen/xen_native.h b/include/hw/xen/xen_native.h
index 1a5ad69..5caf91a 100644
--- a/include/hw/xen/xen_native.h
+++ b/include/hw/xen/xen_native.h
@@ -464,10 +464,11 @@ static inline void xen_unmap_pcidev(domid_t dom,
}
static inline int xen_create_ioreq_server(domid_t dom,
+ int handle_bufioreq,
ioservid_t *ioservid)
{
int rc = xendevicemodel_create_ioreq_server(xen_dmod, dom,
- HVM_IOREQSRV_BUFIOREQ_ATOMIC,
+ handle_bufioreq,
ioservid);
if (rc == 0) {
diff --git a/include/io/channel.h b/include/io/channel.h
index 7986c49..bdf0bca 100644
--- a/include/io/channel.h
+++ b/include/io/channel.h
@@ -160,6 +160,9 @@ struct QIOChannelClass {
void *opaque);
int (*io_flush)(QIOChannel *ioc,
Error **errp);
+ int (*io_peerpid)(QIOChannel *ioc,
+ unsigned int *pid,
+ Error **errp);
};
/* General I/O handling functions */
@@ -981,4 +984,22 @@ int coroutine_mixed_fn qio_channel_writev_full_all(QIOChannel *ioc,
int qio_channel_flush(QIOChannel *ioc,
Error **errp);
+/**
+ * qio_channel_get_peercred:
+ * @ioc: the channel object
+ * @pid: pointer to pid
+ * @errp: pointer to a NULL-initialized error object
+ *
+ * Returns the pid of the peer process connected to this socket.
+ *
+ * The use of this function is possible only for connected
+ * AF_UNIX stream sockets and for AF_UNIX stream and datagram
+ * socket pairs on Linux.
+ * Return -1 on error with pid -1 for the non-Linux OS.
+ *
+ */
+int qio_channel_get_peerpid(QIOChannel *ioc,
+ unsigned int *pid,
+ Error **errp);
+
#endif /* QIO_CHANNEL_H */
diff --git a/include/net/net.h b/include/net/net.h
index c8f6797..cdd5b10 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -172,9 +172,6 @@ ssize_t qemu_sendv_packet_async(NetClientState *nc, const struct iovec *iov,
int iovcnt, NetPacketSent *sent_cb);
ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size);
ssize_t qemu_receive_packet(NetClientState *nc, const uint8_t *buf, int size);
-ssize_t qemu_receive_packet_iov(NetClientState *nc,
- const struct iovec *iov,
- int iovcnt);
ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size);
ssize_t qemu_send_packet_async(NetClientState *nc, const uint8_t *buf,
int size, NetPacketSent *sent_cb);
@@ -307,7 +304,6 @@ void hmp_host_net_remove(Monitor *mon, const QDict *qdict);
void netdev_add(QemuOpts *opts, Error **errp);
int net_hub_id_for_client(NetClientState *nc, int *id);
-NetClientState *net_hub_port_find(int hub_id);
#define DEFAULT_NETWORK_SCRIPT CONFIG_SYSCONFDIR "/qemu-ifup"
#define DEFAULT_NETWORK_DOWN_SCRIPT CONFIG_SYSCONFDIR "/qemu-ifdown"
diff --git a/include/net/queue.h b/include/net/queue.h
index 9f2f289..2e686b1 100644
--- a/include/net/queue.h
+++ b/include/net/queue.h
@@ -59,10 +59,6 @@ ssize_t qemu_net_queue_receive(NetQueue *queue,
const uint8_t *data,
size_t size);
-ssize_t qemu_net_queue_receive_iov(NetQueue *queue,
- const struct iovec *iov,
- int iovcnt);
-
ssize_t qemu_net_queue_send(NetQueue *queue,
NetClientState *sender,
unsigned flags,
diff --git a/include/qapi/qmp/qerror.h b/include/qapi/qmp/qerror.h
index 38e8976..d1db6f1 100644
--- a/include/qapi/qmp/qerror.h
+++ b/include/qapi/qmp/qerror.h
@@ -23,10 +23,4 @@
#define QERR_MISSING_PARAMETER \
"Parameter '%s' is missing"
-#define QERR_PROPERTY_VALUE_OUT_OF_RANGE \
- "Property %s.%s doesn't take value %" PRId64 " (minimum: %" PRId64 ", maximum: %" PRId64 ")"
-
-#define QERR_UNSUPPORTED \
- "this feature or command is not currently supported"
-
#endif /* QERROR_H */
diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h
index 89b97d8..256d782 100644
--- a/include/qapi/qmp/qobject.h
+++ b/include/qapi/qmp/qobject.h
@@ -54,7 +54,7 @@ struct QObject {
typeof(obj) _obj = (obj); \
_obj ? container_of(&_obj->base, QObject, base) : NULL; \
})
-#define QOBJECT(obj) QOBJECT_INTERNAL((obj), MAKE_IDENTFIER(_obj))
+#define QOBJECT(obj) QOBJECT_INTERNAL((obj), MAKE_IDENTIFIER(_obj))
/* Required for qobject_to() */
#define QTYPE_CAST_TO_QNull QTYPE_QNULL
diff --git a/include/qemu/atomic.h b/include/qemu/atomic.h
index dc4118d..7a3f2e6 100644
--- a/include/qemu/atomic.h
+++ b/include/qemu/atomic.h
@@ -128,7 +128,7 @@
_val; \
})
#define qatomic_rcu_read(ptr) \
- qatomic_rcu_read_internal((ptr), MAKE_IDENTFIER(_val))
+ qatomic_rcu_read_internal((ptr), MAKE_IDENTIFIER(_val))
#define qatomic_rcu_set(ptr, i) do { \
qemu_build_assert(sizeof(*ptr) <= ATOMIC_REG_SIZE); \
diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h
index ad22910..b915835 100644
--- a/include/qemu/bswap.h
+++ b/include/qemu/bswap.h
@@ -140,6 +140,8 @@ CPU_CONVERT(le, 16, uint16_t)
CPU_CONVERT(le, 32, uint32_t)
CPU_CONVERT(le, 64, uint64_t)
+#undef CPU_CONVERT
+
/*
* Same as cpu_to_le{16,32,64}, except that gcc will figure the result is
* a compile-time constant if you pass in a constant. So this can be
diff --git a/include/qemu/co-shared-resource.h b/include/qemu/co-shared-resource.h
index 78ca585..41be1a8 100644
--- a/include/qemu/co-shared-resource.h
+++ b/include/qemu/co-shared-resource.h
@@ -45,13 +45,6 @@ SharedResource *shres_create(uint64_t total);
void shres_destroy(SharedResource *s);
/*
- * Try to allocate an amount of @n. Return true on success, and false
- * if there is too little left of the collective resource to fulfill
- * the request.
- */
-bool co_try_get_from_shres(SharedResource *s, uint64_t n);
-
-/*
* Allocate an amount of @n, and, if necessary, yield until
* that becomes possible.
*/
diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h
index 554c5ce..c06954c 100644
--- a/include/qemu/compiler.h
+++ b/include/qemu/compiler.h
@@ -38,7 +38,7 @@
#endif
/* Expands into an identifier stemN, where N is another number each time */
-#define MAKE_IDENTFIER(stem) glue(stem, __COUNTER__)
+#define MAKE_IDENTIFIER(stem) glue(stem, __COUNTER__)
#ifndef likely
#define likely(x) __builtin_expect(!!(x), 1)
diff --git a/include/qemu/crc-ccitt.h b/include/qemu/crc-ccitt.h
index 8918daf..ce28e29 100644
--- a/include/qemu/crc-ccitt.h
+++ b/include/qemu/crc-ccitt.h
@@ -8,7 +8,7 @@
*
* From Linux kernel v5.10 include/linux/crc-ccitt.h
*
- * SPDX-License-Identifier: GPL-2.0
+ * SPDX-License-Identifier: GPL-2.0-only
*/
#ifndef CRC_CCITT_H
diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h
index da15547..34a9b9b 100644
--- a/include/qemu/cutils.h
+++ b/include/qemu/cutils.h
@@ -241,13 +241,10 @@ int uleb128_decode_small(const uint8_t *in, uint32_t *n);
int qemu_pstrcmp0(const char **str1, const char **str2);
/* Find program directory, and save it for later usage with
- * qemu_get_exec_dir().
+ * get_relocated_path().
* Try OS specific API first, if not working, parse from argv0. */
void qemu_init_exec_dir(const char *argv0);
-/* Get the saved exec dir. */
-const char *qemu_get_exec_dir(void);
-
/**
* get_relocated_path:
* @dir: the directory (typically a `CONFIG_*DIR` variable) to be relocated.
diff --git a/include/qemu/envlist.h b/include/qemu/envlist.h
index 6006dfa..b2883f6 100644
--- a/include/qemu/envlist.h
+++ b/include/qemu/envlist.h
@@ -7,8 +7,6 @@ envlist_t *envlist_create(void);
void envlist_free(envlist_t *);
int envlist_setenv(envlist_t *, const char *);
int envlist_unsetenv(envlist_t *, const char *);
-int envlist_parse_set(envlist_t *, const char *);
-int envlist_parse_unset(envlist_t *, const char *);
char **envlist_to_environ(const envlist_t *, size_t *);
#endif /* ENVLIST_H */
diff --git a/include/qemu/fifo8.h b/include/qemu/fifo8.h
index c6295c6..4f768d4 100644
--- a/include/qemu/fifo8.h
+++ b/include/qemu/fifo8.h
@@ -15,10 +15,9 @@ typedef struct {
* @fifo: struct Fifo8 to initialise with new FIFO
* @capacity: capacity of the newly created FIFO
*
- * Create a FIFO of the specified size. Clients should call fifo8_destroy()
+ * Create a FIFO of the specified capacity. Clients should call fifo8_destroy()
* when finished using the fifo. The FIFO is initially empty.
*/
-
void fifo8_create(Fifo8 *fifo, uint32_t capacity);
/**
@@ -26,9 +25,8 @@ void fifo8_create(Fifo8 *fifo, uint32_t capacity);
* @fifo: FIFO to cleanup
*
* Cleanup a FIFO created with fifo8_create(). Frees memory created for FIFO
- *storage. The FIFO is no longer usable after this has been called.
+ * storage. The FIFO is no longer usable after this has been called.
*/
-
void fifo8_destroy(Fifo8 *fifo);
/**
@@ -39,7 +37,6 @@ void fifo8_destroy(Fifo8 *fifo);
* Push a data byte to the FIFO. Behaviour is undefined if the FIFO is full.
* Clients are responsible for checking for fullness using fifo8_is_full().
*/
-
void fifo8_push(Fifo8 *fifo, uint8_t data);
/**
@@ -52,7 +49,6 @@ void fifo8_push(Fifo8 *fifo, uint8_t data);
* Clients are responsible for checking the space left in the FIFO using
* fifo8_num_free().
*/
-
void fifo8_push_all(Fifo8 *fifo, const uint8_t *data, uint32_t num);
/**
@@ -64,25 +60,65 @@ void fifo8_push_all(Fifo8 *fifo, const uint8_t *data, uint32_t num);
*
* Returns: The popped data byte.
*/
-
uint8_t fifo8_pop(Fifo8 *fifo);
/**
+ * fifo8_peek:
+ * @fifo: fifo to peek from
+ *
+ * Peek the data byte at the current head of the FIFO. Clients are responsible
+ * for checking for emptyness using fifo8_is_empty().
+ *
+ * Returns: The peeked data byte.
+ */
+uint8_t fifo8_peek(Fifo8 *fifo);
+
+/**
* fifo8_pop_buf:
* @fifo: FIFO to pop from
+ * @dest: the buffer to write the data into (can be NULL)
+ * @destlen: size of @dest and maximum number of bytes to pop
+ *
+ * Pop a number of elements from the FIFO up to a maximum of @destlen.
+ * The popped data is copied into the @dest buffer.
+ * Care is taken when the data wraps around in the ring buffer.
+ *
+ * Returns: number of bytes popped.
+ */
+uint32_t fifo8_pop_buf(Fifo8 *fifo, uint8_t *dest, uint32_t destlen);
+
+/**
+ * fifo8_peek_buf:
+ * @fifo: FIFO to read from
+ * @dest: the buffer to write the data into (can be NULL)
+ * @destlen: size of @dest and maximum number of bytes to peek
+ *
+ * Peek a number of elements from the FIFO up to a maximum of @destlen.
+ * The peeked data is copied into the @dest buffer.
+ * Care is taken when the data wraps around in the ring buffer.
+ *
+ * Returns: number of bytes peeked.
+ */
+uint32_t fifo8_peek_buf(Fifo8 *fifo, uint8_t *dest, uint32_t destlen);
+
+/**
+ * fifo8_pop_bufptr:
+ * @fifo: FIFO to pop from
* @max: maximum number of bytes to pop
* @numptr: pointer filled with number of bytes returned (can be NULL)
*
- * Pop a number of elements from the FIFO up to a maximum of max. The buffer
+ * New code should prefer to use fifo8_pop_buf() instead of fifo8_pop_bufptr().
+ *
+ * Pop a number of elements from the FIFO up to a maximum of @max. The buffer
* containing the popped data is returned. This buffer points directly into
- * the FIFO backing store and data is invalidated once any of the fifo8_* APIs
- * are called on the FIFO.
+ * the internal FIFO backing store and data (without checking for overflow!)
+ * and is invalidated once any of the fifo8_* APIs are called on the FIFO.
*
* The function may return fewer bytes than requested when the data wraps
* around in the ring buffer; in this case only a contiguous part of the data
* is returned.
*
- * The number of valid bytes returned is populated in *numptr; will always
+ * The number of valid bytes returned is populated in *@numptr; will always
* return at least 1 byte. max must not be 0 or greater than the number of
* bytes in the FIFO.
*
@@ -91,15 +127,15 @@ uint8_t fifo8_pop(Fifo8 *fifo);
*
* Returns: A pointer to popped data.
*/
-const uint8_t *fifo8_pop_buf(Fifo8 *fifo, uint32_t max, uint32_t *numptr);
+const uint8_t *fifo8_pop_bufptr(Fifo8 *fifo, uint32_t max, uint32_t *numptr);
/**
- * fifo8_peek_buf: read upto max bytes from the fifo
+ * fifo8_peek_bufptr: read upto max bytes from the fifo
* @fifo: FIFO to read from
* @max: maximum number of bytes to peek
* @numptr: pointer filled with number of bytes returned (can be NULL)
*
- * Peek into a number of elements from the FIFO up to a maximum of max.
+ * Peek into a number of elements from the FIFO up to a maximum of @max.
* The buffer containing the data peeked into is returned. This buffer points
* directly into the FIFO backing store. Since data is invalidated once any
* of the fifo8_* APIs are called on the FIFO, it is the caller responsibility
@@ -109,7 +145,7 @@ const uint8_t *fifo8_pop_buf(Fifo8 *fifo, uint32_t max, uint32_t *numptr);
* around in the ring buffer; in this case only a contiguous part of the data
* is returned.
*
- * The number of valid bytes returned is populated in *numptr; will always
+ * The number of valid bytes returned is populated in *@numptr; will always
* return at least 1 byte. max must not be 0 or greater than the number of
* bytes in the FIFO.
*
@@ -118,7 +154,16 @@ const uint8_t *fifo8_pop_buf(Fifo8 *fifo, uint32_t max, uint32_t *numptr);
*
* Returns: A pointer to peekable data.
*/
-const uint8_t *fifo8_peek_buf(Fifo8 *fifo, uint32_t max, uint32_t *numptr);
+const uint8_t *fifo8_peek_bufptr(Fifo8 *fifo, uint32_t max, uint32_t *numptr);
+
+/**
+ * fifo8_drop:
+ * @fifo: FIFO to drop bytes
+ * @len: number of bytes to drop
+ *
+ * Drop (consume) bytes from a FIFO.
+ */
+void fifo8_drop(Fifo8 *fifo, uint32_t len);
/**
* fifo8_reset:
@@ -126,7 +171,6 @@ const uint8_t *fifo8_peek_buf(Fifo8 *fifo, uint32_t max, uint32_t *numptr);
*
* Reset a FIFO. All data is discarded and the FIFO is emptied.
*/
-
void fifo8_reset(Fifo8 *fifo);
/**
@@ -137,7 +181,6 @@ void fifo8_reset(Fifo8 *fifo);
*
* Returns: True if the fifo is empty, false otherwise.
*/
-
bool fifo8_is_empty(Fifo8 *fifo);
/**
@@ -148,7 +191,6 @@ bool fifo8_is_empty(Fifo8 *fifo);
*
* Returns: True if the fifo is full, false otherwise.
*/
-
bool fifo8_is_full(Fifo8 *fifo);
/**
@@ -159,7 +201,6 @@ bool fifo8_is_full(Fifo8 *fifo);
*
* Returns: Number of free bytes.
*/
-
uint32_t fifo8_num_free(Fifo8 *fifo);
/**
@@ -170,7 +211,6 @@ uint32_t fifo8_num_free(Fifo8 *fifo);
*
* Returns: Number of used bytes.
*/
-
uint32_t fifo8_num_used(Fifo8 *fifo);
extern const VMStateDescription vmstate_fifo8;
diff --git a/include/qemu/iov.h b/include/qemu/iov.h
index 63a1c01..44f9db5 100644
--- a/include/qemu/iov.h
+++ b/include/qemu/iov.h
@@ -1,6 +1,7 @@
/*
* Helpers for using (partial) iovecs.
*
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
* Copyright (C) 2010 Red Hat, Inc.
*
* Author(s):
@@ -76,6 +77,32 @@ size_t iov_memset(const struct iovec *iov, const unsigned int iov_cnt,
size_t offset, int fillc, size_t bytes);
/*
+ * Send/recv data from/to iovec buffers directly, with the provided
+ * socket flags.
+ *
+ * `offset' bytes in the beginning of iovec buffer are skipped and
+ * next `bytes' bytes are used, which must be within data of iovec.
+ *
+ * r = iov_send_recv_with_flags(sockfd, sockflags, iov, iovcnt,
+ * offset, bytes, true);
+ *
+ * is logically equivalent to
+ *
+ * char *buf = malloc(bytes);
+ * iov_to_buf(iov, iovcnt, offset, buf, bytes);
+ * r = send(sockfd, buf, bytes, sockflags);
+ * free(buf);
+ *
+ * For iov_send_recv_with_flags() _whole_ area being sent or received
+ * should be within the iovec, not only beginning of it.
+ */
+ssize_t iov_send_recv_with_flags(int sockfd, int sockflags,
+ const struct iovec *iov,
+ unsigned iov_cnt, size_t offset,
+ size_t bytes,
+ bool do_send);
+
+/*
* Send/recv data from/to iovec buffers directly
*
* `offset' bytes in the beginning of iovec buffer are skipped and
diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h
index 2a10a70..44a4593 100644
--- a/include/qemu/iova-tree.h
+++ b/include/qemu/iova-tree.h
@@ -112,31 +112,6 @@ const DMAMap *iova_tree_find(const IOVATree *tree, const DMAMap *map);
const DMAMap *iova_tree_find_iova(const IOVATree *tree, const DMAMap *map);
/**
- * iova_tree_find_address:
- *
- * @tree: the iova tree to search from
- * @iova: the iova address to find
- *
- * Similar to iova_tree_find(), but it tries to find mapping with
- * range iova=iova & size=0.
- *
- * Return: same as iova_tree_find().
- */
-const DMAMap *iova_tree_find_address(const IOVATree *tree, hwaddr iova);
-
-/**
- * iova_tree_foreach:
- *
- * @tree: the iova tree to iterate on
- * @iterator: the iterator for the mappings, return true to stop
- *
- * Iterate over the iova tree.
- *
- * Return: 1 if found any overlap, 0 if not, <0 if error.
- */
-void iova_tree_foreach(IOVATree *tree, iova_tree_iterator iterator);
-
-/**
* iova_tree_alloc_map:
*
* @tree: the iova tree to allocate from
diff --git a/include/qemu/lockcnt.h b/include/qemu/lockcnt.h
new file mode 100644
index 0000000..f4b62a3
--- /dev/null
+++ b/include/qemu/lockcnt.h
@@ -0,0 +1,130 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QemuLockCnt implementation
+ *
+ * Copyright Red Hat, Inc. 2017
+ *
+ * Author:
+ * Paolo Bonzini <pbonzini@redhat.com>
+ *
+ */
+
+#ifndef QEMU_LOCKCNT_H
+#define QEMU_LOCKCNT_H
+
+#include "qemu/thread.h"
+
+typedef struct QemuLockCnt QemuLockCnt;
+
+struct QemuLockCnt {
+#ifndef CONFIG_LINUX
+ QemuMutex mutex;
+#endif
+ unsigned count;
+};
+
+/**
+ * qemu_lockcnt_init: initialize a QemuLockcnt
+ * @lockcnt: the lockcnt to initialize
+ *
+ * Initialize lockcnt's counter to zero and prepare its mutex
+ * for usage.
+ */
+void qemu_lockcnt_init(QemuLockCnt *lockcnt);
+
+/**
+ * qemu_lockcnt_destroy: destroy a QemuLockcnt
+ * @lockcnt: the lockcnt to destruct
+ *
+ * Destroy lockcnt's mutex.
+ */
+void qemu_lockcnt_destroy(QemuLockCnt *lockcnt);
+
+/**
+ * qemu_lockcnt_inc: increment a QemuLockCnt's counter
+ * @lockcnt: the lockcnt to operate on
+ *
+ * If the lockcnt's count is zero, wait for critical sections
+ * to finish and increment lockcnt's count to 1. If the count
+ * is not zero, just increment it.
+ *
+ * Because this function can wait on the mutex, it must not be
+ * called while the lockcnt's mutex is held by the current thread.
+ * For the same reason, qemu_lockcnt_inc can also contribute to
+ * AB-BA deadlocks. This is a sample deadlock scenario::
+ *
+ * thread 1 thread 2
+ * -------------------------------------------------------
+ * qemu_lockcnt_lock(&lc1);
+ * qemu_lockcnt_lock(&lc2);
+ * qemu_lockcnt_inc(&lc2);
+ * qemu_lockcnt_inc(&lc1);
+ */
+void qemu_lockcnt_inc(QemuLockCnt *lockcnt);
+
+/**
+ * qemu_lockcnt_dec: decrement a QemuLockCnt's counter
+ * @lockcnt: the lockcnt to operate on
+ */
+void qemu_lockcnt_dec(QemuLockCnt *lockcnt);
+
+/**
+ * qemu_lockcnt_dec_and_lock: decrement a QemuLockCnt's counter and
+ * possibly lock it.
+ * @lockcnt: the lockcnt to operate on
+ *
+ * Decrement lockcnt's count. If the new count is zero, lock
+ * the mutex and return true. Otherwise, return false.
+ */
+bool qemu_lockcnt_dec_and_lock(QemuLockCnt *lockcnt);
+
+/**
+ * qemu_lockcnt_dec_if_lock: possibly decrement a QemuLockCnt's counter and
+ * lock it.
+ * @lockcnt: the lockcnt to operate on
+ *
+ * If the count is 1, decrement the count to zero, lock
+ * the mutex and return true. Otherwise, return false.
+ */
+bool qemu_lockcnt_dec_if_lock(QemuLockCnt *lockcnt);
+
+/**
+ * qemu_lockcnt_lock: lock a QemuLockCnt's mutex.
+ * @lockcnt: the lockcnt to operate on
+ *
+ * Remember that concurrent visits are not blocked unless the count is
+ * also zero. You can use qemu_lockcnt_count to check for this inside a
+ * critical section.
+ */
+void qemu_lockcnt_lock(QemuLockCnt *lockcnt);
+
+/**
+ * qemu_lockcnt_unlock: release a QemuLockCnt's mutex.
+ * @lockcnt: the lockcnt to operate on.
+ */
+void qemu_lockcnt_unlock(QemuLockCnt *lockcnt);
+
+/**
+ * qemu_lockcnt_inc_and_unlock: combined unlock/increment on a QemuLockCnt.
+ * @lockcnt: the lockcnt to operate on.
+ *
+ * This is the same as
+ *
+ * qemu_lockcnt_unlock(lockcnt);
+ * qemu_lockcnt_inc(lockcnt);
+ *
+ * but more efficient.
+ */
+void qemu_lockcnt_inc_and_unlock(QemuLockCnt *lockcnt);
+
+/**
+ * qemu_lockcnt_count: query a LockCnt's count.
+ * @lockcnt: the lockcnt to query.
+ *
+ * Note that the count can change at any time. Still, while the
+ * lockcnt is locked, one can usefully check whether the count
+ * is non-zero.
+ */
+unsigned qemu_lockcnt_count(QemuLockCnt *lockcnt);
+
+#endif
diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
index 191916f..fe7c3c5 100644
--- a/include/qemu/osdep.h
+++ b/include/qemu/osdep.h
@@ -399,7 +399,7 @@ void QEMU_ERROR("code path is reachable")
})
#undef MIN
#define MIN(a, b) \
- MIN_INTERNAL((a), (b), MAKE_IDENTFIER(_a), MAKE_IDENTFIER(_b))
+ MIN_INTERNAL((a), (b), MAKE_IDENTIFIER(_a), MAKE_IDENTIFIER(_b))
#define MAX_INTERNAL(a, b, _a, _b) \
({ \
@@ -408,7 +408,7 @@ void QEMU_ERROR("code path is reachable")
})
#undef MAX
#define MAX(a, b) \
- MAX_INTERNAL((a), (b), MAKE_IDENTFIER(_a), MAKE_IDENTFIER(_b))
+ MAX_INTERNAL((a), (b), MAKE_IDENTIFIER(_a), MAKE_IDENTIFIER(_b))
#ifdef __COVERITY__
# define MIN_CONST(a, b) ((a) < (b) ? (a) : (b))
@@ -440,7 +440,7 @@ void QEMU_ERROR("code path is reachable")
_a == 0 ? _b : (_b == 0 || _b > _a) ? _a : _b; \
})
#define MIN_NON_ZERO(a, b) \
- MIN_NON_ZERO_INTERNAL((a), (b), MAKE_IDENTFIER(_a), MAKE_IDENTFIER(_b))
+ MIN_NON_ZERO_INTERNAL((a), (b), MAKE_IDENTIFIER(_a), MAKE_IDENTIFIER(_b))
/*
* Round number down to multiple. Safe when m is not a power of 2 (see
@@ -758,6 +758,17 @@ static inline void qemu_reset_optind(void)
int qemu_fdatasync(int fd);
/**
+ * qemu_close_all_open_fd:
+ *
+ * Close all open file descriptors except the ones supplied in the @skip array
+ *
+ * @skip: ordered array of distinct file descriptors that should not be closed
+ * if any, or NULL.
+ * @nskip: number of entries in the @skip array or 0 if @skip is NULL.
+ */
+void qemu_close_all_open_fd(const int *skip, unsigned int nskip);
+
+/**
* Sync changes made to the memory mapped file back to the backing
* storage. For POSIX compliant systems this will fallback
* to regular msync call. Otherwise it will trigger whole file sync
@@ -786,8 +797,7 @@ size_t qemu_get_host_physmem(void);
* Toggle write/execute on the pages marked MAP_JIT
* for the current thread.
*/
-#if defined(MAC_OS_VERSION_11_0) && \
- MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+#ifdef __APPLE__
static inline void qemu_thread_jit_execute(void)
{
pthread_jit_write_protect_np(true);
diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
index af5f9db..9726a9e 100644
--- a/include/qemu/plugin.h
+++ b/include/qemu/plugin.h
@@ -167,6 +167,8 @@ qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1,
void qemu_plugin_vcpu_syscall_ret(CPUState *cpu, int64_t num, int64_t ret);
void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr,
+ uint64_t value_low,
+ uint64_t value_high,
MemOpIdx oi, enum qemu_plugin_mem_rw rw);
void qemu_plugin_flush_cb(void);
@@ -251,6 +253,8 @@ void qemu_plugin_vcpu_syscall_ret(CPUState *cpu, int64_t num, int64_t ret)
{ }
static inline void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr,
+ uint64_t value_low,
+ uint64_t value_high,
MemOpIdx oi,
enum qemu_plugin_mem_rw rw)
{ }
diff --git a/include/qemu/pmem.h b/include/qemu/pmem.h
index d2d7ad0..e12a67b 100644
--- a/include/qemu/pmem.h
+++ b/include/qemu/pmem.h
@@ -22,7 +22,6 @@ pmem_memcpy_persist(void *pmemdest, const void *src, size_t len)
/* If 'pmem' option is 'on', we should always have libpmem support,
or qemu will report a error and exit, never come here. */
g_assert_not_reached();
- return NULL;
}
static inline void
diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
index c71c705..622c9a0 100644
--- a/include/qemu/qemu-plugin.h
+++ b/include/qemu/qemu-plugin.h
@@ -57,11 +57,19 @@ typedef uint64_t qemu_plugin_id_t;
* - Remove qemu_plugin_register_vcpu_{tb, insn, mem}_exec_inline.
* Those functions are replaced by *_per_vcpu variants, which guarantee
* thread-safety for operations.
+ *
+ * version 3:
+ * - modified arguments and return value of qemu_plugin_insn_data to copy
+ * the data into a user-provided buffer instead of returning a pointer
+ * to the data.
+ *
+ * version 4:
+ * - added qemu_plugin_read_memory_vaddr
*/
extern QEMU_PLUGIN_EXPORT int qemu_plugin_version;
-#define QEMU_PLUGIN_VERSION 3
+#define QEMU_PLUGIN_VERSION 4
/**
* struct qemu_info_t - system information for plugins
@@ -262,6 +270,29 @@ enum qemu_plugin_mem_rw {
QEMU_PLUGIN_MEM_RW,
};
+enum qemu_plugin_mem_value_type {
+ QEMU_PLUGIN_MEM_VALUE_U8,
+ QEMU_PLUGIN_MEM_VALUE_U16,
+ QEMU_PLUGIN_MEM_VALUE_U32,
+ QEMU_PLUGIN_MEM_VALUE_U64,
+ QEMU_PLUGIN_MEM_VALUE_U128,
+};
+
+/* typedef qemu_plugin_mem_value - value accessed during a load/store */
+typedef struct {
+ enum qemu_plugin_mem_value_type type;
+ union {
+ uint8_t u8;
+ uint16_t u16;
+ uint32_t u32;
+ uint64_t u64;
+ struct {
+ uint64_t low;
+ uint64_t high;
+ } u128;
+ } data;
+} qemu_plugin_mem_value;
+
/**
* enum qemu_plugin_cond - condition to enable callback
*
@@ -552,6 +583,15 @@ QEMU_PLUGIN_API
bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info);
/**
+ * qemu_plugin_mem_get_mem_value() - return last value loaded/stored
+ * @info: opaque memory transaction handle
+ *
+ * Returns: memory value
+ */
+QEMU_PLUGIN_API
+qemu_plugin_mem_value qemu_plugin_mem_get_value(qemu_plugin_meminfo_t info);
+
+/**
* qemu_plugin_get_hwaddr() - return handle for memory operation
* @info: opaque memory info structure
* @vaddr: the virtual address of the memory operation
@@ -853,6 +893,28 @@ QEMU_PLUGIN_API
GArray *qemu_plugin_get_registers(void);
/**
+ * qemu_plugin_read_memory_vaddr() - read from memory using a virtual address
+ *
+ * @addr: A virtual address to read from
+ * @data: A byte array to store data into
+ * @len: The number of bytes to read, starting from @addr
+ *
+ * @len bytes of data is read starting at @addr and stored into @data. If @data
+ * is not large enough to hold @len bytes, it will be expanded to the necessary
+ * size, reallocating if necessary. @len must be greater than 0.
+ *
+ * This function does not ensure writes are flushed prior to reading, so
+ * callers should take care when calling this function in plugin callbacks to
+ * avoid attempting to read data which may not yet be written and should use
+ * the memory callback API instead.
+ *
+ * Returns true on success and false on failure.
+ */
+QEMU_PLUGIN_API
+bool qemu_plugin_read_memory_vaddr(uint64_t addr,
+ GByteArray *data, size_t len);
+
+/**
* qemu_plugin_read_register() - read register for current vCPU
*
* @handle: a @qemu_plugin_reg_handle handle
diff --git a/include/qemu/range.h b/include/qemu/range.h
index 4ce694a..d446ad8 100644
--- a/include/qemu/range.h
+++ b/include/qemu/range.h
@@ -210,8 +210,8 @@ static inline int range_covers_byte(uint64_t offset, uint64_t len,
/* Check whether 2 given ranges overlap.
* Undefined if ranges that wrap around 0. */
-static inline int ranges_overlap(uint64_t first1, uint64_t len1,
- uint64_t first2, uint64_t len2)
+static inline bool ranges_overlap(uint64_t first1, uint64_t len1,
+ uint64_t first2, uint64_t len2)
{
uint64_t last1 = range_get_last(first1, len1);
uint64_t last2 = range_get_last(first2, len2);
diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
index d935fd8..c562690 100644
--- a/include/qemu/sockets.h
+++ b/include/qemu/sockets.h
@@ -61,7 +61,6 @@ int socket_set_fast_reuse(int fd);
int inet_ai_family_from_address(InetSocketAddress *addr,
Error **errp);
int inet_parse(InetSocketAddress *addr, const char *str, Error **errp);
-int inet_connect(const char *str, Error **errp);
int inet_connect_saddr(InetSocketAddress *saddr, Error **errp);
NetworkAddressFamily inet_netfamily(int family);
@@ -118,21 +117,6 @@ socket_sockaddr_to_address(struct sockaddr_storage *sa,
SocketAddress *socket_local_address(int fd, Error **errp);
/**
- * socket_remote_address:
- * @fd: the socket file handle
- * @errp: pointer to uninitialized error object
- *
- * Get the string representation of the remote socket
- * address. A pointer to the allocated address information
- * struct will be returned, which the caller is required to
- * release with a call qapi_free_SocketAddress() when no
- * longer required.
- *
- * Returns: the socket address struct, or NULL on error
- */
-SocketAddress *socket_remote_address(int fd, Error **errp);
-
-/**
* socket_address_flatten:
* @addr: the socket address to flatten
*
diff --git a/include/qemu/thread.h b/include/qemu/thread.h
index fb74e21..7eba27a 100644
--- a/include/qemu/thread.h
+++ b/include/qemu/thread.h
@@ -293,115 +293,4 @@ static inline void qemu_spin_unlock(QemuSpin *spin)
#endif
}
-struct QemuLockCnt {
-#ifndef CONFIG_LINUX
- QemuMutex mutex;
-#endif
- unsigned count;
-};
-
-/**
- * qemu_lockcnt_init: initialize a QemuLockcnt
- * @lockcnt: the lockcnt to initialize
- *
- * Initialize lockcnt's counter to zero and prepare its mutex
- * for usage.
- */
-void qemu_lockcnt_init(QemuLockCnt *lockcnt);
-
-/**
- * qemu_lockcnt_destroy: destroy a QemuLockcnt
- * @lockcnt: the lockcnt to destruct
- *
- * Destroy lockcnt's mutex.
- */
-void qemu_lockcnt_destroy(QemuLockCnt *lockcnt);
-
-/**
- * qemu_lockcnt_inc: increment a QemuLockCnt's counter
- * @lockcnt: the lockcnt to operate on
- *
- * If the lockcnt's count is zero, wait for critical sections
- * to finish and increment lockcnt's count to 1. If the count
- * is not zero, just increment it.
- *
- * Because this function can wait on the mutex, it must not be
- * called while the lockcnt's mutex is held by the current thread.
- * For the same reason, qemu_lockcnt_inc can also contribute to
- * AB-BA deadlocks. This is a sample deadlock scenario:
- *
- * thread 1 thread 2
- * -------------------------------------------------------
- * qemu_lockcnt_lock(&lc1);
- * qemu_lockcnt_lock(&lc2);
- * qemu_lockcnt_inc(&lc2);
- * qemu_lockcnt_inc(&lc1);
- */
-void qemu_lockcnt_inc(QemuLockCnt *lockcnt);
-
-/**
- * qemu_lockcnt_dec: decrement a QemuLockCnt's counter
- * @lockcnt: the lockcnt to operate on
- */
-void qemu_lockcnt_dec(QemuLockCnt *lockcnt);
-
-/**
- * qemu_lockcnt_dec_and_lock: decrement a QemuLockCnt's counter and
- * possibly lock it.
- * @lockcnt: the lockcnt to operate on
- *
- * Decrement lockcnt's count. If the new count is zero, lock
- * the mutex and return true. Otherwise, return false.
- */
-bool qemu_lockcnt_dec_and_lock(QemuLockCnt *lockcnt);
-
-/**
- * qemu_lockcnt_dec_if_lock: possibly decrement a QemuLockCnt's counter and
- * lock it.
- * @lockcnt: the lockcnt to operate on
- *
- * If the count is 1, decrement the count to zero, lock
- * the mutex and return true. Otherwise, return false.
- */
-bool qemu_lockcnt_dec_if_lock(QemuLockCnt *lockcnt);
-
-/**
- * qemu_lockcnt_lock: lock a QemuLockCnt's mutex.
- * @lockcnt: the lockcnt to operate on
- *
- * Remember that concurrent visits are not blocked unless the count is
- * also zero. You can use qemu_lockcnt_count to check for this inside a
- * critical section.
- */
-void qemu_lockcnt_lock(QemuLockCnt *lockcnt);
-
-/**
- * qemu_lockcnt_unlock: release a QemuLockCnt's mutex.
- * @lockcnt: the lockcnt to operate on.
- */
-void qemu_lockcnt_unlock(QemuLockCnt *lockcnt);
-
-/**
- * qemu_lockcnt_inc_and_unlock: combined unlock/increment on a QemuLockCnt.
- * @lockcnt: the lockcnt to operate on.
- *
- * This is the same as
- *
- * qemu_lockcnt_unlock(lockcnt);
- * qemu_lockcnt_inc(lockcnt);
- *
- * but more efficient.
- */
-void qemu_lockcnt_inc_and_unlock(QemuLockCnt *lockcnt);
-
-/**
- * qemu_lockcnt_count: query a LockCnt's count.
- * @lockcnt: the lockcnt to query.
- *
- * Note that the count can change at any time. Still, while the
- * lockcnt is locked, one can usefully check whether the count
- * is non-zero.
- */
-unsigned qemu_lockcnt_count(QemuLockCnt *lockcnt);
-
#endif
diff --git a/include/qemu/timed-average.h b/include/qemu/timed-average.h
index 08245e7..dfd8d65 100644
--- a/include/qemu/timed-average.h
+++ b/include/qemu/timed-average.h
@@ -8,10 +8,12 @@
* BenoƮt Canet <benoit.canet@nodalink.com>
* Alberto Garcia <berto@igalia.com>
*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
* 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) version 3 or any later version.
+ * (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
diff --git a/include/qemu/timer.h b/include/qemu/timer.h
index fa56ec9..cc167bd 100644
--- a/include/qemu/timer.h
+++ b/include/qemu/timer.h
@@ -191,16 +191,6 @@ bool qemu_clock_use_for_deadline(QEMUClockType type);
int64_t qemu_clock_deadline_ns_all(QEMUClockType type, int attr_mask);
/**
- * qemu_clock_get_main_loop_timerlist:
- * @type: the clock type
- *
- * Return the default timer list associated with a clock.
- *
- * Returns: the default timer list
- */
-QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClockType type);
-
-/**
* qemu_clock_nofify:
* @type: the clock type
*
@@ -327,17 +317,6 @@ bool timerlist_expired(QEMUTimerList *timer_list);
int64_t timerlist_deadline_ns(QEMUTimerList *timer_list);
/**
- * timerlist_get_clock:
- * @timer_list: the timer list to operate on
- *
- * Determine the clock type associated with a timer list.
- *
- * Returns: the clock type associated with the
- * timer list.
- */
-QEMUClockType timerlist_get_clock(QEMUTimerList *timer_list);
-
-/**
* timerlist_run_timers:
* @timer_list: the timer list to use
*
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 9d222dc..3d84efc 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -40,6 +40,7 @@ typedef struct ConfidentialGuestSupport ConfidentialGuestSupport;
typedef struct CPUArchState CPUArchState;
typedef struct CPUPluginState CPUPluginState;
typedef struct CPUState CPUState;
+typedef struct CPUTLBEntryFull CPUTLBEntryFull;
typedef struct DeviceState DeviceState;
typedef struct DirtyBitmapSnapshot DirtyBitmapSnapshot;
typedef struct DisasContextBase DisasContextBase;
diff --git a/include/qemu/userfaultfd.h b/include/qemu/userfaultfd.h
index 18a4314..a197930 100644
--- a/include/qemu/userfaultfd.h
+++ b/include/qemu/userfaultfd.h
@@ -39,7 +39,6 @@ int uffd_copy_page(int uffd_fd, void *dst_addr, void *src_addr,
int uffd_zero_page(int uffd_fd, void *addr, uint64_t length, bool dont_wake);
int uffd_wakeup(int uffd_fd, void *addr, uint64_t length);
int uffd_read_events(int uffd_fd, struct uffd_msg *msgs, int count);
-bool uffd_poll_events(int uffd_fd, int tmo);
#endif /* CONFIG_LINUX */
diff --git a/include/qom/object.h b/include/qom/object.h
index 13d3a65..2af9854 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -1569,8 +1569,8 @@ char *object_get_canonical_path(const Object *obj);
/**
* object_resolve_path:
* @path: the path to resolve
- * @ambiguous: returns true if the path resolution failed because of an
- * ambiguous match
+ * @ambiguous: (out) (optional): location to store whether the lookup failed
+ * because it was ambiguous, or %NULL. Set to %false on success.
*
* There are two types of supported paths--absolute paths and partial paths.
*
@@ -1587,7 +1587,7 @@ char *object_get_canonical_path(const Object *obj);
* only one match is found. If more than one match is found, a flag is
* returned to indicate that the match was ambiguous.
*
- * Returns: The matched object or NULL on path lookup failure.
+ * Returns: The matched object or %NULL on path lookup failure.
*/
Object *object_resolve_path(const char *path, bool *ambiguous);
@@ -1595,10 +1595,10 @@ Object *object_resolve_path(const char *path, bool *ambiguous);
* object_resolve_path_type:
* @path: the path to resolve
* @typename: the type to look for.
- * @ambiguous: returns true if the path resolution failed because of an
- * ambiguous match
+ * @ambiguous: (out) (optional): location to store whether the lookup failed
+ * because it was ambiguous, or %NULL. Set to %false on success.
*
- * This is similar to object_resolve_path. However, when looking for a
+ * This is similar to object_resolve_path(). However, when looking for a
* partial path only matches that implement the given type are considered.
* This restricts the search and avoids spuriously flagging matches as
* ambiguous.
diff --git a/include/semihosting/syscalls.h b/include/semihosting/syscalls.h
index 3a5ec22..b5937c6 100644
--- a/include/semihosting/syscalls.h
+++ b/include/semihosting/syscalls.h
@@ -9,6 +9,8 @@
#ifndef SEMIHOSTING_SYSCALLS_H
#define SEMIHOSTING_SYSCALLS_H
+#include "gdbstub/syscalls.h"
+
/*
* Argument loading from the guest is performed by the caller;
* results are returned via the 'complete' callback.
diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h
index 8d041aa..5b1c102 100644
--- a/include/sysemu/arch_init.h
+++ b/include/sysemu/arch_init.h
@@ -6,7 +6,6 @@ enum {
QEMU_ARCH_ALL = -1,
QEMU_ARCH_ALPHA = (1 << 0),
QEMU_ARCH_ARM = (1 << 1),
- QEMU_ARCH_CRIS = (1 << 2),
QEMU_ARCH_I386 = (1 << 3),
QEMU_ARCH_M68K = (1 << 4),
QEMU_ARCH_MICROBLAZE = (1 << 6),
diff --git a/include/sysemu/block-backend-global-state.h b/include/sysemu/block-backend-global-state.h
index 49c12b0f..9cc9b00 100644
--- a/include/sysemu/block-backend-global-state.h
+++ b/include/sysemu/block-backend-global-state.h
@@ -54,7 +54,6 @@ bool monitor_add_blk(BlockBackend *blk, const char *name, Error **errp);
void monitor_remove_blk(BlockBackend *blk);
BlockBackendPublic *blk_get_public(BlockBackend *blk);
-BlockBackend *blk_by_public(BlockBackendPublic *public);
void blk_remove_bs(BlockBackend *blk);
int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp);
@@ -67,7 +66,6 @@ void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm);
void blk_iostatus_enable(BlockBackend *blk);
BlockDeviceIoStatus blk_iostatus(const BlockBackend *blk);
-void blk_iostatus_disable(BlockBackend *blk);
void blk_iostatus_reset(BlockBackend *blk);
int blk_attach_dev(BlockBackend *blk, DeviceState *dev);
void blk_detach_dev(BlockBackend *blk, DeviceState *dev);
@@ -76,8 +74,6 @@ BlockBackend *blk_by_dev(void *dev);
BlockBackend *blk_by_qdev_id(const char *id, Error **errp);
void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, void *opaque);
-void blk_activate(BlockBackend *blk, Error **errp);
-
int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags);
void blk_aio_cancel(BlockAIOCB *acb);
int blk_commit_all(void);
@@ -91,9 +87,6 @@ bool blk_is_sg(BlockBackend *blk);
void blk_set_enable_write_cache(BlockBackend *blk, bool wce);
int blk_get_flags(BlockBackend *blk);
bool blk_op_is_blocked(BlockBackend *blk, BlockOpType op, Error **errp);
-void blk_op_unblock(BlockBackend *blk, BlockOpType op, Error *reason);
-void blk_op_block_all(BlockBackend *blk, Error *reason);
-void blk_op_unblock_all(BlockBackend *blk, Error *reason);
int blk_set_aio_context(BlockBackend *blk, AioContext *new_context,
Error **errp);
void blk_add_aio_context_notifier(BlockBackend *blk,
@@ -105,7 +98,6 @@ void blk_remove_aio_context_notifier(BlockBackend *blk,
void (*detach_aio_context)(void *),
void *opaque);
void blk_add_remove_bs_notifier(BlockBackend *blk, Notifier *notify);
-void blk_add_insert_bs_notifier(BlockBackend *blk, Notifier *notify);
BlockBackendRootState *blk_get_root_state(BlockBackend *blk);
void blk_update_root_state(BlockBackend *blk);
bool blk_get_detect_zeroes_from_root_state(BlockBackend *blk);
diff --git a/include/sysemu/cryptodev.h b/include/sysemu/cryptodev.h
index 96d3998..b20822d 100644
--- a/include/sysemu/cryptodev.h
+++ b/include/sysemu/cryptodev.h
@@ -178,7 +178,7 @@ typedef struct CryptoDevBackendAsymOpInfo {
typedef void (*CryptoDevCompletionFunc) (void *opaque, int ret);
typedef struct CryptoDevBackendOpInfo {
- QCryptodevBackendAlgType algtype;
+ QCryptodevBackendAlgoType algtype;
uint32_t op_code;
uint32_t queue_index;
CryptoDevCompletionFunc cb;
diff --git a/include/sysemu/dma.h b/include/sysemu/dma.h
index a1ac5bc..5a49a30 100644
--- a/include/sysemu/dma.h
+++ b/include/sysemu/dma.h
@@ -152,7 +152,7 @@ static inline MemTxResult dma_memory_read(AddressSpace *as, dma_addr_t addr,
}
/**
- * address_space_write: Write to address space from DMA controller.
+ * dma_memory_write: Write to address space from DMA controller.
*
* Return a MemTxResult indicating whether the operation succeeded
* or failed (eg unassigned memory, device rejected the transaction,
@@ -189,7 +189,7 @@ MemTxResult dma_memory_set(AddressSpace *as, dma_addr_t addr,
uint8_t c, dma_addr_t len, MemTxAttrs attrs);
/**
- * address_space_map: Map a physical memory region into a host virtual address.
+ * dma_memory_map: Map a physical memory region into a host virtual address.
*
* May map a subset of the requested range, given by and returned in @plen.
* May return %NULL and set *@plen to zero(0), if resources needed to perform
@@ -216,16 +216,15 @@ static inline void *dma_memory_map(AddressSpace *as,
}
/**
- * address_space_unmap: Unmaps a memory region previously mapped
- * by dma_memory_map()
+ * dma_memory_unmap: Unmaps a memory region previously mapped by dma_memory_map()
*
* Will also mark the memory as dirty if @dir == %DMA_DIRECTION_FROM_DEVICE.
* @access_len gives the amount of memory that was actually read or written
* by the caller.
*
* @as: #AddressSpace used
- * @buffer: host pointer as returned by address_space_map()
- * @len: buffer length as returned by address_space_map()
+ * @buffer: host pointer as returned by dma_memory_map()
+ * @len: buffer length as returned by dma_memory_map()
* @dir: indicates the transfer direction
* @access_len: amount of data actually transferred
*/
diff --git a/include/sysemu/host_iommu_device.h b/include/sysemu/host_iommu_device.h
index c1bf74a..809cced 100644
--- a/include/sysemu/host_iommu_device.h
+++ b/include/sysemu/host_iommu_device.h
@@ -20,11 +20,12 @@
*
* @type: host platform IOMMU type.
*
- * @aw_bits: host IOMMU address width. 0xff if no limitation.
+ * @hw_caps: host platform IOMMU capabilities (e.g. on IOMMUFD this represents
+ * the @out_capabilities value returned from IOMMU_GET_HW_INFO ioctl)
*/
typedef struct HostIOMMUDeviceCaps {
uint32_t type;
- uint8_t aw_bits;
+ uint64_t hw_caps;
} HostIOMMUDeviceCaps;
#define TYPE_HOST_IOMMU_DEVICE "host-iommu-device"
diff --git a/include/sysemu/hvf_int.h b/include/sysemu/hvf_int.h
index 5b28d17..42ae184 100644
--- a/include/sysemu/hvf_int.h
+++ b/include/sysemu/hvf_int.h
@@ -65,6 +65,7 @@ void assert_hvf_ok_impl(hv_return_t ret, const char *file, unsigned int line,
#define assert_hvf_ok(EX) assert_hvf_ok_impl((EX), __FILE__, __LINE__, #EX)
const char *hvf_return_string(hv_return_t ret);
int hvf_arch_init(void);
+hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range);
int hvf_arch_init_vcpu(CPUState *cpu);
void hvf_arch_vcpu_destroy(CPUState *cpu);
int hvf_vcpu_exec(CPUState *);
diff --git a/include/sysemu/iommufd.h b/include/sysemu/iommufd.h
index 9edfec6..4c4886c 100644
--- a/include/sysemu/iommufd.h
+++ b/include/sysemu/iommufd.h
@@ -49,7 +49,18 @@ int iommufd_backend_unmap_dma(IOMMUFDBackend *be, uint32_t ioas_id,
hwaddr iova, ram_addr_t size);
bool iommufd_backend_get_device_info(IOMMUFDBackend *be, uint32_t devid,
uint32_t *type, void *data, uint32_t len,
- Error **errp);
+ uint64_t *caps, Error **errp);
+bool iommufd_backend_alloc_hwpt(IOMMUFDBackend *be, uint32_t dev_id,
+ uint32_t pt_id, uint32_t flags,
+ uint32_t data_type, uint32_t data_len,
+ void *data_ptr, uint32_t *out_hwpt,
+ Error **errp);
+bool iommufd_backend_set_dirty_tracking(IOMMUFDBackend *be, uint32_t hwpt_id,
+ bool start, Error **errp);
+bool iommufd_backend_get_dirty_bitmap(IOMMUFDBackend *be, uint32_t hwpt_id,
+ uint64_t iova, ram_addr_t size,
+ uint64_t page_size, uint64_t *data,
+ Error **errp);
#define TYPE_HOST_IOMMU_DEVICE_IOMMUFD TYPE_HOST_IOMMU_DEVICE "-iommufd"
#endif
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index c31d9c7..c3a60b2 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -235,11 +235,11 @@ static inline int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_t
/* internal API */
-int kvm_ioctl(KVMState *s, int type, ...);
+int kvm_ioctl(KVMState *s, unsigned long type, ...);
-int kvm_vm_ioctl(KVMState *s, int type, ...);
+int kvm_vm_ioctl(KVMState *s, unsigned long type, ...);
-int kvm_vcpu_ioctl(CPUState *cpu, int type, ...);
+int kvm_vcpu_ioctl(CPUState *cpu, unsigned long type, ...);
/**
* kvm_device_ioctl - call an ioctl on a kvm device
@@ -248,7 +248,7 @@ int kvm_vcpu_ioctl(CPUState *cpu, int type, ...);
*
* Returns: -errno on error, nonnegative on success
*/
-int kvm_device_ioctl(int fd, int type, ...);
+int kvm_device_ioctl(int fd, unsigned long type, ...);
/**
* kvm_vm_check_attr - check for existence of a specific vm attribute
@@ -313,6 +313,39 @@ int kvm_create_device(KVMState *s, uint64_t type, bool test);
*/
bool kvm_device_supported(int vmfd, uint64_t type);
+/**
+ * kvm_create_vcpu - Gets a parked KVM vCPU or creates a KVM vCPU
+ * @cpu: QOM CPUState object for which KVM vCPU has to be fetched/created.
+ *
+ * @returns: 0 when success, errno (<0) when failed.
+ */
+int kvm_create_vcpu(CPUState *cpu);
+
+/**
+ * kvm_park_vcpu - Park QEMU KVM vCPU context
+ * @cpu: QOM CPUState object for which QEMU KVM vCPU context has to be parked.
+ *
+ * @returns: none
+ */
+void kvm_park_vcpu(CPUState *cpu);
+
+/**
+ * kvm_unpark_vcpu - unpark QEMU KVM vCPU context
+ * @s: KVM State
+ * @vcpu_id: Architecture vCPU ID of the parked vCPU
+ *
+ * @returns: KVM fd
+ */
+int kvm_unpark_vcpu(KVMState *s, unsigned long vcpu_id);
+
+/**
+ * kvm_create_and_park_vcpu - Create and park a KVM vCPU
+ * @cpu: QOM CPUState object for which KVM vCPU has to be created and parked.
+ *
+ * @returns: 0 when success, errno (<0) when failed.
+ */
+int kvm_create_and_park_vcpu(CPUState *cpu);
+
/* Arch specific hooks */
extern const KVMCapabilityInfo kvm_arch_required_capabilities[];
@@ -326,7 +359,7 @@ int kvm_arch_handle_exit(CPUState *cpu, struct kvm_run *run);
int kvm_arch_process_async_events(CPUState *cpu);
-int kvm_arch_get_registers(CPUState *cpu);
+int kvm_arch_get_registers(CPUState *cpu, Error **errp);
/* state subset only touched by the VCPU itself during runtime */
#define KVM_PUT_RUNTIME_STATE 1
@@ -335,7 +368,7 @@ int kvm_arch_get_registers(CPUState *cpu);
/* full state set, modified during initialization or on vmload */
#define KVM_PUT_FULL_STATE 3
-int kvm_arch_put_registers(CPUState *cpu, int level);
+int kvm_arch_put_registers(CPUState *cpu, int level, Error **errp);
int kvm_arch_get_default_type(MachineState *ms);
diff --git a/include/sysemu/kvm_int.h b/include/sysemu/kvm_int.h
index 3f3d13f..a1e7276 100644
--- a/include/sysemu/kvm_int.h
+++ b/include/sysemu/kvm_int.h
@@ -14,6 +14,9 @@
#include "qemu/accel.h"
#include "qemu/queue.h"
#include "sysemu/kvm.h"
+#include "hw/boards.h"
+#include "hw/i386/topology.h"
+#include "io/channel-socket.h"
typedef struct KVMSlot
{
@@ -42,7 +45,8 @@ typedef struct KVMMemoryUpdate {
typedef struct KVMMemoryListener {
MemoryListener listener;
KVMSlot *slots;
- unsigned int nr_used_slots;
+ unsigned int nr_slots_used;
+ unsigned int nr_slots_allocated;
int as_id;
QSIMPLEQ_HEAD(, KVMMemoryUpdate) transaction_add;
QSIMPLEQ_HEAD(, KVMMemoryUpdate) transaction_del;
@@ -50,6 +54,34 @@ typedef struct KVMMemoryListener {
#define KVM_MSI_HASHTAB_SIZE 256
+typedef struct KVMHostTopoInfo {
+ /* Number of package on the Host */
+ unsigned int maxpkgs;
+ /* Number of cpus on the Host */
+ unsigned int maxcpus;
+ /* Number of cpus on each different package */
+ unsigned int *pkg_cpu_count;
+ /* Each package can have different maxticks */
+ unsigned int *maxticks;
+} KVMHostTopoInfo;
+
+struct KVMMsrEnergy {
+ pid_t pid;
+ bool enable;
+ char *socket_path;
+ QIOChannelSocket *sioc;
+ QemuThread msr_thr;
+ unsigned int guest_vcpus;
+ unsigned int guest_vsockets;
+ X86CPUTopoInfo guest_topo_info;
+ KVMHostTopoInfo host_topo;
+ const CPUArchIdList *guest_cpu_list;
+ uint64_t *msr_value;
+ uint64_t msr_unit;
+ uint64_t msr_limit;
+ uint64_t msr_info;
+};
+
enum KVMDirtyRingReaperState {
KVM_DIRTY_RING_REAPER_NONE = 0,
/* The reaper is sleeping */
@@ -71,8 +103,8 @@ struct KVMDirtyRingReaper {
struct KVMState
{
AccelState parent_obj;
-
- int nr_slots;
+ /* Max number of KVM slots supported */
+ int nr_slots_max;
int fd;
int vmfd;
int coalesced_mmio;
@@ -91,10 +123,19 @@ struct KVMState
bool sync_mmu;
bool guest_state_protected;
uint64_t manual_dirty_log_protect;
- /* The man page (and posix) say ioctl numbers are signed int, but
- * they're not. Linux, glibc and *BSD all treat ioctl numbers as
- * unsigned, and treating them as signed here can break things */
- unsigned irq_set_ioctl;
+ /*
+ * Older POSIX says that ioctl numbers are signed int, but in
+ * practice they are not. (Newer POSIX doesn't specify ioctl
+ * at all.) Linux, glibc and *BSD all treat ioctl numbers as
+ * unsigned, and real-world ioctl values like KVM_GET_XSAVE have
+ * bit 31 set, which means that passing them via an 'int' will
+ * result in sign-extension when they get converted back to the
+ * 'unsigned long' which the ioctl() prototype uses. Luckily Linux
+ * always treats the argument as an unsigned 32-bit int, so any
+ * possible sign-extension is deliberately ignored, but for
+ * consistency we keep to the same type that glibc is using.
+ */
+ unsigned long irq_set_ioctl;
unsigned int sigmask_len;
GHashTable *gsimap;
#ifdef KVM_CAP_IRQ_ROUTING
@@ -117,6 +158,7 @@ struct KVMState
bool kvm_dirty_ring_with_bitmap;
uint64_t kvm_eager_split_size; /* Eager Page Splitting chunk size */
struct KVMDirtyRingReaper reaper;
+ struct KVMMsrEnergy msr_energy;
NotifyVmexitOption notify_vmexit;
uint32_t notify_window;
uint32_t xen_version;
diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index f229b21..cba74fa 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -73,11 +73,6 @@ int replay_get_instructions(void);
/*! Updates instructions counter in replay mode. */
void replay_account_executed_instructions(void);
-/**
- * replay_can_wait: check if we should pause for wait-io
- */
-bool replay_can_wait(void);
-
/* Processing clocks and other time sources */
/*! Save the specified clock */
@@ -122,8 +117,6 @@ void replay_async_events(void);
/* Asynchronous events queue */
-/*! Disables storing events in the queue */
-void replay_disable_events(void);
/*! Enables storing events in the queue */
void replay_enable_events(void);
/*! Returns true when saving events is enabled */
diff --git a/include/sysemu/reset.h b/include/sysemu/reset.h
index ae43604..0e297c0 100644
--- a/include/sysemu/reset.h
+++ b/include/sysemu/reset.h
@@ -27,6 +27,7 @@
#ifndef QEMU_SYSEMU_RESET_H
#define QEMU_SYSEMU_RESET_H
+#include "hw/resettable.h"
#include "qapi/qapi-events-run-state.h"
typedef void QEMUResetHandler(void *opaque);
@@ -110,7 +111,7 @@ void qemu_unregister_reset(QEMUResetHandler *func, void *opaque);
/**
* qemu_devices_reset: Perform a complete system reset
- * @reason: reason for the reset
+ * @reason: type of the reset
*
* This function performs the low-level work needed to do a complete reset
* of the system (calling all the callbacks registered with
@@ -121,6 +122,6 @@ void qemu_unregister_reset(QEMUResetHandler *func, void *opaque);
* If you want to trigger a system reset from, for instance, a device
* model, don't use this function. Use qemu_system_reset_request().
*/
-void qemu_devices_reset(ShutdownCause reason);
+void qemu_devices_reset(ResetType type);
#endif
diff --git a/include/sysemu/runstate.h b/include/sysemu/runstate.h
index e210a37..11c7ff3 100644
--- a/include/sysemu/runstate.h
+++ b/include/sysemu/runstate.h
@@ -9,6 +9,7 @@ void runstate_set(RunState new_state);
RunState runstate_get(void);
bool runstate_is_running(void);
bool runstate_needs_reset(void);
+void runstate_replay_enable(void);
typedef void VMChangeStateHandler(void *opaque, bool running, RunState state);
diff --git a/include/sysemu/spdm-socket.h b/include/sysemu/spdm-socket.h
new file mode 100644
index 0000000..5d8bd9a
--- /dev/null
+++ b/include/sysemu/spdm-socket.h
@@ -0,0 +1,74 @@
+/*
+ * QEMU SPDM socket support
+ *
+ * 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 SPDM_REQUESTER_H
+#define SPDM_REQUESTER_H
+
+/**
+ * spdm_socket_connect: connect to an external SPDM socket
+ * @port: port to connect to
+ * @errp: error object handle
+ *
+ * This will connect to an external SPDM socket server. On error
+ * it will return -1 and errp will be set. On success this function
+ * will return the socket number.
+ */
+int spdm_socket_connect(uint16_t port, Error **errp);
+
+/**
+ * spdm_socket_rsp: send and receive a message to a SPDM server
+ * @socket: socket returned from spdm_socket_connect()
+ * @transport_type: SPDM_SOCKET_TRANSPORT_TYPE_* macro
+ * @req: request buffer
+ * @req_len: request buffer length
+ * @rsp: response buffer
+ * @rsp_len: response buffer length
+ *
+ * Send platform data to a SPDM server on socket and then receive
+ * a response.
+ */
+uint32_t spdm_socket_rsp(const int socket, uint32_t transport_type,
+ void *req, uint32_t req_len,
+ void *rsp, uint32_t rsp_len);
+
+/**
+ * spdm_socket_close: send a shutdown command to the server
+ * @socket: socket returned from spdm_socket_connect()
+ * @transport_type: SPDM_SOCKET_TRANSPORT_TYPE_* macro
+ *
+ * This will issue a shutdown command to the server.
+ */
+void spdm_socket_close(const int socket, uint32_t transport_type);
+
+#define SPDM_SOCKET_COMMAND_NORMAL 0x0001
+#define SPDM_SOCKET_COMMAND_OOB_ENCAP_KEY_UPDATE 0x8001
+#define SPDM_SOCKET_COMMAND_CONTINUE 0xFFFD
+#define SPDM_SOCKET_COMMAND_SHUTDOWN 0xFFFE
+#define SPDM_SOCKET_COMMAND_UNKOWN 0xFFFF
+#define SPDM_SOCKET_COMMAND_TEST 0xDEAD
+
+#define SPDM_SOCKET_TRANSPORT_TYPE_MCTP 0x01
+#define SPDM_SOCKET_TRANSPORT_TYPE_PCI_DOE 0x02
+
+#define SPDM_SOCKET_MAX_MESSAGE_BUFFER_SIZE 0x1200
+
+#endif
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 5b4397e..7ec419c 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -41,7 +41,6 @@ extern int graphic_height;
extern int graphic_depth;
extern int display_opengl;
extern const char *keyboard_layout;
-extern int graphic_rotate;
extern int old_param;
extern uint8_t *boot_splash_filedata;
extern bool enable_mlock;
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
index 21d5884..a77ed12 100644
--- a/include/tcg/tcg.h
+++ b/include/tcg/tcg.h
@@ -281,29 +281,6 @@ static inline int tcg_type_size(TCGType t)
return 4 << i;
}
-/**
- * get_alignment_bits
- * @memop: MemOp value
- *
- * Extract the alignment size from the memop.
- */
-static inline unsigned get_alignment_bits(MemOp memop)
-{
- unsigned a = memop & MO_AMASK;
-
- if (a == MO_UNALN) {
- /* No alignment required. */
- a = 0;
- } else if (a == MO_ALIGN) {
- /* A natural alignment requirement. */
- a = memop & MO_SIZE;
- } else {
- /* A specific alignment requirement. */
- a = a >> MO_ASHIFT;
- }
- return a;
-}
-
typedef tcg_target_ulong TCGArg;
/* Define type and accessor macros for TCG variables.
@@ -544,6 +521,12 @@ struct TCGContext {
struct qemu_plugin_insn *plugin_insn;
#endif
+ /* For host-specific values. */
+#ifdef __riscv
+ MemOp riscv_cur_vsew;
+ TCGType riscv_cur_type;
+#endif
+
GHashTable *const_table[TCG_TYPE_COUNT];
TCGTempSet free_temps[TCG_TYPE_COUNT];
TCGTemp temps[TCG_MAX_TEMPS]; /* globals first, temps after */
diff --git a/include/ui/console.h b/include/ui/console.h
index fa986ab..5832d52 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -175,7 +175,6 @@ int cursor_get_mono_bpl(QEMUCursor *c);
void cursor_set_mono(QEMUCursor *c,
uint32_t foreground, uint32_t background, uint8_t *image,
int transparent, uint8_t *mask);
-void cursor_get_mono_image(QEMUCursor *c, int foreground, uint8_t *mask);
void cursor_get_mono_mask(QEMUCursor *c, int transparent, uint8_t *mask);
typedef void *QEMUGLContext;
diff --git a/include/ui/qemu-pixman.h b/include/ui/qemu-pixman.h
index ef13a82..193bc04 100644
--- a/include/ui/qemu-pixman.h
+++ b/include/ui/qemu-pixman.h
@@ -12,6 +12,8 @@
#include "pixman-minimal.h"
#endif
+#include "qapi/error.h"
+
/*
* pixman image formats are defined to be native endian,
* that means host byte order on qemu. So we go define
@@ -97,6 +99,28 @@ void qemu_pixman_glyph_render(pixman_image_t *glyph,
void qemu_pixman_image_unref(pixman_image_t *image);
+#ifdef WIN32
+typedef HANDLE qemu_pixman_shareable;
+#define SHAREABLE_NONE (NULL)
+#define SHAREABLE_TO_PTR(handle) (handle)
+#define PTR_TO_SHAREABLE(ptr) (ptr)
+#else
+typedef int qemu_pixman_shareable;
+#define SHAREABLE_NONE (-1)
+#define SHAREABLE_TO_PTR(handle) GINT_TO_POINTER(handle)
+#define PTR_TO_SHAREABLE(ptr) GPOINTER_TO_INT(ptr)
+#endif
+
+bool qemu_pixman_image_new_shareable(
+ pixman_image_t **image,
+ qemu_pixman_shareable *handle,
+ const char *name,
+ pixman_format_code_t format,
+ int width,
+ int height,
+ int rowstride_bytes,
+ Error **errp);
+
G_DEFINE_AUTOPTR_CLEANUP_FUNC(pixman_image_t, qemu_pixman_image_unref)
#endif /* QEMU_PIXMAN_H */
diff --git a/include/ui/sdl2.h b/include/ui/sdl2.h
index e3acc7c..dbe6e3d 100644
--- a/include/ui/sdl2.h
+++ b/include/ui/sdl2.h
@@ -42,6 +42,7 @@ struct sdl2_console {
int updates;
int idle_counter;
int ignore_hotkeys;
+ bool gui_keysym;
SDL_GLContext winctx;
QKbdState *kbd;
#ifdef CONFIG_OPENGL
@@ -60,6 +61,7 @@ void sdl2_poll_events(struct sdl2_console *scon);
void sdl2_process_key(struct sdl2_console *scon,
SDL_KeyboardEvent *ev);
+void sdl2_release_modifiers(struct sdl2_console *scon);
void sdl2_2d_update(DisplayChangeListener *dcl,
int x, int y, int w, int h);
diff --git a/include/ui/surface.h b/include/ui/surface.h
index 345b191..f16f7be 100644
--- a/include/ui/surface.h
+++ b/include/ui/surface.h
@@ -23,10 +23,8 @@ typedef struct DisplaySurface {
GLenum gltype;
GLuint texture;
#endif
-#ifdef WIN32
- HANDLE handle;
- uint32_t handle_offset;
-#endif
+ qemu_pixman_shareable share_handle;
+ uint32_t share_handle_offset;
} DisplaySurface;
PixelFormat qemu_default_pixelformat(int bpp);
@@ -37,10 +35,10 @@ DisplaySurface *qemu_create_displaysurface_from(int width, int height,
DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image);
DisplaySurface *qemu_create_placeholder_surface(int w, int h,
const char *msg);
-#ifdef WIN32
-void qemu_displaysurface_win32_set_handle(DisplaySurface *surface,
- HANDLE h, uint32_t offset);
-#endif
+
+void qemu_displaysurface_set_share_handle(DisplaySurface *surface,
+ qemu_pixman_shareable handle,
+ uint32_t offset);
DisplaySurface *qemu_create_displaysurface(int width, int height);
void qemu_free_displaysurface(DisplaySurface *surface);
diff --git a/include/user/abitypes.h b/include/user/abitypes.h
index 5c9a955..7528124 100644
--- a/include/user/abitypes.h
+++ b/include/user/abitypes.h
@@ -21,13 +21,6 @@
#define ABI_LLONG_ALIGNMENT 2
#endif
-#ifdef TARGET_CRIS
-#define ABI_SHORT_ALIGNMENT 1
-#define ABI_INT_ALIGNMENT 1
-#define ABI_LONG_ALIGNMENT 1
-#define ABI_LLONG_ALIGNMENT 1
-#endif
-
#if (defined(TARGET_I386) && !defined(TARGET_X86_64)) \
|| defined(TARGET_SH4) \
|| defined(TARGET_OPENRISC) \
diff --git a/io/channel-socket.c b/io/channel-socket.c
index 3a899b0..608bcf0 100644
--- a/io/channel-socket.c
+++ b/io/channel-socket.c
@@ -841,6 +841,33 @@ qio_channel_socket_set_cork(QIOChannel *ioc,
socket_set_cork(sioc->fd, v);
}
+static int
+qio_channel_socket_get_peerpid(QIOChannel *ioc,
+ unsigned int *pid,
+ Error **errp)
+{
+#ifdef CONFIG_LINUX
+ QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
+ Error *err = NULL;
+ socklen_t len = sizeof(struct ucred);
+
+ struct ucred cred;
+ if (getsockopt(sioc->fd,
+ SOL_SOCKET, SO_PEERCRED,
+ &cred, &len) == -1) {
+ error_setg_errno(&err, errno, "Unable to get peer credentials");
+ error_propagate(errp, err);
+ *pid = -1;
+ return -1;
+ }
+ *pid = (unsigned int)cred.pid;
+ return 0;
+#else
+ error_setg(errp, "Unsupported feature");
+ *pid = -1;
+ return -1;
+#endif
+}
static int
qio_channel_socket_close(QIOChannel *ioc,
@@ -938,6 +965,7 @@ static void qio_channel_socket_class_init(ObjectClass *klass,
#ifdef QEMU_MSG_ZEROCOPY
ioc_klass->io_flush = qio_channel_socket_flush;
#endif
+ ioc_klass->io_peerpid = qio_channel_socket_get_peerpid;
}
static const TypeInfo qio_channel_socket_info = {
diff --git a/io/channel-tls.c b/io/channel-tls.c
index 67b9700..aab630e 100644
--- a/io/channel-tls.c
+++ b/io/channel-tls.c
@@ -28,17 +28,16 @@
static ssize_t qio_channel_tls_write_handler(const char *buf,
size_t len,
- void *opaque)
+ void *opaque,
+ Error **errp)
{
QIOChannelTLS *tioc = QIO_CHANNEL_TLS(opaque);
ssize_t ret;
- ret = qio_channel_write(tioc->master, buf, len, NULL);
+ ret = qio_channel_write(tioc->master, buf, len, errp);
if (ret == QIO_CHANNEL_ERR_BLOCK) {
- errno = EAGAIN;
- return -1;
+ return QCRYPTO_TLS_SESSION_ERR_BLOCK;
} else if (ret < 0) {
- errno = EIO;
return -1;
}
return ret;
@@ -46,17 +45,16 @@ static ssize_t qio_channel_tls_write_handler(const char *buf,
static ssize_t qio_channel_tls_read_handler(char *buf,
size_t len,
- void *opaque)
+ void *opaque,
+ Error **errp)
{
QIOChannelTLS *tioc = QIO_CHANNEL_TLS(opaque);
ssize_t ret;
- ret = qio_channel_read(tioc->master, buf, len, NULL);
+ ret = qio_channel_read(tioc->master, buf, len, errp);
if (ret == QIO_CHANNEL_ERR_BLOCK) {
- errno = EAGAIN;
- return -1;
+ return QCRYPTO_TLS_SESSION_ERR_BLOCK;
} else if (ret < 0) {
- errno = EIO;
return -1;
}
return ret;
@@ -277,24 +275,19 @@ static ssize_t qio_channel_tls_readv(QIOChannel *ioc,
ssize_t got = 0;
for (i = 0 ; i < niov ; i++) {
- ssize_t ret = qcrypto_tls_session_read(tioc->session,
- iov[i].iov_base,
- iov[i].iov_len);
- if (ret < 0) {
- if (errno == EAGAIN) {
- if (got) {
- return got;
- } else {
- return QIO_CHANNEL_ERR_BLOCK;
- }
- } else if (errno == ECONNABORTED &&
- (qatomic_load_acquire(&tioc->shutdown) &
- QIO_CHANNEL_SHUTDOWN_READ)) {
- return 0;
+ ssize_t ret = qcrypto_tls_session_read(
+ tioc->session,
+ iov[i].iov_base,
+ iov[i].iov_len,
+ qatomic_load_acquire(&tioc->shutdown) & QIO_CHANNEL_SHUTDOWN_READ,
+ errp);
+ if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
+ if (got) {
+ return got;
+ } else {
+ return QIO_CHANNEL_ERR_BLOCK;
}
-
- error_setg_errno(errp, errno,
- "Cannot read from TLS channel");
+ } else if (ret < 0) {
return -1;
}
got += ret;
@@ -321,18 +314,15 @@ static ssize_t qio_channel_tls_writev(QIOChannel *ioc,
for (i = 0 ; i < niov ; i++) {
ssize_t ret = qcrypto_tls_session_write(tioc->session,
iov[i].iov_base,
- iov[i].iov_len);
- if (ret <= 0) {
- if (errno == EAGAIN) {
- if (done) {
- return done;
- } else {
- return QIO_CHANNEL_ERR_BLOCK;
- }
+ iov[i].iov_len,
+ errp);
+ if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
+ if (done) {
+ return done;
+ } else {
+ return QIO_CHANNEL_ERR_BLOCK;
}
-
- error_setg_errno(errp, errno,
- "Cannot write to TLS channel");
+ } else if (ret < 0) {
return -1;
}
done += ret;
diff --git a/io/channel-websock.c b/io/channel-websock.c
index de39f0d..55192b7 100644
--- a/io/channel-websock.c
+++ b/io/channel-websock.c
@@ -351,7 +351,7 @@ static void qio_channel_websock_handshake_send_res_ok(QIOChannelWebsock *ioc,
QIO_CHANNEL_WEBSOCK_GUID_LEN + 1);
/* hash and encode it */
- if (qcrypto_hash_base64(QCRYPTO_HASH_ALG_SHA1,
+ if (qcrypto_hash_base64(QCRYPTO_HASH_ALGO_SHA1,
combined_key,
QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN +
QIO_CHANNEL_WEBSOCK_GUID_LEN,
diff --git a/io/channel.c b/io/channel.c
index a1f12f8..e3f17c2 100644
--- a/io/channel.c
+++ b/io/channel.c
@@ -548,6 +548,19 @@ void qio_channel_set_cork(QIOChannel *ioc,
}
}
+int qio_channel_get_peerpid(QIOChannel *ioc,
+ unsigned int *pid,
+ Error **errp)
+{
+ QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
+
+ if (!klass->io_peerpid) {
+ error_setg(errp, "Channel does not support peer pid");
+ return -1;
+ }
+ klass->io_peerpid(ioc, pid, errp);
+ return 0;
+}
off_t qio_channel_io_seek(QIOChannel *ioc,
off_t offset,
diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h
index 1691297..eaeda00 100644
--- a/linux-headers/asm-powerpc/kvm.h
+++ b/linux-headers/asm-powerpc/kvm.h
@@ -645,6 +645,9 @@ struct kvm_ppc_cpu_char {
#define KVM_REG_PPC_SIER3 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc3)
#define KVM_REG_PPC_DAWR1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc4)
#define KVM_REG_PPC_DAWRX1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc5)
+#define KVM_REG_PPC_DEXCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc6)
+#define KVM_REG_PPC_HASHKEYR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc7)
+#define KVM_REG_PPC_HASHPKEYR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xc8)
/* Transactional Memory checkpointed state:
* This is all GPRs, all VSX regs and a subset of SPRs
diff --git a/linux-user/aarch64/meson.build b/linux-user/aarch64/meson.build
index f75bb3c..f25a67a 100644
--- a/linux-user/aarch64/meson.build
+++ b/linux-user/aarch64/meson.build
@@ -11,3 +11,9 @@ vdso_le_inc = gen_vdso.process('vdso-le.so',
linux_user_ss.add(when: 'TARGET_AARCH64', if_true: [vdso_be_inc, vdso_le_inc])
linux_user_ss.add(when: 'TARGET_AARCH64', if_true: [files('mte_user_helper.c')])
+
+syscall_nr_generators += {
+ 'aarch64': generator(sh,
+ arguments: [ meson.current_source_dir() / 'syscallhdr.sh', '@INPUT@', '@OUTPUT@', '@EXTRA_ARGS@' ],
+ output: '@BASENAME@_nr.h')
+}
diff --git a/linux-user/aarch64/syscall_64.tbl b/linux-user/aarch64/syscall_64.tbl
new file mode 100644
index 0000000..845e24e
--- /dev/null
+++ b/linux-user/aarch64/syscall_64.tbl
@@ -0,0 +1,405 @@
+# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+#
+# This file contains the system call numbers for all of the
+# more recently added architectures.
+#
+# As a basic principle, no duplication of functionality
+# should be added, e.g. we don't use lseek when llseek
+# is present. New architectures should use this file
+# and implement the less feature-full calls in user space.
+#
+0 common io_setup sys_io_setup compat_sys_io_setup
+1 common io_destroy sys_io_destroy
+2 common io_submit sys_io_submit compat_sys_io_submit
+3 common io_cancel sys_io_cancel
+4 time32 io_getevents sys_io_getevents_time32
+4 64 io_getevents sys_io_getevents
+5 common setxattr sys_setxattr
+6 common lsetxattr sys_lsetxattr
+7 common fsetxattr sys_fsetxattr
+8 common getxattr sys_getxattr
+9 common lgetxattr sys_lgetxattr
+10 common fgetxattr sys_fgetxattr
+11 common listxattr sys_listxattr
+12 common llistxattr sys_llistxattr
+13 common flistxattr sys_flistxattr
+14 common removexattr sys_removexattr
+15 common lremovexattr sys_lremovexattr
+16 common fremovexattr sys_fremovexattr
+17 common getcwd sys_getcwd
+18 common lookup_dcookie sys_ni_syscall
+19 common eventfd2 sys_eventfd2
+20 common epoll_create1 sys_epoll_create1
+21 common epoll_ctl sys_epoll_ctl
+22 common epoll_pwait sys_epoll_pwait compat_sys_epoll_pwait
+23 common dup sys_dup
+24 common dup3 sys_dup3
+25 32 fcntl64 sys_fcntl64 compat_sys_fcntl64
+25 64 fcntl sys_fcntl
+26 common inotify_init1 sys_inotify_init1
+27 common inotify_add_watch sys_inotify_add_watch
+28 common inotify_rm_watch sys_inotify_rm_watch
+29 common ioctl sys_ioctl compat_sys_ioctl
+30 common ioprio_set sys_ioprio_set
+31 common ioprio_get sys_ioprio_get
+32 common flock sys_flock
+33 common mknodat sys_mknodat
+34 common mkdirat sys_mkdirat
+35 common unlinkat sys_unlinkat
+36 common symlinkat sys_symlinkat
+37 common linkat sys_linkat
+# renameat is superseded with flags by renameat2
+38 renameat renameat sys_renameat
+39 common umount2 sys_umount
+40 common mount sys_mount
+41 common pivot_root sys_pivot_root
+42 common nfsservctl sys_ni_syscall
+43 32 statfs64 sys_statfs64 compat_sys_statfs64
+43 64 statfs sys_statfs
+44 32 fstatfs64 sys_fstatfs64 compat_sys_fstatfs64
+44 64 fstatfs sys_fstatfs
+45 32 truncate64 sys_truncate64 compat_sys_truncate64
+45 64 truncate sys_truncate
+46 32 ftruncate64 sys_ftruncate64 compat_sys_ftruncate64
+46 64 ftruncate sys_ftruncate
+47 common fallocate sys_fallocate compat_sys_fallocate
+48 common faccessat sys_faccessat
+49 common chdir sys_chdir
+50 common fchdir sys_fchdir
+51 common chroot sys_chroot
+52 common fchmod sys_fchmod
+53 common fchmodat sys_fchmodat
+54 common fchownat sys_fchownat
+55 common fchown sys_fchown
+56 common openat sys_openat
+57 common close sys_close
+58 common vhangup sys_vhangup
+59 common pipe2 sys_pipe2
+60 common quotactl sys_quotactl
+61 common getdents64 sys_getdents64
+62 32 llseek sys_llseek
+62 64 lseek sys_lseek
+63 common read sys_read
+64 common write sys_write
+65 common readv sys_readv sys_readv
+66 common writev sys_writev sys_writev
+67 common pread64 sys_pread64 compat_sys_pread64
+68 common pwrite64 sys_pwrite64 compat_sys_pwrite64
+69 common preadv sys_preadv compat_sys_preadv
+70 common pwritev sys_pwritev compat_sys_pwritev
+71 32 sendfile64 sys_sendfile64
+71 64 sendfile sys_sendfile64
+72 time32 pselect6 sys_pselect6_time32 compat_sys_pselect6_time32
+72 64 pselect6 sys_pselect6
+73 time32 ppoll sys_ppoll_time32 compat_sys_ppoll_time32
+73 64 ppoll sys_ppoll
+74 common signalfd4 sys_signalfd4 compat_sys_signalfd4
+75 common vmsplice sys_vmsplice
+76 common splice sys_splice
+77 common tee sys_tee
+78 common readlinkat sys_readlinkat
+79 stat64 fstatat64 sys_fstatat64
+79 64 newfstatat sys_newfstatat
+80 stat64 fstat64 sys_fstat64
+80 64 fstat sys_newfstat
+81 common sync sys_sync
+82 common fsync sys_fsync
+83 common fdatasync sys_fdatasync
+84 common sync_file_range sys_sync_file_range compat_sys_sync_file_range
+85 common timerfd_create sys_timerfd_create
+86 time32 timerfd_settime sys_timerfd_settime32
+86 64 timerfd_settime sys_timerfd_settime
+87 time32 timerfd_gettime sys_timerfd_gettime32
+87 64 timerfd_gettime sys_timerfd_gettime
+88 time32 utimensat sys_utimensat_time32
+88 64 utimensat sys_utimensat
+89 common acct sys_acct
+90 common capget sys_capget
+91 common capset sys_capset
+92 common personality sys_personality
+93 common exit sys_exit
+94 common exit_group sys_exit_group
+95 common waitid sys_waitid compat_sys_waitid
+96 common set_tid_address sys_set_tid_address
+97 common unshare sys_unshare
+98 time32 futex sys_futex_time32
+98 64 futex sys_futex
+99 common set_robust_list sys_set_robust_list compat_sys_set_robust_list
+100 common get_robust_list sys_get_robust_list compat_sys_get_robust_list
+101 time32 nanosleep sys_nanosleep_time32
+101 64 nanosleep sys_nanosleep
+102 common getitimer sys_getitimer compat_sys_getitimer
+103 common setitimer sys_setitimer compat_sys_setitimer
+104 common kexec_load sys_kexec_load compat_sys_kexec_load
+105 common init_module sys_init_module
+106 common delete_module sys_delete_module
+107 common timer_create sys_timer_create compat_sys_timer_create
+108 time32 timer_gettime sys_timer_gettime32
+108 64 timer_gettime sys_timer_gettime
+109 common timer_getoverrun sys_timer_getoverrun
+110 time32 timer_settime sys_timer_settime32
+110 64 timer_settime sys_timer_settime
+111 common timer_delete sys_timer_delete
+112 time32 clock_settime sys_clock_settime32
+112 64 clock_settime sys_clock_settime
+113 time32 clock_gettime sys_clock_gettime32
+113 64 clock_gettime sys_clock_gettime
+114 time32 clock_getres sys_clock_getres_time32
+114 64 clock_getres sys_clock_getres
+115 time32 clock_nanosleep sys_clock_nanosleep_time32
+115 64 clock_nanosleep sys_clock_nanosleep
+116 common syslog sys_syslog
+117 common ptrace sys_ptrace compat_sys_ptrace
+118 common sched_setparam sys_sched_setparam
+119 common sched_setscheduler sys_sched_setscheduler
+120 common sched_getscheduler sys_sched_getscheduler
+121 common sched_getparam sys_sched_getparam
+122 common sched_setaffinity sys_sched_setaffinity compat_sys_sched_setaffinity
+123 common sched_getaffinity sys_sched_getaffinity compat_sys_sched_getaffinity
+124 common sched_yield sys_sched_yield
+125 common sched_get_priority_max sys_sched_get_priority_max
+126 common sched_get_priority_min sys_sched_get_priority_min
+127 time32 sched_rr_get_interval sys_sched_rr_get_interval_time32
+127 64 sched_rr_get_interval sys_sched_rr_get_interval
+128 common restart_syscall sys_restart_syscall
+129 common kill sys_kill
+130 common tkill sys_tkill
+131 common tgkill sys_tgkill
+132 common sigaltstack sys_sigaltstack compat_sys_sigaltstack
+133 common rt_sigsuspend sys_rt_sigsuspend compat_sys_rt_sigsuspend
+134 common rt_sigaction sys_rt_sigaction compat_sys_rt_sigaction
+135 common rt_sigprocmask sys_rt_sigprocmask compat_sys_rt_sigprocmask
+136 common rt_sigpending sys_rt_sigpending compat_sys_rt_sigpending
+137 time32 rt_sigtimedwait sys_rt_sigtimedwait_time32 compat_sys_rt_sigtimedwait_time32
+137 64 rt_sigtimedwait sys_rt_sigtimedwait
+138 common rt_sigqueueinfo sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo
+139 common rt_sigreturn sys_rt_sigreturn compat_sys_rt_sigreturn
+140 common setpriority sys_setpriority
+141 common getpriority sys_getpriority
+142 common reboot sys_reboot
+143 common setregid sys_setregid
+144 common setgid sys_setgid
+145 common setreuid sys_setreuid
+146 common setuid sys_setuid
+147 common setresuid sys_setresuid
+148 common getresuid sys_getresuid
+149 common setresgid sys_setresgid
+150 common getresgid sys_getresgid
+151 common setfsuid sys_setfsuid
+152 common setfsgid sys_setfsgid
+153 common times sys_times compat_sys_times
+154 common setpgid sys_setpgid
+155 common getpgid sys_getpgid
+156 common getsid sys_getsid
+157 common setsid sys_setsid
+158 common getgroups sys_getgroups
+159 common setgroups sys_setgroups
+160 common uname sys_newuname
+161 common sethostname sys_sethostname
+162 common setdomainname sys_setdomainname
+# getrlimit and setrlimit are superseded with prlimit64
+163 rlimit getrlimit sys_getrlimit compat_sys_getrlimit
+164 rlimit setrlimit sys_setrlimit compat_sys_setrlimit
+165 common getrusage sys_getrusage compat_sys_getrusage
+166 common umask sys_umask
+167 common prctl sys_prctl
+168 common getcpu sys_getcpu
+169 time32 gettimeofday sys_gettimeofday compat_sys_gettimeofday
+169 64 gettimeofday sys_gettimeofday
+170 time32 settimeofday sys_settimeofday compat_sys_settimeofday
+170 64 settimeofday sys_settimeofday
+171 time32 adjtimex sys_adjtimex_time32
+171 64 adjtimex sys_adjtimex
+172 common getpid sys_getpid
+173 common getppid sys_getppid
+174 common getuid sys_getuid
+175 common geteuid sys_geteuid
+176 common getgid sys_getgid
+177 common getegid sys_getegid
+178 common gettid sys_gettid
+179 common sysinfo sys_sysinfo compat_sys_sysinfo
+180 common mq_open sys_mq_open compat_sys_mq_open
+181 common mq_unlink sys_mq_unlink
+182 time32 mq_timedsend sys_mq_timedsend_time32
+182 64 mq_timedsend sys_mq_timedsend
+183 time32 mq_timedreceive sys_mq_timedreceive_time32
+183 64 mq_timedreceive sys_mq_timedreceive
+184 common mq_notify sys_mq_notify compat_sys_mq_notify
+185 common mq_getsetattr sys_mq_getsetattr compat_sys_mq_getsetattr
+186 common msgget sys_msgget
+187 common msgctl sys_msgctl compat_sys_msgctl
+188 common msgrcv sys_msgrcv compat_sys_msgrcv
+189 common msgsnd sys_msgsnd compat_sys_msgsnd
+190 common semget sys_semget
+191 common semctl sys_semctl compat_sys_semctl
+192 time32 semtimedop sys_semtimedop_time32
+192 64 semtimedop sys_semtimedop
+193 common semop sys_semop
+194 common shmget sys_shmget
+195 common shmctl sys_shmctl compat_sys_shmctl
+196 common shmat sys_shmat compat_sys_shmat
+197 common shmdt sys_shmdt
+198 common socket sys_socket
+199 common socketpair sys_socketpair
+200 common bind sys_bind
+201 common listen sys_listen
+202 common accept sys_accept
+203 common connect sys_connect
+204 common getsockname sys_getsockname
+205 common getpeername sys_getpeername
+206 common sendto sys_sendto
+207 common recvfrom sys_recvfrom compat_sys_recvfrom
+208 common setsockopt sys_setsockopt sys_setsockopt
+209 common getsockopt sys_getsockopt sys_getsockopt
+210 common shutdown sys_shutdown
+211 common sendmsg sys_sendmsg compat_sys_sendmsg
+212 common recvmsg sys_recvmsg compat_sys_recvmsg
+213 common readahead sys_readahead compat_sys_readahead
+214 common brk sys_brk
+215 common munmap sys_munmap
+216 common mremap sys_mremap
+217 common add_key sys_add_key
+218 common request_key sys_request_key
+219 common keyctl sys_keyctl compat_sys_keyctl
+220 common clone sys_clone
+221 common execve sys_execve compat_sys_execve
+222 32 mmap2 sys_mmap2
+222 64 mmap sys_mmap
+223 32 fadvise64_64 sys_fadvise64_64 compat_sys_fadvise64_64
+223 64 fadvise64 sys_fadvise64_64
+224 common swapon sys_swapon
+225 common swapoff sys_swapoff
+226 common mprotect sys_mprotect
+227 common msync sys_msync
+228 common mlock sys_mlock
+229 common munlock sys_munlock
+230 common mlockall sys_mlockall
+231 common munlockall sys_munlockall
+232 common mincore sys_mincore
+233 common madvise sys_madvise
+234 common remap_file_pages sys_remap_file_pages
+235 common mbind sys_mbind
+236 common get_mempolicy sys_get_mempolicy
+237 common set_mempolicy sys_set_mempolicy
+238 common migrate_pages sys_migrate_pages
+239 common move_pages sys_move_pages
+240 common rt_tgsigqueueinfo sys_rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo
+241 common perf_event_open sys_perf_event_open
+242 common accept4 sys_accept4
+243 time32 recvmmsg sys_recvmmsg_time32 compat_sys_recvmmsg_time32
+243 64 recvmmsg sys_recvmmsg
+# Architectures may provide up to 16 syscalls of their own between 244 and 259
+244 arc cacheflush sys_cacheflush
+245 arc arc_settls sys_arc_settls
+246 arc arc_gettls sys_arc_gettls
+247 arc sysfs sys_sysfs
+248 arc arc_usr_cmpxchg sys_arc_usr_cmpxchg
+
+244 csky set_thread_area sys_set_thread_area
+245 csky cacheflush sys_cacheflush
+
+244 nios2 cacheflush sys_cacheflush
+
+244 or1k or1k_atomic sys_or1k_atomic
+
+258 riscv riscv_hwprobe sys_riscv_hwprobe
+259 riscv riscv_flush_icache sys_riscv_flush_icache
+
+260 time32 wait4 sys_wait4 compat_sys_wait4
+260 64 wait4 sys_wait4
+261 common prlimit64 sys_prlimit64
+262 common fanotify_init sys_fanotify_init
+263 common fanotify_mark sys_fanotify_mark
+264 common name_to_handle_at sys_name_to_handle_at
+265 common open_by_handle_at sys_open_by_handle_at
+266 time32 clock_adjtime sys_clock_adjtime32
+266 64 clock_adjtime sys_clock_adjtime
+267 common syncfs sys_syncfs
+268 common setns sys_setns
+269 common sendmmsg sys_sendmmsg compat_sys_sendmmsg
+270 common process_vm_readv sys_process_vm_readv
+271 common process_vm_writev sys_process_vm_writev
+272 common kcmp sys_kcmp
+273 common finit_module sys_finit_module
+274 common sched_setattr sys_sched_setattr
+275 common sched_getattr sys_sched_getattr
+276 common renameat2 sys_renameat2
+277 common seccomp sys_seccomp
+278 common getrandom sys_getrandom
+279 common memfd_create sys_memfd_create
+280 common bpf sys_bpf
+281 common execveat sys_execveat compat_sys_execveat
+282 common userfaultfd sys_userfaultfd
+283 common membarrier sys_membarrier
+284 common mlock2 sys_mlock2
+285 common copy_file_range sys_copy_file_range
+286 common preadv2 sys_preadv2 compat_sys_preadv2
+287 common pwritev2 sys_pwritev2 compat_sys_pwritev2
+288 common pkey_mprotect sys_pkey_mprotect
+289 common pkey_alloc sys_pkey_alloc
+290 common pkey_free sys_pkey_free
+291 common statx sys_statx
+292 time32 io_pgetevents sys_io_pgetevents_time32 compat_sys_io_pgetevents
+292 64 io_pgetevents sys_io_pgetevents
+293 common rseq sys_rseq
+294 common kexec_file_load sys_kexec_file_load
+# 295 through 402 are unassigned to sync up with generic numbers don't use
+403 32 clock_gettime64 sys_clock_gettime
+404 32 clock_settime64 sys_clock_settime
+405 32 clock_adjtime64 sys_clock_adjtime
+406 32 clock_getres_time64 sys_clock_getres
+407 32 clock_nanosleep_time64 sys_clock_nanosleep
+408 32 timer_gettime64 sys_timer_gettime
+409 32 timer_settime64 sys_timer_settime
+410 32 timerfd_gettime64 sys_timerfd_gettime
+411 32 timerfd_settime64 sys_timerfd_settime
+412 32 utimensat_time64 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 compat_sys_io_pgetevents_time64
+417 32 recvmmsg_time64 sys_recvmmsg compat_sys_recvmmsg_time64
+418 32 mq_timedsend_time64 sys_mq_timedsend
+419 32 mq_timedreceive_time64 sys_mq_timedreceive
+420 32 semtimedop_time64 sys_semtimedop
+421 32 rt_sigtimedwait_time64 sys_rt_sigtimedwait compat_sys_rt_sigtimedwait_time64
+422 32 futex_time64 sys_futex
+423 32 sched_rr_get_interval_time64 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 common clone3 sys_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
+440 common process_madvise sys_process_madvise
+441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
+442 common mount_setattr sys_mount_setattr
+443 common quotactl_fd sys_quotactl_fd
+444 common landlock_create_ruleset sys_landlock_create_ruleset
+445 common landlock_add_rule sys_landlock_add_rule
+446 common landlock_restrict_self sys_landlock_restrict_self
+447 memfd_secret memfd_secret sys_memfd_secret
+448 common process_mrelease sys_process_mrelease
+449 common futex_waitv sys_futex_waitv
+450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common cachestat sys_cachestat
+452 common fchmodat2 sys_fchmodat2
+453 common map_shadow_stack sys_map_shadow_stack
+454 common futex_wake sys_futex_wake
+455 common futex_wait sys_futex_wait
+456 common futex_requeue sys_futex_requeue
+457 common statmount sys_statmount
+458 common listmount sys_listmount
+459 common lsm_get_self_attr sys_lsm_get_self_attr
+460 common lsm_set_self_attr sys_lsm_set_self_attr
+461 common lsm_list_modules sys_lsm_list_modules
+462 common mseal sys_mseal
diff --git a/linux-user/aarch64/syscall_nr.h b/linux-user/aarch64/syscall_nr.h
index 12ef002..760302c 100644
--- a/linux-user/aarch64/syscall_nr.h
+++ b/linux-user/aarch64/syscall_nr.h
@@ -1,313 +1 @@
-/*
- * This file contains the system call numbers.
- * Do not modify.
- * This file is generated by scripts/gensyscalls.sh
- */
-#ifndef LINUX_USER_AARCH64_SYSCALL_NR_H
-#define LINUX_USER_AARCH64_SYSCALL_NR_H
-
-#define TARGET_NR_io_setup 0
-#define TARGET_NR_io_destroy 1
-#define TARGET_NR_io_submit 2
-#define TARGET_NR_io_cancel 3
-#define TARGET_NR_io_getevents 4
-#define TARGET_NR_setxattr 5
-#define TARGET_NR_lsetxattr 6
-#define TARGET_NR_fsetxattr 7
-#define TARGET_NR_getxattr 8
-#define TARGET_NR_lgetxattr 9
-#define TARGET_NR_fgetxattr 10
-#define TARGET_NR_listxattr 11
-#define TARGET_NR_llistxattr 12
-#define TARGET_NR_flistxattr 13
-#define TARGET_NR_removexattr 14
-#define TARGET_NR_lremovexattr 15
-#define TARGET_NR_fremovexattr 16
-#define TARGET_NR_getcwd 17
-#define TARGET_NR_lookup_dcookie 18
-#define TARGET_NR_eventfd2 19
-#define TARGET_NR_epoll_create1 20
-#define TARGET_NR_epoll_ctl 21
-#define TARGET_NR_epoll_pwait 22
-#define TARGET_NR_dup 23
-#define TARGET_NR_dup3 24
-#define TARGET_NR_fcntl 25
-#define TARGET_NR_inotify_init1 26
-#define TARGET_NR_inotify_add_watch 27
-#define TARGET_NR_inotify_rm_watch 28
-#define TARGET_NR_ioctl 29
-#define TARGET_NR_ioprio_set 30
-#define TARGET_NR_ioprio_get 31
-#define TARGET_NR_flock 32
-#define TARGET_NR_mknodat 33
-#define TARGET_NR_mkdirat 34
-#define TARGET_NR_unlinkat 35
-#define TARGET_NR_symlinkat 36
-#define TARGET_NR_linkat 37
-#define TARGET_NR_renameat 38
-#define TARGET_NR_umount2 39
-#define TARGET_NR_mount 40
-#define TARGET_NR_pivot_root 41
-#define TARGET_NR_nfsservctl 42
-#define TARGET_NR_statfs 43
-#define TARGET_NR_fstatfs 44
-#define TARGET_NR_truncate 45
-#define TARGET_NR_ftruncate 46
-#define TARGET_NR_fallocate 47
-#define TARGET_NR_faccessat 48
-#define TARGET_NR_chdir 49
-#define TARGET_NR_fchdir 50
-#define TARGET_NR_chroot 51
-#define TARGET_NR_fchmod 52
-#define TARGET_NR_fchmodat 53
-#define TARGET_NR_fchownat 54
-#define TARGET_NR_fchown 55
-#define TARGET_NR_openat 56
-#define TARGET_NR_close 57
-#define TARGET_NR_vhangup 58
-#define TARGET_NR_pipe2 59
-#define TARGET_NR_quotactl 60
-#define TARGET_NR_getdents64 61
-#define TARGET_NR_lseek 62
-#define TARGET_NR_read 63
-#define TARGET_NR_write 64
-#define TARGET_NR_readv 65
-#define TARGET_NR_writev 66
-#define TARGET_NR_pread64 67
-#define TARGET_NR_pwrite64 68
-#define TARGET_NR_preadv 69
-#define TARGET_NR_pwritev 70
-#define TARGET_NR_sendfile 71
-#define TARGET_NR_pselect6 72
-#define TARGET_NR_ppoll 73
-#define TARGET_NR_signalfd4 74
-#define TARGET_NR_vmsplice 75
-#define TARGET_NR_splice 76
-#define TARGET_NR_tee 77
-#define TARGET_NR_readlinkat 78
-#define TARGET_NR_newfstatat 79
-#define TARGET_NR_fstat 80
-#define TARGET_NR_sync 81
-#define TARGET_NR_fsync 82
-#define TARGET_NR_fdatasync 83
-#define TARGET_NR_sync_file_range 84
-#define TARGET_NR_timerfd_create 85
-#define TARGET_NR_timerfd_settime 86
-#define TARGET_NR_timerfd_gettime 87
-#define TARGET_NR_utimensat 88
-#define TARGET_NR_acct 89
-#define TARGET_NR_capget 90
-#define TARGET_NR_capset 91
-#define TARGET_NR_personality 92
-#define TARGET_NR_exit 93
-#define TARGET_NR_exit_group 94
-#define TARGET_NR_waitid 95
-#define TARGET_NR_set_tid_address 96
-#define TARGET_NR_unshare 97
-#define TARGET_NR_futex 98
-#define TARGET_NR_set_robust_list 99
-#define TARGET_NR_get_robust_list 100
-#define TARGET_NR_nanosleep 101
-#define TARGET_NR_getitimer 102
-#define TARGET_NR_setitimer 103
-#define TARGET_NR_kexec_load 104
-#define TARGET_NR_init_module 105
-#define TARGET_NR_delete_module 106
-#define TARGET_NR_timer_create 107
-#define TARGET_NR_timer_gettime 108
-#define TARGET_NR_timer_getoverrun 109
-#define TARGET_NR_timer_settime 110
-#define TARGET_NR_timer_delete 111
-#define TARGET_NR_clock_settime 112
-#define TARGET_NR_clock_gettime 113
-#define TARGET_NR_clock_getres 114
-#define TARGET_NR_clock_nanosleep 115
-#define TARGET_NR_syslog 116
-#define TARGET_NR_ptrace 117
-#define TARGET_NR_sched_setparam 118
-#define TARGET_NR_sched_setscheduler 119
-#define TARGET_NR_sched_getscheduler 120
-#define TARGET_NR_sched_getparam 121
-#define TARGET_NR_sched_setaffinity 122
-#define TARGET_NR_sched_getaffinity 123
-#define TARGET_NR_sched_yield 124
-#define TARGET_NR_sched_get_priority_max 125
-#define TARGET_NR_sched_get_priority_min 126
-#define TARGET_NR_sched_rr_get_interval 127
-#define TARGET_NR_restart_syscall 128
-#define TARGET_NR_kill 129
-#define TARGET_NR_tkill 130
-#define TARGET_NR_tgkill 131
-#define TARGET_NR_sigaltstack 132
-#define TARGET_NR_rt_sigsuspend 133
-#define TARGET_NR_rt_sigaction 134
-#define TARGET_NR_rt_sigprocmask 135
-#define TARGET_NR_rt_sigpending 136
-#define TARGET_NR_rt_sigtimedwait 137
-#define TARGET_NR_rt_sigqueueinfo 138
-#define TARGET_NR_rt_sigreturn 139
-#define TARGET_NR_setpriority 140
-#define TARGET_NR_getpriority 141
-#define TARGET_NR_reboot 142
-#define TARGET_NR_setregid 143
-#define TARGET_NR_setgid 144
-#define TARGET_NR_setreuid 145
-#define TARGET_NR_setuid 146
-#define TARGET_NR_setresuid 147
-#define TARGET_NR_getresuid 148
-#define TARGET_NR_setresgid 149
-#define TARGET_NR_getresgid 150
-#define TARGET_NR_setfsuid 151
-#define TARGET_NR_setfsgid 152
-#define TARGET_NR_times 153
-#define TARGET_NR_setpgid 154
-#define TARGET_NR_getpgid 155
-#define TARGET_NR_getsid 156
-#define TARGET_NR_setsid 157
-#define TARGET_NR_getgroups 158
-#define TARGET_NR_setgroups 159
-#define TARGET_NR_uname 160
-#define TARGET_NR_sethostname 161
-#define TARGET_NR_setdomainname 162
-#define TARGET_NR_getrlimit 163
-#define TARGET_NR_setrlimit 164
-#define TARGET_NR_getrusage 165
-#define TARGET_NR_umask 166
-#define TARGET_NR_prctl 167
-#define TARGET_NR_getcpu 168
-#define TARGET_NR_gettimeofday 169
-#define TARGET_NR_settimeofday 170
-#define TARGET_NR_adjtimex 171
-#define TARGET_NR_getpid 172
-#define TARGET_NR_getppid 173
-#define TARGET_NR_getuid 174
-#define TARGET_NR_geteuid 175
-#define TARGET_NR_getgid 176
-#define TARGET_NR_getegid 177
-#define TARGET_NR_gettid 178
-#define TARGET_NR_sysinfo 179
-#define TARGET_NR_mq_open 180
-#define TARGET_NR_mq_unlink 181
-#define TARGET_NR_mq_timedsend 182
-#define TARGET_NR_mq_timedreceive 183
-#define TARGET_NR_mq_notify 184
-#define TARGET_NR_mq_getsetattr 185
-#define TARGET_NR_msgget 186
-#define TARGET_NR_msgctl 187
-#define TARGET_NR_msgrcv 188
-#define TARGET_NR_msgsnd 189
-#define TARGET_NR_semget 190
-#define TARGET_NR_semctl 191
-#define TARGET_NR_semtimedop 192
-#define TARGET_NR_semop 193
-#define TARGET_NR_shmget 194
-#define TARGET_NR_shmctl 195
-#define TARGET_NR_shmat 196
-#define TARGET_NR_shmdt 197
-#define TARGET_NR_socket 198
-#define TARGET_NR_socketpair 199
-#define TARGET_NR_bind 200
-#define TARGET_NR_listen 201
-#define TARGET_NR_accept 202
-#define TARGET_NR_connect 203
-#define TARGET_NR_getsockname 204
-#define TARGET_NR_getpeername 205
-#define TARGET_NR_sendto 206
-#define TARGET_NR_recvfrom 207
-#define TARGET_NR_setsockopt 208
-#define TARGET_NR_getsockopt 209
-#define TARGET_NR_shutdown 210
-#define TARGET_NR_sendmsg 211
-#define TARGET_NR_recvmsg 212
-#define TARGET_NR_readahead 213
-#define TARGET_NR_brk 214
-#define TARGET_NR_munmap 215
-#define TARGET_NR_mremap 216
-#define TARGET_NR_add_key 217
-#define TARGET_NR_request_key 218
-#define TARGET_NR_keyctl 219
-#define TARGET_NR_clone 220
-#define TARGET_NR_execve 221
-#define TARGET_NR_mmap 222
-#define TARGET_NR_fadvise64 223
-#define TARGET_NR_swapon 224
-#define TARGET_NR_swapoff 225
-#define TARGET_NR_mprotect 226
-#define TARGET_NR_msync 227
-#define TARGET_NR_mlock 228
-#define TARGET_NR_munlock 229
-#define TARGET_NR_mlockall 230
-#define TARGET_NR_munlockall 231
-#define TARGET_NR_mincore 232
-#define TARGET_NR_madvise 233
-#define TARGET_NR_remap_file_pages 234
-#define TARGET_NR_mbind 235
-#define TARGET_NR_get_mempolicy 236
-#define TARGET_NR_set_mempolicy 237
-#define TARGET_NR_migrate_pages 238
-#define TARGET_NR_move_pages 239
-#define TARGET_NR_rt_tgsigqueueinfo 240
-#define TARGET_NR_perf_event_open 241
-#define TARGET_NR_accept4 242
-#define TARGET_NR_recvmmsg 243
-#define TARGET_NR_arch_specific_syscall 244
-#define TARGET_NR_wait4 260
-#define TARGET_NR_prlimit64 261
-#define TARGET_NR_fanotify_init 262
-#define TARGET_NR_fanotify_mark 263
-#define TARGET_NR_name_to_handle_at 264
-#define TARGET_NR_open_by_handle_at 265
-#define TARGET_NR_clock_adjtime 266
-#define TARGET_NR_syncfs 267
-#define TARGET_NR_setns 268
-#define TARGET_NR_sendmmsg 269
-#define TARGET_NR_process_vm_readv 270
-#define TARGET_NR_process_vm_writev 271
-#define TARGET_NR_kcmp 272
-#define TARGET_NR_finit_module 273
-#define TARGET_NR_sched_setattr 274
-#define TARGET_NR_sched_getattr 275
-#define TARGET_NR_renameat2 276
-#define TARGET_NR_seccomp 277
-#define TARGET_NR_getrandom 278
-#define TARGET_NR_memfd_create 279
-#define TARGET_NR_bpf 280
-#define TARGET_NR_execveat 281
-#define TARGET_NR_userfaultfd 282
-#define TARGET_NR_membarrier 283
-#define TARGET_NR_mlock2 284
-#define TARGET_NR_copy_file_range 285
-#define TARGET_NR_preadv2 286
-#define TARGET_NR_pwritev2 287
-#define TARGET_NR_pkey_mprotect 288
-#define TARGET_NR_pkey_alloc 289
-#define TARGET_NR_pkey_free 290
-#define TARGET_NR_statx 291
-#define TARGET_NR_io_pgetevents 292
-#define TARGET_NR_rseq 293
-#define TARGET_NR_kexec_file_load 294
-#define TARGET_NR_pidfd_send_signal 424
-#define TARGET_NR_io_uring_setup 425
-#define TARGET_NR_io_uring_enter 426
-#define TARGET_NR_io_uring_register 427
-#define TARGET_NR_open_tree 428
-#define TARGET_NR_move_mount 429
-#define TARGET_NR_fsopen 430
-#define TARGET_NR_fsconfig 431
-#define TARGET_NR_fsmount 432
-#define TARGET_NR_fspick 433
-#define TARGET_NR_pidfd_open 434
-#define TARGET_NR_clone3 435
-#define TARGET_NR_close_range 436
-#define TARGET_NR_openat2 437
-#define TARGET_NR_pidfd_getfd 438
-#define TARGET_NR_faccessat2 439
-#define TARGET_NR_process_madvise 440
-#define TARGET_NR_epoll_pwait2 441
-#define TARGET_NR_mount_setattr 442
-#define TARGET_NR_landlock_create_ruleset 444
-#define TARGET_NR_landlock_add_rule 445
-#define TARGET_NR_landlock_restrict_self 446
-#define TARGET_NR_syscalls 447
-
-#endif /* LINUX_USER_AARCH64_SYSCALL_NR_H */
+#include "syscall_64_nr.h"
diff --git a/linux-user/aarch64/syscallhdr.sh b/linux-user/aarch64/syscallhdr.sh
new file mode 100644
index 0000000..dd6b586
--- /dev/null
+++ b/linux-user/aarch64/syscallhdr.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+in="$1"
+out="$2"
+my_abis=`echo "($3)" | tr ',' '|'`
+prefix="$4"
+offset="$5"
+
+fileguard=LINUX_USER_AARCH64_`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 | (
+ echo "#ifndef ${fileguard}"
+ echo "#define ${fileguard} 1"
+ echo ""
+
+ while read nr abi name entry compat; do
+ if [ -z "$offset" ]; then
+ echo "#define TARGET_NR_${prefix}${name} $nr"
+ else
+ echo "#define TARGET_NR_${prefix}${name} ($offset + $nr)"
+ fi
+ done
+
+ echo ""
+ echo "#endif /* ${fileguard} */"
+) > "$out"
diff --git a/linux-user/alpha/syscall.tbl b/linux-user/alpha/syscall.tbl
index 3000a2e..54ee7aa 100644
--- a/linux-user/alpha/syscall.tbl
+++ b/linux-user/alpha/syscall.tbl
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
#
# system call numbers and entry vectors for alpha
#
@@ -125,8 +125,8 @@
116 common osf_gettimeofday sys_osf_gettimeofday
117 common osf_getrusage sys_osf_getrusage
118 common getsockopt sys_getsockopt
-120 common readv sys_osf_readv
-121 common writev sys_osf_writev
+120 common readv sys_readv
+121 common writev sys_writev
122 common osf_settimeofday sys_osf_settimeofday
123 common fchown sys_fchown
124 common fchmod sys_fchmod
@@ -230,7 +230,7 @@
259 common osf_swapctl sys_ni_syscall
260 common osf_memcntl sys_ni_syscall
261 common osf_fdatasync sys_ni_syscall
-300 common bdflush sys_bdflush
+300 common bdflush sys_ni_syscall
301 common sethae sys_sethae
302 common mount sys_mount
303 common old_adjtimex sys_old_adjtimex
@@ -334,7 +334,7 @@
401 common io_submit sys_io_submit
402 common io_cancel sys_io_cancel
405 common exit_group sys_exit_group
-406 common lookup_dcookie sys_lookup_dcookie
+406 common lookup_dcookie sys_ni_syscall
407 common epoll_create sys_epoll_create
408 common epoll_ctl sys_epoll_ctl
409 common epoll_wait sys_epoll_wait
@@ -474,7 +474,7 @@
542 common fsmount sys_fsmount
543 common fspick sys_fspick
544 common pidfd_open sys_pidfd_open
-# 545 reserved for clone3
+545 common clone3 alpha_clone3
546 common close_range sys_close_range
547 common openat2 sys_openat2
548 common pidfd_getfd sys_pidfd_getfd
@@ -482,7 +482,23 @@
550 common process_madvise sys_process_madvise
551 common epoll_pwait2 sys_epoll_pwait2
552 common mount_setattr sys_mount_setattr
-# 553 reserved for quotactl_path
+553 common quotactl_fd sys_quotactl_fd
554 common landlock_create_ruleset sys_landlock_create_ruleset
555 common landlock_add_rule sys_landlock_add_rule
556 common landlock_restrict_self sys_landlock_restrict_self
+# 557 reserved for memfd_secret
+558 common process_mrelease sys_process_mrelease
+559 common futex_waitv sys_futex_waitv
+560 common set_mempolicy_home_node sys_ni_syscall
+561 common cachestat sys_cachestat
+562 common fchmodat2 sys_fchmodat2
+563 common map_shadow_stack sys_map_shadow_stack
+564 common futex_wake sys_futex_wake
+565 common futex_wait sys_futex_wait
+566 common futex_requeue sys_futex_requeue
+567 common statmount sys_statmount
+568 common listmount sys_listmount
+569 common lsm_get_self_attr sys_lsm_get_self_attr
+570 common lsm_set_self_attr sys_lsm_set_self_attr
+571 common lsm_list_modules sys_lsm_list_modules
+572 common mseal sys_mseal
diff --git a/linux-user/alpha/syscallhdr.sh b/linux-user/alpha/syscallhdr.sh
index 55cafe6..6da0c95 100644
--- a/linux-user/alpha/syscallhdr.sh
+++ b/linux-user/alpha/syscallhdr.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
in="$1"
out="$2"
diff --git a/linux-user/arm/syscall.tbl b/linux-user/arm/syscall.tbl
index 28e03b5..23c9820 100644
--- a/linux-user/arm/syscall.tbl
+++ b/linux-user/arm/syscall.tbl
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
#
# Linux system call numbers and entry vectors
#
@@ -147,7 +148,7 @@
131 common quotactl sys_quotactl
132 common getpgid sys_getpgid
133 common fchdir sys_fchdir
-134 common bdflush sys_bdflush
+134 common bdflush sys_ni_syscall
135 common sysfs sys_sysfs
136 common personality sys_personality
# 137 was sys_afs_syscall
@@ -263,10 +264,10 @@
246 common io_submit sys_io_submit
247 common io_cancel sys_io_cancel
248 common exit_group sys_exit_group
-249 common lookup_dcookie sys_lookup_dcookie
+249 common lookup_dcookie sys_ni_syscall
250 common epoll_create sys_epoll_create
251 common epoll_ctl sys_epoll_ctl sys_oabi_epoll_ctl
-252 common epoll_wait sys_epoll_wait sys_oabi_epoll_wait
+252 common epoll_wait sys_epoll_wait
253 common remap_file_pages sys_remap_file_pages
# 254 for set_thread_area
# 255 for get_thread_area
@@ -456,7 +457,23 @@
440 common process_madvise sys_process_madvise
441 common epoll_pwait2 sys_epoll_pwait2
442 common mount_setattr sys_mount_setattr
-# 443 reserved for quotactl_path
+443 common quotactl_fd sys_quotactl_fd
444 common landlock_create_ruleset sys_landlock_create_ruleset
445 common landlock_add_rule sys_landlock_add_rule
446 common landlock_restrict_self sys_landlock_restrict_self
+# 447 reserved for memfd_secret
+448 common process_mrelease sys_process_mrelease
+449 common futex_waitv sys_futex_waitv
+450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common cachestat sys_cachestat
+452 common fchmodat2 sys_fchmodat2
+453 common map_shadow_stack sys_map_shadow_stack
+454 common futex_wake sys_futex_wake
+455 common futex_wait sys_futex_wait
+456 common futex_requeue sys_futex_requeue
+457 common statmount sys_statmount
+458 common listmount sys_listmount
+459 common lsm_get_self_attr sys_lsm_get_self_attr
+460 common lsm_set_self_attr sys_lsm_set_self_attr
+461 common lsm_list_modules sys_lsm_list_modules
+462 common mseal sys_mseal
diff --git a/linux-user/arm/syscallhdr.sh b/linux-user/arm/syscallhdr.sh
index 4c952b2..692fd6a 100644
--- a/linux-user/arm/syscallhdr.sh
+++ b/linux-user/arm/syscallhdr.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
in="$1"
out="$2"
diff --git a/linux-user/cris/cpu_loop.c b/linux-user/cris/cpu_loop.c
deleted file mode 100644
index 04c9086..0000000
--- a/linux-user/cris/cpu_loop.c
+++ /dev/null
@@ -1,95 +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 "qemu/osdep.h"
-#include "qemu.h"
-#include "user-internals.h"
-#include "cpu_loop-common.h"
-#include "signal-common.h"
-
-void cpu_loop(CPUCRISState *env)
-{
- CPUState *cs = env_cpu(env);
- int trapnr, ret;
-
- while (1) {
- cpu_exec_start(cs);
- trapnr = cpu_exec(cs);
- cpu_exec_end(cs);
- process_queued_cpu_work(cs);
-
- switch (trapnr) {
- case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
- case EXCP_BREAK:
- ret = do_syscall(env,
- env->regs[9],
- env->regs[10],
- env->regs[11],
- env->regs[12],
- env->regs[13],
- env->pregs[7],
- env->pregs[11],
- 0, 0);
- if (ret == -QEMU_ERESTARTSYS) {
- env->pc -= 2;
- } else if (ret != -QEMU_ESIGRETURN) {
- env->regs[10] = ret;
- }
- break;
- case EXCP_DEBUG:
- force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
- break;
- case EXCP_ATOMIC:
- cpu_exec_step_atomic(cs);
- break;
- default:
- fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr);
- cpu_dump_state(cs, stderr, 0);
- exit(EXIT_FAILURE);
- }
- process_pending_signals (env);
- }
-}
-
-void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
-{
- CPUState *cpu = env_cpu(env);
- TaskState *ts = get_task_state(cpu);
- struct image_info *info = ts->info;
-
- env->regs[0] = regs->r0;
- env->regs[1] = regs->r1;
- env->regs[2] = regs->r2;
- env->regs[3] = regs->r3;
- env->regs[4] = regs->r4;
- env->regs[5] = regs->r5;
- env->regs[6] = regs->r6;
- env->regs[7] = regs->r7;
- env->regs[8] = regs->r8;
- env->regs[9] = regs->r9;
- env->regs[10] = regs->r10;
- env->regs[11] = regs->r11;
- env->regs[12] = regs->r12;
- env->regs[13] = regs->r13;
- env->regs[14] = info->start_stack;
- env->regs[15] = regs->acr;
- env->pc = regs->erp;
-}
diff --git a/linux-user/cris/signal.c b/linux-user/cris/signal.c
deleted file mode 100644
index 10948bc..0000000
--- a/linux-user/cris/signal.c
+++ /dev/null
@@ -1,194 +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 "qemu/osdep.h"
-#include "qemu.h"
-#include "user-internals.h"
-#include "signal-common.h"
-#include "linux-user/trace.h"
-
-struct target_sigcontext {
- struct target_pt_regs regs; /* needs to be first */
- uint32_t oldmask;
- uint32_t usp; /* usp before stacking this gunk on it */
-};
-
-/* Signal frames. */
-struct target_signal_frame {
- struct target_sigcontext sc;
- uint32_t extramask[TARGET_NSIG_WORDS - 1];
- uint16_t retcode[4]; /* Trampoline code. */
-};
-
-static void setup_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
-{
- __put_user(env->regs[0], &sc->regs.r0);
- __put_user(env->regs[1], &sc->regs.r1);
- __put_user(env->regs[2], &sc->regs.r2);
- __put_user(env->regs[3], &sc->regs.r3);
- __put_user(env->regs[4], &sc->regs.r4);
- __put_user(env->regs[5], &sc->regs.r5);
- __put_user(env->regs[6], &sc->regs.r6);
- __put_user(env->regs[7], &sc->regs.r7);
- __put_user(env->regs[8], &sc->regs.r8);
- __put_user(env->regs[9], &sc->regs.r9);
- __put_user(env->regs[10], &sc->regs.r10);
- __put_user(env->regs[11], &sc->regs.r11);
- __put_user(env->regs[12], &sc->regs.r12);
- __put_user(env->regs[13], &sc->regs.r13);
- __put_user(env->regs[14], &sc->usp);
- __put_user(env->regs[15], &sc->regs.acr);
- __put_user(env->pregs[PR_MOF], &sc->regs.mof);
- __put_user(env->pregs[PR_SRP], &sc->regs.srp);
- __put_user(env->pc, &sc->regs.erp);
-}
-
-static void restore_sigcontext(struct target_sigcontext *sc, CPUCRISState *env)
-{
- __get_user(env->regs[0], &sc->regs.r0);
- __get_user(env->regs[1], &sc->regs.r1);
- __get_user(env->regs[2], &sc->regs.r2);
- __get_user(env->regs[3], &sc->regs.r3);
- __get_user(env->regs[4], &sc->regs.r4);
- __get_user(env->regs[5], &sc->regs.r5);
- __get_user(env->regs[6], &sc->regs.r6);
- __get_user(env->regs[7], &sc->regs.r7);
- __get_user(env->regs[8], &sc->regs.r8);
- __get_user(env->regs[9], &sc->regs.r9);
- __get_user(env->regs[10], &sc->regs.r10);
- __get_user(env->regs[11], &sc->regs.r11);
- __get_user(env->regs[12], &sc->regs.r12);
- __get_user(env->regs[13], &sc->regs.r13);
- __get_user(env->regs[14], &sc->usp);
- __get_user(env->regs[15], &sc->regs.acr);
- __get_user(env->pregs[PR_MOF], &sc->regs.mof);
- __get_user(env->pregs[PR_SRP], &sc->regs.srp);
- __get_user(env->pc, &sc->regs.erp);
-}
-
-static abi_ulong get_sigframe(CPUCRISState *env, int framesize)
-{
- abi_ulong sp;
- /* Align the stack downwards to 4. */
- sp = (env->regs[R_SP] & ~3);
- return sp - framesize;
-}
-
-static void setup_sigreturn(uint16_t *retcode)
-{
- /* This is movu.w __NR_sigreturn, r9; break 13; */
- __put_user(0x9c5f, retcode + 0);
- __put_user(TARGET_NR_sigreturn, retcode + 1);
- __put_user(0xe93d, retcode + 2);
-}
-
-void setup_frame(int sig, struct target_sigaction *ka,
- target_sigset_t *set, CPUCRISState *env)
-{
- struct target_signal_frame *frame;
- abi_ulong frame_addr;
- int i;
-
- frame_addr = get_sigframe(env, sizeof *frame);
- trace_user_setup_frame(env, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
- goto badframe;
-
- /*
- * The CRIS signal return trampoline. A real linux/CRIS kernel doesn't
- * use this trampoline anymore but it sets it up for GDB.
- */
- setup_sigreturn(frame->retcode);
-
- /* Save the mask. */
- __put_user(set->sig[0], &frame->sc.oldmask);
-
- for(i = 1; i < TARGET_NSIG_WORDS; i++) {
- __put_user(set->sig[i], &frame->extramask[i - 1]);
- }
-
- setup_sigcontext(&frame->sc, env);
-
- /* Move the stack and setup the arguments for the handler. */
- env->regs[R_SP] = frame_addr;
- env->regs[10] = sig;
- env->pc = (unsigned long) ka->_sa_handler;
- /* Link SRP so the guest returns through the trampoline. */
- env->pregs[PR_SRP] = default_sigreturn;
-
- unlock_user_struct(frame, frame_addr, 1);
- return;
-badframe:
- force_sigsegv(sig);
-}
-
-void setup_rt_frame(int sig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUCRISState *env)
-{
- qemu_log_mask(LOG_UNIMP, "setup_rt_frame: not implemented\n");
-}
-
-long do_sigreturn(CPUCRISState *env)
-{
- struct target_signal_frame *frame;
- abi_ulong frame_addr;
- target_sigset_t target_set;
- sigset_t set;
- int i;
-
- frame_addr = env->regs[R_SP];
- trace_user_do_sigreturn(env, frame_addr);
- /* Make sure the guest isn't playing games. */
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1)) {
- goto badframe;
- }
-
- /* Restore blocked signals */
- __get_user(target_set.sig[0], &frame->sc.oldmask);
- for(i = 1; i < TARGET_NSIG_WORDS; i++) {
- __get_user(target_set.sig[i], &frame->extramask[i - 1]);
- }
- target_to_host_sigset_internal(&set, &target_set);
- set_sigmask(&set);
-
- restore_sigcontext(&frame->sc, env);
- unlock_user_struct(frame, frame_addr, 0);
- return -QEMU_ESIGRETURN;
-badframe:
- force_sig(TARGET_SIGSEGV);
- return -QEMU_ESIGRETURN;
-}
-
-long do_rt_sigreturn(CPUCRISState *env)
-{
- trace_user_do_rt_sigreturn(env, 0);
- qemu_log_mask(LOG_UNIMP, "do_rt_sigreturn: not implemented\n");
- return -TARGET_ENOSYS;
-}
-
-void setup_sigtramp(abi_ulong sigtramp_page)
-{
- uint16_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 6, 0);
- assert(tramp != NULL);
-
- default_sigreturn = sigtramp_page;
- setup_sigreturn(tramp);
-
- unlock_user(tramp, sigtramp_page, 6);
-}
diff --git a/linux-user/cris/sockbits.h b/linux-user/cris/sockbits.h
deleted file mode 100644
index 0e4c8f0..0000000
--- a/linux-user/cris/sockbits.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../generic/sockbits.h"
diff --git a/linux-user/cris/syscall_nr.h b/linux-user/cris/syscall_nr.h
deleted file mode 100644
index 4b6cf65..0000000
--- a/linux-user/cris/syscall_nr.h
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * This file contains the system call numbers, and stub macros for libc.
- */
-
-#ifndef LINUX_USER_CRIS_SYSCALL_NR_H
-#define LINUX_USER_CRIS_SYSCALL_NR_H
-
-#define TARGET_NR_restart_syscall 0
-#define TARGET_NR_exit 1
-#define TARGET_NR_fork 2
-#define TARGET_NR_read 3
-#define TARGET_NR_write 4
-#define TARGET_NR_open 5
-#define TARGET_NR_close 6
-#define TARGET_NR_waitpid 7
-#define TARGET_NR_creat 8
-#define TARGET_NR_link 9
-#define TARGET_NR_unlink 10
-#define TARGET_NR_execve 11
-#define TARGET_NR_chdir 12
-#define TARGET_NR_time 13
-#define TARGET_NR_mknod 14
-#define TARGET_NR_chmod 15
-#define TARGET_NR_lchown 16
-#define TARGET_NR_break 17
-#define TARGET_NR_oldstat 18
-#define TARGET_NR_lseek 19
-#define TARGET_NR_getpid 20
-#define TARGET_NR_mount 21
-#define TARGET_NR_umount 22
-#define TARGET_NR_setuid 23
-#define TARGET_NR_getuid 24
-#define TARGET_NR_stime 25
-#define TARGET_NR_ptrace 26
-#define TARGET_NR_alarm 27
-#define TARGET_NR_oldfstat 28
-#define TARGET_NR_pause 29
-#define TARGET_NR_utime 30
-#define TARGET_NR_stty 31
-#define TARGET_NR_gtty 32
-#define TARGET_NR_access 33
-#define TARGET_NR_nice 34
-#define TARGET_NR_ftime 35
-#define TARGET_NR_sync 36
-#define TARGET_NR_kill 37
-#define TARGET_NR_rename 38
-#define TARGET_NR_mkdir 39
-#define TARGET_NR_rmdir 40
-#define TARGET_NR_dup 41
-#define TARGET_NR_pipe 42
-#define TARGET_NR_times 43
-#define TARGET_NR_prof 44
-#define TARGET_NR_brk 45
-#define TARGET_NR_setgid 46
-#define TARGET_NR_getgid 47
-#define TARGET_NR_signal 48
-#define TARGET_NR_geteuid 49
-#define TARGET_NR_getegid 50
-#define TARGET_NR_acct 51
-#define TARGET_NR_umount2 52
-#define TARGET_NR_lock 53
-#define TARGET_NR_ioctl 54
-#define TARGET_NR_fcntl 55
-#define TARGET_NR_mpx 56
-#define TARGET_NR_setpgid 57
-#define TARGET_NR_ulimit 58
-#define TARGET_NR_oldolduname 59
-#define TARGET_NR_umask 60
-#define TARGET_NR_chroot 61
-#define TARGET_NR_ustat 62
-#define TARGET_NR_dup2 63
-#define TARGET_NR_getppid 64
-#define TARGET_NR_getpgrp 65
-#define TARGET_NR_setsid 66
-#define TARGET_NR_sigaction 67
-#define TARGET_NR_sgetmask 68
-#define TARGET_NR_ssetmask 69
-#define TARGET_NR_setreuid 70
-#define TARGET_NR_setregid 71
-#define TARGET_NR_sigsuspend 72
-#define TARGET_NR_sigpending 73
-#define TARGET_NR_sethostname 74
-#define TARGET_NR_setrlimit 75
-#define TARGET_NR_getrlimit 76
-#define TARGET_NR_getrusage 77
-#define TARGET_NR_gettimeofday 78
-#define TARGET_NR_settimeofday 79
-#define TARGET_NR_getgroups 80
-#define TARGET_NR_setgroups 81
-#define TARGET_NR_select 82
-#define TARGET_NR_symlink 83
-#define TARGET_NR_oldlstat 84
-#define TARGET_NR_readlink 85
-#define TARGET_NR_uselib 86
-#define TARGET_NR_swapon 87
-#define TARGET_NR_reboot 88
-#define TARGET_NR_readdir 89
-#define TARGET_NR_mmap 90
-#define TARGET_NR_munmap 91
-#define TARGET_NR_truncate 92
-#define TARGET_NR_ftruncate 93
-#define TARGET_NR_fchmod 94
-#define TARGET_NR_fchown 95
-#define TARGET_NR_getpriority 96
-#define TARGET_NR_setpriority 97
-#define TARGET_NR_profil 98
-#define TARGET_NR_statfs 99
-#define TARGET_NR_fstatfs 100
-#define TARGET_NR_ioperm 101
-#define TARGET_NR_socketcall 102
-#define TARGET_NR_syslog 103
-#define TARGET_NR_setitimer 104
-#define TARGET_NR_getitimer 105
-#define TARGET_NR_stat 106
-#define TARGET_NR_lstat 107
-#define TARGET_NR_fstat 108
-#define TARGET_NR_olduname 109
-#define TARGET_NR_iopl 110
-#define TARGET_NR_vhangup 111
-#define TARGET_NR_idle 112
-#define TARGET_NR_vm86 113
-#define TARGET_NR_wait4 114
-#define TARGET_NR_swapoff 115
-#define TARGET_NR_sysinfo 116
-#define TARGET_NR_ipc 117
-#define TARGET_NR_fsync 118
-#define TARGET_NR_sigreturn 119
-#define TARGET_NR_clone 120
-#define TARGET_NR_setdomainname 121
-#define TARGET_NR_uname 122
-#define TARGET_NR_modify_ldt 123
-#define TARGET_NR_adjtimex 124
-#define TARGET_NR_mprotect 125
-#define TARGET_NR_sigprocmask 126
-#define TARGET_NR_create_module 127
-#define TARGET_NR_init_module 128
-#define TARGET_NR_delete_module 129
-#define TARGET_NR_get_kernel_syms 130
-#define TARGET_NR_quotactl 131
-#define TARGET_NR_getpgid 132
-#define TARGET_NR_fchdir 133
-#define TARGET_NR_bdflush 134
-#define TARGET_NR_sysfs 135
-#define TARGET_NR_personality 136
-#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */
-#define TARGET_NR_setfsuid 138
-#define TARGET_NR_setfsgid 139
-#define TARGET_NR__llseek 140
-#define TARGET_NR_getdents 141
-#define TARGET_NR__newselect 142
-#define TARGET_NR_flock 143
-#define TARGET_NR_msync 144
-#define TARGET_NR_readv 145
-#define TARGET_NR_writev 146
-#define TARGET_NR_getsid 147
-#define TARGET_NR_fdatasync 148
-#define TARGET_NR__sysctl 149
-#define TARGET_NR_mlock 150
-#define TARGET_NR_munlock 151
-#define TARGET_NR_mlockall 152
-#define TARGET_NR_munlockall 153
-#define TARGET_NR_sched_setparam 154
-#define TARGET_NR_sched_getparam 155
-#define TARGET_NR_sched_setscheduler 156
-#define TARGET_NR_sched_getscheduler 157
-#define TARGET_NR_sched_yield 158
-#define TARGET_NR_sched_get_priority_max 159
-#define TARGET_NR_sched_get_priority_min 160
-#define TARGET_NR_sched_rr_get_interval 161
-#define TARGET_NR_nanosleep 162
-#define TARGET_NR_mremap 163
-#define TARGET_NR_setresuid 164
-#define TARGET_NR_getresuid 165
-
-#define TARGET_NR_query_module 167
-#define TARGET_NR_poll 168
-#define TARGET_NR_nfsservctl 169
-#define TARGET_NR_setresgid 170
-#define TARGET_NR_getresgid 171
-#define TARGET_NR_prctl 172
-#define TARGET_NR_rt_sigreturn 173
-#define TARGET_NR_rt_sigaction 174
-#define TARGET_NR_rt_sigprocmask 175
-#define TARGET_NR_rt_sigpending 176
-#define TARGET_NR_rt_sigtimedwait 177
-#define TARGET_NR_rt_sigqueueinfo 178
-#define TARGET_NR_rt_sigsuspend 179
-#define TARGET_NR_pread64 180
-#define TARGET_NR_pwrite64 181
-#define TARGET_NR_chown 182
-#define TARGET_NR_getcwd 183
-#define TARGET_NR_capget 184
-#define TARGET_NR_capset 185
-#define TARGET_NR_sigaltstack 186
-#define TARGET_NR_sendfile 187
-#define TARGET_NR_getpmsg 188 /* some people actually want streams */
-#define TARGET_NR_putpmsg 189 /* some people actually want streams */
-#define TARGET_NR_vfork 190
-#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */
-#define TARGET_NR_mmap2 192
-#define TARGET_NR_truncate64 193
-#define TARGET_NR_ftruncate64 194
-#define TARGET_NR_stat64 195
-#define TARGET_NR_lstat64 196
-#define TARGET_NR_fstat64 197
-#define TARGET_NR_lchown32 198
-#define TARGET_NR_getuid32 199
-#define TARGET_NR_getgid32 200
-#define TARGET_NR_geteuid32 201
-#define TARGET_NR_getegid32 202
-#define TARGET_NR_setreuid32 203
-#define TARGET_NR_setregid32 204
-#define TARGET_NR_getgroups32 205
-#define TARGET_NR_setgroups32 206
-#define TARGET_NR_fchown32 207
-#define TARGET_NR_setresuid32 208
-#define TARGET_NR_getresuid32 209
-#define TARGET_NR_setresgid32 210
-#define TARGET_NR_getresgid32 211
-#define TARGET_NR_chown32 212
-#define TARGET_NR_setuid32 213
-#define TARGET_NR_setgid32 214
-#define TARGET_NR_setfsuid32 215
-#define TARGET_NR_setfsgid32 216
-#define TARGET_NR_pivot_root 217
-#define TARGET_NR_mincore 218
-#define TARGET_NR_madvise 219
-#define TARGET_NR_getdents64 220
-#define TARGET_NR_fcntl64 221
-/* 223 is unused */
-#define TARGET_NR_gettid 224
-#define TARGET_NR_readahead 225
-#define TARGET_NR_setxattr 226
-#define TARGET_NR_lsetxattr 227
-#define TARGET_NR_fsetxattr 228
-#define TARGET_NR_getxattr 229
-#define TARGET_NR_lgetxattr 230
-#define TARGET_NR_fgetxattr 231
-#define TARGET_NR_listxattr 232
-#define TARGET_NR_llistxattr 233
-#define TARGET_NR_flistxattr 234
-#define TARGET_NR_removexattr 235
-#define TARGET_NR_lremovexattr 236
-#define TARGET_NR_fremovexattr 237
-#define TARGET_NR_tkill 238
-#define TARGET_NR_sendfile64 239
-#define TARGET_NR_futex 240
-#define TARGET_NR_sched_setaffinity 241
-#define TARGET_NR_sched_getaffinity 242
-#define TARGET_NR_set_thread_area 243
-#define TARGET_NR_get_thread_area 244
-#define TARGET_NR_io_setup 245
-#define TARGET_NR_io_destroy 246
-#define TARGET_NR_io_getevents 247
-#define TARGET_NR_io_submit 248
-#define TARGET_NR_io_cancel 249
-#define TARGET_NR_fadvise64 250
-#define TARGET_NR_exit_group 252
-#define TARGET_NR_lookup_dcookie 253
-#define TARGET_NR_epoll_create 254
-#define TARGET_NR_epoll_ctl 255
-#define TARGET_NR_epoll_wait 256
-#define TARGET_NR_remap_file_pages 257
-#define TARGET_NR_set_tid_address 258
-#define TARGET_NR_timer_create 259
-#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1)
-#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2)
-#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3)
-#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4)
-#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5)
-#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6)
-#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7)
-#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8)
-#define TARGET_NR_statfs64 268
-#define TARGET_NR_fstatfs64 269
-#define TARGET_NR_tgkill 270
-#define TARGET_NR_utimes 271
-#define TARGET_NR_fadvise64_64 272
-#define TARGET_NR_vserver 273
-#define TARGET_NR_mbind 274
-#define TARGET_NR_get_mempolicy 275
-#define TARGET_NR_set_mempolicy 276
-#define TARGET_NR_mq_open 277
-#define TARGET_NR_mq_unlink (TARGET_NR_mq_open+1)
-#define TARGET_NR_mq_timedsend (TARGET_NR_mq_open+2)
-#define TARGET_NR_mq_timedreceive (TARGET_NR_mq_open+3)
-#define TARGET_NR_mq_notify (TARGET_NR_mq_open+4)
-#define TARGET_NR_mq_getsetattr (TARGET_NR_mq_open+5)
-#define TARGET_NR_kexec_load 283
-#define TARGET_NR_waitid 284
-/* #define TARGET_NR_sys_setaltroot 285 */
-#define TARGET_NR_add_key 286
-#define TARGET_NR_request_key 287
-#define TARGET_NR_keyctl 288
-#define TARGET_NR_ioprio_set 289
-#define TARGET_NR_ioprio_get 290
-#define TARGET_NR_inotify_init 291
-#define TARGET_NR_inotify_add_watch 292
-#define TARGET_NR_inotify_rm_watch 293
-#define TARGET_NR_migrate_pages 294
-#define TARGET_NR_openat 295
-#define TARGET_NR_mkdirat 296
-#define TARGET_NR_mknodat 297
-#define TARGET_NR_fchownat 298
-#define TARGET_NR_futimesat 299
-#define TARGET_NR_fstatat64 300
-#define TARGET_NR_unlinkat 301
-#define TARGET_NR_renameat 302
-#define TARGET_NR_linkat 303
-#define TARGET_NR_symlinkat 304
-#define TARGET_NR_readlinkat 305
-#define TARGET_NR_fchmodat 306
-#define TARGET_NR_faccessat 307
-#define TARGET_NR_pselect6 308
-#define TARGET_NR_ppoll 309
-#define TARGET_NR_unshare 310
-#define TARGET_NR_set_robust_list 311
-#define TARGET_NR_get_robust_list 312
-#define TARGET_NR_splice 313
-#define TARGET_NR_sync_file_range 314
-#define TARGET_NR_tee 315
-#define TARGET_NR_vmsplice 316
-#define TARGET_NR_move_pages 317
-#define TARGET_NR_getcpu 318
-#define TARGET_NR_epoll_pwait 319
-#define TARGET_NR_utimensat 320
-#define TARGET_NR_signalfd 321
-#define TARGET_NR_timerfd_create 322
-#define TARGET_NR_eventfd 323
-#define TARGET_NR_fallocate 324
-#define TARGET_NR_timerfd_settime 325
-#define TARGET_NR_timerfd_gettime 326
-#define TARGET_NR_signalfd4 327
-#define TARGET_NR_eventfd2 328
-#define TARGET_NR_epoll_create1 329
-#define TARGET_NR_dup3 330
-#define TARGET_NR_pipe2 331
-#define TARGET_NR_inotify_init1 332
-#define TARGET_NR_preadv 333
-#define TARGET_NR_pwritev 334
-#define TARGET_NR_setns 335
-#define TARGET_NR_name_to_handle_at 336
-#define TARGET_NR_open_by_handle_at 337
-#define TARGET_NR_rt_tgsigqueueinfo 338
-#define TARGET_NR_perf_event_open 339
-#define TARGET_NR_recvmmsg 340
-#define TARGET_NR_accept4 341
-#define TARGET_NR_fanotify_init 342
-#define TARGET_NR_fanotify_mark 343
-#define TARGET_NR_prlimit64 344
-#define TARGET_NR_clock_adjtime 345
-#define TARGET_NR_syncfs 346
-#define TARGET_NR_sendmmsg 347
-#define TARGET_NR_process_vm_readv 348
-#define TARGET_NR_process_vm_writev 349
-#define TARGET_NR_kcmp 350
-#define TARGET_NR_finit_module 351
-#define TARGET_NR_sched_setattr 352
-#define TARGET_NR_sched_getattr 353
-#define TARGET_NR_renameat2 354
-#define TARGET_NR_seccomp 355
-#define TARGET_NR_getrandom 356
-#define TARGET_NR_memfd_create 357
-#define TARGET_NR_bpf 358
-#define TARGET_NR_execveat 359
-
-#endif
diff --git a/linux-user/cris/target_cpu.h b/linux-user/cris/target_cpu.h
deleted file mode 100644
index 7f6cade..0000000
--- a/linux-user/cris/target_cpu.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * CRIS specific CPU ABI and functions for linux-user
- *
- * Copyright (c) 2007 AXIS Communications AB
- * Written by Edgar E. Iglesias
- *
- * 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
- * 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 CRIS_TARGET_CPU_H
-#define CRIS_TARGET_CPU_H
-
-static inline void cpu_clone_regs_child(CPUCRISState *env, target_ulong newsp,
- unsigned flags)
-{
- if (newsp) {
- env->regs[14] = newsp;
- }
- env->regs[10] = 0;
-}
-
-static inline void cpu_clone_regs_parent(CPUCRISState *env, unsigned flags)
-{
-}
-
-static inline void cpu_set_tls(CPUCRISState *env, target_ulong newtls)
-{
- env->pregs[PR_PID] = (env->pregs[PR_PID] & 0xff) | newtls;
-}
-
-static inline abi_ulong get_sp_from_cpustate(CPUCRISState *state)
-{
- return state->regs[14];
-}
-#endif
diff --git a/linux-user/cris/target_elf.h b/linux-user/cris/target_elf.h
deleted file mode 100644
index 99eb4ec..0000000
--- a/linux-user/cris/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 CRIS_TARGET_ELF_H
-#define CRIS_TARGET_ELF_H
-static inline const char *cpu_get_model(uint32_t eflags)
-{
- return "any";
-}
-#endif
diff --git a/linux-user/cris/target_errno_defs.h b/linux-user/cris/target_errno_defs.h
deleted file mode 100644
index 1cf43b1..0000000
--- a/linux-user/cris/target_errno_defs.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef CRIS_TARGET_ERRNO_DEFS_H
-#define CRIS_TARGET_ERRNO_DEFS_H
-
-/* Target uses generic errno */
-#include "../generic/target_errno_defs.h"
-
-#endif
diff --git a/linux-user/cris/target_fcntl.h b/linux-user/cris/target_fcntl.h
deleted file mode 100644
index df0acee..0000000
--- a/linux-user/cris/target_fcntl.h
+++ /dev/null
@@ -1,11 +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 CRIS_TARGET_FCNTL_H
-#define CRIS_TARGET_FCNTL_H
-#include "../generic/fcntl.h"
-#endif
diff --git a/linux-user/cris/target_mman.h b/linux-user/cris/target_mman.h
deleted file mode 100644
index 9ace8ac..0000000
--- a/linux-user/cris/target_mman.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * arch/cris/include/asm/processor.h:
- * TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3))
- *
- * arch/cris/include/arch-v32/arch/processor.h
- * TASK_SIZE 0xb0000000
- */
-#define TASK_UNMAPPED_BASE TARGET_PAGE_ALIGN(0xb0000000 / 3)
-
-/* arch/cris/include/uapi/asm/elf.h */
-#define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE * 2)
-
-#include "../generic/target_mman.h"
diff --git a/linux-user/cris/target_prctl.h b/linux-user/cris/target_prctl.h
deleted file mode 100644
index eb53b31..0000000
--- a/linux-user/cris/target_prctl.h
+++ /dev/null
@@ -1 +0,0 @@
-/* No special prctl support required. */
diff --git a/linux-user/cris/target_proc.h b/linux-user/cris/target_proc.h
deleted file mode 100644
index 43fe29c..0000000
--- a/linux-user/cris/target_proc.h
+++ /dev/null
@@ -1 +0,0 @@
-/* No target-specific /proc support */
diff --git a/linux-user/cris/target_resource.h b/linux-user/cris/target_resource.h
deleted file mode 100644
index 2272595..0000000
--- a/linux-user/cris/target_resource.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../generic/target_resource.h"
diff --git a/linux-user/cris/target_signal.h b/linux-user/cris/target_signal.h
deleted file mode 100644
index ab0653f..0000000
--- a/linux-user/cris/target_signal.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef CRIS_TARGET_SIGNAL_H
-#define CRIS_TARGET_SIGNAL_H
-
-#include "../generic/signal.h"
-
-#define TARGET_ARCH_HAS_SETUP_FRAME
-#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 1
-
-#endif /* CRIS_TARGET_SIGNAL_H */
diff --git a/linux-user/cris/target_structs.h b/linux-user/cris/target_structs.h
deleted file mode 100644
index 3a06f37..0000000
--- a/linux-user/cris/target_structs.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../generic/target_structs.h"
diff --git a/linux-user/cris/target_syscall.h b/linux-user/cris/target_syscall.h
deleted file mode 100644
index 0b5ebf1..0000000
--- a/linux-user/cris/target_syscall.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef CRIS_TARGET_SYSCALL_H
-#define CRIS_TARGET_SYSCALL_H
-
-#define UNAME_MACHINE "cris"
-#define UNAME_MINIMUM_RELEASE "2.6.32"
-
-/* pt_regs not only specifies the format in the user-struct during
- * ptrace but is also the frame format used in the kernel prologue/epilogues
- * themselves
- */
-
-struct target_pt_regs {
- unsigned long orig_r10;
- /* pushed by movem r13, [sp] in SAVE_ALL. */
- unsigned long r0;
- unsigned long r1;
- unsigned long r2;
- unsigned long r3;
- unsigned long r4;
- unsigned long r5;
- unsigned long r6;
- unsigned long r7;
- unsigned long r8;
- unsigned long r9;
- unsigned long r10;
- unsigned long r11;
- unsigned long r12;
- unsigned long r13;
- unsigned long acr;
- unsigned long srs;
- unsigned long mof;
- unsigned long spc;
- unsigned long ccs;
- unsigned long srp;
- unsigned long erp; /* This is actually the debugged process's PC */
- /* For debugging purposes; saved only when needed. */
- unsigned long exs;
- unsigned long eda;
-};
-
-#define TARGET_CLONE_BACKWARDS2
-#define TARGET_MCL_CURRENT 1
-#define TARGET_MCL_FUTURE 2
-#define TARGET_MCL_ONFAULT 4
-
-#endif
diff --git a/linux-user/cris/termbits.h b/linux-user/cris/termbits.h
deleted file mode 100644
index 0c8d8fc..0000000
--- a/linux-user/cris/termbits.h
+++ /dev/null
@@ -1,225 +0,0 @@
-/* from asm/termbits.h */
-
-#ifndef LINUX_USER_CRIS_TERMBITS_H
-#define LINUX_USER_CRIS_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_iflag bits */
-#define TARGET_IGNBRK 0000001
-#define TARGET_BRKINT 0000002
-#define TARGET_IGNPAR 0000004
-#define TARGET_PARMRK 0000010
-#define TARGET_INPCK 0000020
-#define TARGET_ISTRIP 0000040
-#define TARGET_INLCR 0000100
-#define TARGET_IGNCR 0000200
-#define TARGET_ICRNL 0000400
-#define TARGET_IUCLC 0001000
-#define TARGET_IXON 0002000
-#define TARGET_IXANY 0004000
-#define TARGET_IXOFF 0010000
-#define TARGET_IMAXBEL 0020000
-#define TARGET_IUTF8 0040000
-
-/* c_oflag bits */
-#define TARGET_OPOST 0000001
-#define TARGET_OLCUC 0000002
-#define TARGET_ONLCR 0000004
-#define TARGET_OCRNL 0000010
-#define TARGET_ONOCR 0000020
-#define TARGET_ONLRET 0000040
-#define TARGET_OFILL 0000100
-#define TARGET_OFDEL 0000200
-#define TARGET_NLDLY 0000400
-#define TARGET_NL0 0000000
-#define TARGET_NL1 0000400
-#define TARGET_CRDLY 0003000
-#define TARGET_CR0 0000000
-#define TARGET_CR1 0001000
-#define TARGET_CR2 0002000
-#define TARGET_CR3 0003000
-#define TARGET_TABDLY 0014000
-#define TARGET_TAB0 0000000
-#define TARGET_TAB1 0004000
-#define TARGET_TAB2 0010000
-#define TARGET_TAB3 0014000
-#define TARGET_XTABS 0014000
-#define TARGET_BSDLY 0020000
-#define TARGET_BS0 0000000
-#define TARGET_BS1 0020000
-#define TARGET_VTDLY 0040000
-#define TARGET_VT0 0000000
-#define TARGET_VT1 0040000
-#define TARGET_FFDLY 0100000
-#define TARGET_FF0 0000000
-#define TARGET_FF1 0100000
-
-/* c_cflag bit meaning */
-#define TARGET_CBAUD 0010017
-#define TARGET_B0 0000000 /* hang up */
-#define TARGET_B50 0000001
-#define TARGET_B75 0000002
-#define TARGET_B110 0000003
-#define TARGET_B134 0000004
-#define TARGET_B150 0000005
-#define TARGET_B200 0000006
-#define TARGET_B300 0000007
-#define TARGET_B600 0000010
-#define TARGET_B1200 0000011
-#define TARGET_B1800 0000012
-#define TARGET_B2400 0000013
-#define TARGET_B4800 0000014
-#define TARGET_B9600 0000015
-#define TARGET_B19200 0000016
-#define TARGET_B38400 0000017
-#define TARGET_EXTA B19200
-#define TARGET_EXTB B38400
-#define TARGET_CSIZE 0000060
-#define TARGET_CS5 0000000
-#define TARGET_CS6 0000020
-#define TARGET_CS7 0000040
-#define TARGET_CS8 0000060
-#define TARGET_CSTOPB 0000100
-#define TARGET_CREAD 0000200
-#define TARGET_PARENB 0000400
-#define TARGET_PARODD 0001000
-#define TARGET_HUPCL 0002000
-#define TARGET_CLOCAL 0004000
-#define TARGET_CBAUDEX 0010000
-#define TARGET_B57600 0010001
-#define TARGET_B115200 0010002
-#define TARGET_B230400 0010003
-#define TARGET_B460800 0010004
-#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */
-#define TARGET_CRTSCTS 020000000000 /* flow control */
-
-/* c_lflag bits */
-#define TARGET_ISIG 0000001
-#define TARGET_ICANON 0000002
-#define TARGET_XCASE 0000004
-#define TARGET_ECHO 0000010
-#define TARGET_ECHOE 0000020
-#define TARGET_ECHOK 0000040
-#define TARGET_ECHONL 0000100
-#define TARGET_NOFLSH 0000200
-#define TARGET_TOSTOP 0000400
-#define TARGET_ECHOCTL 0001000
-#define TARGET_ECHOPRT 0002000
-#define TARGET_ECHOKE 0004000
-#define TARGET_FLUSHO 0010000
-#define TARGET_PENDIN 0040000
-#define TARGET_IEXTEN 0100000
-#define TARGET_EXTPROC 0200000
-
-/* c_cc character offsets */
-#define TARGET_VINTR 0
-#define TARGET_VQUIT 1
-#define TARGET_VERASE 2
-#define TARGET_VKILL 3
-#define TARGET_VEOF 4
-#define TARGET_VTIME 5
-#define TARGET_VMIN 6
-#define TARGET_VSWTC 7
-#define TARGET_VSTART 8
-#define TARGET_VSTOP 9
-#define TARGET_VSUSP 10
-#define TARGET_VEOL 11
-#define TARGET_VREPRINT 12
-#define TARGET_VDISCARD 13
-#define TARGET_VWERASE 14
-#define TARGET_VLNEXT 15
-#define TARGET_VEOL2 16
-
-/* ioctls */
-
-#define TARGET_TCGETS 0x5401
-#define TARGET_TCSETS 0x5402
-#define TARGET_TCSETSW 0x5403
-#define TARGET_TCSETSF 0x5404
-#define TARGET_TCGETA 0x5405
-#define TARGET_TCSETA 0x5406
-#define TARGET_TCSETAW 0x5407
-#define TARGET_TCSETAF 0x5408
-#define TARGET_TCSBRK 0x5409
-#define TARGET_TCXONC 0x540A
-#define TARGET_TCFLSH 0x540B
-
-#define TARGET_TIOCEXCL 0x540C
-#define TARGET_TIOCNXCL 0x540D
-#define TARGET_TIOCSCTTY 0x540E
-#define TARGET_TIOCGPGRP 0x540F
-#define TARGET_TIOCSPGRP 0x5410
-#define TARGET_TIOCOUTQ 0x5411
-#define TARGET_TIOCSTI 0x5412
-#define TARGET_TIOCGWINSZ 0x5413
-#define TARGET_TIOCSWINSZ 0x5414
-#define TARGET_TIOCMGET 0x5415
-#define TARGET_TIOCMBIS 0x5416
-#define TARGET_TIOCMBIC 0x5417
-#define TARGET_TIOCMSET 0x5418
-#define TARGET_TIOCGSOFTCAR 0x5419
-#define TARGET_TIOCSSOFTCAR 0x541A
-#define TARGET_FIONREAD 0x541B
-#define TARGET_TIOCINQ TARGET_FIONREAD
-#define TARGET_TIOCLINUX 0x541C
-#define TARGET_TIOCCONS 0x541D
-#define TARGET_TIOCGSERIAL 0x541E
-#define TARGET_TIOCSSERIAL 0x541F
-#define TARGET_TIOCPKT 0x5420
-#define TARGET_FIONBIO 0x5421
-#define TARGET_TIOCNOTTY 0x5422
-#define TARGET_TIOCSETD 0x5423
-#define TARGET_TIOCGETD 0x5424
-#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
-#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */
-#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
-#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
-#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
-#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
-#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
-#define TARGET_TIOCGPTPEER TARGET_IO('T', 0x41) /* Safely open the slave */
-
-#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
-#define TARGET_FIOCLEX 0x5451
-#define TARGET_FIOASYNC 0x5452
-#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 for a change on serial input line(s) */
-#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
-#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
-#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
-
-/* Used for packet mode */
-#define TARGET_TIOCPKT_DATA 0
-#define TARGET_TIOCPKT_FLUSHREAD 1
-#define TARGET_TIOCPKT_FLUSHWRITE 2
-#define TARGET_TIOCPKT_STOP 4
-#define TARGET_TIOCPKT_START 8
-#define TARGET_TIOCPKT_NOSTOP 16
-#define TARGET_TIOCPKT_DOSTOP 32
-
-#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
-
-#endif
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 0d4dc1f..6cef8db 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -203,7 +203,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *en
(*regs)[12] = tswapreg(env->regs[R_EDX]);
(*regs)[13] = tswapreg(env->regs[R_ESI]);
(*regs)[14] = tswapreg(env->regs[R_EDI]);
- (*regs)[15] = tswapreg(env->regs[R_EAX]); /* XXX */
+ (*regs)[15] = tswapreg(get_task_state(env_cpu_const(env))->orig_ax);
(*regs)[16] = tswapreg(env->eip);
(*regs)[17] = tswapreg(env->segs[R_CS].selector & 0xffff);
(*regs)[18] = tswapreg(env->eflags);
@@ -306,7 +306,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *en
(*regs)[8] = tswapreg(env->segs[R_ES].selector & 0xffff);
(*regs)[9] = tswapreg(env->segs[R_FS].selector & 0xffff);
(*regs)[10] = tswapreg(env->segs[R_GS].selector & 0xffff);
- (*regs)[11] = tswapreg(env->regs[R_EAX]); /* XXX */
+ (*regs)[11] = tswapreg(get_task_state(env_cpu_const(env))->orig_ax);
(*regs)[12] = tswapreg(env->eip);
(*regs)[13] = tswapreg(env->segs[R_CS].selector & 0xffff);
(*regs)[14] = tswapreg(env->eflags);
@@ -1647,21 +1647,6 @@ static uint32_t get_elf_hwcap(void)
#endif
-#ifdef TARGET_CRIS
-
-#define ELF_CLASS ELFCLASS32
-#define ELF_ARCH EM_CRIS
-
-static inline void init_thread(struct target_pt_regs *regs,
- struct image_info *infop)
-{
- regs->erp = infop->entry;
-}
-
-#define ELF_EXEC_PAGESIZE 8192
-
-#endif
-
#ifdef TARGET_M68K
#define ELF_CLASS ELFCLASS32
@@ -3136,11 +3121,11 @@ static bool parse_elf_properties(const ImageSource *src,
}
/*
- * The contents of a valid PT_GNU_PROPERTY is a sequence
- * of uint32_t -- swap them all now.
+ * The contents of a valid PT_GNU_PROPERTY is a sequence of uint32_t.
+ * Swap most of them now, beyond the header and namesz.
*/
#ifdef BSWAP_NEEDED
- for (int i = 0; i < n / 4; i++) {
+ for (int i = 4; i < n / 4; i++) {
bswap32s(note.data + i);
}
#endif
@@ -3150,15 +3135,15 @@ static bool parse_elf_properties(const ImageSource *src,
* immediately follows nhdr and is thus at the 4th word. Further, all
* of the inputs to the kernel's round_up are multiples of 4.
*/
- if (note.nhdr.n_type != NT_GNU_PROPERTY_TYPE_0 ||
- note.nhdr.n_namesz != NOTE_NAME_SZ ||
+ if (tswap32(note.nhdr.n_type) != NT_GNU_PROPERTY_TYPE_0 ||
+ tswap32(note.nhdr.n_namesz) != NOTE_NAME_SZ ||
note.data[3] != GNU0_MAGIC) {
error_setg(errp, "Invalid note in PT_GNU_PROPERTY");
return false;
}
off = sizeof(note.nhdr) + NOTE_NAME_SZ;
- datasz = note.nhdr.n_descsz + off;
+ datasz = tswap32(note.nhdr.n_descsz) + off;
if (datasz > n) {
error_setg(errp, "Invalid note size in PT_GNU_PROPERTY");
return false;
@@ -4102,8 +4087,7 @@ static void fill_elf_note_phdr(struct elf_phdr *phdr, size_t sz, off_t offset)
bswap_phdr(phdr, 1);
}
-static void fill_prstatus_note(void *data, const TaskState *ts,
- CPUState *cpu, int signr)
+static void fill_prstatus_note(void *data, CPUState *cpu, int signr)
{
/*
* Because note memory is only aligned to 4, and target_elf_prstatus
@@ -4113,7 +4097,7 @@ static void fill_prstatus_note(void *data, const TaskState *ts,
struct target_elf_prstatus prstatus = {
.pr_info.si_signo = signr,
.pr_cursig = signr,
- .pr_pid = ts->ts_tid,
+ .pr_pid = get_task_state(cpu)->ts_tid,
.pr_ppid = getppid(),
.pr_pgrp = getpgrp(),
.pr_sid = getsid(0),
@@ -4330,7 +4314,7 @@ static int wmr_write_region(void *opaque, target_ulong start,
*/
static int elf_core_dump(int signr, const CPUArchState *env)
{
- const CPUState *cpu = env_cpu((CPUArchState *)env);
+ const CPUState *cpu = env_cpu_const(env);
const TaskState *ts = (const TaskState *)get_task_state((CPUState *)cpu);
struct rlimit dumpsize;
CountAndSizeRegions css;
@@ -4428,8 +4412,7 @@ static int elf_core_dump(int signr, const CPUArchState *env)
CPU_FOREACH(cpu_iter) {
dptr = fill_note(&hptr, NT_PRSTATUS, "CORE",
sizeof(struct target_elf_prstatus));
- fill_prstatus_note(dptr, ts, cpu_iter,
- cpu_iter == cpu ? signr : 0);
+ fill_prstatus_note(dptr, cpu_iter, cpu_iter == cpu ? signr : 0);
}
if (dump_write(fd, header, data_offset) < 0) {
diff --git a/linux-user/flatload.c b/linux-user/flatload.c
index 04d8138..0e4be5b 100644
--- a/linux-user/flatload.c
+++ b/linux-user/flatload.c
@@ -487,7 +487,10 @@ int load_flt_binary(struct linux_binprm *bprm, struct image_info *info)
stack_len += (bprm->envc + 1) * 4; /* the envp array */
+ mmap_lock();
res = load_flat_file(bprm, libinfo, 0, &stack_len);
+ mmap_unlock();
+
if (is_error(res)) {
return res;
}
diff --git a/linux-user/hexagon/meson.build b/linux-user/hexagon/meson.build
new file mode 100644
index 0000000..d203c3e
--- /dev/null
+++ b/linux-user/hexagon/meson.build
@@ -0,0 +1,6 @@
+
+syscall_nr_generators += {
+ 'hexagon': generator(sh,
+ arguments: [ meson.current_source_dir() / 'syscallhdr.sh', '@INPUT@', '@OUTPUT@', '@EXTRA_ARGS@' ],
+ output: '@BASENAME@_nr.h')
+}
diff --git a/linux-user/hexagon/syscall.tbl b/linux-user/hexagon/syscall.tbl
new file mode 100644
index 0000000..845e24e
--- /dev/null
+++ b/linux-user/hexagon/syscall.tbl
@@ -0,0 +1,405 @@
+# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+#
+# This file contains the system call numbers for all of the
+# more recently added architectures.
+#
+# As a basic principle, no duplication of functionality
+# should be added, e.g. we don't use lseek when llseek
+# is present. New architectures should use this file
+# and implement the less feature-full calls in user space.
+#
+0 common io_setup sys_io_setup compat_sys_io_setup
+1 common io_destroy sys_io_destroy
+2 common io_submit sys_io_submit compat_sys_io_submit
+3 common io_cancel sys_io_cancel
+4 time32 io_getevents sys_io_getevents_time32
+4 64 io_getevents sys_io_getevents
+5 common setxattr sys_setxattr
+6 common lsetxattr sys_lsetxattr
+7 common fsetxattr sys_fsetxattr
+8 common getxattr sys_getxattr
+9 common lgetxattr sys_lgetxattr
+10 common fgetxattr sys_fgetxattr
+11 common listxattr sys_listxattr
+12 common llistxattr sys_llistxattr
+13 common flistxattr sys_flistxattr
+14 common removexattr sys_removexattr
+15 common lremovexattr sys_lremovexattr
+16 common fremovexattr sys_fremovexattr
+17 common getcwd sys_getcwd
+18 common lookup_dcookie sys_ni_syscall
+19 common eventfd2 sys_eventfd2
+20 common epoll_create1 sys_epoll_create1
+21 common epoll_ctl sys_epoll_ctl
+22 common epoll_pwait sys_epoll_pwait compat_sys_epoll_pwait
+23 common dup sys_dup
+24 common dup3 sys_dup3
+25 32 fcntl64 sys_fcntl64 compat_sys_fcntl64
+25 64 fcntl sys_fcntl
+26 common inotify_init1 sys_inotify_init1
+27 common inotify_add_watch sys_inotify_add_watch
+28 common inotify_rm_watch sys_inotify_rm_watch
+29 common ioctl sys_ioctl compat_sys_ioctl
+30 common ioprio_set sys_ioprio_set
+31 common ioprio_get sys_ioprio_get
+32 common flock sys_flock
+33 common mknodat sys_mknodat
+34 common mkdirat sys_mkdirat
+35 common unlinkat sys_unlinkat
+36 common symlinkat sys_symlinkat
+37 common linkat sys_linkat
+# renameat is superseded with flags by renameat2
+38 renameat renameat sys_renameat
+39 common umount2 sys_umount
+40 common mount sys_mount
+41 common pivot_root sys_pivot_root
+42 common nfsservctl sys_ni_syscall
+43 32 statfs64 sys_statfs64 compat_sys_statfs64
+43 64 statfs sys_statfs
+44 32 fstatfs64 sys_fstatfs64 compat_sys_fstatfs64
+44 64 fstatfs sys_fstatfs
+45 32 truncate64 sys_truncate64 compat_sys_truncate64
+45 64 truncate sys_truncate
+46 32 ftruncate64 sys_ftruncate64 compat_sys_ftruncate64
+46 64 ftruncate sys_ftruncate
+47 common fallocate sys_fallocate compat_sys_fallocate
+48 common faccessat sys_faccessat
+49 common chdir sys_chdir
+50 common fchdir sys_fchdir
+51 common chroot sys_chroot
+52 common fchmod sys_fchmod
+53 common fchmodat sys_fchmodat
+54 common fchownat sys_fchownat
+55 common fchown sys_fchown
+56 common openat sys_openat
+57 common close sys_close
+58 common vhangup sys_vhangup
+59 common pipe2 sys_pipe2
+60 common quotactl sys_quotactl
+61 common getdents64 sys_getdents64
+62 32 llseek sys_llseek
+62 64 lseek sys_lseek
+63 common read sys_read
+64 common write sys_write
+65 common readv sys_readv sys_readv
+66 common writev sys_writev sys_writev
+67 common pread64 sys_pread64 compat_sys_pread64
+68 common pwrite64 sys_pwrite64 compat_sys_pwrite64
+69 common preadv sys_preadv compat_sys_preadv
+70 common pwritev sys_pwritev compat_sys_pwritev
+71 32 sendfile64 sys_sendfile64
+71 64 sendfile sys_sendfile64
+72 time32 pselect6 sys_pselect6_time32 compat_sys_pselect6_time32
+72 64 pselect6 sys_pselect6
+73 time32 ppoll sys_ppoll_time32 compat_sys_ppoll_time32
+73 64 ppoll sys_ppoll
+74 common signalfd4 sys_signalfd4 compat_sys_signalfd4
+75 common vmsplice sys_vmsplice
+76 common splice sys_splice
+77 common tee sys_tee
+78 common readlinkat sys_readlinkat
+79 stat64 fstatat64 sys_fstatat64
+79 64 newfstatat sys_newfstatat
+80 stat64 fstat64 sys_fstat64
+80 64 fstat sys_newfstat
+81 common sync sys_sync
+82 common fsync sys_fsync
+83 common fdatasync sys_fdatasync
+84 common sync_file_range sys_sync_file_range compat_sys_sync_file_range
+85 common timerfd_create sys_timerfd_create
+86 time32 timerfd_settime sys_timerfd_settime32
+86 64 timerfd_settime sys_timerfd_settime
+87 time32 timerfd_gettime sys_timerfd_gettime32
+87 64 timerfd_gettime sys_timerfd_gettime
+88 time32 utimensat sys_utimensat_time32
+88 64 utimensat sys_utimensat
+89 common acct sys_acct
+90 common capget sys_capget
+91 common capset sys_capset
+92 common personality sys_personality
+93 common exit sys_exit
+94 common exit_group sys_exit_group
+95 common waitid sys_waitid compat_sys_waitid
+96 common set_tid_address sys_set_tid_address
+97 common unshare sys_unshare
+98 time32 futex sys_futex_time32
+98 64 futex sys_futex
+99 common set_robust_list sys_set_robust_list compat_sys_set_robust_list
+100 common get_robust_list sys_get_robust_list compat_sys_get_robust_list
+101 time32 nanosleep sys_nanosleep_time32
+101 64 nanosleep sys_nanosleep
+102 common getitimer sys_getitimer compat_sys_getitimer
+103 common setitimer sys_setitimer compat_sys_setitimer
+104 common kexec_load sys_kexec_load compat_sys_kexec_load
+105 common init_module sys_init_module
+106 common delete_module sys_delete_module
+107 common timer_create sys_timer_create compat_sys_timer_create
+108 time32 timer_gettime sys_timer_gettime32
+108 64 timer_gettime sys_timer_gettime
+109 common timer_getoverrun sys_timer_getoverrun
+110 time32 timer_settime sys_timer_settime32
+110 64 timer_settime sys_timer_settime
+111 common timer_delete sys_timer_delete
+112 time32 clock_settime sys_clock_settime32
+112 64 clock_settime sys_clock_settime
+113 time32 clock_gettime sys_clock_gettime32
+113 64 clock_gettime sys_clock_gettime
+114 time32 clock_getres sys_clock_getres_time32
+114 64 clock_getres sys_clock_getres
+115 time32 clock_nanosleep sys_clock_nanosleep_time32
+115 64 clock_nanosleep sys_clock_nanosleep
+116 common syslog sys_syslog
+117 common ptrace sys_ptrace compat_sys_ptrace
+118 common sched_setparam sys_sched_setparam
+119 common sched_setscheduler sys_sched_setscheduler
+120 common sched_getscheduler sys_sched_getscheduler
+121 common sched_getparam sys_sched_getparam
+122 common sched_setaffinity sys_sched_setaffinity compat_sys_sched_setaffinity
+123 common sched_getaffinity sys_sched_getaffinity compat_sys_sched_getaffinity
+124 common sched_yield sys_sched_yield
+125 common sched_get_priority_max sys_sched_get_priority_max
+126 common sched_get_priority_min sys_sched_get_priority_min
+127 time32 sched_rr_get_interval sys_sched_rr_get_interval_time32
+127 64 sched_rr_get_interval sys_sched_rr_get_interval
+128 common restart_syscall sys_restart_syscall
+129 common kill sys_kill
+130 common tkill sys_tkill
+131 common tgkill sys_tgkill
+132 common sigaltstack sys_sigaltstack compat_sys_sigaltstack
+133 common rt_sigsuspend sys_rt_sigsuspend compat_sys_rt_sigsuspend
+134 common rt_sigaction sys_rt_sigaction compat_sys_rt_sigaction
+135 common rt_sigprocmask sys_rt_sigprocmask compat_sys_rt_sigprocmask
+136 common rt_sigpending sys_rt_sigpending compat_sys_rt_sigpending
+137 time32 rt_sigtimedwait sys_rt_sigtimedwait_time32 compat_sys_rt_sigtimedwait_time32
+137 64 rt_sigtimedwait sys_rt_sigtimedwait
+138 common rt_sigqueueinfo sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo
+139 common rt_sigreturn sys_rt_sigreturn compat_sys_rt_sigreturn
+140 common setpriority sys_setpriority
+141 common getpriority sys_getpriority
+142 common reboot sys_reboot
+143 common setregid sys_setregid
+144 common setgid sys_setgid
+145 common setreuid sys_setreuid
+146 common setuid sys_setuid
+147 common setresuid sys_setresuid
+148 common getresuid sys_getresuid
+149 common setresgid sys_setresgid
+150 common getresgid sys_getresgid
+151 common setfsuid sys_setfsuid
+152 common setfsgid sys_setfsgid
+153 common times sys_times compat_sys_times
+154 common setpgid sys_setpgid
+155 common getpgid sys_getpgid
+156 common getsid sys_getsid
+157 common setsid sys_setsid
+158 common getgroups sys_getgroups
+159 common setgroups sys_setgroups
+160 common uname sys_newuname
+161 common sethostname sys_sethostname
+162 common setdomainname sys_setdomainname
+# getrlimit and setrlimit are superseded with prlimit64
+163 rlimit getrlimit sys_getrlimit compat_sys_getrlimit
+164 rlimit setrlimit sys_setrlimit compat_sys_setrlimit
+165 common getrusage sys_getrusage compat_sys_getrusage
+166 common umask sys_umask
+167 common prctl sys_prctl
+168 common getcpu sys_getcpu
+169 time32 gettimeofday sys_gettimeofday compat_sys_gettimeofday
+169 64 gettimeofday sys_gettimeofday
+170 time32 settimeofday sys_settimeofday compat_sys_settimeofday
+170 64 settimeofday sys_settimeofday
+171 time32 adjtimex sys_adjtimex_time32
+171 64 adjtimex sys_adjtimex
+172 common getpid sys_getpid
+173 common getppid sys_getppid
+174 common getuid sys_getuid
+175 common geteuid sys_geteuid
+176 common getgid sys_getgid
+177 common getegid sys_getegid
+178 common gettid sys_gettid
+179 common sysinfo sys_sysinfo compat_sys_sysinfo
+180 common mq_open sys_mq_open compat_sys_mq_open
+181 common mq_unlink sys_mq_unlink
+182 time32 mq_timedsend sys_mq_timedsend_time32
+182 64 mq_timedsend sys_mq_timedsend
+183 time32 mq_timedreceive sys_mq_timedreceive_time32
+183 64 mq_timedreceive sys_mq_timedreceive
+184 common mq_notify sys_mq_notify compat_sys_mq_notify
+185 common mq_getsetattr sys_mq_getsetattr compat_sys_mq_getsetattr
+186 common msgget sys_msgget
+187 common msgctl sys_msgctl compat_sys_msgctl
+188 common msgrcv sys_msgrcv compat_sys_msgrcv
+189 common msgsnd sys_msgsnd compat_sys_msgsnd
+190 common semget sys_semget
+191 common semctl sys_semctl compat_sys_semctl
+192 time32 semtimedop sys_semtimedop_time32
+192 64 semtimedop sys_semtimedop
+193 common semop sys_semop
+194 common shmget sys_shmget
+195 common shmctl sys_shmctl compat_sys_shmctl
+196 common shmat sys_shmat compat_sys_shmat
+197 common shmdt sys_shmdt
+198 common socket sys_socket
+199 common socketpair sys_socketpair
+200 common bind sys_bind
+201 common listen sys_listen
+202 common accept sys_accept
+203 common connect sys_connect
+204 common getsockname sys_getsockname
+205 common getpeername sys_getpeername
+206 common sendto sys_sendto
+207 common recvfrom sys_recvfrom compat_sys_recvfrom
+208 common setsockopt sys_setsockopt sys_setsockopt
+209 common getsockopt sys_getsockopt sys_getsockopt
+210 common shutdown sys_shutdown
+211 common sendmsg sys_sendmsg compat_sys_sendmsg
+212 common recvmsg sys_recvmsg compat_sys_recvmsg
+213 common readahead sys_readahead compat_sys_readahead
+214 common brk sys_brk
+215 common munmap sys_munmap
+216 common mremap sys_mremap
+217 common add_key sys_add_key
+218 common request_key sys_request_key
+219 common keyctl sys_keyctl compat_sys_keyctl
+220 common clone sys_clone
+221 common execve sys_execve compat_sys_execve
+222 32 mmap2 sys_mmap2
+222 64 mmap sys_mmap
+223 32 fadvise64_64 sys_fadvise64_64 compat_sys_fadvise64_64
+223 64 fadvise64 sys_fadvise64_64
+224 common swapon sys_swapon
+225 common swapoff sys_swapoff
+226 common mprotect sys_mprotect
+227 common msync sys_msync
+228 common mlock sys_mlock
+229 common munlock sys_munlock
+230 common mlockall sys_mlockall
+231 common munlockall sys_munlockall
+232 common mincore sys_mincore
+233 common madvise sys_madvise
+234 common remap_file_pages sys_remap_file_pages
+235 common mbind sys_mbind
+236 common get_mempolicy sys_get_mempolicy
+237 common set_mempolicy sys_set_mempolicy
+238 common migrate_pages sys_migrate_pages
+239 common move_pages sys_move_pages
+240 common rt_tgsigqueueinfo sys_rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo
+241 common perf_event_open sys_perf_event_open
+242 common accept4 sys_accept4
+243 time32 recvmmsg sys_recvmmsg_time32 compat_sys_recvmmsg_time32
+243 64 recvmmsg sys_recvmmsg
+# Architectures may provide up to 16 syscalls of their own between 244 and 259
+244 arc cacheflush sys_cacheflush
+245 arc arc_settls sys_arc_settls
+246 arc arc_gettls sys_arc_gettls
+247 arc sysfs sys_sysfs
+248 arc arc_usr_cmpxchg sys_arc_usr_cmpxchg
+
+244 csky set_thread_area sys_set_thread_area
+245 csky cacheflush sys_cacheflush
+
+244 nios2 cacheflush sys_cacheflush
+
+244 or1k or1k_atomic sys_or1k_atomic
+
+258 riscv riscv_hwprobe sys_riscv_hwprobe
+259 riscv riscv_flush_icache sys_riscv_flush_icache
+
+260 time32 wait4 sys_wait4 compat_sys_wait4
+260 64 wait4 sys_wait4
+261 common prlimit64 sys_prlimit64
+262 common fanotify_init sys_fanotify_init
+263 common fanotify_mark sys_fanotify_mark
+264 common name_to_handle_at sys_name_to_handle_at
+265 common open_by_handle_at sys_open_by_handle_at
+266 time32 clock_adjtime sys_clock_adjtime32
+266 64 clock_adjtime sys_clock_adjtime
+267 common syncfs sys_syncfs
+268 common setns sys_setns
+269 common sendmmsg sys_sendmmsg compat_sys_sendmmsg
+270 common process_vm_readv sys_process_vm_readv
+271 common process_vm_writev sys_process_vm_writev
+272 common kcmp sys_kcmp
+273 common finit_module sys_finit_module
+274 common sched_setattr sys_sched_setattr
+275 common sched_getattr sys_sched_getattr
+276 common renameat2 sys_renameat2
+277 common seccomp sys_seccomp
+278 common getrandom sys_getrandom
+279 common memfd_create sys_memfd_create
+280 common bpf sys_bpf
+281 common execveat sys_execveat compat_sys_execveat
+282 common userfaultfd sys_userfaultfd
+283 common membarrier sys_membarrier
+284 common mlock2 sys_mlock2
+285 common copy_file_range sys_copy_file_range
+286 common preadv2 sys_preadv2 compat_sys_preadv2
+287 common pwritev2 sys_pwritev2 compat_sys_pwritev2
+288 common pkey_mprotect sys_pkey_mprotect
+289 common pkey_alloc sys_pkey_alloc
+290 common pkey_free sys_pkey_free
+291 common statx sys_statx
+292 time32 io_pgetevents sys_io_pgetevents_time32 compat_sys_io_pgetevents
+292 64 io_pgetevents sys_io_pgetevents
+293 common rseq sys_rseq
+294 common kexec_file_load sys_kexec_file_load
+# 295 through 402 are unassigned to sync up with generic numbers don't use
+403 32 clock_gettime64 sys_clock_gettime
+404 32 clock_settime64 sys_clock_settime
+405 32 clock_adjtime64 sys_clock_adjtime
+406 32 clock_getres_time64 sys_clock_getres
+407 32 clock_nanosleep_time64 sys_clock_nanosleep
+408 32 timer_gettime64 sys_timer_gettime
+409 32 timer_settime64 sys_timer_settime
+410 32 timerfd_gettime64 sys_timerfd_gettime
+411 32 timerfd_settime64 sys_timerfd_settime
+412 32 utimensat_time64 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 compat_sys_io_pgetevents_time64
+417 32 recvmmsg_time64 sys_recvmmsg compat_sys_recvmmsg_time64
+418 32 mq_timedsend_time64 sys_mq_timedsend
+419 32 mq_timedreceive_time64 sys_mq_timedreceive
+420 32 semtimedop_time64 sys_semtimedop
+421 32 rt_sigtimedwait_time64 sys_rt_sigtimedwait compat_sys_rt_sigtimedwait_time64
+422 32 futex_time64 sys_futex
+423 32 sched_rr_get_interval_time64 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 common clone3 sys_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
+440 common process_madvise sys_process_madvise
+441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
+442 common mount_setattr sys_mount_setattr
+443 common quotactl_fd sys_quotactl_fd
+444 common landlock_create_ruleset sys_landlock_create_ruleset
+445 common landlock_add_rule sys_landlock_add_rule
+446 common landlock_restrict_self sys_landlock_restrict_self
+447 memfd_secret memfd_secret sys_memfd_secret
+448 common process_mrelease sys_process_mrelease
+449 common futex_waitv sys_futex_waitv
+450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common cachestat sys_cachestat
+452 common fchmodat2 sys_fchmodat2
+453 common map_shadow_stack sys_map_shadow_stack
+454 common futex_wake sys_futex_wake
+455 common futex_wait sys_futex_wait
+456 common futex_requeue sys_futex_requeue
+457 common statmount sys_statmount
+458 common listmount sys_listmount
+459 common lsm_get_self_attr sys_lsm_get_self_attr
+460 common lsm_set_self_attr sys_lsm_set_self_attr
+461 common lsm_list_modules sys_lsm_list_modules
+462 common mseal sys_mseal
diff --git a/linux-user/hexagon/syscall_nr.h b/linux-user/hexagon/syscall_nr.h
deleted file mode 100644
index b047dbb..0000000
--- a/linux-user/hexagon/syscall_nr.h
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * This file contains the system call numbers.
- * Do not modify.
- * This file is generated by scripts/gensyscalls.sh
- */
-#ifndef LINUX_USER_HEXAGON_SYSCALL_NR_H
-#define LINUX_USER_HEXAGON_SYSCALL_NR_H
-
-#define TARGET_NR_io_setup 0
-#define TARGET_NR_io_destroy 1
-#define TARGET_NR_io_submit 2
-#define TARGET_NR_io_cancel 3
-#define TARGET_NR_io_getevents 4
-#define TARGET_NR_setxattr 5
-#define TARGET_NR_lsetxattr 6
-#define TARGET_NR_fsetxattr 7
-#define TARGET_NR_getxattr 8
-#define TARGET_NR_lgetxattr 9
-#define TARGET_NR_fgetxattr 10
-#define TARGET_NR_listxattr 11
-#define TARGET_NR_llistxattr 12
-#define TARGET_NR_flistxattr 13
-#define TARGET_NR_removexattr 14
-#define TARGET_NR_lremovexattr 15
-#define TARGET_NR_fremovexattr 16
-#define TARGET_NR_getcwd 17
-#define TARGET_NR_lookup_dcookie 18
-#define TARGET_NR_eventfd2 19
-#define TARGET_NR_epoll_create1 20
-#define TARGET_NR_epoll_ctl 21
-#define TARGET_NR_epoll_pwait 22
-#define TARGET_NR_dup 23
-#define TARGET_NR_dup3 24
-#define TARGET_NR_fcntl64 25
-#define TARGET_NR_inotify_init1 26
-#define TARGET_NR_inotify_add_watch 27
-#define TARGET_NR_inotify_rm_watch 28
-#define TARGET_NR_ioctl 29
-#define TARGET_NR_ioprio_set 30
-#define TARGET_NR_ioprio_get 31
-#define TARGET_NR_flock 32
-#define TARGET_NR_mknodat 33
-#define TARGET_NR_mkdirat 34
-#define TARGET_NR_unlinkat 35
-#define TARGET_NR_symlinkat 36
-#define TARGET_NR_linkat 37
-#define TARGET_NR_renameat 38
-#define TARGET_NR_umount2 39
-#define TARGET_NR_mount 40
-#define TARGET_NR_pivot_root 41
-#define TARGET_NR_nfsservctl 42
-#define TARGET_NR_statfs64 43
-#define TARGET_NR_fstatfs64 44
-#define TARGET_NR_truncate64 45
-#define TARGET_NR_ftruncate64 46
-#define TARGET_NR_fallocate 47
-#define TARGET_NR_faccessat 48
-#define TARGET_NR_chdir 49
-#define TARGET_NR_fchdir 50
-#define TARGET_NR_chroot 51
-#define TARGET_NR_fchmod 52
-#define TARGET_NR_fchmodat 53
-#define TARGET_NR_fchownat 54
-#define TARGET_NR_fchown 55
-#define TARGET_NR_openat 56
-#define TARGET_NR_close 57
-#define TARGET_NR_vhangup 58
-#define TARGET_NR_pipe2 59
-#define TARGET_NR_quotactl 60
-#define TARGET_NR_getdents64 61
-#define TARGET_NR_llseek 62
-#define TARGET_NR_read 63
-#define TARGET_NR_write 64
-#define TARGET_NR_readv 65
-#define TARGET_NR_writev 66
-#define TARGET_NR_pread64 67
-#define TARGET_NR_pwrite64 68
-#define TARGET_NR_preadv 69
-#define TARGET_NR_pwritev 70
-#define TARGET_NR_sendfile64 71
-#define TARGET_NR_pselect6 72
-#define TARGET_NR_ppoll 73
-#define TARGET_NR_signalfd4 74
-#define TARGET_NR_vmsplice 75
-#define TARGET_NR_splice 76
-#define TARGET_NR_tee 77
-#define TARGET_NR_readlinkat 78
-#define TARGET_NR_fstatat64 79
-#define TARGET_NR_fstat64 80
-#define TARGET_NR_sync 81
-#define TARGET_NR_fsync 82
-#define TARGET_NR_fdatasync 83
-#define TARGET_NR_sync_file_range 84
-#define TARGET_NR_timerfd_create 85
-#define TARGET_NR_timerfd_settime 86
-#define TARGET_NR_timerfd_gettime 87
-#define TARGET_NR_utimensat 88
-#define TARGET_NR_acct 89
-#define TARGET_NR_capget 90
-#define TARGET_NR_capset 91
-#define TARGET_NR_personality 92
-#define TARGET_NR_exit 93
-#define TARGET_NR_exit_group 94
-#define TARGET_NR_waitid 95
-#define TARGET_NR_set_tid_address 96
-#define TARGET_NR_unshare 97
-#define TARGET_NR_futex 98
-#define TARGET_NR_set_robust_list 99
-#define TARGET_NR_get_robust_list 100
-#define TARGET_NR_nanosleep 101
-#define TARGET_NR_getitimer 102
-#define TARGET_NR_setitimer 103
-#define TARGET_NR_kexec_load 104
-#define TARGET_NR_init_module 105
-#define TARGET_NR_delete_module 106
-#define TARGET_NR_timer_create 107
-#define TARGET_NR_timer_gettime 108
-#define TARGET_NR_timer_getoverrun 109
-#define TARGET_NR_timer_settime 110
-#define TARGET_NR_timer_delete 111
-#define TARGET_NR_clock_settime 112
-#define TARGET_NR_clock_gettime 113
-#define TARGET_NR_clock_getres 114
-#define TARGET_NR_clock_nanosleep 115
-#define TARGET_NR_syslog 116
-#define TARGET_NR_ptrace 117
-#define TARGET_NR_sched_setparam 118
-#define TARGET_NR_sched_setscheduler 119
-#define TARGET_NR_sched_getscheduler 120
-#define TARGET_NR_sched_getparam 121
-#define TARGET_NR_sched_setaffinity 122
-#define TARGET_NR_sched_getaffinity 123
-#define TARGET_NR_sched_yield 124
-#define TARGET_NR_sched_get_priority_max 125
-#define TARGET_NR_sched_get_priority_min 126
-#define TARGET_NR_sched_rr_get_interval 127
-#define TARGET_NR_restart_syscall 128
-#define TARGET_NR_kill 129
-#define TARGET_NR_tkill 130
-#define TARGET_NR_tgkill 131
-#define TARGET_NR_sigaltstack 132
-#define TARGET_NR_rt_sigsuspend 133
-#define TARGET_NR_rt_sigaction 134
-#define TARGET_NR_rt_sigprocmask 135
-#define TARGET_NR_rt_sigpending 136
-#define TARGET_NR_rt_sigtimedwait 137
-#define TARGET_NR_rt_sigqueueinfo 138
-#define TARGET_NR_rt_sigreturn 139
-#define TARGET_NR_setpriority 140
-#define TARGET_NR_getpriority 141
-#define TARGET_NR_reboot 142
-#define TARGET_NR_setregid 143
-#define TARGET_NR_setgid 144
-#define TARGET_NR_setreuid 145
-#define TARGET_NR_setuid 146
-#define TARGET_NR_setresuid 147
-#define TARGET_NR_getresuid 148
-#define TARGET_NR_setresgid 149
-#define TARGET_NR_getresgid 150
-#define TARGET_NR_setfsuid 151
-#define TARGET_NR_setfsgid 152
-#define TARGET_NR_times 153
-#define TARGET_NR_setpgid 154
-#define TARGET_NR_getpgid 155
-#define TARGET_NR_getsid 156
-#define TARGET_NR_setsid 157
-#define TARGET_NR_getgroups 158
-#define TARGET_NR_setgroups 159
-#define TARGET_NR_uname 160
-#define TARGET_NR_sethostname 161
-#define TARGET_NR_setdomainname 162
-#define TARGET_NR_getrlimit 163
-#define TARGET_NR_setrlimit 164
-#define TARGET_NR_getrusage 165
-#define TARGET_NR_umask 166
-#define TARGET_NR_prctl 167
-#define TARGET_NR_getcpu 168
-#define TARGET_NR_gettimeofday 169
-#define TARGET_NR_settimeofday 170
-#define TARGET_NR_adjtimex 171
-#define TARGET_NR_getpid 172
-#define TARGET_NR_getppid 173
-#define TARGET_NR_getuid 174
-#define TARGET_NR_geteuid 175
-#define TARGET_NR_getgid 176
-#define TARGET_NR_getegid 177
-#define TARGET_NR_gettid 178
-#define TARGET_NR_sysinfo 179
-#define TARGET_NR_mq_open 180
-#define TARGET_NR_mq_unlink 181
-#define TARGET_NR_mq_timedsend 182
-#define TARGET_NR_mq_timedreceive 183
-#define TARGET_NR_mq_notify 184
-#define TARGET_NR_mq_getsetattr 185
-#define TARGET_NR_msgget 186
-#define TARGET_NR_msgctl 187
-#define TARGET_NR_msgrcv 188
-#define TARGET_NR_msgsnd 189
-#define TARGET_NR_semget 190
-#define TARGET_NR_semctl 191
-#define TARGET_NR_semtimedop 192
-#define TARGET_NR_semop 193
-#define TARGET_NR_shmget 194
-#define TARGET_NR_shmctl 195
-#define TARGET_NR_shmat 196
-#define TARGET_NR_shmdt 197
-#define TARGET_NR_socket 198
-#define TARGET_NR_socketpair 199
-#define TARGET_NR_bind 200
-#define TARGET_NR_listen 201
-#define TARGET_NR_accept 202
-#define TARGET_NR_connect 203
-#define TARGET_NR_getsockname 204
-#define TARGET_NR_getpeername 205
-#define TARGET_NR_sendto 206
-#define TARGET_NR_recvfrom 207
-#define TARGET_NR_setsockopt 208
-#define TARGET_NR_getsockopt 209
-#define TARGET_NR_shutdown 210
-#define TARGET_NR_sendmsg 211
-#define TARGET_NR_recvmsg 212
-#define TARGET_NR_readahead 213
-#define TARGET_NR_brk 214
-#define TARGET_NR_munmap 215
-#define TARGET_NR_mremap 216
-#define TARGET_NR_add_key 217
-#define TARGET_NR_request_key 218
-#define TARGET_NR_keyctl 219
-#define TARGET_NR_clone 220
-#define TARGET_NR_execve 221
-#define TARGET_NR_mmap2 222
-#define TARGET_NR_fadvise64_64 223
-#define TARGET_NR_swapon 224
-#define TARGET_NR_swapoff 225
-#define TARGET_NR_mprotect 226
-#define TARGET_NR_msync 227
-#define TARGET_NR_mlock 228
-#define TARGET_NR_munlock 229
-#define TARGET_NR_mlockall 230
-#define TARGET_NR_munlockall 231
-#define TARGET_NR_mincore 232
-#define TARGET_NR_madvise 233
-#define TARGET_NR_remap_file_pages 234
-#define TARGET_NR_mbind 235
-#define TARGET_NR_get_mempolicy 236
-#define TARGET_NR_set_mempolicy 237
-#define TARGET_NR_migrate_pages 238
-#define TARGET_NR_move_pages 239
-#define TARGET_NR_rt_tgsigqueueinfo 240
-#define TARGET_NR_perf_event_open 241
-#define TARGET_NR_accept4 242
-#define TARGET_NR_recvmmsg 243
-#define TARGET_NR_arch_specific_syscall 244
-#define TARGET_NR_wait4 260
-#define TARGET_NR_prlimit64 261
-#define TARGET_NR_fanotify_init 262
-#define TARGET_NR_fanotify_mark 263
-#define TARGET_NR_name_to_handle_at 264
-#define TARGET_NR_open_by_handle_at 265
-#define TARGET_NR_clock_adjtime 266
-#define TARGET_NR_syncfs 267
-#define TARGET_NR_setns 268
-#define TARGET_NR_sendmmsg 269
-#define TARGET_NR_process_vm_readv 270
-#define TARGET_NR_process_vm_writev 271
-#define TARGET_NR_kcmp 272
-#define TARGET_NR_finit_module 273
-#define TARGET_NR_sched_setattr 274
-#define TARGET_NR_sched_getattr 275
-#define TARGET_NR_renameat2 276
-#define TARGET_NR_seccomp 277
-#define TARGET_NR_getrandom 278
-#define TARGET_NR_memfd_create 279
-#define TARGET_NR_bpf 280
-#define TARGET_NR_execveat 281
-#define TARGET_NR_userfaultfd 282
-#define TARGET_NR_membarrier 283
-#define TARGET_NR_mlock2 284
-#define TARGET_NR_copy_file_range 285
-#define TARGET_NR_preadv2 286
-#define TARGET_NR_pwritev2 287
-#define TARGET_NR_pkey_mprotect 288
-#define TARGET_NR_pkey_alloc 289
-#define TARGET_NR_pkey_free 290
-#define TARGET_NR_statx 291
-#define TARGET_NR_io_pgetevents 292
-#define TARGET_NR_rseq 293
-#define TARGET_NR_kexec_file_load 294
-#define TARGET_NR_clock_gettime64 403
-#define TARGET_NR_clock_settime64 404
-#define TARGET_NR_clock_adjtime64 405
-#define TARGET_NR_clock_getres_time64 406
-#define TARGET_NR_clock_nanosleep_time64 407
-#define TARGET_NR_timer_gettime64 408
-#define TARGET_NR_timer_settime64 409
-#define TARGET_NR_timerfd_gettime64 410
-#define TARGET_NR_timerfd_settime64 411
-#define TARGET_NR_utimensat_time64 412
-#define TARGET_NR_pselect6_time64 413
-#define TARGET_NR_ppoll_time64 414
-#define TARGET_NR_io_pgetevents_time64 416
-#define TARGET_NR_recvmmsg_time64 417
-#define TARGET_NR_mq_timedsend_time64 418
-#define TARGET_NR_mq_timedreceive_time64 419
-#define TARGET_NR_semtimedop_time64 420
-#define TARGET_NR_rt_sigtimedwait_time64 421
-#define TARGET_NR_futex_time64 422
-#define TARGET_NR_sched_rr_get_interval_time64 423
-#define TARGET_NR_pidfd_send_signal 424
-#define TARGET_NR_io_uring_setup 425
-#define TARGET_NR_io_uring_enter 426
-#define TARGET_NR_io_uring_register 427
-#define TARGET_NR_open_tree 428
-#define TARGET_NR_move_mount 429
-#define TARGET_NR_fsopen 430
-#define TARGET_NR_fsconfig 431
-#define TARGET_NR_fsmount 432
-#define TARGET_NR_fspick 433
-#define TARGET_NR_pidfd_open 434
-#define TARGET_NR_close_range 436
-#define TARGET_NR_openat2 437
-#define TARGET_NR_pidfd_getfd 438
-#define TARGET_NR_faccessat2 439
-#define TARGET_NR_process_madvise 440
-#define TARGET_NR_epoll_pwait2 441
-#define TARGET_NR_mount_setattr 442
-#define TARGET_NR_landlock_create_ruleset 444
-#define TARGET_NR_landlock_add_rule 445
-#define TARGET_NR_landlock_restrict_self 446
-#define TARGET_NR_syscalls 447
-
-#endif /* LINUX_USER_HEXAGON_SYSCALL_NR_H */
diff --git a/linux-user/hexagon/syscallhdr.sh b/linux-user/hexagon/syscallhdr.sh
new file mode 100644
index 0000000..ed605c0
--- /dev/null
+++ b/linux-user/hexagon/syscallhdr.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+in="$1"
+out="$2"
+my_abis=`echo "($3)" | tr ',' '|'`
+prefix="$4"
+offset="$5"
+
+fileguard=LINUX_USER_HEXAGON_`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 | (
+ echo "#ifndef ${fileguard}"
+ echo "#define ${fileguard} 1"
+ echo ""
+
+ while read nr abi name entry compat ; do
+ if [ -z "$offset" ]; then
+ echo "#define TARGET_NR_${prefix}${name} $nr"
+ else
+ echo "#define TARGET_NR_${prefix}${name} ($offset + $nr)"
+ fi
+ done
+
+ echo ""
+ echo "#endif /* ${fileguard} */"
+) > "$out"
diff --git a/linux-user/hppa/cpu_loop.c b/linux-user/hppa/cpu_loop.c
index bc093b8..23b38ff 100644
--- a/linux-user/hppa/cpu_loop.c
+++ b/linux-user/hppa/cpu_loop.c
@@ -99,6 +99,8 @@ static abi_ulong hppa_lws(CPUHPPAState *env)
#endif
}
break;
+ default:
+ g_assert_not_reached();
}
break;
}
diff --git a/linux-user/hppa/syscall.tbl b/linux-user/hppa/syscall.tbl
index aabc37f..647f08e 100644
--- a/linux-user/hppa/syscall.tbl
+++ b/linux-user/hppa/syscall.tbl
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
#
# system call numbers and entry vectors for parisc
#
@@ -108,7 +108,7 @@
95 common fchown sys_fchown
96 common getpriority sys_getpriority
97 common setpriority sys_setpriority
-98 common recv sys_recv
+98 common recv sys_recv compat_sys_recv
99 common statfs sys_statfs compat_sys_statfs
100 common fstatfs sys_fstatfs compat_sys_fstatfs
101 common stat64 sys_stat64
@@ -131,11 +131,11 @@
116 common sysinfo sys_sysinfo compat_sys_sysinfo
117 common shutdown sys_shutdown
118 common fsync sys_fsync
-119 common madvise sys_madvise
+119 common madvise parisc_madvise
120 common clone sys_clone_wrapper
121 common setdomainname sys_setdomainname
122 common sendfile sys_sendfile compat_sys_sendfile
-123 common recvfrom sys_recvfrom
+123 common recvfrom sys_recvfrom compat_sys_recvfrom
124 32 adjtimex sys_adjtimex_time32
124 64 adjtimex sys_adjtimex
125 common mprotect sys_mprotect
@@ -147,7 +147,7 @@
131 common quotactl sys_quotactl
132 common getpgid sys_getpgid
133 common fchdir sys_fchdir
-134 common bdflush sys_bdflush
+134 common bdflush sys_ni_syscall
135 common sysfs sys_sysfs
136 32 personality parisc_personality
136 64 personality sys_personality
@@ -245,7 +245,7 @@
# 220 was alloc_hugepages
# 221 was free_hugepages
222 common exit_group sys_exit_group
-223 common lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie
+223 common lookup_dcookie sys_ni_syscall
224 common epoll_create sys_epoll_create
225 common epoll_ctl sys_epoll_ctl
226 common epoll_wait sys_epoll_wait
@@ -292,9 +292,9 @@
258 32 clock_nanosleep sys_clock_nanosleep_time32
258 64 clock_nanosleep sys_clock_nanosleep
259 common tgkill sys_tgkill
-260 common mbind sys_mbind compat_sys_mbind
-261 common get_mempolicy sys_get_mempolicy compat_sys_get_mempolicy
-262 common set_mempolicy sys_set_mempolicy compat_sys_set_mempolicy
+260 common mbind sys_mbind
+261 common get_mempolicy sys_get_mempolicy
+262 common set_mempolicy sys_set_mempolicy
# 263 was vserver
264 common add_key sys_add_key
265 common request_key sys_request_key
@@ -331,7 +331,7 @@
292 64 sync_file_range sys_sync_file_range
293 common tee sys_tee
294 common vmsplice sys_vmsplice
-295 common move_pages sys_move_pages compat_sys_move_pages
+295 common move_pages sys_move_pages
296 common getcpu sys_getcpu
297 common epoll_pwait sys_epoll_pwait compat_sys_epoll_pwait
298 common statfs64 sys_statfs64 compat_sys_statfs64
@@ -364,7 +364,7 @@
320 common accept4 sys_accept4
321 common prlimit64 sys_prlimit64
322 common fanotify_init sys_fanotify_init
-323 common fanotify_mark sys_fanotify_mark sys32_fanotify_mark
+323 common fanotify_mark sys_fanotify_mark compat_sys_fanotify_mark
324 32 clock_adjtime sys_clock_adjtime32
324 64 clock_adjtime sys_clock_adjtime
325 common name_to_handle_at sys_name_to_handle_at
@@ -400,6 +400,7 @@
353 common pkey_free sys_pkey_free
354 common rseq sys_rseq
355 common kexec_file_load sys_kexec_file_load sys_kexec_file_load
+356 common cacheflush sys_cacheflush
# up to 402 is unassigned and reserved for arch specific syscalls
403 32 clock_gettime64 sys_clock_gettime sys_clock_gettime
404 32 clock_settime64 sys_clock_settime sys_clock_settime
@@ -413,7 +414,7 @@
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
+416 32 io_pgetevents_time64 sys_io_pgetevents compat_sys_io_pgetevents_time64
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
@@ -440,7 +441,23 @@
440 common process_madvise sys_process_madvise
441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
442 common mount_setattr sys_mount_setattr
-# 443 reserved for quotactl_path
+443 common quotactl_fd sys_quotactl_fd
444 common landlock_create_ruleset sys_landlock_create_ruleset
445 common landlock_add_rule sys_landlock_add_rule
446 common landlock_restrict_self sys_landlock_restrict_self
+# 447 reserved for memfd_secret
+448 common process_mrelease sys_process_mrelease
+449 common futex_waitv sys_futex_waitv
+450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common cachestat sys_cachestat
+452 common fchmodat2 sys_fchmodat2
+453 common map_shadow_stack sys_map_shadow_stack
+454 common futex_wake sys_futex_wake
+455 common futex_wait sys_futex_wait
+456 common futex_requeue sys_futex_requeue
+457 common statmount sys_statmount
+458 common listmount sys_listmount
+459 common lsm_get_self_attr sys_lsm_get_self_attr
+460 common lsm_set_self_attr sys_lsm_set_self_attr
+461 common lsm_list_modules sys_lsm_list_modules
+462 common mseal sys_mseal
diff --git a/linux-user/hppa/syscallhdr.sh b/linux-user/hppa/syscallhdr.sh
index ac91a95..bf1c1d4 100644
--- a/linux-user/hppa/syscallhdr.sh
+++ b/linux-user/hppa/syscallhdr.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
in="$1"
out="$2"
diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c
index 92beb68..7a35215 100644
--- a/linux-user/i386/cpu_loop.c
+++ b/linux-user/i386/cpu_loop.c
@@ -172,6 +172,7 @@ static void emulate_vsyscall(CPUX86State *env)
/*
* Perform the syscall. None of the vsyscalls should need restarting.
*/
+ get_task_state(env_cpu(env))->orig_ax = syscall;
ret = do_syscall(env, syscall, env->regs[R_EDI], env->regs[R_ESI],
env->regs[R_EDX], env->regs[10], env->regs[8],
env->regs[9], 0, 0);
@@ -221,6 +222,7 @@ void cpu_loop(CPUX86State *env)
case EXCP_SYSCALL:
#endif
/* linux syscall from int $0x80 */
+ get_task_state(cs)->orig_ax = env->regs[R_EAX];
ret = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EBX],
@@ -239,6 +241,7 @@ void cpu_loop(CPUX86State *env)
#ifdef TARGET_X86_64
case EXCP_SYSCALL:
/* linux syscall from syscall instruction. */
+ get_task_state(cs)->orig_ax = env->regs[R_EAX];
ret = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EDI],
diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c
index cb90711..0f11dba 100644
--- a/linux-user/i386/signal.c
+++ b/linux-user/i386/signal.c
@@ -754,8 +754,8 @@ static bool restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc)
env->eip = tswapl(sc->rip);
#endif
- cpu_x86_load_seg(env, R_CS, lduw_p(&sc->cs) | 3);
- cpu_x86_load_seg(env, R_SS, lduw_p(&sc->ss) | 3);
+ cpu_x86_load_seg(env, R_CS, lduw_le_p(&sc->cs) | 3);
+ cpu_x86_load_seg(env, R_SS, lduw_le_p(&sc->ss) | 3);
tmpflags = tswapl(sc->eflags);
env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
diff --git a/linux-user/i386/syscall_32.tbl b/linux-user/i386/syscall_32.tbl
index 4bbc267..534c74b 100644
--- a/linux-user/i386/syscall_32.tbl
+++ b/linux-user/i386/syscall_32.tbl
@@ -1,8 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
#
# 32-bit system call numbers and entry vectors
#
# The format is:
-# <number> <abi> <name> <entry point> <compat entry point>
+# <number> <abi> <name> <entry point> [<compat entry point> [noreturn]]
#
# The __ia32_sys and __ia32_compat_sys stubs are created on-the-fly for
# sys_*() system calls and compat_sys_*() compat system calls if
@@ -12,7 +13,7 @@
# The abi is always "i386" for this file.
#
0 i386 restart_syscall sys_restart_syscall
-1 i386 exit sys_exit
+1 i386 exit sys_exit - noreturn
2 i386 fork sys_fork
3 i386 read sys_read
4 i386 write sys_write
@@ -145,7 +146,7 @@
131 i386 quotactl sys_quotactl
132 i386 getpgid sys_getpgid
133 i386 fchdir sys_fchdir
-134 i386 bdflush sys_bdflush
+134 i386 bdflush sys_ni_syscall
135 i386 sysfs sys_sysfs
136 i386 personality sys_personality
137 i386 afs_syscall
@@ -263,8 +264,8 @@
249 i386 io_cancel sys_io_cancel
250 i386 fadvise64 sys_ia32_fadvise64
# 251 is available for reuse (was briefly sys_set_zone_reclaim)
-252 i386 exit_group sys_exit_group
-253 i386 lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie
+252 i386 exit_group sys_exit_group - noreturn
+253 i386 lookup_dcookie
254 i386 epoll_create sys_epoll_create
255 i386 epoll_ctl sys_epoll_ctl
256 i386 epoll_wait sys_epoll_wait
@@ -286,7 +287,7 @@
272 i386 fadvise64_64 sys_ia32_fadvise64_64
273 i386 vserver
274 i386 mbind sys_mbind
-275 i386 get_mempolicy sys_get_mempolicy compat_sys_get_mempolicy
+275 i386 get_mempolicy sys_get_mempolicy
276 i386 set_mempolicy sys_set_mempolicy
277 i386 mq_open sys_mq_open compat_sys_mq_open
278 i386 mq_unlink sys_mq_unlink
@@ -328,7 +329,7 @@
314 i386 sync_file_range sys_ia32_sync_file_range
315 i386 tee sys_tee
316 i386 vmsplice sys_vmsplice
-317 i386 move_pages sys_move_pages compat_sys_move_pages
+317 i386 move_pages sys_move_pages
318 i386 getcpu sys_getcpu
319 i386 epoll_pwait sys_epoll_pwait
320 i386 utimensat sys_utimensat_time32
@@ -420,7 +421,7 @@
412 i386 utimensat_time64 sys_utimensat
413 i386 pselect6_time64 sys_pselect6 compat_sys_pselect6_time64
414 i386 ppoll_time64 sys_ppoll compat_sys_ppoll_time64
-416 i386 io_pgetevents_time64 sys_io_pgetevents
+416 i386 io_pgetevents_time64 sys_io_pgetevents compat_sys_io_pgetevents_time64
417 i386 recvmmsg_time64 sys_recvmmsg compat_sys_recvmmsg_time64
418 i386 mq_timedsend_time64 sys_mq_timedsend
419 i386 mq_timedreceive_time64 sys_mq_timedreceive
@@ -447,7 +448,23 @@
440 i386 process_madvise sys_process_madvise
441 i386 epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
442 i386 mount_setattr sys_mount_setattr
-# 443 reserved for quotactl_path
+443 i386 quotactl_fd sys_quotactl_fd
444 i386 landlock_create_ruleset sys_landlock_create_ruleset
445 i386 landlock_add_rule sys_landlock_add_rule
446 i386 landlock_restrict_self sys_landlock_restrict_self
+447 i386 memfd_secret sys_memfd_secret
+448 i386 process_mrelease sys_process_mrelease
+449 i386 futex_waitv sys_futex_waitv
+450 i386 set_mempolicy_home_node sys_set_mempolicy_home_node
+451 i386 cachestat sys_cachestat
+452 i386 fchmodat2 sys_fchmodat2
+453 i386 map_shadow_stack sys_map_shadow_stack
+454 i386 futex_wake sys_futex_wake
+455 i386 futex_wait sys_futex_wait
+456 i386 futex_requeue sys_futex_requeue
+457 i386 statmount sys_statmount
+458 i386 listmount sys_listmount
+459 i386 lsm_get_self_attr sys_lsm_get_self_attr
+460 i386 lsm_set_self_attr sys_lsm_set_self_attr
+461 i386 lsm_list_modules sys_lsm_list_modules
+462 i386 mseal sys_mseal
diff --git a/linux-user/i386/syscallhdr.sh b/linux-user/i386/syscallhdr.sh
index b2eca96..938a793 100644
--- a/linux-user/i386/syscallhdr.sh
+++ b/linux-user/i386/syscallhdr.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
in="$1"
out="$2"
diff --git a/linux-user/loongarch64/meson.build b/linux-user/loongarch64/meson.build
index 1789653..64cb537 100644
--- a/linux-user/loongarch64/meson.build
+++ b/linux-user/loongarch64/meson.build
@@ -2,3 +2,10 @@ vdso_inc = gen_vdso.process('vdso.so',
extra_args: ['-r', '__vdso_rt_sigreturn'])
linux_user_ss.add(when: 'TARGET_LOONGARCH64', if_true: vdso_inc)
+
+
+syscall_nr_generators += {
+ 'loongarch64': generator(sh,
+ arguments: [ meson.current_source_dir() / 'syscallhdr.sh', '@INPUT@', '@OUTPUT@', '@EXTRA_ARGS@' ],
+ output: '@BASENAME@_nr.h')
+}
diff --git a/linux-user/loongarch64/syscall.tbl b/linux-user/loongarch64/syscall.tbl
new file mode 100644
index 0000000..845e24e
--- /dev/null
+++ b/linux-user/loongarch64/syscall.tbl
@@ -0,0 +1,405 @@
+# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+#
+# This file contains the system call numbers for all of the
+# more recently added architectures.
+#
+# As a basic principle, no duplication of functionality
+# should be added, e.g. we don't use lseek when llseek
+# is present. New architectures should use this file
+# and implement the less feature-full calls in user space.
+#
+0 common io_setup sys_io_setup compat_sys_io_setup
+1 common io_destroy sys_io_destroy
+2 common io_submit sys_io_submit compat_sys_io_submit
+3 common io_cancel sys_io_cancel
+4 time32 io_getevents sys_io_getevents_time32
+4 64 io_getevents sys_io_getevents
+5 common setxattr sys_setxattr
+6 common lsetxattr sys_lsetxattr
+7 common fsetxattr sys_fsetxattr
+8 common getxattr sys_getxattr
+9 common lgetxattr sys_lgetxattr
+10 common fgetxattr sys_fgetxattr
+11 common listxattr sys_listxattr
+12 common llistxattr sys_llistxattr
+13 common flistxattr sys_flistxattr
+14 common removexattr sys_removexattr
+15 common lremovexattr sys_lremovexattr
+16 common fremovexattr sys_fremovexattr
+17 common getcwd sys_getcwd
+18 common lookup_dcookie sys_ni_syscall
+19 common eventfd2 sys_eventfd2
+20 common epoll_create1 sys_epoll_create1
+21 common epoll_ctl sys_epoll_ctl
+22 common epoll_pwait sys_epoll_pwait compat_sys_epoll_pwait
+23 common dup sys_dup
+24 common dup3 sys_dup3
+25 32 fcntl64 sys_fcntl64 compat_sys_fcntl64
+25 64 fcntl sys_fcntl
+26 common inotify_init1 sys_inotify_init1
+27 common inotify_add_watch sys_inotify_add_watch
+28 common inotify_rm_watch sys_inotify_rm_watch
+29 common ioctl sys_ioctl compat_sys_ioctl
+30 common ioprio_set sys_ioprio_set
+31 common ioprio_get sys_ioprio_get
+32 common flock sys_flock
+33 common mknodat sys_mknodat
+34 common mkdirat sys_mkdirat
+35 common unlinkat sys_unlinkat
+36 common symlinkat sys_symlinkat
+37 common linkat sys_linkat
+# renameat is superseded with flags by renameat2
+38 renameat renameat sys_renameat
+39 common umount2 sys_umount
+40 common mount sys_mount
+41 common pivot_root sys_pivot_root
+42 common nfsservctl sys_ni_syscall
+43 32 statfs64 sys_statfs64 compat_sys_statfs64
+43 64 statfs sys_statfs
+44 32 fstatfs64 sys_fstatfs64 compat_sys_fstatfs64
+44 64 fstatfs sys_fstatfs
+45 32 truncate64 sys_truncate64 compat_sys_truncate64
+45 64 truncate sys_truncate
+46 32 ftruncate64 sys_ftruncate64 compat_sys_ftruncate64
+46 64 ftruncate sys_ftruncate
+47 common fallocate sys_fallocate compat_sys_fallocate
+48 common faccessat sys_faccessat
+49 common chdir sys_chdir
+50 common fchdir sys_fchdir
+51 common chroot sys_chroot
+52 common fchmod sys_fchmod
+53 common fchmodat sys_fchmodat
+54 common fchownat sys_fchownat
+55 common fchown sys_fchown
+56 common openat sys_openat
+57 common close sys_close
+58 common vhangup sys_vhangup
+59 common pipe2 sys_pipe2
+60 common quotactl sys_quotactl
+61 common getdents64 sys_getdents64
+62 32 llseek sys_llseek
+62 64 lseek sys_lseek
+63 common read sys_read
+64 common write sys_write
+65 common readv sys_readv sys_readv
+66 common writev sys_writev sys_writev
+67 common pread64 sys_pread64 compat_sys_pread64
+68 common pwrite64 sys_pwrite64 compat_sys_pwrite64
+69 common preadv sys_preadv compat_sys_preadv
+70 common pwritev sys_pwritev compat_sys_pwritev
+71 32 sendfile64 sys_sendfile64
+71 64 sendfile sys_sendfile64
+72 time32 pselect6 sys_pselect6_time32 compat_sys_pselect6_time32
+72 64 pselect6 sys_pselect6
+73 time32 ppoll sys_ppoll_time32 compat_sys_ppoll_time32
+73 64 ppoll sys_ppoll
+74 common signalfd4 sys_signalfd4 compat_sys_signalfd4
+75 common vmsplice sys_vmsplice
+76 common splice sys_splice
+77 common tee sys_tee
+78 common readlinkat sys_readlinkat
+79 stat64 fstatat64 sys_fstatat64
+79 64 newfstatat sys_newfstatat
+80 stat64 fstat64 sys_fstat64
+80 64 fstat sys_newfstat
+81 common sync sys_sync
+82 common fsync sys_fsync
+83 common fdatasync sys_fdatasync
+84 common sync_file_range sys_sync_file_range compat_sys_sync_file_range
+85 common timerfd_create sys_timerfd_create
+86 time32 timerfd_settime sys_timerfd_settime32
+86 64 timerfd_settime sys_timerfd_settime
+87 time32 timerfd_gettime sys_timerfd_gettime32
+87 64 timerfd_gettime sys_timerfd_gettime
+88 time32 utimensat sys_utimensat_time32
+88 64 utimensat sys_utimensat
+89 common acct sys_acct
+90 common capget sys_capget
+91 common capset sys_capset
+92 common personality sys_personality
+93 common exit sys_exit
+94 common exit_group sys_exit_group
+95 common waitid sys_waitid compat_sys_waitid
+96 common set_tid_address sys_set_tid_address
+97 common unshare sys_unshare
+98 time32 futex sys_futex_time32
+98 64 futex sys_futex
+99 common set_robust_list sys_set_robust_list compat_sys_set_robust_list
+100 common get_robust_list sys_get_robust_list compat_sys_get_robust_list
+101 time32 nanosleep sys_nanosleep_time32
+101 64 nanosleep sys_nanosleep
+102 common getitimer sys_getitimer compat_sys_getitimer
+103 common setitimer sys_setitimer compat_sys_setitimer
+104 common kexec_load sys_kexec_load compat_sys_kexec_load
+105 common init_module sys_init_module
+106 common delete_module sys_delete_module
+107 common timer_create sys_timer_create compat_sys_timer_create
+108 time32 timer_gettime sys_timer_gettime32
+108 64 timer_gettime sys_timer_gettime
+109 common timer_getoverrun sys_timer_getoverrun
+110 time32 timer_settime sys_timer_settime32
+110 64 timer_settime sys_timer_settime
+111 common timer_delete sys_timer_delete
+112 time32 clock_settime sys_clock_settime32
+112 64 clock_settime sys_clock_settime
+113 time32 clock_gettime sys_clock_gettime32
+113 64 clock_gettime sys_clock_gettime
+114 time32 clock_getres sys_clock_getres_time32
+114 64 clock_getres sys_clock_getres
+115 time32 clock_nanosleep sys_clock_nanosleep_time32
+115 64 clock_nanosleep sys_clock_nanosleep
+116 common syslog sys_syslog
+117 common ptrace sys_ptrace compat_sys_ptrace
+118 common sched_setparam sys_sched_setparam
+119 common sched_setscheduler sys_sched_setscheduler
+120 common sched_getscheduler sys_sched_getscheduler
+121 common sched_getparam sys_sched_getparam
+122 common sched_setaffinity sys_sched_setaffinity compat_sys_sched_setaffinity
+123 common sched_getaffinity sys_sched_getaffinity compat_sys_sched_getaffinity
+124 common sched_yield sys_sched_yield
+125 common sched_get_priority_max sys_sched_get_priority_max
+126 common sched_get_priority_min sys_sched_get_priority_min
+127 time32 sched_rr_get_interval sys_sched_rr_get_interval_time32
+127 64 sched_rr_get_interval sys_sched_rr_get_interval
+128 common restart_syscall sys_restart_syscall
+129 common kill sys_kill
+130 common tkill sys_tkill
+131 common tgkill sys_tgkill
+132 common sigaltstack sys_sigaltstack compat_sys_sigaltstack
+133 common rt_sigsuspend sys_rt_sigsuspend compat_sys_rt_sigsuspend
+134 common rt_sigaction sys_rt_sigaction compat_sys_rt_sigaction
+135 common rt_sigprocmask sys_rt_sigprocmask compat_sys_rt_sigprocmask
+136 common rt_sigpending sys_rt_sigpending compat_sys_rt_sigpending
+137 time32 rt_sigtimedwait sys_rt_sigtimedwait_time32 compat_sys_rt_sigtimedwait_time32
+137 64 rt_sigtimedwait sys_rt_sigtimedwait
+138 common rt_sigqueueinfo sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo
+139 common rt_sigreturn sys_rt_sigreturn compat_sys_rt_sigreturn
+140 common setpriority sys_setpriority
+141 common getpriority sys_getpriority
+142 common reboot sys_reboot
+143 common setregid sys_setregid
+144 common setgid sys_setgid
+145 common setreuid sys_setreuid
+146 common setuid sys_setuid
+147 common setresuid sys_setresuid
+148 common getresuid sys_getresuid
+149 common setresgid sys_setresgid
+150 common getresgid sys_getresgid
+151 common setfsuid sys_setfsuid
+152 common setfsgid sys_setfsgid
+153 common times sys_times compat_sys_times
+154 common setpgid sys_setpgid
+155 common getpgid sys_getpgid
+156 common getsid sys_getsid
+157 common setsid sys_setsid
+158 common getgroups sys_getgroups
+159 common setgroups sys_setgroups
+160 common uname sys_newuname
+161 common sethostname sys_sethostname
+162 common setdomainname sys_setdomainname
+# getrlimit and setrlimit are superseded with prlimit64
+163 rlimit getrlimit sys_getrlimit compat_sys_getrlimit
+164 rlimit setrlimit sys_setrlimit compat_sys_setrlimit
+165 common getrusage sys_getrusage compat_sys_getrusage
+166 common umask sys_umask
+167 common prctl sys_prctl
+168 common getcpu sys_getcpu
+169 time32 gettimeofday sys_gettimeofday compat_sys_gettimeofday
+169 64 gettimeofday sys_gettimeofday
+170 time32 settimeofday sys_settimeofday compat_sys_settimeofday
+170 64 settimeofday sys_settimeofday
+171 time32 adjtimex sys_adjtimex_time32
+171 64 adjtimex sys_adjtimex
+172 common getpid sys_getpid
+173 common getppid sys_getppid
+174 common getuid sys_getuid
+175 common geteuid sys_geteuid
+176 common getgid sys_getgid
+177 common getegid sys_getegid
+178 common gettid sys_gettid
+179 common sysinfo sys_sysinfo compat_sys_sysinfo
+180 common mq_open sys_mq_open compat_sys_mq_open
+181 common mq_unlink sys_mq_unlink
+182 time32 mq_timedsend sys_mq_timedsend_time32
+182 64 mq_timedsend sys_mq_timedsend
+183 time32 mq_timedreceive sys_mq_timedreceive_time32
+183 64 mq_timedreceive sys_mq_timedreceive
+184 common mq_notify sys_mq_notify compat_sys_mq_notify
+185 common mq_getsetattr sys_mq_getsetattr compat_sys_mq_getsetattr
+186 common msgget sys_msgget
+187 common msgctl sys_msgctl compat_sys_msgctl
+188 common msgrcv sys_msgrcv compat_sys_msgrcv
+189 common msgsnd sys_msgsnd compat_sys_msgsnd
+190 common semget sys_semget
+191 common semctl sys_semctl compat_sys_semctl
+192 time32 semtimedop sys_semtimedop_time32
+192 64 semtimedop sys_semtimedop
+193 common semop sys_semop
+194 common shmget sys_shmget
+195 common shmctl sys_shmctl compat_sys_shmctl
+196 common shmat sys_shmat compat_sys_shmat
+197 common shmdt sys_shmdt
+198 common socket sys_socket
+199 common socketpair sys_socketpair
+200 common bind sys_bind
+201 common listen sys_listen
+202 common accept sys_accept
+203 common connect sys_connect
+204 common getsockname sys_getsockname
+205 common getpeername sys_getpeername
+206 common sendto sys_sendto
+207 common recvfrom sys_recvfrom compat_sys_recvfrom
+208 common setsockopt sys_setsockopt sys_setsockopt
+209 common getsockopt sys_getsockopt sys_getsockopt
+210 common shutdown sys_shutdown
+211 common sendmsg sys_sendmsg compat_sys_sendmsg
+212 common recvmsg sys_recvmsg compat_sys_recvmsg
+213 common readahead sys_readahead compat_sys_readahead
+214 common brk sys_brk
+215 common munmap sys_munmap
+216 common mremap sys_mremap
+217 common add_key sys_add_key
+218 common request_key sys_request_key
+219 common keyctl sys_keyctl compat_sys_keyctl
+220 common clone sys_clone
+221 common execve sys_execve compat_sys_execve
+222 32 mmap2 sys_mmap2
+222 64 mmap sys_mmap
+223 32 fadvise64_64 sys_fadvise64_64 compat_sys_fadvise64_64
+223 64 fadvise64 sys_fadvise64_64
+224 common swapon sys_swapon
+225 common swapoff sys_swapoff
+226 common mprotect sys_mprotect
+227 common msync sys_msync
+228 common mlock sys_mlock
+229 common munlock sys_munlock
+230 common mlockall sys_mlockall
+231 common munlockall sys_munlockall
+232 common mincore sys_mincore
+233 common madvise sys_madvise
+234 common remap_file_pages sys_remap_file_pages
+235 common mbind sys_mbind
+236 common get_mempolicy sys_get_mempolicy
+237 common set_mempolicy sys_set_mempolicy
+238 common migrate_pages sys_migrate_pages
+239 common move_pages sys_move_pages
+240 common rt_tgsigqueueinfo sys_rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo
+241 common perf_event_open sys_perf_event_open
+242 common accept4 sys_accept4
+243 time32 recvmmsg sys_recvmmsg_time32 compat_sys_recvmmsg_time32
+243 64 recvmmsg sys_recvmmsg
+# Architectures may provide up to 16 syscalls of their own between 244 and 259
+244 arc cacheflush sys_cacheflush
+245 arc arc_settls sys_arc_settls
+246 arc arc_gettls sys_arc_gettls
+247 arc sysfs sys_sysfs
+248 arc arc_usr_cmpxchg sys_arc_usr_cmpxchg
+
+244 csky set_thread_area sys_set_thread_area
+245 csky cacheflush sys_cacheflush
+
+244 nios2 cacheflush sys_cacheflush
+
+244 or1k or1k_atomic sys_or1k_atomic
+
+258 riscv riscv_hwprobe sys_riscv_hwprobe
+259 riscv riscv_flush_icache sys_riscv_flush_icache
+
+260 time32 wait4 sys_wait4 compat_sys_wait4
+260 64 wait4 sys_wait4
+261 common prlimit64 sys_prlimit64
+262 common fanotify_init sys_fanotify_init
+263 common fanotify_mark sys_fanotify_mark
+264 common name_to_handle_at sys_name_to_handle_at
+265 common open_by_handle_at sys_open_by_handle_at
+266 time32 clock_adjtime sys_clock_adjtime32
+266 64 clock_adjtime sys_clock_adjtime
+267 common syncfs sys_syncfs
+268 common setns sys_setns
+269 common sendmmsg sys_sendmmsg compat_sys_sendmmsg
+270 common process_vm_readv sys_process_vm_readv
+271 common process_vm_writev sys_process_vm_writev
+272 common kcmp sys_kcmp
+273 common finit_module sys_finit_module
+274 common sched_setattr sys_sched_setattr
+275 common sched_getattr sys_sched_getattr
+276 common renameat2 sys_renameat2
+277 common seccomp sys_seccomp
+278 common getrandom sys_getrandom
+279 common memfd_create sys_memfd_create
+280 common bpf sys_bpf
+281 common execveat sys_execveat compat_sys_execveat
+282 common userfaultfd sys_userfaultfd
+283 common membarrier sys_membarrier
+284 common mlock2 sys_mlock2
+285 common copy_file_range sys_copy_file_range
+286 common preadv2 sys_preadv2 compat_sys_preadv2
+287 common pwritev2 sys_pwritev2 compat_sys_pwritev2
+288 common pkey_mprotect sys_pkey_mprotect
+289 common pkey_alloc sys_pkey_alloc
+290 common pkey_free sys_pkey_free
+291 common statx sys_statx
+292 time32 io_pgetevents sys_io_pgetevents_time32 compat_sys_io_pgetevents
+292 64 io_pgetevents sys_io_pgetevents
+293 common rseq sys_rseq
+294 common kexec_file_load sys_kexec_file_load
+# 295 through 402 are unassigned to sync up with generic numbers don't use
+403 32 clock_gettime64 sys_clock_gettime
+404 32 clock_settime64 sys_clock_settime
+405 32 clock_adjtime64 sys_clock_adjtime
+406 32 clock_getres_time64 sys_clock_getres
+407 32 clock_nanosleep_time64 sys_clock_nanosleep
+408 32 timer_gettime64 sys_timer_gettime
+409 32 timer_settime64 sys_timer_settime
+410 32 timerfd_gettime64 sys_timerfd_gettime
+411 32 timerfd_settime64 sys_timerfd_settime
+412 32 utimensat_time64 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 compat_sys_io_pgetevents_time64
+417 32 recvmmsg_time64 sys_recvmmsg compat_sys_recvmmsg_time64
+418 32 mq_timedsend_time64 sys_mq_timedsend
+419 32 mq_timedreceive_time64 sys_mq_timedreceive
+420 32 semtimedop_time64 sys_semtimedop
+421 32 rt_sigtimedwait_time64 sys_rt_sigtimedwait compat_sys_rt_sigtimedwait_time64
+422 32 futex_time64 sys_futex
+423 32 sched_rr_get_interval_time64 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 common clone3 sys_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
+440 common process_madvise sys_process_madvise
+441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
+442 common mount_setattr sys_mount_setattr
+443 common quotactl_fd sys_quotactl_fd
+444 common landlock_create_ruleset sys_landlock_create_ruleset
+445 common landlock_add_rule sys_landlock_add_rule
+446 common landlock_restrict_self sys_landlock_restrict_self
+447 memfd_secret memfd_secret sys_memfd_secret
+448 common process_mrelease sys_process_mrelease
+449 common futex_waitv sys_futex_waitv
+450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common cachestat sys_cachestat
+452 common fchmodat2 sys_fchmodat2
+453 common map_shadow_stack sys_map_shadow_stack
+454 common futex_wake sys_futex_wake
+455 common futex_wait sys_futex_wait
+456 common futex_requeue sys_futex_requeue
+457 common statmount sys_statmount
+458 common listmount sys_listmount
+459 common lsm_get_self_attr sys_lsm_get_self_attr
+460 common lsm_set_self_attr sys_lsm_set_self_attr
+461 common lsm_list_modules sys_lsm_list_modules
+462 common mseal sys_mseal
diff --git a/linux-user/loongarch64/syscall_nr.h b/linux-user/loongarch64/syscall_nr.h
deleted file mode 100644
index be00915..0000000
--- a/linux-user/loongarch64/syscall_nr.h
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * This file contains the system call numbers.
- * Do not modify.
- * This file is generated by scripts/gensyscalls.sh
- */
-#ifndef LINUX_USER_LOONGARCH_SYSCALL_NR_H
-#define LINUX_USER_LOONGARCH_SYSCALL_NR_H
-
-#define TARGET_NR_io_setup 0
-#define TARGET_NR_io_destroy 1
-#define TARGET_NR_io_submit 2
-#define TARGET_NR_io_cancel 3
-#define TARGET_NR_io_getevents 4
-#define TARGET_NR_setxattr 5
-#define TARGET_NR_lsetxattr 6
-#define TARGET_NR_fsetxattr 7
-#define TARGET_NR_getxattr 8
-#define TARGET_NR_lgetxattr 9
-#define TARGET_NR_fgetxattr 10
-#define TARGET_NR_listxattr 11
-#define TARGET_NR_llistxattr 12
-#define TARGET_NR_flistxattr 13
-#define TARGET_NR_removexattr 14
-#define TARGET_NR_lremovexattr 15
-#define TARGET_NR_fremovexattr 16
-#define TARGET_NR_getcwd 17
-#define TARGET_NR_lookup_dcookie 18
-#define TARGET_NR_eventfd2 19
-#define TARGET_NR_epoll_create1 20
-#define TARGET_NR_epoll_ctl 21
-#define TARGET_NR_epoll_pwait 22
-#define TARGET_NR_dup 23
-#define TARGET_NR_dup3 24
-#define TARGET_NR_fcntl 25
-#define TARGET_NR_inotify_init1 26
-#define TARGET_NR_inotify_add_watch 27
-#define TARGET_NR_inotify_rm_watch 28
-#define TARGET_NR_ioctl 29
-#define TARGET_NR_ioprio_set 30
-#define TARGET_NR_ioprio_get 31
-#define TARGET_NR_flock 32
-#define TARGET_NR_mknodat 33
-#define TARGET_NR_mkdirat 34
-#define TARGET_NR_unlinkat 35
-#define TARGET_NR_symlinkat 36
-#define TARGET_NR_linkat 37
-#define TARGET_NR_umount2 39
-#define TARGET_NR_mount 40
-#define TARGET_NR_pivot_root 41
-#define TARGET_NR_nfsservctl 42
-#define TARGET_NR_statfs 43
-#define TARGET_NR_fstatfs 44
-#define TARGET_NR_truncate 45
-#define TARGET_NR_ftruncate 46
-#define TARGET_NR_fallocate 47
-#define TARGET_NR_faccessat 48
-#define TARGET_NR_chdir 49
-#define TARGET_NR_fchdir 50
-#define TARGET_NR_chroot 51
-#define TARGET_NR_fchmod 52
-#define TARGET_NR_fchmodat 53
-#define TARGET_NR_fchownat 54
-#define TARGET_NR_fchown 55
-#define TARGET_NR_openat 56
-#define TARGET_NR_close 57
-#define TARGET_NR_vhangup 58
-#define TARGET_NR_pipe2 59
-#define TARGET_NR_quotactl 60
-#define TARGET_NR_getdents64 61
-#define TARGET_NR_lseek 62
-#define TARGET_NR_read 63
-#define TARGET_NR_write 64
-#define TARGET_NR_readv 65
-#define TARGET_NR_writev 66
-#define TARGET_NR_pread64 67
-#define TARGET_NR_pwrite64 68
-#define TARGET_NR_preadv 69
-#define TARGET_NR_pwritev 70
-#define TARGET_NR_sendfile 71
-#define TARGET_NR_pselect6 72
-#define TARGET_NR_ppoll 73
-#define TARGET_NR_signalfd4 74
-#define TARGET_NR_vmsplice 75
-#define TARGET_NR_splice 76
-#define TARGET_NR_tee 77
-#define TARGET_NR_readlinkat 78
-#define TARGET_NR_sync 81
-#define TARGET_NR_fsync 82
-#define TARGET_NR_fdatasync 83
-#define TARGET_NR_sync_file_range 84
-#define TARGET_NR_timerfd_create 85
-#define TARGET_NR_timerfd_settime 86
-#define TARGET_NR_timerfd_gettime 87
-#define TARGET_NR_utimensat 88
-#define TARGET_NR_acct 89
-#define TARGET_NR_capget 90
-#define TARGET_NR_capset 91
-#define TARGET_NR_personality 92
-#define TARGET_NR_exit 93
-#define TARGET_NR_exit_group 94
-#define TARGET_NR_waitid 95
-#define TARGET_NR_set_tid_address 96
-#define TARGET_NR_unshare 97
-#define TARGET_NR_futex 98
-#define TARGET_NR_set_robust_list 99
-#define TARGET_NR_get_robust_list 100
-#define TARGET_NR_nanosleep 101
-#define TARGET_NR_getitimer 102
-#define TARGET_NR_setitimer 103
-#define TARGET_NR_kexec_load 104
-#define TARGET_NR_init_module 105
-#define TARGET_NR_delete_module 106
-#define TARGET_NR_timer_create 107
-#define TARGET_NR_timer_gettime 108
-#define TARGET_NR_timer_getoverrun 109
-#define TARGET_NR_timer_settime 110
-#define TARGET_NR_timer_delete 111
-#define TARGET_NR_clock_settime 112
-#define TARGET_NR_clock_gettime 113
-#define TARGET_NR_clock_getres 114
-#define TARGET_NR_clock_nanosleep 115
-#define TARGET_NR_syslog 116
-#define TARGET_NR_ptrace 117
-#define TARGET_NR_sched_setparam 118
-#define TARGET_NR_sched_setscheduler 119
-#define TARGET_NR_sched_getscheduler 120
-#define TARGET_NR_sched_getparam 121
-#define TARGET_NR_sched_setaffinity 122
-#define TARGET_NR_sched_getaffinity 123
-#define TARGET_NR_sched_yield 124
-#define TARGET_NR_sched_get_priority_max 125
-#define TARGET_NR_sched_get_priority_min 126
-#define TARGET_NR_sched_rr_get_interval 127
-#define TARGET_NR_restart_syscall 128
-#define TARGET_NR_kill 129
-#define TARGET_NR_tkill 130
-#define TARGET_NR_tgkill 131
-#define TARGET_NR_sigaltstack 132
-#define TARGET_NR_rt_sigsuspend 133
-#define TARGET_NR_rt_sigaction 134
-#define TARGET_NR_rt_sigprocmask 135
-#define TARGET_NR_rt_sigpending 136
-#define TARGET_NR_rt_sigtimedwait 137
-#define TARGET_NR_rt_sigqueueinfo 138
-#define TARGET_NR_rt_sigreturn 139
-#define TARGET_NR_setpriority 140
-#define TARGET_NR_getpriority 141
-#define TARGET_NR_reboot 142
-#define TARGET_NR_setregid 143
-#define TARGET_NR_setgid 144
-#define TARGET_NR_setreuid 145
-#define TARGET_NR_setuid 146
-#define TARGET_NR_setresuid 147
-#define TARGET_NR_getresuid 148
-#define TARGET_NR_setresgid 149
-#define TARGET_NR_getresgid 150
-#define TARGET_NR_setfsuid 151
-#define TARGET_NR_setfsgid 152
-#define TARGET_NR_times 153
-#define TARGET_NR_setpgid 154
-#define TARGET_NR_getpgid 155
-#define TARGET_NR_getsid 156
-#define TARGET_NR_setsid 157
-#define TARGET_NR_getgroups 158
-#define TARGET_NR_setgroups 159
-#define TARGET_NR_uname 160
-#define TARGET_NR_sethostname 161
-#define TARGET_NR_setdomainname 162
-#define TARGET_NR_getrusage 165
-#define TARGET_NR_umask 166
-#define TARGET_NR_prctl 167
-#define TARGET_NR_getcpu 168
-#define TARGET_NR_gettimeofday 169
-#define TARGET_NR_settimeofday 170
-#define TARGET_NR_adjtimex 171
-#define TARGET_NR_getpid 172
-#define TARGET_NR_getppid 173
-#define TARGET_NR_getuid 174
-#define TARGET_NR_geteuid 175
-#define TARGET_NR_getgid 176
-#define TARGET_NR_getegid 177
-#define TARGET_NR_gettid 178
-#define TARGET_NR_sysinfo 179
-#define TARGET_NR_mq_open 180
-#define TARGET_NR_mq_unlink 181
-#define TARGET_NR_mq_timedsend 182
-#define TARGET_NR_mq_timedreceive 183
-#define TARGET_NR_mq_notify 184
-#define TARGET_NR_mq_getsetattr 185
-#define TARGET_NR_msgget 186
-#define TARGET_NR_msgctl 187
-#define TARGET_NR_msgrcv 188
-#define TARGET_NR_msgsnd 189
-#define TARGET_NR_semget 190
-#define TARGET_NR_semctl 191
-#define TARGET_NR_semtimedop 192
-#define TARGET_NR_semop 193
-#define TARGET_NR_shmget 194
-#define TARGET_NR_shmctl 195
-#define TARGET_NR_shmat 196
-#define TARGET_NR_shmdt 197
-#define TARGET_NR_socket 198
-#define TARGET_NR_socketpair 199
-#define TARGET_NR_bind 200
-#define TARGET_NR_listen 201
-#define TARGET_NR_accept 202
-#define TARGET_NR_connect 203
-#define TARGET_NR_getsockname 204
-#define TARGET_NR_getpeername 205
-#define TARGET_NR_sendto 206
-#define TARGET_NR_recvfrom 207
-#define TARGET_NR_setsockopt 208
-#define TARGET_NR_getsockopt 209
-#define TARGET_NR_shutdown 210
-#define TARGET_NR_sendmsg 211
-#define TARGET_NR_recvmsg 212
-#define TARGET_NR_readahead 213
-#define TARGET_NR_brk 214
-#define TARGET_NR_munmap 215
-#define TARGET_NR_mremap 216
-#define TARGET_NR_add_key 217
-#define TARGET_NR_request_key 218
-#define TARGET_NR_keyctl 219
-#define TARGET_NR_clone 220
-#define TARGET_NR_execve 221
-#define TARGET_NR_mmap 222
-#define TARGET_NR_fadvise64 223
-#define TARGET_NR_swapon 224
-#define TARGET_NR_swapoff 225
-#define TARGET_NR_mprotect 226
-#define TARGET_NR_msync 227
-#define TARGET_NR_mlock 228
-#define TARGET_NR_munlock 229
-#define TARGET_NR_mlockall 230
-#define TARGET_NR_munlockall 231
-#define TARGET_NR_mincore 232
-#define TARGET_NR_madvise 233
-#define TARGET_NR_remap_file_pages 234
-#define TARGET_NR_mbind 235
-#define TARGET_NR_get_mempolicy 236
-#define TARGET_NR_set_mempolicy 237
-#define TARGET_NR_migrate_pages 238
-#define TARGET_NR_move_pages 239
-#define TARGET_NR_rt_tgsigqueueinfo 240
-#define TARGET_NR_perf_event_open 241
-#define TARGET_NR_accept4 242
-#define TARGET_NR_recvmmsg 243
-#define TARGET_NR_arch_specific_syscall 244
-#define TARGET_NR_wait4 260
-#define TARGET_NR_prlimit64 261
-#define TARGET_NR_fanotify_init 262
-#define TARGET_NR_fanotify_mark 263
-#define TARGET_NR_name_to_handle_at 264
-#define TARGET_NR_open_by_handle_at 265
-#define TARGET_NR_clock_adjtime 266
-#define TARGET_NR_syncfs 267
-#define TARGET_NR_setns 268
-#define TARGET_NR_sendmmsg 269
-#define TARGET_NR_process_vm_readv 270
-#define TARGET_NR_process_vm_writev 271
-#define TARGET_NR_kcmp 272
-#define TARGET_NR_finit_module 273
-#define TARGET_NR_sched_setattr 274
-#define TARGET_NR_sched_getattr 275
-#define TARGET_NR_renameat2 276
-#define TARGET_NR_seccomp 277
-#define TARGET_NR_getrandom 278
-#define TARGET_NR_memfd_create 279
-#define TARGET_NR_bpf 280
-#define TARGET_NR_execveat 281
-#define TARGET_NR_userfaultfd 282
-#define TARGET_NR_membarrier 283
-#define TARGET_NR_mlock2 284
-#define TARGET_NR_copy_file_range 285
-#define TARGET_NR_preadv2 286
-#define TARGET_NR_pwritev2 287
-#define TARGET_NR_pkey_mprotect 288
-#define TARGET_NR_pkey_alloc 289
-#define TARGET_NR_pkey_free 290
-#define TARGET_NR_statx 291
-#define TARGET_NR_io_pgetevents 292
-#define TARGET_NR_rseq 293
-#define TARGET_NR_kexec_file_load 294
-#define TARGET_NR_pidfd_send_signal 424
-#define TARGET_NR_io_uring_setup 425
-#define TARGET_NR_io_uring_enter 426
-#define TARGET_NR_io_uring_register 427
-#define TARGET_NR_open_tree 428
-#define TARGET_NR_move_mount 429
-#define TARGET_NR_fsopen 430
-#define TARGET_NR_fsconfig 431
-#define TARGET_NR_fsmount 432
-#define TARGET_NR_fspick 433
-#define TARGET_NR_pidfd_open 434
-#define TARGET_NR_clone3 435
-#define TARGET_NR_close_range 436
-#define TARGET_NR_openat2 437
-#define TARGET_NR_pidfd_getfd 438
-#define TARGET_NR_faccessat2 439
-#define TARGET_NR_process_madvise 440
-#define TARGET_NR_epoll_pwait2 441
-#define TARGET_NR_mount_setattr 442
-#define TARGET_NR_quotactl_fd 443
-#define TARGET_NR_landlock_create_ruleset 444
-#define TARGET_NR_landlock_add_rule 445
-#define TARGET_NR_landlock_restrict_self 446
-#define TARGET_NR_process_mrelease 448
-#define TARGET_NR_futex_waitv 449
-#define TARGET_NR_set_mempolicy_home_node 450
-#define TARGET_NR_syscalls 451
-
-#endif /* LINUX_USER_LOONGARCH_SYSCALL_NR_H */
diff --git a/linux-user/loongarch64/syscallhdr.sh b/linux-user/loongarch64/syscallhdr.sh
new file mode 100644
index 0000000..3d8a993
--- /dev/null
+++ b/linux-user/loongarch64/syscallhdr.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+in="$1"
+out="$2"
+my_abis=`echo "($3)" | tr ',' '|'`
+prefix="$4"
+offset="$5"
+
+fileguard=LINUX_USER_LOONGARCH64_`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 | (
+ echo "#ifndef ${fileguard}"
+ echo "#define ${fileguard} 1"
+ echo ""
+
+ while read nr abi name entry compat ; do
+ if [ -z "$offset" ]; then
+ echo "#define TARGET_NR_${prefix}${name} $nr"
+ else
+ echo "#define TARGET_NR_${prefix}${name} ($offset + $nr)"
+ fi
+ done
+
+ echo ""
+ echo "#endif /* ${fileguard} */"
+) > "$out"
diff --git a/linux-user/m68k/syscall.tbl b/linux-user/m68k/syscall.tbl
index 79c2d24..b6094f8 100644
--- a/linux-user/m68k/syscall.tbl
+++ b/linux-user/m68k/syscall.tbl
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
#
# system call numbers and entry vectors for m68k
#
@@ -141,7 +141,7 @@
131 common quotactl sys_quotactl
132 common getpgid sys_getpgid
133 common fchdir sys_fchdir
-134 common bdflush sys_bdflush
+134 common bdflush sys_ni_syscall
135 common sysfs sys_sysfs
136 common personality sys_personality
# 137 was afs_syscall
@@ -255,7 +255,7 @@
245 common io_cancel sys_io_cancel
246 common fadvise64 sys_fadvise64
247 common exit_group sys_exit_group
-248 common lookup_dcookie sys_lookup_dcookie
+248 common lookup_dcookie sys_ni_syscall
249 common epoll_create sys_epoll_create
250 common epoll_ctl sys_epoll_ctl
251 common epoll_wait sys_epoll_wait
@@ -442,7 +442,23 @@
440 common process_madvise sys_process_madvise
441 common epoll_pwait2 sys_epoll_pwait2
442 common mount_setattr sys_mount_setattr
-# 443 reserved for quotactl_path
+443 common quotactl_fd sys_quotactl_fd
444 common landlock_create_ruleset sys_landlock_create_ruleset
445 common landlock_add_rule sys_landlock_add_rule
446 common landlock_restrict_self sys_landlock_restrict_self
+# 447 reserved for memfd_secret
+448 common process_mrelease sys_process_mrelease
+449 common futex_waitv sys_futex_waitv
+450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common cachestat sys_cachestat
+452 common fchmodat2 sys_fchmodat2
+453 common map_shadow_stack sys_map_shadow_stack
+454 common futex_wake sys_futex_wake
+455 common futex_wait sys_futex_wait
+456 common futex_requeue sys_futex_requeue
+457 common statmount sys_statmount
+458 common listmount sys_listmount
+459 common lsm_get_self_attr sys_lsm_get_self_attr
+460 common lsm_set_self_attr sys_lsm_set_self_attr
+461 common lsm_list_modules sys_lsm_list_modules
+462 common mseal sys_mseal
diff --git a/linux-user/m68k/syscallhdr.sh b/linux-user/m68k/syscallhdr.sh
index eeb4d01..39b11dd 100644
--- a/linux-user/m68k/syscallhdr.sh
+++ b/linux-user/m68k/syscallhdr.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
in="$1"
out="$2"
diff --git a/linux-user/main.c b/linux-user/main.c
index 7d3cf45..8143a0d 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -755,8 +755,9 @@ int main(int argc, char **argv, char **envp)
/*
* Manage binfmt-misc open-binary flag
*/
+ errno = 0;
execfd = qemu_getauxval(AT_EXECFD);
- if (execfd == 0) {
+ if (errno != 0) {
execfd = open(exec_path, O_RDONLY);
if (execfd < 0) {
printf("Error while loading %s: %s\n", exec_path, strerror(errno));
diff --git a/linux-user/meson.build b/linux-user/meson.build
index bc41e8c..f75b4fe 100644
--- a/linux-user/meson.build
+++ b/linux-user/meson.build
@@ -38,6 +38,7 @@ gen_vdso = generator(gen_vdso_exe, output: '@BASENAME@.c.inc',
subdir('aarch64')
subdir('alpha')
subdir('arm')
+subdir('hexagon')
subdir('hppa')
subdir('i386')
subdir('loongarch64')
@@ -45,6 +46,7 @@ subdir('m68k')
subdir('microblaze')
subdir('mips64')
subdir('mips')
+subdir('openrisc')
subdir('ppc')
subdir('riscv')
subdir('s390x')
diff --git a/linux-user/microblaze/syscall.tbl b/linux-user/microblaze/syscall.tbl
index b11395a..e3b6438 100644
--- a/linux-user/microblaze/syscall.tbl
+++ b/linux-user/microblaze/syscall.tbl
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
#
# system call numbers and entry vectors for microblaze
#
@@ -141,7 +141,7 @@
131 common quotactl sys_quotactl
132 common getpgid sys_getpgid
133 common fchdir sys_fchdir
-134 common bdflush sys_bdflush
+134 common bdflush sys_ni_syscall
135 common sysfs sys_sysfs
136 common personality sys_personality
137 common afs_syscall sys_ni_syscall
@@ -260,7 +260,7 @@
250 common fadvise64 sys_fadvise64
# 251 is available for reuse (was briefly sys_set_zone_reclaim)
252 common exit_group sys_exit_group
-253 common lookup_dcookie sys_lookup_dcookie
+253 common lookup_dcookie sys_ni_syscall
254 common epoll_create sys_epoll_create
255 common epoll_ctl sys_epoll_ctl
256 common epoll_wait sys_epoll_wait
@@ -448,7 +448,23 @@
440 common process_madvise sys_process_madvise
441 common epoll_pwait2 sys_epoll_pwait2
442 common mount_setattr sys_mount_setattr
-# 443 reserved for quotactl_path
+443 common quotactl_fd sys_quotactl_fd
444 common landlock_create_ruleset sys_landlock_create_ruleset
445 common landlock_add_rule sys_landlock_add_rule
446 common landlock_restrict_self sys_landlock_restrict_self
+# 447 reserved for memfd_secret
+448 common process_mrelease sys_process_mrelease
+449 common futex_waitv sys_futex_waitv
+450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common cachestat sys_cachestat
+452 common fchmodat2 sys_fchmodat2
+453 common map_shadow_stack sys_map_shadow_stack
+454 common futex_wake sys_futex_wake
+455 common futex_wait sys_futex_wait
+456 common futex_requeue sys_futex_requeue
+457 common statmount sys_statmount
+458 common listmount sys_listmount
+459 common lsm_get_self_attr sys_lsm_get_self_attr
+460 common lsm_set_self_attr sys_lsm_set_self_attr
+461 common lsm_list_modules sys_lsm_list_modules
+462 common mseal sys_mseal
diff --git a/linux-user/microblaze/syscallhdr.sh b/linux-user/microblaze/syscallhdr.sh
index f55dce8a..b42b669 100644
--- a/linux-user/microblaze/syscallhdr.sh
+++ b/linux-user/microblaze/syscallhdr.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
in="$1"
out="$2"
diff --git a/linux-user/mips/syscall-args-o32.c.inc b/linux-user/mips/syscall-args-o32.c.inc
index a6a2c5c..780c0a8 100644
--- a/linux-user/mips/syscall-args-o32.c.inc
+++ b/linux-user/mips/syscall-args-o32.c.inc
@@ -441,3 +441,23 @@
[ 440] = 5, /* process_madvise */
[ 441] = 6, /* epoll_pwait2 */
[ 442] = 5, /* mount_setattr */
+ [ 443] = 4, /* quotactl_fd */
+ [ 444] = 3, /* landlock_create_ruleset */
+ [ 445] = 4, /* landlock_add_rule */
+ [ 446] = 2, /* landlock_restrict_self */
+ [ 447] = 1, /* memfd_secret */
+ [ 448] = 2, /* process_mrelease */
+ [ 449] = 5, /* futex_waitv */
+ [ 450] = 4, /* set_mempolicy_home_node */
+ [ 451] = 4, /* cachestat */
+ [ 452] = 4, /* fchmodat2 */
+ [ 453] = 3, /* map_shadow_stack */
+ [ 454] = 4, /* futex_wake */
+ [ 455] = 6, /* futex_wait */
+ [ 456] = 4, /* futex_requeue */
+ [ 457] = 4, /* statmount */
+ [ 458] = 4, /* listmount */
+ [ 459] = 4, /* lsm_get_self_attr */
+ [ 460] = 4, /* lsm_set_self_attr */
+ [ 461] = 3, /* lsm_list_modules */
+ [ 462] = 3, /* mseal */
diff --git a/linux-user/mips/syscall_o32.tbl b/linux-user/mips/syscall_o32.tbl
index d560c46..360055c 100644
--- a/linux-user/mips/syscall_o32.tbl
+++ b/linux-user/mips/syscall_o32.tbl
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
#
# system call numbers and entry vectors for mips
#
@@ -27,7 +27,7 @@
17 o32 break sys_ni_syscall
# 18 was sys_stat
18 o32 unused18 sys_ni_syscall
-19 o32 lseek sys_lseek
+19 o32 lseek sys_lseek compat_sys_lseek
20 o32 getpid sys_getpid
21 o32 mount sys_mount
22 o32 umount sys_oldumount
@@ -145,7 +145,7 @@
131 o32 quotactl sys_quotactl
132 o32 getpgid sys_getpgid
133 o32 fchdir sys_fchdir
-134 o32 bdflush sys_bdflush
+134 o32 bdflush sys_ni_syscall
135 o32 sysfs sys_sysfs
136 o32 personality sys_personality sys_32_personality
137 o32 afs_syscall sys_ni_syscall
@@ -258,7 +258,7 @@
244 o32 io_submit sys_io_submit compat_sys_io_submit
245 o32 io_cancel sys_io_cancel
246 o32 exit_group sys_exit_group
-247 o32 lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie
+247 o32 lookup_dcookie sys_ni_syscall
248 o32 epoll_create sys_epoll_create
249 o32 epoll_ctl sys_epoll_ctl
250 o32 epoll_wait sys_epoll_wait
@@ -279,9 +279,9 @@
265 o32 clock_nanosleep sys_clock_nanosleep_time32
266 o32 tgkill sys_tgkill
267 o32 utimes sys_utimes_time32
-268 o32 mbind sys_mbind compat_sys_mbind
-269 o32 get_mempolicy sys_get_mempolicy compat_sys_get_mempolicy
-270 o32 set_mempolicy sys_set_mempolicy compat_sys_set_mempolicy
+268 o32 mbind sys_mbind
+269 o32 get_mempolicy sys_get_mempolicy
+270 o32 set_mempolicy sys_set_mempolicy
271 o32 mq_open sys_mq_open compat_sys_mq_open
272 o32 mq_unlink sys_mq_unlink
273 o32 mq_timedsend sys_mq_timedsend_time32
@@ -298,7 +298,7 @@
284 o32 inotify_init sys_inotify_init
285 o32 inotify_add_watch sys_inotify_add_watch
286 o32 inotify_rm_watch sys_inotify_rm_watch
-287 o32 migrate_pages sys_migrate_pages compat_sys_migrate_pages
+287 o32 migrate_pages sys_migrate_pages
288 o32 openat sys_openat compat_sys_openat
289 o32 mkdirat sys_mkdirat
290 o32 mknodat sys_mknodat
@@ -319,7 +319,7 @@
305 o32 sync_file_range sys_sync_file_range sys32_sync_file_range
306 o32 tee sys_tee
307 o32 vmsplice sys_vmsplice
-308 o32 move_pages sys_move_pages compat_sys_move_pages
+308 o32 move_pages sys_move_pages
309 o32 set_robust_list sys_set_robust_list compat_sys_set_robust_list
310 o32 get_robust_list sys_get_robust_list compat_sys_get_robust_list
311 o32 kexec_load sys_kexec_load compat_sys_kexec_load
@@ -403,7 +403,7 @@
412 o32 utimensat_time64 sys_utimensat sys_utimensat
413 o32 pselect6_time64 sys_pselect6 compat_sys_pselect6_time64
414 o32 ppoll_time64 sys_ppoll compat_sys_ppoll_time64
-416 o32 io_pgetevents_time64 sys_io_pgetevents sys_io_pgetevents
+416 o32 io_pgetevents_time64 sys_io_pgetevents compat_sys_io_pgetevents_time64
417 o32 recvmmsg_time64 sys_recvmmsg compat_sys_recvmmsg_time64
418 o32 mq_timedsend_time64 sys_mq_timedsend sys_mq_timedsend
419 o32 mq_timedreceive_time64 sys_mq_timedreceive sys_mq_timedreceive
@@ -430,7 +430,23 @@
440 o32 process_madvise sys_process_madvise
441 o32 epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
442 o32 mount_setattr sys_mount_setattr
-# 443 reserved for quotactl_path
+443 o32 quotactl_fd sys_quotactl_fd
444 o32 landlock_create_ruleset sys_landlock_create_ruleset
445 o32 landlock_add_rule sys_landlock_add_rule
446 o32 landlock_restrict_self sys_landlock_restrict_self
+# 447 reserved for memfd_secret
+448 o32 process_mrelease sys_process_mrelease
+449 o32 futex_waitv sys_futex_waitv
+450 o32 set_mempolicy_home_node sys_set_mempolicy_home_node
+451 o32 cachestat sys_cachestat
+452 o32 fchmodat2 sys_fchmodat2
+453 o32 map_shadow_stack sys_map_shadow_stack
+454 o32 futex_wake sys_futex_wake
+455 o32 futex_wait sys_futex_wait
+456 o32 futex_requeue sys_futex_requeue
+457 o32 statmount sys_statmount
+458 o32 listmount sys_listmount
+459 o32 lsm_get_self_attr sys_lsm_get_self_attr
+460 o32 lsm_set_self_attr sys_lsm_set_self_attr
+461 o32 lsm_list_modules sys_lsm_list_modules
+462 o32 mseal sys_mseal
diff --git a/linux-user/mips/syscallhdr.sh b/linux-user/mips/syscallhdr.sh
index 761e3e4..cd7043e 100644
--- a/linux-user/mips/syscallhdr.sh
+++ b/linux-user/mips/syscallhdr.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
in="$1"
out="$2"
diff --git a/linux-user/mips/target_elf.h b/linux-user/mips/target_elf.h
index b965e86..71a3231 100644
--- a/linux-user/mips/target_elf.h
+++ b/linux-user/mips/target_elf.h
@@ -12,9 +12,6 @@ static inline const char *cpu_get_model(uint32_t eflags)
if ((eflags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R6) {
return "mips32r6-generic";
}
- if ((eflags & EF_MIPS_MACH) == EF_MIPS_MACH_5900) {
- return "R5900";
- }
if (eflags & EF_MIPS_NAN2008) {
return "P5600";
}
diff --git a/linux-user/mips64/syscall_n32.tbl b/linux-user/mips64/syscall_n32.tbl
index 9220909..793eca6 100644
--- a/linux-user/mips64/syscall_n32.tbl
+++ b/linux-user/mips64/syscall_n32.tbl
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
#
# system call numbers and entry vectors for mips
#
@@ -214,7 +214,7 @@
203 n32 io_submit compat_sys_io_submit
204 n32 io_cancel sys_io_cancel
205 n32 exit_group sys_exit_group
-206 n32 lookup_dcookie sys_lookup_dcookie
+206 n32 lookup_dcookie sys_ni_syscall
207 n32 epoll_create sys_epoll_create
208 n32 epoll_ctl sys_epoll_ctl
209 n32 epoll_wait sys_epoll_wait
@@ -239,9 +239,9 @@
228 n32 clock_nanosleep sys_clock_nanosleep_time32
229 n32 tgkill sys_tgkill
230 n32 utimes sys_utimes_time32
-231 n32 mbind compat_sys_mbind
-232 n32 get_mempolicy compat_sys_get_mempolicy
-233 n32 set_mempolicy compat_sys_set_mempolicy
+231 n32 mbind sys_mbind
+232 n32 get_mempolicy sys_get_mempolicy
+233 n32 set_mempolicy sys_set_mempolicy
234 n32 mq_open compat_sys_mq_open
235 n32 mq_unlink sys_mq_unlink
236 n32 mq_timedsend sys_mq_timedsend_time32
@@ -258,7 +258,7 @@
247 n32 inotify_init sys_inotify_init
248 n32 inotify_add_watch sys_inotify_add_watch
249 n32 inotify_rm_watch sys_inotify_rm_watch
-250 n32 migrate_pages compat_sys_migrate_pages
+250 n32 migrate_pages sys_migrate_pages
251 n32 openat sys_openat
252 n32 mkdirat sys_mkdirat
253 n32 mknodat sys_mknodat
@@ -279,7 +279,7 @@
268 n32 sync_file_range sys_sync_file_range
269 n32 tee sys_tee
270 n32 vmsplice sys_vmsplice
-271 n32 move_pages compat_sys_move_pages
+271 n32 move_pages sys_move_pages
272 n32 set_robust_list compat_sys_set_robust_list
273 n32 get_robust_list compat_sys_get_robust_list
274 n32 kexec_load compat_sys_kexec_load
@@ -354,7 +354,7 @@
412 n32 utimensat_time64 sys_utimensat
413 n32 pselect6_time64 compat_sys_pselect6_time64
414 n32 ppoll_time64 compat_sys_ppoll_time64
-416 n32 io_pgetevents_time64 sys_io_pgetevents
+416 n32 io_pgetevents_time64 compat_sys_io_pgetevents_time64
417 n32 recvmmsg_time64 compat_sys_recvmmsg_time64
418 n32 mq_timedsend_time64 sys_mq_timedsend
419 n32 mq_timedreceive_time64 sys_mq_timedreceive
@@ -381,7 +381,23 @@
440 n32 process_madvise sys_process_madvise
441 n32 epoll_pwait2 compat_sys_epoll_pwait2
442 n32 mount_setattr sys_mount_setattr
-# 443 reserved for quotactl_path
+443 n32 quotactl_fd sys_quotactl_fd
444 n32 landlock_create_ruleset sys_landlock_create_ruleset
445 n32 landlock_add_rule sys_landlock_add_rule
446 n32 landlock_restrict_self sys_landlock_restrict_self
+# 447 reserved for memfd_secret
+448 n32 process_mrelease sys_process_mrelease
+449 n32 futex_waitv sys_futex_waitv
+450 n32 set_mempolicy_home_node sys_set_mempolicy_home_node
+451 n32 cachestat sys_cachestat
+452 n32 fchmodat2 sys_fchmodat2
+453 n32 map_shadow_stack sys_map_shadow_stack
+454 n32 futex_wake sys_futex_wake
+455 n32 futex_wait sys_futex_wait
+456 n32 futex_requeue sys_futex_requeue
+457 n32 statmount sys_statmount
+458 n32 listmount sys_listmount
+459 n32 lsm_get_self_attr sys_lsm_get_self_attr
+460 n32 lsm_set_self_attr sys_lsm_set_self_attr
+461 n32 lsm_list_modules sys_lsm_list_modules
+462 n32 mseal sys_mseal
diff --git a/linux-user/mips64/syscall_n64.tbl b/linux-user/mips64/syscall_n64.tbl
index 9cd1c34..ebff531 100644
--- a/linux-user/mips64/syscall_n64.tbl
+++ b/linux-user/mips64/syscall_n64.tbl
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
#
# system call numbers and entry vectors for mips
#
@@ -214,7 +214,7 @@
203 n64 io_submit sys_io_submit
204 n64 io_cancel sys_io_cancel
205 n64 exit_group sys_exit_group
-206 n64 lookup_dcookie sys_lookup_dcookie
+206 n64 lookup_dcookie sys_ni_syscall
207 n64 epoll_create sys_epoll_create
208 n64 epoll_ctl sys_epoll_ctl
209 n64 epoll_wait sys_epoll_wait
@@ -357,7 +357,23 @@
440 n64 process_madvise sys_process_madvise
441 n64 epoll_pwait2 sys_epoll_pwait2
442 n64 mount_setattr sys_mount_setattr
-# 443 reserved for quotactl_path
+443 n64 quotactl_fd sys_quotactl_fd
444 n64 landlock_create_ruleset sys_landlock_create_ruleset
445 n64 landlock_add_rule sys_landlock_add_rule
446 n64 landlock_restrict_self sys_landlock_restrict_self
+# 447 reserved for memfd_secret
+448 n64 process_mrelease sys_process_mrelease
+449 n64 futex_waitv sys_futex_waitv
+450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 n64 cachestat sys_cachestat
+452 n64 fchmodat2 sys_fchmodat2
+453 n64 map_shadow_stack sys_map_shadow_stack
+454 n64 futex_wake sys_futex_wake
+455 n64 futex_wait sys_futex_wait
+456 n64 futex_requeue sys_futex_requeue
+457 n64 statmount sys_statmount
+458 n64 listmount sys_listmount
+459 n64 lsm_get_self_attr sys_lsm_get_self_attr
+460 n64 lsm_set_self_attr sys_lsm_set_self_attr
+461 n64 lsm_list_modules sys_lsm_list_modules
+462 n64 mseal sys_mseal
diff --git a/linux-user/mips64/syscallhdr.sh b/linux-user/mips64/syscallhdr.sh
index ed5a451..a4339b2 100644
--- a/linux-user/mips64/syscallhdr.sh
+++ b/linux-user/mips64/syscallhdr.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
in="$1"
out="$2"
diff --git a/linux-user/mips64/target_elf.h b/linux-user/mips64/target_elf.h
index 5f2f2df..502af9d 100644
--- a/linux-user/mips64/target_elf.h
+++ b/linux-user/mips64/target_elf.h
@@ -9,11 +9,27 @@
#define MIPS64_TARGET_ELF_H
static inline const char *cpu_get_model(uint32_t eflags)
{
- if ((eflags & EF_MIPS_ARCH) == EF_MIPS_ARCH_64R6) {
- return "I6400";
+ switch (eflags & EF_MIPS_MACH) {
+ case EF_MIPS_MACH_OCTEON:
+ case EF_MIPS_MACH_OCTEON2:
+ case EF_MIPS_MACH_OCTEON3:
+ return "Octeon68XX";
+ case EF_MIPS_MACH_LS2E:
+ return "Loongson-2E";
+ case EF_MIPS_MACH_LS2F:
+ return "Loongson-2F";
+ case EF_MIPS_MACH_LS3A:
+ return "Loongson-3A1000";
+ default:
+ break;
}
- if ((eflags & EF_MIPS_MACH) == EF_MIPS_MACH_5900) {
- return "R5900";
+ switch (eflags & EF_MIPS_ARCH) {
+ case EF_MIPS_ARCH_64R6:
+ return "I6400";
+ case EF_MIPS_ARCH_64R2:
+ return "MIPS64R2-generic";
+ default:
+ break;
}
return "5KEf";
}
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index 4d09a72..e4bf5d5 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -284,6 +284,40 @@ static int do_munmap(void *addr, size_t len)
}
/*
+ * Perform a pread on behalf of target_mmap. We can reach EOF, we can be
+ * interrupted by signals, and in general there's no good error return path.
+ * If @zero, zero the rest of the block at EOF.
+ * Return true on success.
+ */
+static bool mmap_pread(int fd, void *p, size_t len, off_t offset, bool zero)
+{
+ while (1) {
+ ssize_t r = pread(fd, p, len, offset);
+
+ if (likely(r == len)) {
+ /* Complete */
+ return true;
+ }
+ if (r == 0) {
+ /* EOF */
+ if (zero) {
+ memset(p, 0, len);
+ }
+ return true;
+ }
+ if (r > 0) {
+ /* Short read */
+ p += r;
+ len -= r;
+ offset += r;
+ } else if (errno != EINTR) {
+ /* Error */
+ return false;
+ }
+ }
+}
+
+/*
* Map an incomplete host page.
*
* Here be dragons. This case will not work if there is an existing
@@ -357,10 +391,9 @@ static bool mmap_frag(abi_ulong real_start, abi_ulong start, abi_ulong last,
/* Read or zero the new guest pages. */
if (flags & MAP_ANONYMOUS) {
memset(g2h_untagged(start), 0, last - start + 1);
- } else {
- if (pread(fd, g2h_untagged(start), last - start + 1, offset) == -1) {
- return false;
- }
+ } else if (!mmap_pread(fd, g2h_untagged(start), last - start + 1,
+ offset, true)) {
+ return false;
}
/* Put final protection */
@@ -560,9 +593,13 @@ static abi_long mmap_h_eq_g(abi_ulong start, abi_ulong len,
int host_prot, int flags, int page_flags,
int fd, off_t offset)
{
- void *p, *want_p = g2h_untagged(start);
+ void *p, *want_p = NULL;
abi_ulong last;
+ if (start || (flags & (MAP_FIXED | MAP_FIXED_NOREPLACE))) {
+ want_p = g2h_untagged(start);
+ }
+
p = mmap(want_p, len, host_prot, flags, fd, offset);
if (p == MAP_FAILED) {
return -1;
@@ -610,11 +647,15 @@ static abi_long mmap_h_lt_g(abi_ulong start, abi_ulong len, int host_prot,
int mmap_flags, int page_flags, int fd,
off_t offset, int host_page_size)
{
- void *p, *want_p = g2h_untagged(start);
+ void *p, *want_p = NULL;
off_t fileend_adj = 0;
int flags = mmap_flags;
abi_ulong last, pass_last;
+ if (start || (flags & (MAP_FIXED | MAP_FIXED_NOREPLACE))) {
+ want_p = g2h_untagged(start);
+ }
+
if (!(flags & MAP_ANONYMOUS)) {
struct stat sb;
@@ -740,12 +781,16 @@ static abi_long mmap_h_gt_g(abi_ulong start, abi_ulong len,
int flags, int page_flags, int fd,
off_t offset, int host_page_size)
{
- void *p, *want_p = g2h_untagged(start);
+ void *p, *want_p = NULL;
off_t host_offset = offset & -host_page_size;
abi_ulong last, real_start, real_last;
bool misaligned_offset = false;
size_t host_len;
+ if (start || (flags & (MAP_FIXED | MAP_FIXED_NOREPLACE))) {
+ want_p = g2h_untagged(start);
+ }
+
if (!(flags & (MAP_FIXED | MAP_FIXED_NOREPLACE))) {
/*
* Adjust the offset to something representable on the host.
@@ -841,8 +886,7 @@ static abi_long mmap_h_gt_g(abi_ulong start, abi_ulong len,
}
if (misaligned_offset) {
- /* TODO: The read could be short. */
- if (pread(fd, p, host_len, offset + real_start - start) != host_len) {
+ if (!mmap_pread(fd, p, host_len, offset + real_start - start, false)) {
do_munmap(p, host_len);
return -1;
}
diff --git a/linux-user/openrisc/meson.build b/linux-user/openrisc/meson.build
new file mode 100644
index 0000000..273e7a0
--- /dev/null
+++ b/linux-user/openrisc/meson.build
@@ -0,0 +1,5 @@
+syscall_nr_generators += {
+ 'openrisc': generator(sh,
+ arguments: [ meson.current_source_dir() / 'syscallhdr.sh', '@INPUT@', '@OUTPUT@', '@EXTRA_ARGS@' ],
+ output: '@BASENAME@_nr.h')
+}
diff --git a/linux-user/openrisc/syscall.tbl b/linux-user/openrisc/syscall.tbl
new file mode 100644
index 0000000..845e24e
--- /dev/null
+++ b/linux-user/openrisc/syscall.tbl
@@ -0,0 +1,405 @@
+# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+#
+# This file contains the system call numbers for all of the
+# more recently added architectures.
+#
+# As a basic principle, no duplication of functionality
+# should be added, e.g. we don't use lseek when llseek
+# is present. New architectures should use this file
+# and implement the less feature-full calls in user space.
+#
+0 common io_setup sys_io_setup compat_sys_io_setup
+1 common io_destroy sys_io_destroy
+2 common io_submit sys_io_submit compat_sys_io_submit
+3 common io_cancel sys_io_cancel
+4 time32 io_getevents sys_io_getevents_time32
+4 64 io_getevents sys_io_getevents
+5 common setxattr sys_setxattr
+6 common lsetxattr sys_lsetxattr
+7 common fsetxattr sys_fsetxattr
+8 common getxattr sys_getxattr
+9 common lgetxattr sys_lgetxattr
+10 common fgetxattr sys_fgetxattr
+11 common listxattr sys_listxattr
+12 common llistxattr sys_llistxattr
+13 common flistxattr sys_flistxattr
+14 common removexattr sys_removexattr
+15 common lremovexattr sys_lremovexattr
+16 common fremovexattr sys_fremovexattr
+17 common getcwd sys_getcwd
+18 common lookup_dcookie sys_ni_syscall
+19 common eventfd2 sys_eventfd2
+20 common epoll_create1 sys_epoll_create1
+21 common epoll_ctl sys_epoll_ctl
+22 common epoll_pwait sys_epoll_pwait compat_sys_epoll_pwait
+23 common dup sys_dup
+24 common dup3 sys_dup3
+25 32 fcntl64 sys_fcntl64 compat_sys_fcntl64
+25 64 fcntl sys_fcntl
+26 common inotify_init1 sys_inotify_init1
+27 common inotify_add_watch sys_inotify_add_watch
+28 common inotify_rm_watch sys_inotify_rm_watch
+29 common ioctl sys_ioctl compat_sys_ioctl
+30 common ioprio_set sys_ioprio_set
+31 common ioprio_get sys_ioprio_get
+32 common flock sys_flock
+33 common mknodat sys_mknodat
+34 common mkdirat sys_mkdirat
+35 common unlinkat sys_unlinkat
+36 common symlinkat sys_symlinkat
+37 common linkat sys_linkat
+# renameat is superseded with flags by renameat2
+38 renameat renameat sys_renameat
+39 common umount2 sys_umount
+40 common mount sys_mount
+41 common pivot_root sys_pivot_root
+42 common nfsservctl sys_ni_syscall
+43 32 statfs64 sys_statfs64 compat_sys_statfs64
+43 64 statfs sys_statfs
+44 32 fstatfs64 sys_fstatfs64 compat_sys_fstatfs64
+44 64 fstatfs sys_fstatfs
+45 32 truncate64 sys_truncate64 compat_sys_truncate64
+45 64 truncate sys_truncate
+46 32 ftruncate64 sys_ftruncate64 compat_sys_ftruncate64
+46 64 ftruncate sys_ftruncate
+47 common fallocate sys_fallocate compat_sys_fallocate
+48 common faccessat sys_faccessat
+49 common chdir sys_chdir
+50 common fchdir sys_fchdir
+51 common chroot sys_chroot
+52 common fchmod sys_fchmod
+53 common fchmodat sys_fchmodat
+54 common fchownat sys_fchownat
+55 common fchown sys_fchown
+56 common openat sys_openat
+57 common close sys_close
+58 common vhangup sys_vhangup
+59 common pipe2 sys_pipe2
+60 common quotactl sys_quotactl
+61 common getdents64 sys_getdents64
+62 32 llseek sys_llseek
+62 64 lseek sys_lseek
+63 common read sys_read
+64 common write sys_write
+65 common readv sys_readv sys_readv
+66 common writev sys_writev sys_writev
+67 common pread64 sys_pread64 compat_sys_pread64
+68 common pwrite64 sys_pwrite64 compat_sys_pwrite64
+69 common preadv sys_preadv compat_sys_preadv
+70 common pwritev sys_pwritev compat_sys_pwritev
+71 32 sendfile64 sys_sendfile64
+71 64 sendfile sys_sendfile64
+72 time32 pselect6 sys_pselect6_time32 compat_sys_pselect6_time32
+72 64 pselect6 sys_pselect6
+73 time32 ppoll sys_ppoll_time32 compat_sys_ppoll_time32
+73 64 ppoll sys_ppoll
+74 common signalfd4 sys_signalfd4 compat_sys_signalfd4
+75 common vmsplice sys_vmsplice
+76 common splice sys_splice
+77 common tee sys_tee
+78 common readlinkat sys_readlinkat
+79 stat64 fstatat64 sys_fstatat64
+79 64 newfstatat sys_newfstatat
+80 stat64 fstat64 sys_fstat64
+80 64 fstat sys_newfstat
+81 common sync sys_sync
+82 common fsync sys_fsync
+83 common fdatasync sys_fdatasync
+84 common sync_file_range sys_sync_file_range compat_sys_sync_file_range
+85 common timerfd_create sys_timerfd_create
+86 time32 timerfd_settime sys_timerfd_settime32
+86 64 timerfd_settime sys_timerfd_settime
+87 time32 timerfd_gettime sys_timerfd_gettime32
+87 64 timerfd_gettime sys_timerfd_gettime
+88 time32 utimensat sys_utimensat_time32
+88 64 utimensat sys_utimensat
+89 common acct sys_acct
+90 common capget sys_capget
+91 common capset sys_capset
+92 common personality sys_personality
+93 common exit sys_exit
+94 common exit_group sys_exit_group
+95 common waitid sys_waitid compat_sys_waitid
+96 common set_tid_address sys_set_tid_address
+97 common unshare sys_unshare
+98 time32 futex sys_futex_time32
+98 64 futex sys_futex
+99 common set_robust_list sys_set_robust_list compat_sys_set_robust_list
+100 common get_robust_list sys_get_robust_list compat_sys_get_robust_list
+101 time32 nanosleep sys_nanosleep_time32
+101 64 nanosleep sys_nanosleep
+102 common getitimer sys_getitimer compat_sys_getitimer
+103 common setitimer sys_setitimer compat_sys_setitimer
+104 common kexec_load sys_kexec_load compat_sys_kexec_load
+105 common init_module sys_init_module
+106 common delete_module sys_delete_module
+107 common timer_create sys_timer_create compat_sys_timer_create
+108 time32 timer_gettime sys_timer_gettime32
+108 64 timer_gettime sys_timer_gettime
+109 common timer_getoverrun sys_timer_getoverrun
+110 time32 timer_settime sys_timer_settime32
+110 64 timer_settime sys_timer_settime
+111 common timer_delete sys_timer_delete
+112 time32 clock_settime sys_clock_settime32
+112 64 clock_settime sys_clock_settime
+113 time32 clock_gettime sys_clock_gettime32
+113 64 clock_gettime sys_clock_gettime
+114 time32 clock_getres sys_clock_getres_time32
+114 64 clock_getres sys_clock_getres
+115 time32 clock_nanosleep sys_clock_nanosleep_time32
+115 64 clock_nanosleep sys_clock_nanosleep
+116 common syslog sys_syslog
+117 common ptrace sys_ptrace compat_sys_ptrace
+118 common sched_setparam sys_sched_setparam
+119 common sched_setscheduler sys_sched_setscheduler
+120 common sched_getscheduler sys_sched_getscheduler
+121 common sched_getparam sys_sched_getparam
+122 common sched_setaffinity sys_sched_setaffinity compat_sys_sched_setaffinity
+123 common sched_getaffinity sys_sched_getaffinity compat_sys_sched_getaffinity
+124 common sched_yield sys_sched_yield
+125 common sched_get_priority_max sys_sched_get_priority_max
+126 common sched_get_priority_min sys_sched_get_priority_min
+127 time32 sched_rr_get_interval sys_sched_rr_get_interval_time32
+127 64 sched_rr_get_interval sys_sched_rr_get_interval
+128 common restart_syscall sys_restart_syscall
+129 common kill sys_kill
+130 common tkill sys_tkill
+131 common tgkill sys_tgkill
+132 common sigaltstack sys_sigaltstack compat_sys_sigaltstack
+133 common rt_sigsuspend sys_rt_sigsuspend compat_sys_rt_sigsuspend
+134 common rt_sigaction sys_rt_sigaction compat_sys_rt_sigaction
+135 common rt_sigprocmask sys_rt_sigprocmask compat_sys_rt_sigprocmask
+136 common rt_sigpending sys_rt_sigpending compat_sys_rt_sigpending
+137 time32 rt_sigtimedwait sys_rt_sigtimedwait_time32 compat_sys_rt_sigtimedwait_time32
+137 64 rt_sigtimedwait sys_rt_sigtimedwait
+138 common rt_sigqueueinfo sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo
+139 common rt_sigreturn sys_rt_sigreturn compat_sys_rt_sigreturn
+140 common setpriority sys_setpriority
+141 common getpriority sys_getpriority
+142 common reboot sys_reboot
+143 common setregid sys_setregid
+144 common setgid sys_setgid
+145 common setreuid sys_setreuid
+146 common setuid sys_setuid
+147 common setresuid sys_setresuid
+148 common getresuid sys_getresuid
+149 common setresgid sys_setresgid
+150 common getresgid sys_getresgid
+151 common setfsuid sys_setfsuid
+152 common setfsgid sys_setfsgid
+153 common times sys_times compat_sys_times
+154 common setpgid sys_setpgid
+155 common getpgid sys_getpgid
+156 common getsid sys_getsid
+157 common setsid sys_setsid
+158 common getgroups sys_getgroups
+159 common setgroups sys_setgroups
+160 common uname sys_newuname
+161 common sethostname sys_sethostname
+162 common setdomainname sys_setdomainname
+# getrlimit and setrlimit are superseded with prlimit64
+163 rlimit getrlimit sys_getrlimit compat_sys_getrlimit
+164 rlimit setrlimit sys_setrlimit compat_sys_setrlimit
+165 common getrusage sys_getrusage compat_sys_getrusage
+166 common umask sys_umask
+167 common prctl sys_prctl
+168 common getcpu sys_getcpu
+169 time32 gettimeofday sys_gettimeofday compat_sys_gettimeofday
+169 64 gettimeofday sys_gettimeofday
+170 time32 settimeofday sys_settimeofday compat_sys_settimeofday
+170 64 settimeofday sys_settimeofday
+171 time32 adjtimex sys_adjtimex_time32
+171 64 adjtimex sys_adjtimex
+172 common getpid sys_getpid
+173 common getppid sys_getppid
+174 common getuid sys_getuid
+175 common geteuid sys_geteuid
+176 common getgid sys_getgid
+177 common getegid sys_getegid
+178 common gettid sys_gettid
+179 common sysinfo sys_sysinfo compat_sys_sysinfo
+180 common mq_open sys_mq_open compat_sys_mq_open
+181 common mq_unlink sys_mq_unlink
+182 time32 mq_timedsend sys_mq_timedsend_time32
+182 64 mq_timedsend sys_mq_timedsend
+183 time32 mq_timedreceive sys_mq_timedreceive_time32
+183 64 mq_timedreceive sys_mq_timedreceive
+184 common mq_notify sys_mq_notify compat_sys_mq_notify
+185 common mq_getsetattr sys_mq_getsetattr compat_sys_mq_getsetattr
+186 common msgget sys_msgget
+187 common msgctl sys_msgctl compat_sys_msgctl
+188 common msgrcv sys_msgrcv compat_sys_msgrcv
+189 common msgsnd sys_msgsnd compat_sys_msgsnd
+190 common semget sys_semget
+191 common semctl sys_semctl compat_sys_semctl
+192 time32 semtimedop sys_semtimedop_time32
+192 64 semtimedop sys_semtimedop
+193 common semop sys_semop
+194 common shmget sys_shmget
+195 common shmctl sys_shmctl compat_sys_shmctl
+196 common shmat sys_shmat compat_sys_shmat
+197 common shmdt sys_shmdt
+198 common socket sys_socket
+199 common socketpair sys_socketpair
+200 common bind sys_bind
+201 common listen sys_listen
+202 common accept sys_accept
+203 common connect sys_connect
+204 common getsockname sys_getsockname
+205 common getpeername sys_getpeername
+206 common sendto sys_sendto
+207 common recvfrom sys_recvfrom compat_sys_recvfrom
+208 common setsockopt sys_setsockopt sys_setsockopt
+209 common getsockopt sys_getsockopt sys_getsockopt
+210 common shutdown sys_shutdown
+211 common sendmsg sys_sendmsg compat_sys_sendmsg
+212 common recvmsg sys_recvmsg compat_sys_recvmsg
+213 common readahead sys_readahead compat_sys_readahead
+214 common brk sys_brk
+215 common munmap sys_munmap
+216 common mremap sys_mremap
+217 common add_key sys_add_key
+218 common request_key sys_request_key
+219 common keyctl sys_keyctl compat_sys_keyctl
+220 common clone sys_clone
+221 common execve sys_execve compat_sys_execve
+222 32 mmap2 sys_mmap2
+222 64 mmap sys_mmap
+223 32 fadvise64_64 sys_fadvise64_64 compat_sys_fadvise64_64
+223 64 fadvise64 sys_fadvise64_64
+224 common swapon sys_swapon
+225 common swapoff sys_swapoff
+226 common mprotect sys_mprotect
+227 common msync sys_msync
+228 common mlock sys_mlock
+229 common munlock sys_munlock
+230 common mlockall sys_mlockall
+231 common munlockall sys_munlockall
+232 common mincore sys_mincore
+233 common madvise sys_madvise
+234 common remap_file_pages sys_remap_file_pages
+235 common mbind sys_mbind
+236 common get_mempolicy sys_get_mempolicy
+237 common set_mempolicy sys_set_mempolicy
+238 common migrate_pages sys_migrate_pages
+239 common move_pages sys_move_pages
+240 common rt_tgsigqueueinfo sys_rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo
+241 common perf_event_open sys_perf_event_open
+242 common accept4 sys_accept4
+243 time32 recvmmsg sys_recvmmsg_time32 compat_sys_recvmmsg_time32
+243 64 recvmmsg sys_recvmmsg
+# Architectures may provide up to 16 syscalls of their own between 244 and 259
+244 arc cacheflush sys_cacheflush
+245 arc arc_settls sys_arc_settls
+246 arc arc_gettls sys_arc_gettls
+247 arc sysfs sys_sysfs
+248 arc arc_usr_cmpxchg sys_arc_usr_cmpxchg
+
+244 csky set_thread_area sys_set_thread_area
+245 csky cacheflush sys_cacheflush
+
+244 nios2 cacheflush sys_cacheflush
+
+244 or1k or1k_atomic sys_or1k_atomic
+
+258 riscv riscv_hwprobe sys_riscv_hwprobe
+259 riscv riscv_flush_icache sys_riscv_flush_icache
+
+260 time32 wait4 sys_wait4 compat_sys_wait4
+260 64 wait4 sys_wait4
+261 common prlimit64 sys_prlimit64
+262 common fanotify_init sys_fanotify_init
+263 common fanotify_mark sys_fanotify_mark
+264 common name_to_handle_at sys_name_to_handle_at
+265 common open_by_handle_at sys_open_by_handle_at
+266 time32 clock_adjtime sys_clock_adjtime32
+266 64 clock_adjtime sys_clock_adjtime
+267 common syncfs sys_syncfs
+268 common setns sys_setns
+269 common sendmmsg sys_sendmmsg compat_sys_sendmmsg
+270 common process_vm_readv sys_process_vm_readv
+271 common process_vm_writev sys_process_vm_writev
+272 common kcmp sys_kcmp
+273 common finit_module sys_finit_module
+274 common sched_setattr sys_sched_setattr
+275 common sched_getattr sys_sched_getattr
+276 common renameat2 sys_renameat2
+277 common seccomp sys_seccomp
+278 common getrandom sys_getrandom
+279 common memfd_create sys_memfd_create
+280 common bpf sys_bpf
+281 common execveat sys_execveat compat_sys_execveat
+282 common userfaultfd sys_userfaultfd
+283 common membarrier sys_membarrier
+284 common mlock2 sys_mlock2
+285 common copy_file_range sys_copy_file_range
+286 common preadv2 sys_preadv2 compat_sys_preadv2
+287 common pwritev2 sys_pwritev2 compat_sys_pwritev2
+288 common pkey_mprotect sys_pkey_mprotect
+289 common pkey_alloc sys_pkey_alloc
+290 common pkey_free sys_pkey_free
+291 common statx sys_statx
+292 time32 io_pgetevents sys_io_pgetevents_time32 compat_sys_io_pgetevents
+292 64 io_pgetevents sys_io_pgetevents
+293 common rseq sys_rseq
+294 common kexec_file_load sys_kexec_file_load
+# 295 through 402 are unassigned to sync up with generic numbers don't use
+403 32 clock_gettime64 sys_clock_gettime
+404 32 clock_settime64 sys_clock_settime
+405 32 clock_adjtime64 sys_clock_adjtime
+406 32 clock_getres_time64 sys_clock_getres
+407 32 clock_nanosleep_time64 sys_clock_nanosleep
+408 32 timer_gettime64 sys_timer_gettime
+409 32 timer_settime64 sys_timer_settime
+410 32 timerfd_gettime64 sys_timerfd_gettime
+411 32 timerfd_settime64 sys_timerfd_settime
+412 32 utimensat_time64 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 compat_sys_io_pgetevents_time64
+417 32 recvmmsg_time64 sys_recvmmsg compat_sys_recvmmsg_time64
+418 32 mq_timedsend_time64 sys_mq_timedsend
+419 32 mq_timedreceive_time64 sys_mq_timedreceive
+420 32 semtimedop_time64 sys_semtimedop
+421 32 rt_sigtimedwait_time64 sys_rt_sigtimedwait compat_sys_rt_sigtimedwait_time64
+422 32 futex_time64 sys_futex
+423 32 sched_rr_get_interval_time64 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 common clone3 sys_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
+440 common process_madvise sys_process_madvise
+441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
+442 common mount_setattr sys_mount_setattr
+443 common quotactl_fd sys_quotactl_fd
+444 common landlock_create_ruleset sys_landlock_create_ruleset
+445 common landlock_add_rule sys_landlock_add_rule
+446 common landlock_restrict_self sys_landlock_restrict_self
+447 memfd_secret memfd_secret sys_memfd_secret
+448 common process_mrelease sys_process_mrelease
+449 common futex_waitv sys_futex_waitv
+450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common cachestat sys_cachestat
+452 common fchmodat2 sys_fchmodat2
+453 common map_shadow_stack sys_map_shadow_stack
+454 common futex_wake sys_futex_wake
+455 common futex_wait sys_futex_wait
+456 common futex_requeue sys_futex_requeue
+457 common statmount sys_statmount
+458 common listmount sys_listmount
+459 common lsm_get_self_attr sys_lsm_get_self_attr
+460 common lsm_set_self_attr sys_lsm_set_self_attr
+461 common lsm_list_modules sys_lsm_list_modules
+462 common mseal sys_mseal
diff --git a/linux-user/openrisc/syscall_nr.h b/linux-user/openrisc/syscall_nr.h
deleted file mode 100644
index f7faddb..0000000
--- a/linux-user/openrisc/syscall_nr.h
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * This file contains the system call numbers.
- * Do not modify.
- * This file is generated by scripts/gensyscalls.sh
- */
-#ifndef LINUX_USER_OPENRISC_SYSCALL_NR_H
-#define LINUX_USER_OPENRISC_SYSCALL_NR_H
-
-#define TARGET_NR_io_setup 0
-#define TARGET_NR_or1k_atomic TARGET_NR_arch_specific_syscall
-#define TARGET_NR_io_destroy 1
-#define TARGET_NR_io_submit 2
-#define TARGET_NR_io_cancel 3
-#define TARGET_NR_io_getevents 4
-#define TARGET_NR_setxattr 5
-#define TARGET_NR_lsetxattr 6
-#define TARGET_NR_fsetxattr 7
-#define TARGET_NR_getxattr 8
-#define TARGET_NR_lgetxattr 9
-#define TARGET_NR_fgetxattr 10
-#define TARGET_NR_listxattr 11
-#define TARGET_NR_llistxattr 12
-#define TARGET_NR_flistxattr 13
-#define TARGET_NR_removexattr 14
-#define TARGET_NR_lremovexattr 15
-#define TARGET_NR_fremovexattr 16
-#define TARGET_NR_getcwd 17
-#define TARGET_NR_lookup_dcookie 18
-#define TARGET_NR_eventfd2 19
-#define TARGET_NR_epoll_create1 20
-#define TARGET_NR_epoll_ctl 21
-#define TARGET_NR_epoll_pwait 22
-#define TARGET_NR_dup 23
-#define TARGET_NR_dup3 24
-#define TARGET_NR_fcntl64 25
-#define TARGET_NR_inotify_init1 26
-#define TARGET_NR_inotify_add_watch 27
-#define TARGET_NR_inotify_rm_watch 28
-#define TARGET_NR_ioctl 29
-#define TARGET_NR_ioprio_set 30
-#define TARGET_NR_ioprio_get 31
-#define TARGET_NR_flock 32
-#define TARGET_NR_mknodat 33
-#define TARGET_NR_mkdirat 34
-#define TARGET_NR_unlinkat 35
-#define TARGET_NR_symlinkat 36
-#define TARGET_NR_linkat 37
-#define TARGET_NR_renameat 38
-#define TARGET_NR_umount2 39
-#define TARGET_NR_mount 40
-#define TARGET_NR_pivot_root 41
-#define TARGET_NR_nfsservctl 42
-#define TARGET_NR_statfs64 43
-#define TARGET_NR_fstatfs64 44
-#define TARGET_NR_truncate64 45
-#define TARGET_NR_ftruncate64 46
-#define TARGET_NR_fallocate 47
-#define TARGET_NR_faccessat 48
-#define TARGET_NR_chdir 49
-#define TARGET_NR_fchdir 50
-#define TARGET_NR_chroot 51
-#define TARGET_NR_fchmod 52
-#define TARGET_NR_fchmodat 53
-#define TARGET_NR_fchownat 54
-#define TARGET_NR_fchown 55
-#define TARGET_NR_openat 56
-#define TARGET_NR_close 57
-#define TARGET_NR_vhangup 58
-#define TARGET_NR_pipe2 59
-#define TARGET_NR_quotactl 60
-#define TARGET_NR_getdents64 61
-#define TARGET_NR_llseek 62
-#define TARGET_NR_read 63
-#define TARGET_NR_write 64
-#define TARGET_NR_readv 65
-#define TARGET_NR_writev 66
-#define TARGET_NR_pread64 67
-#define TARGET_NR_pwrite64 68
-#define TARGET_NR_preadv 69
-#define TARGET_NR_pwritev 70
-#define TARGET_NR_sendfile64 71
-#define TARGET_NR_pselect6 72
-#define TARGET_NR_ppoll 73
-#define TARGET_NR_signalfd4 74
-#define TARGET_NR_vmsplice 75
-#define TARGET_NR_splice 76
-#define TARGET_NR_tee 77
-#define TARGET_NR_readlinkat 78
-#define TARGET_NR_fstatat64 79
-#define TARGET_NR_fstat64 80
-#define TARGET_NR_sync 81
-#define TARGET_NR_fsync 82
-#define TARGET_NR_fdatasync 83
-#define TARGET_NR_sync_file_range 84
-#define TARGET_NR_timerfd_create 85
-#define TARGET_NR_timerfd_settime 86
-#define TARGET_NR_timerfd_gettime 87
-#define TARGET_NR_utimensat 88
-#define TARGET_NR_acct 89
-#define TARGET_NR_capget 90
-#define TARGET_NR_capset 91
-#define TARGET_NR_personality 92
-#define TARGET_NR_exit 93
-#define TARGET_NR_exit_group 94
-#define TARGET_NR_waitid 95
-#define TARGET_NR_set_tid_address 96
-#define TARGET_NR_unshare 97
-#define TARGET_NR_futex 98
-#define TARGET_NR_set_robust_list 99
-#define TARGET_NR_get_robust_list 100
-#define TARGET_NR_nanosleep 101
-#define TARGET_NR_getitimer 102
-#define TARGET_NR_setitimer 103
-#define TARGET_NR_kexec_load 104
-#define TARGET_NR_init_module 105
-#define TARGET_NR_delete_module 106
-#define TARGET_NR_timer_create 107
-#define TARGET_NR_timer_gettime 108
-#define TARGET_NR_timer_getoverrun 109
-#define TARGET_NR_timer_settime 110
-#define TARGET_NR_timer_delete 111
-#define TARGET_NR_clock_settime 112
-#define TARGET_NR_clock_gettime 113
-#define TARGET_NR_clock_getres 114
-#define TARGET_NR_clock_nanosleep 115
-#define TARGET_NR_syslog 116
-#define TARGET_NR_ptrace 117
-#define TARGET_NR_sched_setparam 118
-#define TARGET_NR_sched_setscheduler 119
-#define TARGET_NR_sched_getscheduler 120
-#define TARGET_NR_sched_getparam 121
-#define TARGET_NR_sched_setaffinity 122
-#define TARGET_NR_sched_getaffinity 123
-#define TARGET_NR_sched_yield 124
-#define TARGET_NR_sched_get_priority_max 125
-#define TARGET_NR_sched_get_priority_min 126
-#define TARGET_NR_sched_rr_get_interval 127
-#define TARGET_NR_restart_syscall 128
-#define TARGET_NR_kill 129
-#define TARGET_NR_tkill 130
-#define TARGET_NR_tgkill 131
-#define TARGET_NR_sigaltstack 132
-#define TARGET_NR_rt_sigsuspend 133
-#define TARGET_NR_rt_sigaction 134
-#define TARGET_NR_rt_sigprocmask 135
-#define TARGET_NR_rt_sigpending 136
-#define TARGET_NR_rt_sigtimedwait 137
-#define TARGET_NR_rt_sigqueueinfo 138
-#define TARGET_NR_rt_sigreturn 139
-#define TARGET_NR_setpriority 140
-#define TARGET_NR_getpriority 141
-#define TARGET_NR_reboot 142
-#define TARGET_NR_setregid 143
-#define TARGET_NR_setgid 144
-#define TARGET_NR_setreuid 145
-#define TARGET_NR_setuid 146
-#define TARGET_NR_setresuid 147
-#define TARGET_NR_getresuid 148
-#define TARGET_NR_setresgid 149
-#define TARGET_NR_getresgid 150
-#define TARGET_NR_setfsuid 151
-#define TARGET_NR_setfsgid 152
-#define TARGET_NR_times 153
-#define TARGET_NR_setpgid 154
-#define TARGET_NR_getpgid 155
-#define TARGET_NR_getsid 156
-#define TARGET_NR_setsid 157
-#define TARGET_NR_getgroups 158
-#define TARGET_NR_setgroups 159
-#define TARGET_NR_uname 160
-#define TARGET_NR_sethostname 161
-#define TARGET_NR_setdomainname 162
-#define TARGET_NR_getrlimit 163
-#define TARGET_NR_setrlimit 164
-#define TARGET_NR_getrusage 165
-#define TARGET_NR_umask 166
-#define TARGET_NR_prctl 167
-#define TARGET_NR_getcpu 168
-#define TARGET_NR_gettimeofday 169
-#define TARGET_NR_settimeofday 170
-#define TARGET_NR_adjtimex 171
-#define TARGET_NR_getpid 172
-#define TARGET_NR_getppid 173
-#define TARGET_NR_getuid 174
-#define TARGET_NR_geteuid 175
-#define TARGET_NR_getgid 176
-#define TARGET_NR_getegid 177
-#define TARGET_NR_gettid 178
-#define TARGET_NR_sysinfo 179
-#define TARGET_NR_mq_open 180
-#define TARGET_NR_mq_unlink 181
-#define TARGET_NR_mq_timedsend 182
-#define TARGET_NR_mq_timedreceive 183
-#define TARGET_NR_mq_notify 184
-#define TARGET_NR_mq_getsetattr 185
-#define TARGET_NR_msgget 186
-#define TARGET_NR_msgctl 187
-#define TARGET_NR_msgrcv 188
-#define TARGET_NR_msgsnd 189
-#define TARGET_NR_semget 190
-#define TARGET_NR_semctl 191
-#define TARGET_NR_semtimedop 192
-#define TARGET_NR_semop 193
-#define TARGET_NR_shmget 194
-#define TARGET_NR_shmctl 195
-#define TARGET_NR_shmat 196
-#define TARGET_NR_shmdt 197
-#define TARGET_NR_socket 198
-#define TARGET_NR_socketpair 199
-#define TARGET_NR_bind 200
-#define TARGET_NR_listen 201
-#define TARGET_NR_accept 202
-#define TARGET_NR_connect 203
-#define TARGET_NR_getsockname 204
-#define TARGET_NR_getpeername 205
-#define TARGET_NR_sendto 206
-#define TARGET_NR_recvfrom 207
-#define TARGET_NR_setsockopt 208
-#define TARGET_NR_getsockopt 209
-#define TARGET_NR_shutdown 210
-#define TARGET_NR_sendmsg 211
-#define TARGET_NR_recvmsg 212
-#define TARGET_NR_readahead 213
-#define TARGET_NR_brk 214
-#define TARGET_NR_munmap 215
-#define TARGET_NR_mremap 216
-#define TARGET_NR_add_key 217
-#define TARGET_NR_request_key 218
-#define TARGET_NR_keyctl 219
-#define TARGET_NR_clone 220
-#define TARGET_NR_execve 221
-#define TARGET_NR_mmap2 222
-#define TARGET_NR_fadvise64_64 223
-#define TARGET_NR_swapon 224
-#define TARGET_NR_swapoff 225
-#define TARGET_NR_mprotect 226
-#define TARGET_NR_msync 227
-#define TARGET_NR_mlock 228
-#define TARGET_NR_munlock 229
-#define TARGET_NR_mlockall 230
-#define TARGET_NR_munlockall 231
-#define TARGET_NR_mincore 232
-#define TARGET_NR_madvise 233
-#define TARGET_NR_remap_file_pages 234
-#define TARGET_NR_mbind 235
-#define TARGET_NR_get_mempolicy 236
-#define TARGET_NR_set_mempolicy 237
-#define TARGET_NR_migrate_pages 238
-#define TARGET_NR_move_pages 239
-#define TARGET_NR_rt_tgsigqueueinfo 240
-#define TARGET_NR_perf_event_open 241
-#define TARGET_NR_accept4 242
-#define TARGET_NR_recvmmsg 243
-#define TARGET_NR_arch_specific_syscall 244
-#define TARGET_NR_wait4 260
-#define TARGET_NR_prlimit64 261
-#define TARGET_NR_fanotify_init 262
-#define TARGET_NR_fanotify_mark 263
-#define TARGET_NR_name_to_handle_at 264
-#define TARGET_NR_open_by_handle_at 265
-#define TARGET_NR_clock_adjtime 266
-#define TARGET_NR_syncfs 267
-#define TARGET_NR_setns 268
-#define TARGET_NR_sendmmsg 269
-#define TARGET_NR_process_vm_readv 270
-#define TARGET_NR_process_vm_writev 271
-#define TARGET_NR_kcmp 272
-#define TARGET_NR_finit_module 273
-#define TARGET_NR_sched_setattr 274
-#define TARGET_NR_sched_getattr 275
-#define TARGET_NR_renameat2 276
-#define TARGET_NR_seccomp 277
-#define TARGET_NR_getrandom 278
-#define TARGET_NR_memfd_create 279
-#define TARGET_NR_bpf 280
-#define TARGET_NR_execveat 281
-#define TARGET_NR_userfaultfd 282
-#define TARGET_NR_membarrier 283
-#define TARGET_NR_mlock2 284
-#define TARGET_NR_copy_file_range 285
-#define TARGET_NR_preadv2 286
-#define TARGET_NR_pwritev2 287
-#define TARGET_NR_pkey_mprotect 288
-#define TARGET_NR_pkey_alloc 289
-#define TARGET_NR_pkey_free 290
-#define TARGET_NR_statx 291
-#define TARGET_NR_io_pgetevents 292
-#define TARGET_NR_rseq 293
-#define TARGET_NR_kexec_file_load 294
-#define TARGET_NR_clock_gettime64 403
-#define TARGET_NR_clock_settime64 404
-#define TARGET_NR_clock_adjtime64 405
-#define TARGET_NR_clock_getres_time64 406
-#define TARGET_NR_clock_nanosleep_time64 407
-#define TARGET_NR_timer_gettime64 408
-#define TARGET_NR_timer_settime64 409
-#define TARGET_NR_timerfd_gettime64 410
-#define TARGET_NR_timerfd_settime64 411
-#define TARGET_NR_utimensat_time64 412
-#define TARGET_NR_pselect6_time64 413
-#define TARGET_NR_ppoll_time64 414
-#define TARGET_NR_io_pgetevents_time64 416
-#define TARGET_NR_recvmmsg_time64 417
-#define TARGET_NR_mq_timedsend_time64 418
-#define TARGET_NR_mq_timedreceive_time64 419
-#define TARGET_NR_semtimedop_time64 420
-#define TARGET_NR_rt_sigtimedwait_time64 421
-#define TARGET_NR_futex_time64 422
-#define TARGET_NR_sched_rr_get_interval_time64 423
-#define TARGET_NR_pidfd_send_signal 424
-#define TARGET_NR_io_uring_setup 425
-#define TARGET_NR_io_uring_enter 426
-#define TARGET_NR_io_uring_register 427
-#define TARGET_NR_open_tree 428
-#define TARGET_NR_move_mount 429
-#define TARGET_NR_fsopen 430
-#define TARGET_NR_fsconfig 431
-#define TARGET_NR_fsmount 432
-#define TARGET_NR_fspick 433
-#define TARGET_NR_pidfd_open 434
-#define TARGET_NR_clone3 435
-#define TARGET_NR_close_range 436
-#define TARGET_NR_openat2 437
-#define TARGET_NR_pidfd_getfd 438
-#define TARGET_NR_faccessat2 439
-#define TARGET_NR_process_madvise 440
-#define TARGET_NR_epoll_pwait2 441
-#define TARGET_NR_mount_setattr 442
-#define TARGET_NR_landlock_create_ruleset 444
-#define TARGET_NR_landlock_add_rule 445
-#define TARGET_NR_landlock_restrict_self 446
-#define TARGET_NR_syscalls 447
-
-#endif /* LINUX_USER_OPENRISC_SYSCALL_NR_H */
diff --git a/linux-user/openrisc/syscallhdr.sh b/linux-user/openrisc/syscallhdr.sh
new file mode 100644
index 0000000..047e9f7
--- /dev/null
+++ b/linux-user/openrisc/syscallhdr.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+in="$1"
+out="$2"
+my_abis=`echo "($3)" | tr ',' '|'`
+prefix="$4"
+offset="$5"
+
+fileguard=LINUX_USER_OPENRISC_`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 | (
+ echo "#ifndef ${fileguard}"
+ echo "#define ${fileguard} 1"
+ echo ""
+
+ while read nr abi name entry ; do
+ if [ -z "$offset" ]; then
+ echo "#define TARGET_NR_${prefix}${name} $nr"
+ else
+ echo "#define TARGET_NR_${prefix}${name} ($offset + $nr)"
+ fi
+ done
+
+ echo ""
+ echo "#endif /* ${fileguard} */"
+) > "$out"
diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c
index a1d8c0b..24e5a02 100644
--- a/linux-user/ppc/signal.c
+++ b/linux-user/ppc/signal.c
@@ -628,7 +628,7 @@ static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
return 1;
- target_to_host_sigset_internal(&blocked, &set);
+ target_to_host_sigset(&blocked, &set);
set_sigmask(&blocked);
restore_user_regs(env, mcp, sig);
diff --git a/linux-user/ppc/syscall.tbl b/linux-user/ppc/syscall.tbl
index 8f052ff..4b428a4 100644
--- a/linux-user/ppc/syscall.tbl
+++ b/linux-user/ppc/syscall.tbl
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
#
# system call numbers and entry vectors for powerpc
#
@@ -110,7 +110,7 @@
79 common settimeofday sys_settimeofday compat_sys_settimeofday
80 common getgroups sys_getgroups
81 common setgroups sys_setgroups
-82 32 select ppc_select sys_ni_syscall
+82 32 select sys_old_select compat_sys_old_select
82 64 select sys_ni_syscall
82 spu select sys_ni_syscall
83 common symlink sys_symlink
@@ -176,11 +176,11 @@
131 nospu quotactl sys_quotactl
132 common getpgid sys_getpgid
133 common fchdir sys_fchdir
-134 common bdflush sys_bdflush
+134 common bdflush sys_ni_syscall
135 common sysfs sys_sysfs
-136 32 personality sys_personality ppc64_personality
-136 64 personality ppc64_personality
-136 spu personality ppc64_personality
+136 32 personality sys_personality compat_sys_ppc64_personality
+136 64 personality sys_ppc64_personality
+136 spu personality sys_ppc64_personality
137 common afs_syscall sys_ni_syscall
138 common setfsuid sys_setfsuid
139 common setfsgid sys_setfsgid
@@ -228,8 +228,12 @@
176 64 rt_sigtimedwait sys_rt_sigtimedwait
177 nospu rt_sigqueueinfo sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo
178 nospu rt_sigsuspend sys_rt_sigsuspend compat_sys_rt_sigsuspend
-179 common pread64 sys_pread64 compat_sys_pread64
-180 common pwrite64 sys_pwrite64 compat_sys_pwrite64
+179 32 pread64 sys_ppc_pread64 compat_sys_ppc_pread64
+179 64 pread64 sys_pread64
+179 spu pread64 sys_pread64
+180 32 pwrite64 sys_ppc_pwrite64 compat_sys_ppc_pwrite64
+180 64 pwrite64 sys_pwrite64
+180 spu pwrite64 sys_pwrite64
181 common chown sys_chown
182 common getcwd sys_getcwd
183 common capget sys_capget
@@ -242,10 +246,12 @@
188 common putpmsg sys_ni_syscall
189 nospu vfork sys_vfork
190 common ugetrlimit sys_getrlimit compat_sys_getrlimit
-191 common readahead sys_readahead compat_sys_readahead
+191 32 readahead sys_ppc_readahead compat_sys_ppc_readahead
+191 64 readahead sys_readahead
+191 spu readahead sys_readahead
192 32 mmap2 sys_mmap2 compat_sys_mmap2
-193 32 truncate64 sys_truncate64 compat_sys_truncate64
-194 32 ftruncate64 sys_ftruncate64 compat_sys_ftruncate64
+193 32 truncate64 sys_ppc_truncate64 compat_sys_ppc_truncate64
+194 32 ftruncate64 sys_ppc_ftruncate64 compat_sys_ppc_ftruncate64
195 32 stat64 sys_stat64
196 32 lstat64 sys_lstat64
197 32 fstat64 sys_fstat64
@@ -288,9 +294,11 @@
230 common io_submit sys_io_submit compat_sys_io_submit
231 common io_cancel sys_io_cancel
232 nospu set_tid_address sys_set_tid_address
-233 common fadvise64 sys_fadvise64 ppc32_fadvise64
+233 32 fadvise64 sys_ppc32_fadvise64 compat_sys_ppc32_fadvise64
+233 64 fadvise64 sys_fadvise64
+233 spu fadvise64 sys_fadvise64
234 nospu exit_group sys_exit_group
-235 nospu lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie
+235 nospu lookup_dcookie sys_ni_syscall
236 common epoll_create sys_epoll_create
237 common epoll_ctl sys_epoll_ctl
238 common epoll_wait sys_epoll_wait
@@ -323,17 +331,17 @@
251 spu utimes sys_utimes
252 common statfs64 sys_statfs64 compat_sys_statfs64
253 common fstatfs64 sys_fstatfs64 compat_sys_fstatfs64
-254 32 fadvise64_64 ppc_fadvise64_64
+254 32 fadvise64_64 sys_ppc_fadvise64_64
254 spu fadvise64_64 sys_ni_syscall
255 common rtas sys_rtas
256 32 sys_debug_setcontext sys_debug_setcontext sys_ni_syscall
256 64 sys_debug_setcontext sys_ni_syscall
256 spu sys_debug_setcontext sys_ni_syscall
# 257 reserved for vserver
-258 nospu migrate_pages sys_migrate_pages compat_sys_migrate_pages
-259 nospu mbind sys_mbind compat_sys_mbind
-260 nospu get_mempolicy sys_get_mempolicy compat_sys_get_mempolicy
-261 nospu set_mempolicy sys_set_mempolicy compat_sys_set_mempolicy
+258 nospu migrate_pages sys_migrate_pages
+259 nospu mbind sys_mbind
+260 nospu get_mempolicy sys_get_mempolicy
+261 nospu set_mempolicy sys_set_mempolicy
262 nospu mq_open sys_mq_open compat_sys_mq_open
263 nospu mq_unlink sys_mq_unlink
264 32 mq_timedsend sys_mq_timedsend_time32
@@ -381,7 +389,7 @@
298 common faccessat sys_faccessat
299 common get_robust_list sys_get_robust_list compat_sys_get_robust_list
300 common set_robust_list sys_set_robust_list compat_sys_set_robust_list
-301 common move_pages sys_move_pages compat_sys_move_pages
+301 common move_pages sys_move_pages
302 common getcpu sys_getcpu
303 nospu epoll_pwait sys_epoll_pwait compat_sys_epoll_pwait
304 32 utimensat sys_utimensat_time32
@@ -390,8 +398,11 @@
305 common signalfd sys_signalfd compat_sys_signalfd
306 common timerfd_create sys_timerfd_create
307 common eventfd sys_eventfd
-308 common sync_file_range2 sys_sync_file_range2 compat_sys_sync_file_range2
-309 nospu fallocate sys_fallocate compat_sys_fallocate
+308 32 sync_file_range2 sys_ppc_sync_file_range2 compat_sys_ppc_sync_file_range2
+308 64 sync_file_range2 sys_sync_file_range2
+308 spu sync_file_range2 sys_sync_file_range2
+309 32 fallocate sys_ppc_fallocate compat_sys_fallocate
+309 64 fallocate sys_fallocate
310 nospu subpage_prot sys_subpage_prot
311 32 timerfd_settime sys_timerfd_settime32
311 64 timerfd_settime sys_timerfd_settime
@@ -495,7 +506,7 @@
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
+416 32 io_pgetevents_time64 sys_io_pgetevents compat_sys_io_pgetevents_time64
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
@@ -522,7 +533,23 @@
440 common process_madvise sys_process_madvise
441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
442 common mount_setattr sys_mount_setattr
-# 443 reserved for quotactl_path
+443 common quotactl_fd sys_quotactl_fd
444 common landlock_create_ruleset sys_landlock_create_ruleset
445 common landlock_add_rule sys_landlock_add_rule
446 common landlock_restrict_self sys_landlock_restrict_self
+# 447 reserved for memfd_secret
+448 common process_mrelease sys_process_mrelease
+449 common futex_waitv sys_futex_waitv
+450 nospu set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common cachestat sys_cachestat
+452 common fchmodat2 sys_fchmodat2
+453 common map_shadow_stack sys_ni_syscall
+454 common futex_wake sys_futex_wake
+455 common futex_wait sys_futex_wait
+456 common futex_requeue sys_futex_requeue
+457 common statmount sys_statmount
+458 common listmount sys_listmount
+459 common lsm_get_self_attr sys_lsm_get_self_attr
+460 common lsm_set_self_attr sys_lsm_set_self_attr
+461 common lsm_list_modules sys_lsm_list_modules
+462 common mseal sys_mseal
diff --git a/linux-user/ppc/syscallhdr.sh b/linux-user/ppc/syscallhdr.sh
index 6c44e0e..6e8b93d 100644
--- a/linux-user/ppc/syscallhdr.sh
+++ b/linux-user/ppc/syscallhdr.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
in="$1"
out="$2"
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 2e90a97..895bdd7 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -114,6 +114,10 @@ struct TaskState {
uint32_t v86flags;
uint32_t v86mask;
#endif
+#if defined(TARGET_I386)
+ /* Last syscall number. */
+ target_ulong orig_ax;
+#endif
abi_ulong child_tidptr;
#ifdef TARGET_M68K
abi_ulong tp_value;
@@ -313,6 +317,15 @@ static inline bool access_ok(CPUState *cpu, int type,
int copy_from_user(void *hptr, abi_ulong gaddr, ssize_t len);
int copy_to_user(abi_ulong gaddr, void *hptr, ssize_t len);
+/*
+ * copy_struct_from_user() copies a target struct to a host struct, in
+ * a way that guarantees backwards-compatibility for struct syscall
+ * arguments.
+ *
+ * Similar to kernels uaccess.h:copy_struct_from_user()
+ */
+int copy_struct_from_user(void *dst, size_t ksize, abi_ptr src, size_t usize);
+
/* Functions for accessing guest memory. The tget and tput functions
read/write single values, byteswapping as necessary. The lock_user function
gets a pointer to a contiguous area of guest memory, but does not perform
diff --git a/linux-user/riscv/cpu_loop.c b/linux-user/riscv/cpu_loop.c
index 52c49c2..0af533e 100644
--- a/linux-user/riscv/cpu_loop.c
+++ b/linux-user/riscv/cpu_loop.c
@@ -47,7 +47,7 @@ void cpu_loop(CPURISCVState *env)
break;
case RISCV_EXCP_U_ECALL:
env->pc += 4;
- if (env->gpr[xA7] == TARGET_NR_arch_specific_syscall + 15) {
+ if (env->gpr[xA7] == TARGET_NR_riscv_flush_icache) {
/* riscv_flush_icache_syscall is a no-op in QEMU as
self-modifying code is automatically detected */
ret = 0;
diff --git a/linux-user/riscv/meson.build b/linux-user/riscv/meson.build
index beb989a..b2e7df0 100644
--- a/linux-user/riscv/meson.build
+++ b/linux-user/riscv/meson.build
@@ -5,3 +5,9 @@ vdso_64_inc = gen_vdso.process('vdso-64.so',
linux_user_ss.add(when: 'TARGET_RISCV32', if_true: vdso_32_inc)
linux_user_ss.add(when: 'TARGET_RISCV64', if_true: vdso_64_inc)
+
+syscall_nr_generators += {
+ 'riscv': generator(sh,
+ arguments: [ meson.current_source_dir() / 'syscallhdr.sh', '@INPUT@', '@OUTPUT@', '@EXTRA_ARGS@' ],
+ output: '@BASENAME@_nr.h')
+}
diff --git a/linux-user/riscv/syscall.tbl b/linux-user/riscv/syscall.tbl
new file mode 100644
index 0000000..845e24e
--- /dev/null
+++ b/linux-user/riscv/syscall.tbl
@@ -0,0 +1,405 @@
+# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+#
+# This file contains the system call numbers for all of the
+# more recently added architectures.
+#
+# As a basic principle, no duplication of functionality
+# should be added, e.g. we don't use lseek when llseek
+# is present. New architectures should use this file
+# and implement the less feature-full calls in user space.
+#
+0 common io_setup sys_io_setup compat_sys_io_setup
+1 common io_destroy sys_io_destroy
+2 common io_submit sys_io_submit compat_sys_io_submit
+3 common io_cancel sys_io_cancel
+4 time32 io_getevents sys_io_getevents_time32
+4 64 io_getevents sys_io_getevents
+5 common setxattr sys_setxattr
+6 common lsetxattr sys_lsetxattr
+7 common fsetxattr sys_fsetxattr
+8 common getxattr sys_getxattr
+9 common lgetxattr sys_lgetxattr
+10 common fgetxattr sys_fgetxattr
+11 common listxattr sys_listxattr
+12 common llistxattr sys_llistxattr
+13 common flistxattr sys_flistxattr
+14 common removexattr sys_removexattr
+15 common lremovexattr sys_lremovexattr
+16 common fremovexattr sys_fremovexattr
+17 common getcwd sys_getcwd
+18 common lookup_dcookie sys_ni_syscall
+19 common eventfd2 sys_eventfd2
+20 common epoll_create1 sys_epoll_create1
+21 common epoll_ctl sys_epoll_ctl
+22 common epoll_pwait sys_epoll_pwait compat_sys_epoll_pwait
+23 common dup sys_dup
+24 common dup3 sys_dup3
+25 32 fcntl64 sys_fcntl64 compat_sys_fcntl64
+25 64 fcntl sys_fcntl
+26 common inotify_init1 sys_inotify_init1
+27 common inotify_add_watch sys_inotify_add_watch
+28 common inotify_rm_watch sys_inotify_rm_watch
+29 common ioctl sys_ioctl compat_sys_ioctl
+30 common ioprio_set sys_ioprio_set
+31 common ioprio_get sys_ioprio_get
+32 common flock sys_flock
+33 common mknodat sys_mknodat
+34 common mkdirat sys_mkdirat
+35 common unlinkat sys_unlinkat
+36 common symlinkat sys_symlinkat
+37 common linkat sys_linkat
+# renameat is superseded with flags by renameat2
+38 renameat renameat sys_renameat
+39 common umount2 sys_umount
+40 common mount sys_mount
+41 common pivot_root sys_pivot_root
+42 common nfsservctl sys_ni_syscall
+43 32 statfs64 sys_statfs64 compat_sys_statfs64
+43 64 statfs sys_statfs
+44 32 fstatfs64 sys_fstatfs64 compat_sys_fstatfs64
+44 64 fstatfs sys_fstatfs
+45 32 truncate64 sys_truncate64 compat_sys_truncate64
+45 64 truncate sys_truncate
+46 32 ftruncate64 sys_ftruncate64 compat_sys_ftruncate64
+46 64 ftruncate sys_ftruncate
+47 common fallocate sys_fallocate compat_sys_fallocate
+48 common faccessat sys_faccessat
+49 common chdir sys_chdir
+50 common fchdir sys_fchdir
+51 common chroot sys_chroot
+52 common fchmod sys_fchmod
+53 common fchmodat sys_fchmodat
+54 common fchownat sys_fchownat
+55 common fchown sys_fchown
+56 common openat sys_openat
+57 common close sys_close
+58 common vhangup sys_vhangup
+59 common pipe2 sys_pipe2
+60 common quotactl sys_quotactl
+61 common getdents64 sys_getdents64
+62 32 llseek sys_llseek
+62 64 lseek sys_lseek
+63 common read sys_read
+64 common write sys_write
+65 common readv sys_readv sys_readv
+66 common writev sys_writev sys_writev
+67 common pread64 sys_pread64 compat_sys_pread64
+68 common pwrite64 sys_pwrite64 compat_sys_pwrite64
+69 common preadv sys_preadv compat_sys_preadv
+70 common pwritev sys_pwritev compat_sys_pwritev
+71 32 sendfile64 sys_sendfile64
+71 64 sendfile sys_sendfile64
+72 time32 pselect6 sys_pselect6_time32 compat_sys_pselect6_time32
+72 64 pselect6 sys_pselect6
+73 time32 ppoll sys_ppoll_time32 compat_sys_ppoll_time32
+73 64 ppoll sys_ppoll
+74 common signalfd4 sys_signalfd4 compat_sys_signalfd4
+75 common vmsplice sys_vmsplice
+76 common splice sys_splice
+77 common tee sys_tee
+78 common readlinkat sys_readlinkat
+79 stat64 fstatat64 sys_fstatat64
+79 64 newfstatat sys_newfstatat
+80 stat64 fstat64 sys_fstat64
+80 64 fstat sys_newfstat
+81 common sync sys_sync
+82 common fsync sys_fsync
+83 common fdatasync sys_fdatasync
+84 common sync_file_range sys_sync_file_range compat_sys_sync_file_range
+85 common timerfd_create sys_timerfd_create
+86 time32 timerfd_settime sys_timerfd_settime32
+86 64 timerfd_settime sys_timerfd_settime
+87 time32 timerfd_gettime sys_timerfd_gettime32
+87 64 timerfd_gettime sys_timerfd_gettime
+88 time32 utimensat sys_utimensat_time32
+88 64 utimensat sys_utimensat
+89 common acct sys_acct
+90 common capget sys_capget
+91 common capset sys_capset
+92 common personality sys_personality
+93 common exit sys_exit
+94 common exit_group sys_exit_group
+95 common waitid sys_waitid compat_sys_waitid
+96 common set_tid_address sys_set_tid_address
+97 common unshare sys_unshare
+98 time32 futex sys_futex_time32
+98 64 futex sys_futex
+99 common set_robust_list sys_set_robust_list compat_sys_set_robust_list
+100 common get_robust_list sys_get_robust_list compat_sys_get_robust_list
+101 time32 nanosleep sys_nanosleep_time32
+101 64 nanosleep sys_nanosleep
+102 common getitimer sys_getitimer compat_sys_getitimer
+103 common setitimer sys_setitimer compat_sys_setitimer
+104 common kexec_load sys_kexec_load compat_sys_kexec_load
+105 common init_module sys_init_module
+106 common delete_module sys_delete_module
+107 common timer_create sys_timer_create compat_sys_timer_create
+108 time32 timer_gettime sys_timer_gettime32
+108 64 timer_gettime sys_timer_gettime
+109 common timer_getoverrun sys_timer_getoverrun
+110 time32 timer_settime sys_timer_settime32
+110 64 timer_settime sys_timer_settime
+111 common timer_delete sys_timer_delete
+112 time32 clock_settime sys_clock_settime32
+112 64 clock_settime sys_clock_settime
+113 time32 clock_gettime sys_clock_gettime32
+113 64 clock_gettime sys_clock_gettime
+114 time32 clock_getres sys_clock_getres_time32
+114 64 clock_getres sys_clock_getres
+115 time32 clock_nanosleep sys_clock_nanosleep_time32
+115 64 clock_nanosleep sys_clock_nanosleep
+116 common syslog sys_syslog
+117 common ptrace sys_ptrace compat_sys_ptrace
+118 common sched_setparam sys_sched_setparam
+119 common sched_setscheduler sys_sched_setscheduler
+120 common sched_getscheduler sys_sched_getscheduler
+121 common sched_getparam sys_sched_getparam
+122 common sched_setaffinity sys_sched_setaffinity compat_sys_sched_setaffinity
+123 common sched_getaffinity sys_sched_getaffinity compat_sys_sched_getaffinity
+124 common sched_yield sys_sched_yield
+125 common sched_get_priority_max sys_sched_get_priority_max
+126 common sched_get_priority_min sys_sched_get_priority_min
+127 time32 sched_rr_get_interval sys_sched_rr_get_interval_time32
+127 64 sched_rr_get_interval sys_sched_rr_get_interval
+128 common restart_syscall sys_restart_syscall
+129 common kill sys_kill
+130 common tkill sys_tkill
+131 common tgkill sys_tgkill
+132 common sigaltstack sys_sigaltstack compat_sys_sigaltstack
+133 common rt_sigsuspend sys_rt_sigsuspend compat_sys_rt_sigsuspend
+134 common rt_sigaction sys_rt_sigaction compat_sys_rt_sigaction
+135 common rt_sigprocmask sys_rt_sigprocmask compat_sys_rt_sigprocmask
+136 common rt_sigpending sys_rt_sigpending compat_sys_rt_sigpending
+137 time32 rt_sigtimedwait sys_rt_sigtimedwait_time32 compat_sys_rt_sigtimedwait_time32
+137 64 rt_sigtimedwait sys_rt_sigtimedwait
+138 common rt_sigqueueinfo sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo
+139 common rt_sigreturn sys_rt_sigreturn compat_sys_rt_sigreturn
+140 common setpriority sys_setpriority
+141 common getpriority sys_getpriority
+142 common reboot sys_reboot
+143 common setregid sys_setregid
+144 common setgid sys_setgid
+145 common setreuid sys_setreuid
+146 common setuid sys_setuid
+147 common setresuid sys_setresuid
+148 common getresuid sys_getresuid
+149 common setresgid sys_setresgid
+150 common getresgid sys_getresgid
+151 common setfsuid sys_setfsuid
+152 common setfsgid sys_setfsgid
+153 common times sys_times compat_sys_times
+154 common setpgid sys_setpgid
+155 common getpgid sys_getpgid
+156 common getsid sys_getsid
+157 common setsid sys_setsid
+158 common getgroups sys_getgroups
+159 common setgroups sys_setgroups
+160 common uname sys_newuname
+161 common sethostname sys_sethostname
+162 common setdomainname sys_setdomainname
+# getrlimit and setrlimit are superseded with prlimit64
+163 rlimit getrlimit sys_getrlimit compat_sys_getrlimit
+164 rlimit setrlimit sys_setrlimit compat_sys_setrlimit
+165 common getrusage sys_getrusage compat_sys_getrusage
+166 common umask sys_umask
+167 common prctl sys_prctl
+168 common getcpu sys_getcpu
+169 time32 gettimeofday sys_gettimeofday compat_sys_gettimeofday
+169 64 gettimeofday sys_gettimeofday
+170 time32 settimeofday sys_settimeofday compat_sys_settimeofday
+170 64 settimeofday sys_settimeofday
+171 time32 adjtimex sys_adjtimex_time32
+171 64 adjtimex sys_adjtimex
+172 common getpid sys_getpid
+173 common getppid sys_getppid
+174 common getuid sys_getuid
+175 common geteuid sys_geteuid
+176 common getgid sys_getgid
+177 common getegid sys_getegid
+178 common gettid sys_gettid
+179 common sysinfo sys_sysinfo compat_sys_sysinfo
+180 common mq_open sys_mq_open compat_sys_mq_open
+181 common mq_unlink sys_mq_unlink
+182 time32 mq_timedsend sys_mq_timedsend_time32
+182 64 mq_timedsend sys_mq_timedsend
+183 time32 mq_timedreceive sys_mq_timedreceive_time32
+183 64 mq_timedreceive sys_mq_timedreceive
+184 common mq_notify sys_mq_notify compat_sys_mq_notify
+185 common mq_getsetattr sys_mq_getsetattr compat_sys_mq_getsetattr
+186 common msgget sys_msgget
+187 common msgctl sys_msgctl compat_sys_msgctl
+188 common msgrcv sys_msgrcv compat_sys_msgrcv
+189 common msgsnd sys_msgsnd compat_sys_msgsnd
+190 common semget sys_semget
+191 common semctl sys_semctl compat_sys_semctl
+192 time32 semtimedop sys_semtimedop_time32
+192 64 semtimedop sys_semtimedop
+193 common semop sys_semop
+194 common shmget sys_shmget
+195 common shmctl sys_shmctl compat_sys_shmctl
+196 common shmat sys_shmat compat_sys_shmat
+197 common shmdt sys_shmdt
+198 common socket sys_socket
+199 common socketpair sys_socketpair
+200 common bind sys_bind
+201 common listen sys_listen
+202 common accept sys_accept
+203 common connect sys_connect
+204 common getsockname sys_getsockname
+205 common getpeername sys_getpeername
+206 common sendto sys_sendto
+207 common recvfrom sys_recvfrom compat_sys_recvfrom
+208 common setsockopt sys_setsockopt sys_setsockopt
+209 common getsockopt sys_getsockopt sys_getsockopt
+210 common shutdown sys_shutdown
+211 common sendmsg sys_sendmsg compat_sys_sendmsg
+212 common recvmsg sys_recvmsg compat_sys_recvmsg
+213 common readahead sys_readahead compat_sys_readahead
+214 common brk sys_brk
+215 common munmap sys_munmap
+216 common mremap sys_mremap
+217 common add_key sys_add_key
+218 common request_key sys_request_key
+219 common keyctl sys_keyctl compat_sys_keyctl
+220 common clone sys_clone
+221 common execve sys_execve compat_sys_execve
+222 32 mmap2 sys_mmap2
+222 64 mmap sys_mmap
+223 32 fadvise64_64 sys_fadvise64_64 compat_sys_fadvise64_64
+223 64 fadvise64 sys_fadvise64_64
+224 common swapon sys_swapon
+225 common swapoff sys_swapoff
+226 common mprotect sys_mprotect
+227 common msync sys_msync
+228 common mlock sys_mlock
+229 common munlock sys_munlock
+230 common mlockall sys_mlockall
+231 common munlockall sys_munlockall
+232 common mincore sys_mincore
+233 common madvise sys_madvise
+234 common remap_file_pages sys_remap_file_pages
+235 common mbind sys_mbind
+236 common get_mempolicy sys_get_mempolicy
+237 common set_mempolicy sys_set_mempolicy
+238 common migrate_pages sys_migrate_pages
+239 common move_pages sys_move_pages
+240 common rt_tgsigqueueinfo sys_rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo
+241 common perf_event_open sys_perf_event_open
+242 common accept4 sys_accept4
+243 time32 recvmmsg sys_recvmmsg_time32 compat_sys_recvmmsg_time32
+243 64 recvmmsg sys_recvmmsg
+# Architectures may provide up to 16 syscalls of their own between 244 and 259
+244 arc cacheflush sys_cacheflush
+245 arc arc_settls sys_arc_settls
+246 arc arc_gettls sys_arc_gettls
+247 arc sysfs sys_sysfs
+248 arc arc_usr_cmpxchg sys_arc_usr_cmpxchg
+
+244 csky set_thread_area sys_set_thread_area
+245 csky cacheflush sys_cacheflush
+
+244 nios2 cacheflush sys_cacheflush
+
+244 or1k or1k_atomic sys_or1k_atomic
+
+258 riscv riscv_hwprobe sys_riscv_hwprobe
+259 riscv riscv_flush_icache sys_riscv_flush_icache
+
+260 time32 wait4 sys_wait4 compat_sys_wait4
+260 64 wait4 sys_wait4
+261 common prlimit64 sys_prlimit64
+262 common fanotify_init sys_fanotify_init
+263 common fanotify_mark sys_fanotify_mark
+264 common name_to_handle_at sys_name_to_handle_at
+265 common open_by_handle_at sys_open_by_handle_at
+266 time32 clock_adjtime sys_clock_adjtime32
+266 64 clock_adjtime sys_clock_adjtime
+267 common syncfs sys_syncfs
+268 common setns sys_setns
+269 common sendmmsg sys_sendmmsg compat_sys_sendmmsg
+270 common process_vm_readv sys_process_vm_readv
+271 common process_vm_writev sys_process_vm_writev
+272 common kcmp sys_kcmp
+273 common finit_module sys_finit_module
+274 common sched_setattr sys_sched_setattr
+275 common sched_getattr sys_sched_getattr
+276 common renameat2 sys_renameat2
+277 common seccomp sys_seccomp
+278 common getrandom sys_getrandom
+279 common memfd_create sys_memfd_create
+280 common bpf sys_bpf
+281 common execveat sys_execveat compat_sys_execveat
+282 common userfaultfd sys_userfaultfd
+283 common membarrier sys_membarrier
+284 common mlock2 sys_mlock2
+285 common copy_file_range sys_copy_file_range
+286 common preadv2 sys_preadv2 compat_sys_preadv2
+287 common pwritev2 sys_pwritev2 compat_sys_pwritev2
+288 common pkey_mprotect sys_pkey_mprotect
+289 common pkey_alloc sys_pkey_alloc
+290 common pkey_free sys_pkey_free
+291 common statx sys_statx
+292 time32 io_pgetevents sys_io_pgetevents_time32 compat_sys_io_pgetevents
+292 64 io_pgetevents sys_io_pgetevents
+293 common rseq sys_rseq
+294 common kexec_file_load sys_kexec_file_load
+# 295 through 402 are unassigned to sync up with generic numbers don't use
+403 32 clock_gettime64 sys_clock_gettime
+404 32 clock_settime64 sys_clock_settime
+405 32 clock_adjtime64 sys_clock_adjtime
+406 32 clock_getres_time64 sys_clock_getres
+407 32 clock_nanosleep_time64 sys_clock_nanosleep
+408 32 timer_gettime64 sys_timer_gettime
+409 32 timer_settime64 sys_timer_settime
+410 32 timerfd_gettime64 sys_timerfd_gettime
+411 32 timerfd_settime64 sys_timerfd_settime
+412 32 utimensat_time64 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 compat_sys_io_pgetevents_time64
+417 32 recvmmsg_time64 sys_recvmmsg compat_sys_recvmmsg_time64
+418 32 mq_timedsend_time64 sys_mq_timedsend
+419 32 mq_timedreceive_time64 sys_mq_timedreceive
+420 32 semtimedop_time64 sys_semtimedop
+421 32 rt_sigtimedwait_time64 sys_rt_sigtimedwait compat_sys_rt_sigtimedwait_time64
+422 32 futex_time64 sys_futex
+423 32 sched_rr_get_interval_time64 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 common clone3 sys_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
+440 common process_madvise sys_process_madvise
+441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
+442 common mount_setattr sys_mount_setattr
+443 common quotactl_fd sys_quotactl_fd
+444 common landlock_create_ruleset sys_landlock_create_ruleset
+445 common landlock_add_rule sys_landlock_add_rule
+446 common landlock_restrict_self sys_landlock_restrict_self
+447 memfd_secret memfd_secret sys_memfd_secret
+448 common process_mrelease sys_process_mrelease
+449 common futex_waitv sys_futex_waitv
+450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common cachestat sys_cachestat
+452 common fchmodat2 sys_fchmodat2
+453 common map_shadow_stack sys_map_shadow_stack
+454 common futex_wake sys_futex_wake
+455 common futex_wait sys_futex_wait
+456 common futex_requeue sys_futex_requeue
+457 common statmount sys_statmount
+458 common listmount sys_listmount
+459 common lsm_get_self_attr sys_lsm_get_self_attr
+460 common lsm_set_self_attr sys_lsm_set_self_attr
+461 common lsm_list_modules sys_lsm_list_modules
+462 common mseal sys_mseal
diff --git a/linux-user/riscv/syscall32_nr.h b/linux-user/riscv/syscall32_nr.h
deleted file mode 100644
index 412e58e..0000000
--- a/linux-user/riscv/syscall32_nr.h
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * This file contains the system call numbers.
- * Do not modify.
- * This file is generated by scripts/gensyscalls.sh
- */
-#ifndef LINUX_USER_RISCV_SYSCALL32_NR_H
-#define LINUX_USER_RISCV_SYSCALL32_NR_H
-
-#define TARGET_NR_io_setup 0
-#define TARGET_NR_io_destroy 1
-#define TARGET_NR_io_submit 2
-#define TARGET_NR_io_cancel 3
-#define TARGET_NR_setxattr 5
-#define TARGET_NR_lsetxattr 6
-#define TARGET_NR_fsetxattr 7
-#define TARGET_NR_getxattr 8
-#define TARGET_NR_lgetxattr 9
-#define TARGET_NR_fgetxattr 10
-#define TARGET_NR_listxattr 11
-#define TARGET_NR_llistxattr 12
-#define TARGET_NR_flistxattr 13
-#define TARGET_NR_removexattr 14
-#define TARGET_NR_lremovexattr 15
-#define TARGET_NR_fremovexattr 16
-#define TARGET_NR_getcwd 17
-#define TARGET_NR_lookup_dcookie 18
-#define TARGET_NR_eventfd2 19
-#define TARGET_NR_epoll_create1 20
-#define TARGET_NR_epoll_ctl 21
-#define TARGET_NR_epoll_pwait 22
-#define TARGET_NR_dup 23
-#define TARGET_NR_dup3 24
-#define TARGET_NR_fcntl64 25
-#define TARGET_NR_inotify_init1 26
-#define TARGET_NR_inotify_add_watch 27
-#define TARGET_NR_inotify_rm_watch 28
-#define TARGET_NR_ioctl 29
-#define TARGET_NR_ioprio_set 30
-#define TARGET_NR_ioprio_get 31
-#define TARGET_NR_flock 32
-#define TARGET_NR_mknodat 33
-#define TARGET_NR_mkdirat 34
-#define TARGET_NR_unlinkat 35
-#define TARGET_NR_symlinkat 36
-#define TARGET_NR_linkat 37
-#define TARGET_NR_umount2 39
-#define TARGET_NR_mount 40
-#define TARGET_NR_pivot_root 41
-#define TARGET_NR_nfsservctl 42
-#define TARGET_NR_statfs64 43
-#define TARGET_NR_fstatfs64 44
-#define TARGET_NR_truncate64 45
-#define TARGET_NR_ftruncate64 46
-#define TARGET_NR_fallocate 47
-#define TARGET_NR_faccessat 48
-#define TARGET_NR_chdir 49
-#define TARGET_NR_fchdir 50
-#define TARGET_NR_chroot 51
-#define TARGET_NR_fchmod 52
-#define TARGET_NR_fchmodat 53
-#define TARGET_NR_fchownat 54
-#define TARGET_NR_fchown 55
-#define TARGET_NR_openat 56
-#define TARGET_NR_close 57
-#define TARGET_NR_vhangup 58
-#define TARGET_NR_pipe2 59
-#define TARGET_NR_quotactl 60
-#define TARGET_NR_getdents64 61
-#define TARGET_NR_llseek 62
-#define TARGET_NR_read 63
-#define TARGET_NR_write 64
-#define TARGET_NR_readv 65
-#define TARGET_NR_writev 66
-#define TARGET_NR_pread64 67
-#define TARGET_NR_pwrite64 68
-#define TARGET_NR_preadv 69
-#define TARGET_NR_pwritev 70
-#define TARGET_NR_sendfile64 71
-#define TARGET_NR_signalfd4 74
-#define TARGET_NR_vmsplice 75
-#define TARGET_NR_splice 76
-#define TARGET_NR_tee 77
-#define TARGET_NR_readlinkat 78
-#define TARGET_NR_fstatat64 79
-#define TARGET_NR_fstat64 80
-#define TARGET_NR_sync 81
-#define TARGET_NR_fsync 82
-#define TARGET_NR_fdatasync 83
-#define TARGET_NR_sync_file_range 84
-#define TARGET_NR_timerfd_create 85
-#define TARGET_NR_acct 89
-#define TARGET_NR_capget 90
-#define TARGET_NR_capset 91
-#define TARGET_NR_personality 92
-#define TARGET_NR_exit 93
-#define TARGET_NR_exit_group 94
-#define TARGET_NR_waitid 95
-#define TARGET_NR_set_tid_address 96
-#define TARGET_NR_unshare 97
-#define TARGET_NR_set_robust_list 99
-#define TARGET_NR_get_robust_list 100
-#define TARGET_NR_getitimer 102
-#define TARGET_NR_setitimer 103
-#define TARGET_NR_kexec_load 104
-#define TARGET_NR_init_module 105
-#define TARGET_NR_delete_module 106
-#define TARGET_NR_timer_create 107
-#define TARGET_NR_timer_getoverrun 109
-#define TARGET_NR_timer_delete 111
-#define TARGET_NR_syslog 116
-#define TARGET_NR_ptrace 117
-#define TARGET_NR_sched_setparam 118
-#define TARGET_NR_sched_setscheduler 119
-#define TARGET_NR_sched_getscheduler 120
-#define TARGET_NR_sched_getparam 121
-#define TARGET_NR_sched_setaffinity 122
-#define TARGET_NR_sched_getaffinity 123
-#define TARGET_NR_sched_yield 124
-#define TARGET_NR_sched_get_priority_max 125
-#define TARGET_NR_sched_get_priority_min 126
-#define TARGET_NR_restart_syscall 128
-#define TARGET_NR_kill 129
-#define TARGET_NR_tkill 130
-#define TARGET_NR_tgkill 131
-#define TARGET_NR_sigaltstack 132
-#define TARGET_NR_rt_sigsuspend 133
-#define TARGET_NR_rt_sigaction 134
-#define TARGET_NR_rt_sigprocmask 135
-#define TARGET_NR_rt_sigpending 136
-#define TARGET_NR_rt_sigqueueinfo 138
-#define TARGET_NR_rt_sigreturn 139
-#define TARGET_NR_setpriority 140
-#define TARGET_NR_getpriority 141
-#define TARGET_NR_reboot 142
-#define TARGET_NR_setregid 143
-#define TARGET_NR_setgid 144
-#define TARGET_NR_setreuid 145
-#define TARGET_NR_setuid 146
-#define TARGET_NR_setresuid 147
-#define TARGET_NR_getresuid 148
-#define TARGET_NR_setresgid 149
-#define TARGET_NR_getresgid 150
-#define TARGET_NR_setfsuid 151
-#define TARGET_NR_setfsgid 152
-#define TARGET_NR_times 153
-#define TARGET_NR_setpgid 154
-#define TARGET_NR_getpgid 155
-#define TARGET_NR_getsid 156
-#define TARGET_NR_setsid 157
-#define TARGET_NR_getgroups 158
-#define TARGET_NR_setgroups 159
-#define TARGET_NR_uname 160
-#define TARGET_NR_sethostname 161
-#define TARGET_NR_setdomainname 162
-#define TARGET_NR_getrlimit 163
-#define TARGET_NR_setrlimit 164
-#define TARGET_NR_getrusage 165
-#define TARGET_NR_umask 166
-#define TARGET_NR_prctl 167
-#define TARGET_NR_getcpu 168
-#define TARGET_NR_getpid 172
-#define TARGET_NR_getppid 173
-#define TARGET_NR_getuid 174
-#define TARGET_NR_geteuid 175
-#define TARGET_NR_getgid 176
-#define TARGET_NR_getegid 177
-#define TARGET_NR_gettid 178
-#define TARGET_NR_sysinfo 179
-#define TARGET_NR_mq_open 180
-#define TARGET_NR_mq_unlink 181
-#define TARGET_NR_mq_notify 184
-#define TARGET_NR_mq_getsetattr 185
-#define TARGET_NR_msgget 186
-#define TARGET_NR_msgctl 187
-#define TARGET_NR_msgrcv 188
-#define TARGET_NR_msgsnd 189
-#define TARGET_NR_semget 190
-#define TARGET_NR_semctl 191
-#define TARGET_NR_semop 193
-#define TARGET_NR_shmget 194
-#define TARGET_NR_shmctl 195
-#define TARGET_NR_shmat 196
-#define TARGET_NR_shmdt 197
-#define TARGET_NR_socket 198
-#define TARGET_NR_socketpair 199
-#define TARGET_NR_bind 200
-#define TARGET_NR_listen 201
-#define TARGET_NR_accept 202
-#define TARGET_NR_connect 203
-#define TARGET_NR_getsockname 204
-#define TARGET_NR_getpeername 205
-#define TARGET_NR_sendto 206
-#define TARGET_NR_recvfrom 207
-#define TARGET_NR_setsockopt 208
-#define TARGET_NR_getsockopt 209
-#define TARGET_NR_shutdown 210
-#define TARGET_NR_sendmsg 211
-#define TARGET_NR_recvmsg 212
-#define TARGET_NR_readahead 213
-#define TARGET_NR_brk 214
-#define TARGET_NR_munmap 215
-#define TARGET_NR_mremap 216
-#define TARGET_NR_add_key 217
-#define TARGET_NR_request_key 218
-#define TARGET_NR_keyctl 219
-#define TARGET_NR_clone 220
-#define TARGET_NR_execve 221
-#define TARGET_NR_mmap2 222
-#define TARGET_NR_fadvise64_64 223
-#define TARGET_NR_swapon 224
-#define TARGET_NR_swapoff 225
-#define TARGET_NR_mprotect 226
-#define TARGET_NR_msync 227
-#define TARGET_NR_mlock 228
-#define TARGET_NR_munlock 229
-#define TARGET_NR_mlockall 230
-#define TARGET_NR_munlockall 231
-#define TARGET_NR_mincore 232
-#define TARGET_NR_madvise 233
-#define TARGET_NR_remap_file_pages 234
-#define TARGET_NR_mbind 235
-#define TARGET_NR_get_mempolicy 236
-#define TARGET_NR_set_mempolicy 237
-#define TARGET_NR_migrate_pages 238
-#define TARGET_NR_move_pages 239
-#define TARGET_NR_rt_tgsigqueueinfo 240
-#define TARGET_NR_perf_event_open 241
-#define TARGET_NR_accept4 242
-#define TARGET_NR_arch_specific_syscall 244
-#define TARGET_NR_riscv_flush_icache (TARGET_NR_arch_specific_syscall + 15)
-#define TARGET_NR_riscv_hwprobe (TARGET_NR_arch_specific_syscall + 14)
-#define TARGET_NR_prlimit64 261
-#define TARGET_NR_fanotify_init 262
-#define TARGET_NR_fanotify_mark 263
-#define TARGET_NR_name_to_handle_at 264
-#define TARGET_NR_open_by_handle_at 265
-#define TARGET_NR_syncfs 267
-#define TARGET_NR_setns 268
-#define TARGET_NR_sendmmsg 269
-#define TARGET_NR_process_vm_readv 270
-#define TARGET_NR_process_vm_writev 271
-#define TARGET_NR_kcmp 272
-#define TARGET_NR_finit_module 273
-#define TARGET_NR_sched_setattr 274
-#define TARGET_NR_sched_getattr 275
-#define TARGET_NR_renameat2 276
-#define TARGET_NR_seccomp 277
-#define TARGET_NR_getrandom 278
-#define TARGET_NR_memfd_create 279
-#define TARGET_NR_bpf 280
-#define TARGET_NR_execveat 281
-#define TARGET_NR_userfaultfd 282
-#define TARGET_NR_membarrier 283
-#define TARGET_NR_mlock2 284
-#define TARGET_NR_copy_file_range 285
-#define TARGET_NR_preadv2 286
-#define TARGET_NR_pwritev2 287
-#define TARGET_NR_pkey_mprotect 288
-#define TARGET_NR_pkey_alloc 289
-#define TARGET_NR_pkey_free 290
-#define TARGET_NR_statx 291
-#define TARGET_NR_rseq 293
-#define TARGET_NR_kexec_file_load 294
-#define TARGET_NR_clock_gettime64 403
-#define TARGET_NR_clock_settime64 404
-#define TARGET_NR_clock_adjtime64 405
-#define TARGET_NR_clock_getres_time64 406
-#define TARGET_NR_clock_nanosleep_time64 407
-#define TARGET_NR_timer_gettime64 408
-#define TARGET_NR_timer_settime64 409
-#define TARGET_NR_timerfd_gettime64 410
-#define TARGET_NR_timerfd_settime64 411
-#define TARGET_NR_utimensat_time64 412
-#define TARGET_NR_pselect6_time64 413
-#define TARGET_NR_ppoll_time64 414
-#define TARGET_NR_io_pgetevents_time64 416
-#define TARGET_NR_recvmmsg_time64 417
-#define TARGET_NR_mq_timedsend_time64 418
-#define TARGET_NR_mq_timedreceive_time64 419
-#define TARGET_NR_semtimedop_time64 420
-#define TARGET_NR_rt_sigtimedwait_time64 421
-#define TARGET_NR_futex_time64 422
-#define TARGET_NR_sched_rr_get_interval_time64 423
-#define TARGET_NR_pidfd_send_signal 424
-#define TARGET_NR_io_uring_setup 425
-#define TARGET_NR_io_uring_enter 426
-#define TARGET_NR_io_uring_register 427
-#define TARGET_NR_open_tree 428
-#define TARGET_NR_move_mount 429
-#define TARGET_NR_fsopen 430
-#define TARGET_NR_fsconfig 431
-#define TARGET_NR_fsmount 432
-#define TARGET_NR_fspick 433
-#define TARGET_NR_pidfd_open 434
-#define TARGET_NR_clone3 435
-#define TARGET_NR_close_range 436
-#define TARGET_NR_openat2 437
-#define TARGET_NR_pidfd_getfd 438
-#define TARGET_NR_faccessat2 439
-#define TARGET_NR_process_madvise 440
-#define TARGET_NR_epoll_pwait2 441
-#define TARGET_NR_mount_setattr 442
-#define TARGET_NR_landlock_create_ruleset 444
-#define TARGET_NR_landlock_add_rule 445
-#define TARGET_NR_landlock_restrict_self 446
-#define TARGET_NR_syscalls 447
-
-#endif /* LINUX_USER_RISCV_SYSCALL32_NR_H */
diff --git a/linux-user/riscv/syscall64_nr.h b/linux-user/riscv/syscall64_nr.h
deleted file mode 100644
index 29e1eb2..0000000
--- a/linux-user/riscv/syscall64_nr.h
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * This file contains the system call numbers.
- * Do not modify.
- * This file is generated by scripts/gensyscalls.sh
- */
-#ifndef LINUX_USER_RISCV_SYSCALL64_NR_H
-#define LINUX_USER_RISCV_SYSCALL64_NR_H
-
-#define TARGET_NR_io_setup 0
-#define TARGET_NR_io_destroy 1
-#define TARGET_NR_io_submit 2
-#define TARGET_NR_io_cancel 3
-#define TARGET_NR_io_getevents 4
-#define TARGET_NR_setxattr 5
-#define TARGET_NR_lsetxattr 6
-#define TARGET_NR_fsetxattr 7
-#define TARGET_NR_getxattr 8
-#define TARGET_NR_lgetxattr 9
-#define TARGET_NR_fgetxattr 10
-#define TARGET_NR_listxattr 11
-#define TARGET_NR_llistxattr 12
-#define TARGET_NR_flistxattr 13
-#define TARGET_NR_removexattr 14
-#define TARGET_NR_lremovexattr 15
-#define TARGET_NR_fremovexattr 16
-#define TARGET_NR_getcwd 17
-#define TARGET_NR_lookup_dcookie 18
-#define TARGET_NR_eventfd2 19
-#define TARGET_NR_epoll_create1 20
-#define TARGET_NR_epoll_ctl 21
-#define TARGET_NR_epoll_pwait 22
-#define TARGET_NR_dup 23
-#define TARGET_NR_dup3 24
-#define TARGET_NR_fcntl 25
-#define TARGET_NR_inotify_init1 26
-#define TARGET_NR_inotify_add_watch 27
-#define TARGET_NR_inotify_rm_watch 28
-#define TARGET_NR_ioctl 29
-#define TARGET_NR_ioprio_set 30
-#define TARGET_NR_ioprio_get 31
-#define TARGET_NR_flock 32
-#define TARGET_NR_mknodat 33
-#define TARGET_NR_mkdirat 34
-#define TARGET_NR_unlinkat 35
-#define TARGET_NR_symlinkat 36
-#define TARGET_NR_linkat 37
-#define TARGET_NR_umount2 39
-#define TARGET_NR_mount 40
-#define TARGET_NR_pivot_root 41
-#define TARGET_NR_nfsservctl 42
-#define TARGET_NR_statfs 43
-#define TARGET_NR_fstatfs 44
-#define TARGET_NR_truncate 45
-#define TARGET_NR_ftruncate 46
-#define TARGET_NR_fallocate 47
-#define TARGET_NR_faccessat 48
-#define TARGET_NR_chdir 49
-#define TARGET_NR_fchdir 50
-#define TARGET_NR_chroot 51
-#define TARGET_NR_fchmod 52
-#define TARGET_NR_fchmodat 53
-#define TARGET_NR_fchownat 54
-#define TARGET_NR_fchown 55
-#define TARGET_NR_openat 56
-#define TARGET_NR_close 57
-#define TARGET_NR_vhangup 58
-#define TARGET_NR_pipe2 59
-#define TARGET_NR_quotactl 60
-#define TARGET_NR_getdents64 61
-#define TARGET_NR_lseek 62
-#define TARGET_NR_read 63
-#define TARGET_NR_write 64
-#define TARGET_NR_readv 65
-#define TARGET_NR_writev 66
-#define TARGET_NR_pread64 67
-#define TARGET_NR_pwrite64 68
-#define TARGET_NR_preadv 69
-#define TARGET_NR_pwritev 70
-#define TARGET_NR_sendfile 71
-#define TARGET_NR_pselect6 72
-#define TARGET_NR_ppoll 73
-#define TARGET_NR_signalfd4 74
-#define TARGET_NR_vmsplice 75
-#define TARGET_NR_splice 76
-#define TARGET_NR_tee 77
-#define TARGET_NR_readlinkat 78
-#define TARGET_NR_newfstatat 79
-#define TARGET_NR_fstat 80
-#define TARGET_NR_sync 81
-#define TARGET_NR_fsync 82
-#define TARGET_NR_fdatasync 83
-#define TARGET_NR_sync_file_range 84
-#define TARGET_NR_timerfd_create 85
-#define TARGET_NR_timerfd_settime 86
-#define TARGET_NR_timerfd_gettime 87
-#define TARGET_NR_utimensat 88
-#define TARGET_NR_acct 89
-#define TARGET_NR_capget 90
-#define TARGET_NR_capset 91
-#define TARGET_NR_personality 92
-#define TARGET_NR_exit 93
-#define TARGET_NR_exit_group 94
-#define TARGET_NR_waitid 95
-#define TARGET_NR_set_tid_address 96
-#define TARGET_NR_unshare 97
-#define TARGET_NR_futex 98
-#define TARGET_NR_set_robust_list 99
-#define TARGET_NR_get_robust_list 100
-#define TARGET_NR_nanosleep 101
-#define TARGET_NR_getitimer 102
-#define TARGET_NR_setitimer 103
-#define TARGET_NR_kexec_load 104
-#define TARGET_NR_init_module 105
-#define TARGET_NR_delete_module 106
-#define TARGET_NR_timer_create 107
-#define TARGET_NR_timer_gettime 108
-#define TARGET_NR_timer_getoverrun 109
-#define TARGET_NR_timer_settime 110
-#define TARGET_NR_timer_delete 111
-#define TARGET_NR_clock_settime 112
-#define TARGET_NR_clock_gettime 113
-#define TARGET_NR_clock_getres 114
-#define TARGET_NR_clock_nanosleep 115
-#define TARGET_NR_syslog 116
-#define TARGET_NR_ptrace 117
-#define TARGET_NR_sched_setparam 118
-#define TARGET_NR_sched_setscheduler 119
-#define TARGET_NR_sched_getscheduler 120
-#define TARGET_NR_sched_getparam 121
-#define TARGET_NR_sched_setaffinity 122
-#define TARGET_NR_sched_getaffinity 123
-#define TARGET_NR_sched_yield 124
-#define TARGET_NR_sched_get_priority_max 125
-#define TARGET_NR_sched_get_priority_min 126
-#define TARGET_NR_sched_rr_get_interval 127
-#define TARGET_NR_restart_syscall 128
-#define TARGET_NR_kill 129
-#define TARGET_NR_tkill 130
-#define TARGET_NR_tgkill 131
-#define TARGET_NR_sigaltstack 132
-#define TARGET_NR_rt_sigsuspend 133
-#define TARGET_NR_rt_sigaction 134
-#define TARGET_NR_rt_sigprocmask 135
-#define TARGET_NR_rt_sigpending 136
-#define TARGET_NR_rt_sigtimedwait 137
-#define TARGET_NR_rt_sigqueueinfo 138
-#define TARGET_NR_rt_sigreturn 139
-#define TARGET_NR_setpriority 140
-#define TARGET_NR_getpriority 141
-#define TARGET_NR_reboot 142
-#define TARGET_NR_setregid 143
-#define TARGET_NR_setgid 144
-#define TARGET_NR_setreuid 145
-#define TARGET_NR_setuid 146
-#define TARGET_NR_setresuid 147
-#define TARGET_NR_getresuid 148
-#define TARGET_NR_setresgid 149
-#define TARGET_NR_getresgid 150
-#define TARGET_NR_setfsuid 151
-#define TARGET_NR_setfsgid 152
-#define TARGET_NR_times 153
-#define TARGET_NR_setpgid 154
-#define TARGET_NR_getpgid 155
-#define TARGET_NR_getsid 156
-#define TARGET_NR_setsid 157
-#define TARGET_NR_getgroups 158
-#define TARGET_NR_setgroups 159
-#define TARGET_NR_uname 160
-#define TARGET_NR_sethostname 161
-#define TARGET_NR_setdomainname 162
-#define TARGET_NR_getrlimit 163
-#define TARGET_NR_setrlimit 164
-#define TARGET_NR_getrusage 165
-#define TARGET_NR_umask 166
-#define TARGET_NR_prctl 167
-#define TARGET_NR_getcpu 168
-#define TARGET_NR_gettimeofday 169
-#define TARGET_NR_settimeofday 170
-#define TARGET_NR_adjtimex 171
-#define TARGET_NR_getpid 172
-#define TARGET_NR_getppid 173
-#define TARGET_NR_getuid 174
-#define TARGET_NR_geteuid 175
-#define TARGET_NR_getgid 176
-#define TARGET_NR_getegid 177
-#define TARGET_NR_gettid 178
-#define TARGET_NR_sysinfo 179
-#define TARGET_NR_mq_open 180
-#define TARGET_NR_mq_unlink 181
-#define TARGET_NR_mq_timedsend 182
-#define TARGET_NR_mq_timedreceive 183
-#define TARGET_NR_mq_notify 184
-#define TARGET_NR_mq_getsetattr 185
-#define TARGET_NR_msgget 186
-#define TARGET_NR_msgctl 187
-#define TARGET_NR_msgrcv 188
-#define TARGET_NR_msgsnd 189
-#define TARGET_NR_semget 190
-#define TARGET_NR_semctl 191
-#define TARGET_NR_semtimedop 192
-#define TARGET_NR_semop 193
-#define TARGET_NR_shmget 194
-#define TARGET_NR_shmctl 195
-#define TARGET_NR_shmat 196
-#define TARGET_NR_shmdt 197
-#define TARGET_NR_socket 198
-#define TARGET_NR_socketpair 199
-#define TARGET_NR_bind 200
-#define TARGET_NR_listen 201
-#define TARGET_NR_accept 202
-#define TARGET_NR_connect 203
-#define TARGET_NR_getsockname 204
-#define TARGET_NR_getpeername 205
-#define TARGET_NR_sendto 206
-#define TARGET_NR_recvfrom 207
-#define TARGET_NR_setsockopt 208
-#define TARGET_NR_getsockopt 209
-#define TARGET_NR_shutdown 210
-#define TARGET_NR_sendmsg 211
-#define TARGET_NR_recvmsg 212
-#define TARGET_NR_readahead 213
-#define TARGET_NR_brk 214
-#define TARGET_NR_munmap 215
-#define TARGET_NR_mremap 216
-#define TARGET_NR_add_key 217
-#define TARGET_NR_request_key 218
-#define TARGET_NR_keyctl 219
-#define TARGET_NR_clone 220
-#define TARGET_NR_execve 221
-#define TARGET_NR_mmap 222
-#define TARGET_NR_fadvise64 223
-#define TARGET_NR_swapon 224
-#define TARGET_NR_swapoff 225
-#define TARGET_NR_mprotect 226
-#define TARGET_NR_msync 227
-#define TARGET_NR_mlock 228
-#define TARGET_NR_munlock 229
-#define TARGET_NR_mlockall 230
-#define TARGET_NR_munlockall 231
-#define TARGET_NR_mincore 232
-#define TARGET_NR_madvise 233
-#define TARGET_NR_remap_file_pages 234
-#define TARGET_NR_mbind 235
-#define TARGET_NR_get_mempolicy 236
-#define TARGET_NR_set_mempolicy 237
-#define TARGET_NR_migrate_pages 238
-#define TARGET_NR_move_pages 239
-#define TARGET_NR_rt_tgsigqueueinfo 240
-#define TARGET_NR_perf_event_open 241
-#define TARGET_NR_accept4 242
-#define TARGET_NR_recvmmsg 243
-#define TARGET_NR_arch_specific_syscall 244
-#define TARGET_NR_riscv_flush_icache (TARGET_NR_arch_specific_syscall + 15)
-#define TARGET_NR_riscv_hwprobe (TARGET_NR_arch_specific_syscall + 14)
-#define TARGET_NR_wait4 260
-#define TARGET_NR_prlimit64 261
-#define TARGET_NR_fanotify_init 262
-#define TARGET_NR_fanotify_mark 263
-#define TARGET_NR_name_to_handle_at 264
-#define TARGET_NR_open_by_handle_at 265
-#define TARGET_NR_clock_adjtime 266
-#define TARGET_NR_syncfs 267
-#define TARGET_NR_setns 268
-#define TARGET_NR_sendmmsg 269
-#define TARGET_NR_process_vm_readv 270
-#define TARGET_NR_process_vm_writev 271
-#define TARGET_NR_kcmp 272
-#define TARGET_NR_finit_module 273
-#define TARGET_NR_sched_setattr 274
-#define TARGET_NR_sched_getattr 275
-#define TARGET_NR_renameat2 276
-#define TARGET_NR_seccomp 277
-#define TARGET_NR_getrandom 278
-#define TARGET_NR_memfd_create 279
-#define TARGET_NR_bpf 280
-#define TARGET_NR_execveat 281
-#define TARGET_NR_userfaultfd 282
-#define TARGET_NR_membarrier 283
-#define TARGET_NR_mlock2 284
-#define TARGET_NR_copy_file_range 285
-#define TARGET_NR_preadv2 286
-#define TARGET_NR_pwritev2 287
-#define TARGET_NR_pkey_mprotect 288
-#define TARGET_NR_pkey_alloc 289
-#define TARGET_NR_pkey_free 290
-#define TARGET_NR_statx 291
-#define TARGET_NR_io_pgetevents 292
-#define TARGET_NR_rseq 293
-#define TARGET_NR_kexec_file_load 294
-#define TARGET_NR_pidfd_send_signal 424
-#define TARGET_NR_io_uring_setup 425
-#define TARGET_NR_io_uring_enter 426
-#define TARGET_NR_io_uring_register 427
-#define TARGET_NR_open_tree 428
-#define TARGET_NR_move_mount 429
-#define TARGET_NR_fsopen 430
-#define TARGET_NR_fsconfig 431
-#define TARGET_NR_fsmount 432
-#define TARGET_NR_fspick 433
-#define TARGET_NR_pidfd_open 434
-#define TARGET_NR_clone3 435
-#define TARGET_NR_close_range 436
-#define TARGET_NR_openat2 437
-#define TARGET_NR_pidfd_getfd 438
-#define TARGET_NR_faccessat2 439
-#define TARGET_NR_process_madvise 440
-#define TARGET_NR_epoll_pwait2 441
-#define TARGET_NR_mount_setattr 442
-#define TARGET_NR_landlock_create_ruleset 444
-#define TARGET_NR_landlock_add_rule 445
-#define TARGET_NR_landlock_restrict_self 446
-#define TARGET_NR_syscalls 447
-
-#endif /* LINUX_USER_RISCV_SYSCALL64_NR_H */
diff --git a/linux-user/riscv/syscall_nr.h b/linux-user/riscv/syscall_nr.h
deleted file mode 100644
index 0a5a2f2..0000000
--- a/linux-user/riscv/syscall_nr.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Syscall numbers from asm-generic, common for most
- * of recently-added arches including RISC-V.
- */
-
-#ifndef LINUX_USER_RISCV_SYSCALL_NR_H
-#define LINUX_USER_RISCV_SYSCALL_NR_H
-
-#ifdef TARGET_RISCV32
-# include "syscall32_nr.h"
-#else
-# include "syscall64_nr.h"
-#endif
-
-#endif
diff --git a/linux-user/riscv/syscallhdr.sh b/linux-user/riscv/syscallhdr.sh
new file mode 100644
index 0000000..4069dc5
--- /dev/null
+++ b/linux-user/riscv/syscallhdr.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+in="$1"
+out="$2"
+my_abis=`echo "($3)" | tr ',' '|'`
+prefix="$4"
+offset="$5"
+
+fileguard=LINUX_USER_X86_64_`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 | (
+ echo "#ifndef ${fileguard}"
+ echo "#define ${fileguard} 1"
+ echo ""
+
+ while read nr abi name entry compat ; do
+ if [ -z "$offset" ]; then
+ echo "#define TARGET_NR_${prefix}${name} $nr"
+ else
+ echo "#define TARGET_NR_${prefix}${name} ($offset + $nr)"
+ fi
+ done
+
+ echo ""
+ echo "#endif /* ${fileguard} */"
+) > "$out"
diff --git a/linux-user/s390x/syscall.tbl b/linux-user/s390x/syscall.tbl
index 0690263..8e0d1f1 100644
--- a/linux-user/s390x/syscall.tbl
+++ b/linux-user/s390x/syscall.tbl
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
#
# System call table for s390
#
@@ -100,7 +100,7 @@
106 common stat sys_newstat compat_sys_newstat
107 common lstat sys_newlstat compat_sys_newlstat
108 common fstat sys_newfstat compat_sys_newfstat
-110 common lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie
+110 common lookup_dcookie - -
111 common vhangup sys_vhangup sys_vhangup
112 common idle - -
114 common wait4 sys_wait4 compat_sys_wait4
@@ -122,7 +122,7 @@
131 common quotactl sys_quotactl sys_quotactl
132 common getpgid sys_getpgid sys_getpgid
133 common fchdir sys_fchdir sys_fchdir
-134 common bdflush sys_bdflush sys_bdflush
+134 common bdflush sys_ni_syscall sys_ni_syscall
135 common sysfs sys_sysfs sys_sysfs
136 common personality sys_s390_personality sys_s390_personality
137 common afs_syscall - -
@@ -274,9 +274,9 @@
265 common statfs64 sys_statfs64 compat_sys_statfs64
266 common fstatfs64 sys_fstatfs64 compat_sys_fstatfs64
267 common remap_file_pages sys_remap_file_pages sys_remap_file_pages
-268 common mbind sys_mbind compat_sys_mbind
-269 common get_mempolicy sys_get_mempolicy compat_sys_get_mempolicy
-270 common set_mempolicy sys_set_mempolicy compat_sys_set_mempolicy
+268 common mbind sys_mbind sys_mbind
+269 common get_mempolicy sys_get_mempolicy sys_get_mempolicy
+270 common set_mempolicy sys_set_mempolicy sys_set_mempolicy
271 common mq_open sys_mq_open compat_sys_mq_open
272 common mq_unlink sys_mq_unlink sys_mq_unlink
273 common mq_timedsend sys_mq_timedsend sys_mq_timedsend_time32
@@ -293,7 +293,7 @@
284 common inotify_init sys_inotify_init sys_inotify_init
285 common inotify_add_watch sys_inotify_add_watch sys_inotify_add_watch
286 common inotify_rm_watch sys_inotify_rm_watch sys_inotify_rm_watch
-287 common migrate_pages sys_migrate_pages compat_sys_migrate_pages
+287 common migrate_pages sys_migrate_pages sys_migrate_pages
288 common openat sys_openat compat_sys_openat
289 common mkdirat sys_mkdirat sys_mkdirat
290 common mknodat sys_mknodat sys_mknodat
@@ -317,7 +317,7 @@
307 common sync_file_range sys_sync_file_range compat_sys_s390_sync_file_range
308 common tee sys_tee sys_tee
309 common vmsplice sys_vmsplice sys_vmsplice
-310 common move_pages sys_move_pages compat_sys_move_pages
+310 common move_pages sys_move_pages sys_move_pages
311 common getcpu sys_getcpu sys_getcpu
312 common epoll_pwait sys_epoll_pwait compat_sys_epoll_pwait
313 common utimes sys_utimes sys_utimes_time32
@@ -418,7 +418,7 @@
412 32 utimensat_time64 - sys_utimensat
413 32 pselect6_time64 - compat_sys_pselect6_time64
414 32 ppoll_time64 - compat_sys_ppoll_time64
-416 32 io_pgetevents_time64 - sys_io_pgetevents
+416 32 io_pgetevents_time64 - compat_sys_io_pgetevents_time64
417 32 recvmmsg_time64 - compat_sys_recvmmsg_time64
418 32 mq_timedsend_time64 - sys_mq_timedsend
419 32 mq_timedreceive_time64 - sys_mq_timedreceive
@@ -445,7 +445,23 @@
440 common process_madvise sys_process_madvise sys_process_madvise
441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
442 common mount_setattr sys_mount_setattr sys_mount_setattr
-# 443 reserved for quotactl_path
+443 common quotactl_fd sys_quotactl_fd sys_quotactl_fd
444 common landlock_create_ruleset sys_landlock_create_ruleset sys_landlock_create_ruleset
445 common landlock_add_rule sys_landlock_add_rule sys_landlock_add_rule
446 common landlock_restrict_self sys_landlock_restrict_self sys_landlock_restrict_self
+447 common memfd_secret sys_memfd_secret sys_memfd_secret
+448 common process_mrelease sys_process_mrelease sys_process_mrelease
+449 common futex_waitv sys_futex_waitv sys_futex_waitv
+450 common set_mempolicy_home_node sys_set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common cachestat sys_cachestat sys_cachestat
+452 common fchmodat2 sys_fchmodat2 sys_fchmodat2
+453 common map_shadow_stack sys_map_shadow_stack sys_map_shadow_stack
+454 common futex_wake sys_futex_wake sys_futex_wake
+455 common futex_wait sys_futex_wait sys_futex_wait
+456 common futex_requeue sys_futex_requeue sys_futex_requeue
+457 common statmount sys_statmount sys_statmount
+458 common listmount sys_listmount sys_listmount
+459 common lsm_get_self_attr sys_lsm_get_self_attr sys_lsm_get_self_attr
+460 common lsm_set_self_attr sys_lsm_set_self_attr sys_lsm_set_self_attr
+461 common lsm_list_modules sys_lsm_list_modules sys_lsm_list_modules
+462 common mseal sys_mseal sys_mseal
diff --git a/linux-user/s390x/syscallhdr.sh b/linux-user/s390x/syscallhdr.sh
index 85a99c4..ac22d42 100755
--- a/linux-user/s390x/syscallhdr.sh
+++ b/linux-user/s390x/syscallhdr.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
in="$1"
out="$2"
diff --git a/linux-user/sh4/syscall.tbl b/linux-user/sh4/syscall.tbl
index 0b91499..cf4ec04 100644
--- a/linux-user/sh4/syscall.tbl
+++ b/linux-user/sh4/syscall.tbl
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
#
# system call numbers and entry vectors for sh
#
@@ -141,7 +141,7 @@
131 common quotactl sys_quotactl
132 common getpgid sys_getpgid
133 common fchdir sys_fchdir
-134 common bdflush sys_bdflush
+134 common bdflush sys_ni_syscall
135 common sysfs sys_sysfs
136 common personality sys_personality
# 137 was afs_syscall
@@ -260,7 +260,7 @@
250 common fadvise64 sys_fadvise64
# 251 is unused
252 common exit_group sys_exit_group
-253 common lookup_dcookie sys_lookup_dcookie
+253 common lookup_dcookie sys_ni_syscall
254 common epoll_create sys_epoll_create
255 common epoll_ctl sys_epoll_ctl
256 common epoll_wait sys_epoll_wait
@@ -321,7 +321,7 @@
311 common set_robust_list sys_set_robust_list
312 common get_robust_list sys_get_robust_list
313 common splice sys_splice
-314 common sync_file_range sys_sync_file_range
+314 common sync_file_range sys_sh_sync_file_range6
315 common tee sys_tee
316 common vmsplice sys_vmsplice
317 common move_pages sys_move_pages
@@ -395,6 +395,7 @@
385 common pkey_alloc sys_pkey_alloc
386 common pkey_free sys_pkey_free
387 common rseq sys_rseq
+388 common sync_file_range2 sys_sync_file_range2
# room for arch specific syscalls
393 common semget sys_semget
394 common semctl sys_semctl
@@ -445,7 +446,23 @@
440 common process_madvise sys_process_madvise
441 common epoll_pwait2 sys_epoll_pwait2
442 common mount_setattr sys_mount_setattr
-# 443 reserved for quotactl_path
+443 common quotactl_fd sys_quotactl_fd
444 common landlock_create_ruleset sys_landlock_create_ruleset
445 common landlock_add_rule sys_landlock_add_rule
446 common landlock_restrict_self sys_landlock_restrict_self
+# 447 reserved for memfd_secret
+448 common process_mrelease sys_process_mrelease
+449 common futex_waitv sys_futex_waitv
+450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common cachestat sys_cachestat
+452 common fchmodat2 sys_fchmodat2
+453 common map_shadow_stack sys_map_shadow_stack
+454 common futex_wake sys_futex_wake
+455 common futex_wait sys_futex_wait
+456 common futex_requeue sys_futex_requeue
+457 common statmount sys_statmount
+458 common listmount sys_listmount
+459 common lsm_get_self_attr sys_lsm_get_self_attr
+460 common lsm_set_self_attr sys_lsm_set_self_attr
+461 common lsm_list_modules sys_lsm_list_modules
+462 common mseal sys_mseal
diff --git a/linux-user/sh4/syscallhdr.sh b/linux-user/sh4/syscallhdr.sh
index 0807905..cb3a5de 100644
--- a/linux-user/sh4/syscallhdr.sh
+++ b/linux-user/sh4/syscallhdr.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
in="$1"
out="$2"
diff --git a/linux-user/sparc/syscall.tbl b/linux-user/sparc/syscall.tbl
index e34cc30..3bc8378 100644
--- a/linux-user/sparc/syscall.tbl
+++ b/linux-user/sparc/syscall.tbl
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
#
# system call numbers and entry vectors for sparc
#
@@ -117,7 +117,7 @@
90 common dup2 sys_dup2
91 32 setfsuid32 sys_setfsuid
92 common fcntl sys_fcntl compat_sys_fcntl
-93 common select sys_select
+93 common select sys_select compat_sys_select
94 32 setfsgid32 sys_setfsgid
95 common fsync sys_fsync
96 common setpriority sys_setpriority
@@ -155,7 +155,7 @@
123 32 fchown sys_fchown16
123 64 fchown sys_fchown
124 common fchmod sys_fchmod
-125 common recvfrom sys_recvfrom
+125 common recvfrom sys_recvfrom compat_sys_recvfrom
126 32 setreuid sys_setreuid16
126 64 setreuid sys_setreuid
127 32 setregid sys_setregid16
@@ -247,9 +247,9 @@
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
+206 common socketcall sys_socketcall compat_sys_socketcall
207 common syslog sys_syslog
-208 common lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie
+208 common lookup_dcookie sys_ni_syscall
209 common fadvise64 sys_fadvise64 compat_sys_fadvise64
210 common fadvise64_64 sys_fadvise64_64 compat_sys_fadvise64_64
211 common tgkill sys_tgkill
@@ -270,7 +270,7 @@
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
+225 common bdflush sys_ni_syscall
226 common sysfs sys_sysfs
227 common afs_syscall sys_nis_syscall
228 common setfsuid sys_setfsuid16
@@ -365,12 +365,12 @@
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
+302 common migrate_pages sys_migrate_pages
+303 common mbind sys_mbind
+304 common get_mempolicy sys_get_mempolicy
+305 common set_mempolicy 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
+307 common move_pages 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
@@ -461,7 +461,7 @@
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
+416 32 io_pgetevents_time64 sys_io_pgetevents compat_sys_io_pgetevents_time64
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
@@ -488,7 +488,23 @@
440 common process_madvise sys_process_madvise
441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
442 common mount_setattr sys_mount_setattr
-# 443 reserved for quotactl_path
+443 common quotactl_fd sys_quotactl_fd
444 common landlock_create_ruleset sys_landlock_create_ruleset
445 common landlock_add_rule sys_landlock_add_rule
446 common landlock_restrict_self sys_landlock_restrict_self
+# 447 reserved for memfd_secret
+448 common process_mrelease sys_process_mrelease
+449 common futex_waitv sys_futex_waitv
+450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common cachestat sys_cachestat
+452 common fchmodat2 sys_fchmodat2
+453 common map_shadow_stack sys_map_shadow_stack
+454 common futex_wake sys_futex_wake
+455 common futex_wait sys_futex_wait
+456 common futex_requeue sys_futex_requeue
+457 common statmount sys_statmount
+458 common listmount sys_listmount
+459 common lsm_get_self_attr sys_lsm_get_self_attr
+460 common lsm_set_self_attr sys_lsm_set_self_attr
+461 common lsm_list_modules sys_lsm_list_modules
+462 common mseal sys_mseal
diff --git a/linux-user/sparc/syscallhdr.sh b/linux-user/sparc/syscallhdr.sh
index 34a99dc..938a02b 100644
--- a/linux-user/sparc/syscallhdr.sh
+++ b/linux-user/sparc/syscallhdr.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
in="$1"
out="$2"
diff --git a/linux-user/strace.c b/linux-user/strace.c
index b4d1098..b70eadc 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -13,6 +13,9 @@
#include <linux/if_packet.h>
#include <linux/in6.h>
#include <linux/netlink.h>
+#ifdef HAVE_OPENAT2_H
+#include <linux/openat2.h>
+#endif
#include <sched.h>
#include "qemu.h"
#include "user-internals.h"
@@ -158,19 +161,20 @@ static const char * const target_signal_name[] = {
};
static void
-print_signal(abi_ulong arg, int last)
+print_signal_1(abi_ulong arg)
{
- const char *signal_name = NULL;
-
if (arg < ARRAY_SIZE(target_signal_name)) {
- signal_name = target_signal_name[arg];
+ qemu_log("%s", target_signal_name[arg]);
+ } else {
+ qemu_log(TARGET_ABI_FMT_lu, arg);
}
+}
- if (signal_name == NULL) {
- print_raw_param("%ld", arg, last);
- return;
- }
- qemu_log("%s%s", signal_name, get_comma(last));
+static void
+print_signal(abi_ulong arg, int last)
+{
+ print_signal_1(arg);
+ qemu_log("%s", get_comma(last));
}
static void print_si_code(int arg)
@@ -373,7 +377,7 @@ print_sockaddr(abi_ulong addr, abi_long addrlen, int last)
un->sun_path[i]; i++) {
qemu_log("%c", un->sun_path[i]);
}
- qemu_log("\"}");
+ qemu_log("\"},");
break;
}
case AF_INET: {
@@ -383,7 +387,7 @@ print_sockaddr(abi_ulong addr, abi_long addrlen, int last)
ntohs(in->sin_port));
qemu_log("sin_addr=inet_addr(\"%d.%d.%d.%d\")",
c[0], c[1], c[2], c[3]);
- qemu_log("}");
+ qemu_log("},");
break;
}
case AF_PACKET: {
@@ -414,12 +418,12 @@ print_sockaddr(abi_ulong addr, abi_long addrlen, int last)
}
qemu_log(",sll_addr=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
- qemu_log("}");
+ qemu_log("},");
break;
}
case AF_NETLINK: {
struct target_sockaddr_nl *nl = (struct target_sockaddr_nl *)sa;
- qemu_log("{nl_family=AF_NETLINK,nl_pid=%u,nl_groups=%u}",
+ qemu_log("{nl_family=AF_NETLINK,nl_pid=%u,nl_groups=%u},",
tswap32(nl->nl_pid), tswap32(nl->nl_groups));
break;
}
@@ -429,14 +433,14 @@ print_sockaddr(abi_ulong addr, abi_long addrlen, int last)
qemu_log("%02x, ", sa->sa_data[i]);
}
qemu_log("%02x}", sa->sa_data[i]);
- qemu_log("}");
+ qemu_log("},");
break;
}
unlock_user(sa, addr, 0);
} else {
- print_raw_param("0x"TARGET_ABI_FMT_lx, addr, 0);
+ print_pointer(addr, 0);
}
- qemu_log(", "TARGET_ABI_FMT_ld"%s", addrlen, get_comma(last));
+ qemu_log(TARGET_ABI_FMT_ld"%s", addrlen, get_comma(last));
}
static void
@@ -715,6 +719,51 @@ print_ipc(CPUArchState *cpu_env, const struct syscallname *name,
}
#endif
+#ifdef TARGET_NR_rt_sigprocmask
+static void print_target_sigset_t_1(target_sigset_t *set, int last)
+{
+ bool first = true;
+ int i, sig = 1;
+
+ qemu_log("[");
+ for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+ abi_ulong bits = 0;
+ int j;
+
+ __get_user(bits, &set->sig[i]);
+ for (j = 0; j < sizeof(bits) * 8; j++) {
+ if (bits & ((abi_ulong)1 << j)) {
+ if (first) {
+ first = false;
+ } else {
+ qemu_log(" ");
+ }
+ print_signal_1(sig);
+ }
+ sig++;
+ }
+ }
+ qemu_log("]%s", get_comma(last));
+}
+
+static void print_target_sigset_t(abi_ulong addr, abi_ulong size, int last)
+{
+ if (addr && size == sizeof(target_sigset_t)) {
+ target_sigset_t *set;
+
+ set = lock_user(VERIFY_READ, addr, sizeof(target_sigset_t), 1);
+ if (set) {
+ print_target_sigset_t_1(set, last);
+ unlock_user(set, addr, 0);
+ } else {
+ print_pointer(addr, last);
+ }
+ } else {
+ print_pointer(addr, last);
+ }
+}
+#endif
+
/*
* Variants for the return value output function
*/
@@ -1063,6 +1112,18 @@ UNUSED static const struct flags open_flags[] = {
FLAG_END,
};
+UNUSED static const struct flags openat2_resolve_flags[] = {
+#ifdef HAVE_OPENAT2_H
+ FLAG_GENERIC(RESOLVE_NO_XDEV),
+ FLAG_GENERIC(RESOLVE_NO_MAGICLINKS),
+ FLAG_GENERIC(RESOLVE_NO_SYMLINKS),
+ FLAG_GENERIC(RESOLVE_BENEATH),
+ FLAG_GENERIC(RESOLVE_IN_ROOT),
+ FLAG_GENERIC(RESOLVE_CACHED),
+#endif
+ FLAG_END,
+};
+
UNUSED static const struct flags mount_flags[] = {
#ifdef MS_BIND
FLAG_GENERIC(MS_BIND),
@@ -1655,6 +1716,13 @@ print_buf(abi_long addr, abi_long len, int last)
}
}
+static void
+print_buf_len(abi_long addr, abi_long len, int last)
+{
+ print_buf(addr, len, 0);
+ print_raw_param(TARGET_ABI_FMT_ld, len, last);
+}
+
/*
* Prints out raw parameter using given format. Caller needs
* to do byte swapping if needed.
@@ -2742,8 +2810,7 @@ static void do_print_sendrecv(const char *name, abi_long arg1)
qemu_log("%s(", name);
print_sockfd(sockfd, 0);
- print_buf(msg, len, 0);
- print_raw_param(TARGET_ABI_FMT_ld, len, 0);
+ print_buf_len(msg, len, 0);
print_flags(msg_flags, flags, 1);
qemu_log(")");
}
@@ -2761,8 +2828,7 @@ static void do_print_msgaddr(const char *name, abi_long arg1)
qemu_log("%s(", name);
print_sockfd(sockfd, 0);
- print_buf(msg, len, 0);
- print_raw_param(TARGET_ABI_FMT_ld, len, 0);
+ print_buf_len(msg, len, 0);
print_flags(msg_flags, flags, 0);
print_sockaddr(addr, addrlen, 0);
qemu_log(")");
@@ -3122,6 +3188,38 @@ print_bind(CPUArchState *cpu_env, const struct syscallname *name,
}
#endif
+#ifdef TARGET_NR_recvfrom
+static void
+print_recvfrom(CPUArchState *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_sockfd(arg0, 0);
+ print_pointer(arg1, 0); /* output */
+ print_raw_param(TARGET_ABI_FMT_ld, arg2, 0);
+ print_flags(msg_flags, arg3, 0);
+ print_pointer(arg4, 0); /* output */
+ print_pointer(arg5, 1); /* in/out */
+ print_syscall_epilogue(name);
+}
+#endif
+
+#ifdef TARGET_NR_sendto
+static void
+print_sendto(CPUArchState *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_sockfd(arg0, 0);
+ print_buf_len(arg1, arg2, 0);
+ print_flags(msg_flags, arg3, 0);
+ print_sockaddr(arg4, arg5, 1);
+ print_syscall_epilogue(name);
+}
+#endif
+
#if defined(TARGET_NR_stat) || defined(TARGET_NR_stat64) || \
defined(TARGET_NR_lstat) || defined(TARGET_NR_lstat64)
static void
@@ -3260,11 +3358,29 @@ print_rt_sigprocmask(CPUArchState *cpu_env, const struct syscallname *name,
case TARGET_SIG_SETMASK: how = "SIG_SETMASK"; break;
}
qemu_log("%s,", how);
- print_pointer(arg1, 0);
+ print_target_sigset_t(arg1, arg3, 0);
print_pointer(arg2, 0);
print_raw_param("%u", arg3, 1);
print_syscall_epilogue(name);
}
+
+static void
+print_rt_sigprocmask_ret(CPUArchState *cpu_env, const struct syscallname *name,
+ abi_long ret, abi_long arg0, abi_long arg1,
+ abi_long arg2, abi_long arg3, abi_long arg4,
+ abi_long arg5)
+{
+ if (!print_syscall_err(ret)) {
+ qemu_log(TARGET_ABI_FMT_ld, ret);
+ if (arg2) {
+ qemu_log(" (oldset=");
+ print_target_sigset_t(arg2, arg3, 1);
+ qemu_log(")");
+ }
+ }
+
+ qemu_log("\n");
+}
#endif
#ifdef TARGET_NR_rt_sigqueueinfo
@@ -3483,6 +3599,38 @@ print_openat(CPUArchState *cpu_env, const struct syscallname *name,
}
#endif
+#ifdef TARGET_NR_openat2
+static void
+print_openat2(CPUArchState *cpu_env, const struct syscallname *name,
+ abi_long arg0, abi_long arg1, abi_long arg2,
+ abi_long arg3, abi_long arg4, abi_long arg5)
+{
+ struct open_how_ver0 how;
+
+ print_syscall_prologue(name);
+ print_at_dirfd(arg0, 0);
+ print_string(arg1, 0);
+
+ if ((abi_ulong)arg3 >= sizeof(struct target_open_how_ver0) &&
+ copy_struct_from_user(&how, sizeof(how), arg2, arg3) == 0) {
+ how.flags = tswap64(how.flags);
+ how.mode = tswap64(how.mode);
+ how.resolve = tswap64(how.resolve);
+ qemu_log("{");
+ print_open_flags(how.flags, 0);
+ if (how.flags & TARGET_O_CREAT) {
+ print_file_mode(how.mode, 0);
+ }
+ print_flags(openat2_resolve_flags, how.resolve, 1);
+ qemu_log("},");
+ } else {
+ print_pointer(arg2, 0);
+ }
+ print_raw_param(TARGET_ABI_FMT_lu, arg3, 1);
+ print_syscall_epilogue(name);
+}
+#endif
+
#ifdef TARGET_NR_pidfd_send_signal
static void
print_pidfd_send_signal(CPUArchState *cpu_env, const struct syscallname *name,
@@ -4168,6 +4316,63 @@ print_ioctl(CPUArchState *cpu_env, const struct syscallname *name,
}
#endif
+#if defined(TARGET_NR_wait4) || defined(TARGET_NR_waitpid)
+static void print_wstatus(int wstatus)
+{
+ if (WIFSIGNALED(wstatus)) {
+ qemu_log("{WIFSIGNALED(s) && WTERMSIG(s) == ");
+ print_signal(WTERMSIG(wstatus), 1);
+ if (WCOREDUMP(wstatus)) {
+ qemu_log(" && WCOREDUMP(s)");
+ }
+ qemu_log("}");
+ } else if (WIFEXITED(wstatus)) {
+ qemu_log("{WIFEXITED(s) && WEXITSTATUS(s) == %d}",
+ WEXITSTATUS(wstatus));
+ } else {
+ print_number(wstatus, 1);
+ }
+}
+
+static void print_ret_wstatus(abi_long ret, abi_long wstatus_addr)
+{
+ int wstatus;
+
+ if (!print_syscall_err(ret)
+ && wstatus_addr
+ && get_user_s32(wstatus, wstatus_addr)) {
+ qemu_log(TARGET_ABI_FMT_ld " (wstatus=", ret);
+ print_wstatus(wstatus);
+ qemu_log(")");
+ }
+ qemu_log("\n");
+}
+#endif
+
+#ifdef TARGET_NR_wait4
+static void
+print_syscall_ret_wait4(CPUArchState *cpu_env,
+ const struct syscallname *name,
+ abi_long ret, abi_long arg0, abi_long arg1,
+ abi_long arg2, abi_long arg3, abi_long arg4,
+ abi_long arg5)
+{
+ print_ret_wstatus(ret, arg1);
+}
+#endif
+
+#ifdef TARGET_NR_waitpid
+static void
+print_syscall_ret_waitpid(CPUArchState *cpu_env,
+ const struct syscallname *name,
+ abi_long ret, abi_long arg0, abi_long arg1,
+ abi_long arg2, abi_long arg3, abi_long arg4,
+ abi_long arg5)
+{
+ print_ret_wstatus(ret, arg1);
+}
+#endif
+
/*
* An array of all of the syscalls we know about
*/
diff --git a/linux-user/strace.list b/linux-user/strace.list
index dfd4237..fdf94ef 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -715,6 +715,9 @@
#ifdef TARGET_NR_openat
{ TARGET_NR_openat, "openat" , NULL, print_openat, NULL },
#endif
+#ifdef TARGET_NR_openat2
+{ TARGET_NR_openat2, "openat2" , NULL, print_openat2, NULL },
+#endif
#ifdef TARGET_NR_osf_adjtime
{ TARGET_NR_osf_adjtime, "osf_adjtime" , NULL, NULL, NULL },
#endif
@@ -1135,7 +1138,7 @@
{ TARGET_NR_recv, "recv" , "%s(%d,%p,%u,%d)", NULL, NULL },
#endif
#ifdef TARGET_NR_recvfrom
-{ TARGET_NR_recvfrom, "recvfrom" , NULL, NULL, NULL },
+{ TARGET_NR_recvfrom, "recvfrom" , NULL, print_recvfrom, NULL },
#endif
#ifdef TARGET_NR_recvmmsg
{ TARGET_NR_recvmmsg, "recvmmsg" , NULL, NULL, NULL },
@@ -1186,7 +1189,8 @@
{ TARGET_NR_rt_sigpending, "rt_sigpending" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_rt_sigprocmask
-{ TARGET_NR_rt_sigprocmask, "rt_sigprocmask" , NULL, print_rt_sigprocmask, NULL },
+{ TARGET_NR_rt_sigprocmask, "rt_sigprocmask" , NULL, print_rt_sigprocmask,
+ print_rt_sigprocmask_ret },
#endif
#ifdef TARGET_NR_rt_sigqueueinfo
{ TARGET_NR_rt_sigqueueinfo, "rt_sigqueueinfo" , NULL, print_rt_sigqueueinfo, NULL },
@@ -1285,7 +1289,7 @@
{ TARGET_NR_sendmsg, "sendmsg" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_sendto
-{ TARGET_NR_sendto, "sendto" , NULL, NULL, NULL },
+{ TARGET_NR_sendto, "sendto" , NULL, print_sendto, NULL },
#endif
#ifdef TARGET_NR_setdomainname
{ TARGET_NR_setdomainname, "setdomainname" , NULL, NULL, NULL },
@@ -1659,13 +1663,15 @@
{ TARGET_NR_vserver, "vserver" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_wait4
-{ TARGET_NR_wait4, "wait4" , "%s(%d,%p,%d,%p)", NULL, NULL },
+{ TARGET_NR_wait4, "wait4" , "%s(%d,%p,%d,%p)", NULL,
+ print_syscall_ret_wait4 },
#endif
#ifdef TARGET_NR_waitid
{ TARGET_NR_waitid, "waitid" , "%s(%#x,%d,%p,%#x)", NULL, NULL },
#endif
#ifdef TARGET_NR_waitpid
-{ TARGET_NR_waitpid, "waitpid" , "%s(%d,%p,%#x)", NULL, NULL },
+{ TARGET_NR_waitpid, "waitpid", "%s(%d,%p,%#x)", NULL,
+ print_syscall_ret_waitpid },
#endif
#ifdef TARGET_NR_write
{ TARGET_NR_write, "write" , "%s(%d,%#x,%d)", NULL, NULL },
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index b8c278b..59b2080 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -54,7 +54,6 @@
#include <utime.h>
#include <sys/sysinfo.h>
#include <sys/signalfd.h>
-//#include <sys/user.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
@@ -602,6 +601,33 @@ static int check_zeroed_user(abi_long addr, size_t ksize, size_t usize)
return 1;
}
+/*
+ * Copies a target struct to a host struct, in a way that guarantees
+ * backwards-compatibility for struct syscall arguments.
+ *
+ * Similar to kernels uaccess.h:copy_struct_from_user()
+ */
+int copy_struct_from_user(void *dst, size_t ksize, abi_ptr src, size_t usize)
+{
+ size_t size = MIN(ksize, usize);
+ size_t rest = MAX(ksize, usize) - size;
+
+ /* Deal with trailing bytes. */
+ if (usize < ksize) {
+ memset(dst + size, 0, rest);
+ } else if (usize > ksize) {
+ int ret = check_zeroed_user(src, ksize, usize);
+ if (ret <= 0) {
+ return ret ?: -TARGET_E2BIG;
+ }
+ }
+ /* Copy the interoperable parts of the struct. */
+ if (copy_from_user(dst, src, size)) {
+ return -TARGET_EFAULT;
+ }
+ return 0;
+}
+
#define safe_syscall0(type, name) \
static type safe_##name(void) \
{ \
@@ -653,6 +679,10 @@ safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count)
safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count)
safe_syscall4(int, openat, int, dirfd, const char *, pathname, \
int, flags, mode_t, mode)
+
+safe_syscall4(int, openat2, int, dirfd, const char *, pathname, \
+ const struct open_how_ver0 *, how, size_t, size)
+
#if defined(TARGET_NR_wait4) || defined(TARGET_NR_waitpid)
safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
struct rusage *, rusage)
@@ -759,10 +789,8 @@ safe_syscall6(ssize_t, copy_file_range, int, infd, loff_t *, pinoff,
* the libc function.
*/
#define safe_ioctl(...) safe_syscall(__NR_ioctl, __VA_ARGS__)
-/* Similarly for fcntl. Note that callers must always:
- * pass the F_GETLK64 etc constants rather than the unsuffixed F_GETLK
- * use the flock64 struct rather than unsuffixed flock
- * This will then work and use a 64-bit offset for both 32-bit and 64-bit hosts.
+/* Similarly for fcntl. Since we always build with LFS enabled,
+ * we should be using the 64-bit structures automatically.
*/
#ifdef __NR_fcntl64
#define safe_fcntl(...) safe_syscall(__NR_fcntl64, __VA_ARGS__)
@@ -6722,13 +6750,13 @@ static int target_to_host_fcntl_cmd(int cmd)
ret = cmd;
break;
case TARGET_F_GETLK:
- ret = F_GETLK64;
+ ret = F_GETLK;
break;
case TARGET_F_SETLK:
- ret = F_SETLK64;
+ ret = F_SETLK;
break;
case TARGET_F_SETLKW:
- ret = F_SETLKW64;
+ ret = F_SETLKW;
break;
case TARGET_F_GETOWN:
ret = F_GETOWN;
@@ -6744,13 +6772,13 @@ static int target_to_host_fcntl_cmd(int cmd)
break;
#if TARGET_ABI_BITS == 32
case TARGET_F_GETLK64:
- ret = F_GETLK64;
+ ret = F_GETLK;
break;
case TARGET_F_SETLK64:
- ret = F_SETLK64;
+ ret = F_SETLK;
break;
case TARGET_F_SETLKW64:
- ret = F_SETLKW64;
+ ret = F_SETLKW;
break;
#endif
case TARGET_F_SETLEASE:
@@ -6804,8 +6832,8 @@ static int target_to_host_fcntl_cmd(int cmd)
* them to 5, 6 and 7 before making the syscall(). Since we make the
* syscall directly, adjust to what is supported by the kernel.
*/
- if (ret >= F_GETLK64 && ret <= F_SETLKW64) {
- ret -= F_GETLK64 - 5;
+ if (ret >= F_GETLK && ret <= F_SETLKW) {
+ ret -= F_GETLK - 5;
}
#endif
@@ -6838,7 +6866,7 @@ static int host_to_target_flock(int type)
return type;
}
-static inline abi_long copy_from_user_flock(struct flock64 *fl,
+static inline abi_long copy_from_user_flock(struct flock *fl,
abi_ulong target_flock_addr)
{
struct target_flock *target_fl;
@@ -6863,7 +6891,7 @@ static inline abi_long copy_from_user_flock(struct flock64 *fl,
}
static inline abi_long copy_to_user_flock(abi_ulong target_flock_addr,
- const struct flock64 *fl)
+ const struct flock *fl)
{
struct target_flock *target_fl;
short l_type;
@@ -6882,8 +6910,8 @@ static inline abi_long copy_to_user_flock(abi_ulong target_flock_addr,
return 0;
}
-typedef abi_long from_flock64_fn(struct flock64 *fl, abi_ulong target_addr);
-typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock64 *fl);
+typedef abi_long from_flock64_fn(struct flock *fl, abi_ulong target_addr);
+typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock *fl);
#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
struct target_oabi_flock64 {
@@ -6894,7 +6922,7 @@ struct target_oabi_flock64 {
abi_int l_pid;
} QEMU_PACKED;
-static inline abi_long copy_from_user_oabi_flock64(struct flock64 *fl,
+static inline abi_long copy_from_user_oabi_flock64(struct flock *fl,
abi_ulong target_flock_addr)
{
struct target_oabi_flock64 *target_fl;
@@ -6919,7 +6947,7 @@ static inline abi_long copy_from_user_oabi_flock64(struct flock64 *fl,
}
static inline abi_long copy_to_user_oabi_flock64(abi_ulong target_flock_addr,
- const struct flock64 *fl)
+ const struct flock *fl)
{
struct target_oabi_flock64 *target_fl;
short l_type;
@@ -6939,7 +6967,7 @@ static inline abi_long copy_to_user_oabi_flock64(abi_ulong target_flock_addr,
}
#endif
-static inline abi_long copy_from_user_flock64(struct flock64 *fl,
+static inline abi_long copy_from_user_flock64(struct flock *fl,
abi_ulong target_flock_addr)
{
struct target_flock64 *target_fl;
@@ -6964,7 +6992,7 @@ static inline abi_long copy_from_user_flock64(struct flock64 *fl,
}
static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
- const struct flock64 *fl)
+ const struct flock *fl)
{
struct target_flock64 *target_fl;
short l_type;
@@ -6985,7 +7013,7 @@ static inline abi_long copy_to_user_flock64(abi_ulong target_flock_addr,
static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
{
- struct flock64 fl64;
+ struct flock fl;
#ifdef F_GETOWN_EX
struct f_owner_ex fox;
struct target_f_owner_ex *target_fox;
@@ -6998,45 +7026,45 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
switch(cmd) {
case TARGET_F_GETLK:
- ret = copy_from_user_flock(&fl64, arg);
+ ret = copy_from_user_flock(&fl, arg);
if (ret) {
return ret;
}
- ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
+ ret = get_errno(safe_fcntl(fd, host_cmd, &fl));
if (ret == 0) {
- ret = copy_to_user_flock(arg, &fl64);
+ ret = copy_to_user_flock(arg, &fl);
}
break;
case TARGET_F_SETLK:
case TARGET_F_SETLKW:
- ret = copy_from_user_flock(&fl64, arg);
+ ret = copy_from_user_flock(&fl, arg);
if (ret) {
return ret;
}
- ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
+ ret = get_errno(safe_fcntl(fd, host_cmd, &fl));
break;
case TARGET_F_GETLK64:
case TARGET_F_OFD_GETLK:
- ret = copy_from_user_flock64(&fl64, arg);
+ ret = copy_from_user_flock64(&fl, arg);
if (ret) {
return ret;
}
- ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
+ ret = get_errno(safe_fcntl(fd, host_cmd, &fl));
if (ret == 0) {
- ret = copy_to_user_flock64(arg, &fl64);
+ ret = copy_to_user_flock64(arg, &fl);
}
break;
case TARGET_F_SETLK64:
case TARGET_F_SETLKW64:
case TARGET_F_OFD_SETLK:
case TARGET_F_OFD_SETLKW:
- ret = copy_from_user_flock64(&fl64, arg);
+ ret = copy_from_user_flock64(&fl, arg);
if (ret) {
return ret;
}
- ret = get_errno(safe_fcntl(fd, host_cmd, &fl64));
+ ret = get_errno(safe_fcntl(fd, host_cmd, &fl));
break;
case TARGET_F_GETFL:
@@ -7267,7 +7295,7 @@ static inline abi_long target_truncate64(CPUArchState *cpu_env, const char *arg1
arg2 = arg3;
arg3 = arg4;
}
- return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
+ return get_errno(truncate(arg1, target_offset64(arg2, arg3)));
}
#endif
@@ -7281,7 +7309,7 @@ static inline abi_long target_ftruncate64(CPUArchState *cpu_env, abi_long arg1,
arg2 = arg3;
arg3 = arg4;
}
- return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
+ return get_errno(ftruncate(arg1, target_offset64(arg2, arg3)));
}
#endif
@@ -8122,17 +8150,19 @@ static int open_self_maps_1(CPUArchState *env, int fd, bool smaps)
{
struct open_self_maps_data d = {
.ts = get_task_state(env_cpu(env)),
- .host_maps = read_self_maps(),
.fd = fd,
.smaps = smaps
};
+ mmap_lock();
+ d.host_maps = read_self_maps();
if (d.host_maps) {
walk_memory_regions(&d, open_self_maps_2);
free_self_maps(d.host_maps);
} else {
walk_memory_regions(&d, open_self_maps_3);
}
+ mmap_unlock();
return 0;
}
@@ -8168,6 +8198,16 @@ static int open_self_stat(CPUArchState *cpu_env, int fd)
} else if (i == 3) {
/* ppid */
g_string_printf(buf, FMT_pid " ", getppid());
+ } else if (i == 19) {
+ /* num_threads */
+ int cpus = 0;
+ WITH_RCU_READ_LOCK_GUARD() {
+ CPUState *cpu_iter;
+ CPU_FOREACH(cpu_iter) {
+ cpus++;
+ }
+ }
+ g_string_printf(buf, "%d ", cpus);
} else if (i == 21) {
/* starttime */
g_string_printf(buf, "%" PRIu64 " ", ts->start_boottime);
@@ -8324,8 +8364,9 @@ static int open_net_route(CPUArchState *cpu_env, int fd)
}
#endif
-int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname,
- int flags, mode_t mode, bool safe)
+static int maybe_do_fake_open(CPUArchState *cpu_env, int dirfd,
+ const char *fname, int flags, mode_t mode,
+ int openat2_resolve, bool safe)
{
g_autofree char *proc_name = NULL;
const char *pathname;
@@ -8362,6 +8403,12 @@ int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname,
}
if (is_proc_myself(pathname, "exe")) {
+ /* Honor openat2 resolve flags */
+ if ((openat2_resolve & RESOLVE_NO_MAGICLINKS) ||
+ (openat2_resolve & RESOLVE_NO_SYMLINKS)) {
+ errno = ELOOP;
+ return -1;
+ }
if (safe) {
return safe_openat(dirfd, exec_path, flags, mode);
} else {
@@ -8408,6 +8455,17 @@ int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname,
return fd;
}
+ return -2;
+}
+
+int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *pathname,
+ int flags, mode_t mode, bool safe)
+{
+ int fd = maybe_do_fake_open(cpu_env, dirfd, pathname, flags, mode, 0, safe);
+ if (fd > -2) {
+ return fd;
+ }
+
if (safe) {
return safe_openat(dirfd, path(pathname), flags, mode);
} else {
@@ -8415,6 +8473,49 @@ int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname,
}
}
+
+static int do_openat2(CPUArchState *cpu_env, abi_long dirfd,
+ abi_ptr guest_pathname, abi_ptr guest_open_how,
+ abi_ulong guest_size)
+{
+ struct open_how_ver0 how = {0};
+ char *pathname;
+ int ret;
+
+ if (guest_size < sizeof(struct target_open_how_ver0)) {
+ return -TARGET_EINVAL;
+ }
+ ret = copy_struct_from_user(&how, sizeof(how), guest_open_how, guest_size);
+ if (ret) {
+ if (ret == -TARGET_E2BIG) {
+ qemu_log_mask(LOG_UNIMP,
+ "Unimplemented openat2 open_how size: "
+ TARGET_ABI_FMT_lu "\n", guest_size);
+ }
+ return ret;
+ }
+ pathname = lock_user_string(guest_pathname);
+ if (!pathname) {
+ return -TARGET_EFAULT;
+ }
+
+ how.flags = target_to_host_bitmask(tswap64(how.flags), fcntl_flags_tbl);
+ how.mode = tswap64(how.mode);
+ how.resolve = tswap64(how.resolve);
+ int fd = maybe_do_fake_open(cpu_env, dirfd, pathname, how.flags, how.mode,
+ how.resolve, true);
+ if (fd > -2) {
+ ret = get_errno(fd);
+ } else {
+ ret = get_errno(safe_openat2(dirfd, pathname, &how,
+ sizeof(struct open_how_ver0)));
+ }
+
+ fd_trans_unregister(ret);
+ unlock_user(pathname, guest_pathname, 0);
+ return ret;
+}
+
ssize_t do_guest_readlink(const char *pathname, char *buf, size_t bufsiz)
{
ssize_t ret;
@@ -8656,7 +8757,7 @@ static int do_getdents(abi_long dirfd, abi_long arg2, abi_long count)
void *tdirp;
int hlen, hoff, toff;
int hreclen, treclen;
- off64_t prev_diroff = 0;
+ off_t prev_diroff = 0;
hdirp = g_try_malloc(count);
if (!hdirp) {
@@ -8709,7 +8810,7 @@ static int do_getdents(abi_long dirfd, abi_long arg2, abi_long count)
* Return what we have, resetting the file pointer to the
* location of the first record not returned.
*/
- lseek64(dirfd, prev_diroff, SEEK_SET);
+ lseek(dirfd, prev_diroff, SEEK_SET);
break;
}
@@ -8743,7 +8844,7 @@ static int do_getdents64(abi_long dirfd, abi_long arg2, abi_long count)
void *tdirp;
int hlen, hoff, toff;
int hreclen, treclen;
- off64_t prev_diroff = 0;
+ off_t prev_diroff = 0;
hdirp = g_try_malloc(count);
if (!hdirp) {
@@ -8785,7 +8886,7 @@ static int do_getdents64(abi_long dirfd, abi_long arg2, abi_long count)
* Return what we have, resetting the file pointer to the
* location of the first record not returned.
*/
- lseek64(dirfd, prev_diroff, SEEK_SET);
+ lseek(dirfd, prev_diroff, SEEK_SET);
break;
}
@@ -8843,7 +8944,7 @@ static int do_getdents64(abi_long dirfd, abi_long arg2, abi_long count)
#define RISCV_HWPROBE_EXT_ZFHMIN (1 << 28)
#define RISCV_HWPROBE_EXT_ZIHINTNTL (1 << 29)
#define RISCV_HWPROBE_EXT_ZVFH (1 << 30)
-#define RISCV_HWPROBE_EXT_ZVFHMIN (1 << 31)
+#define RISCV_HWPROBE_EXT_ZVFHMIN (1ULL << 31)
#define RISCV_HWPROBE_EXT_ZFA (1ULL << 32)
#define RISCV_HWPROBE_EXT_ZTSO (1ULL << 33)
#define RISCV_HWPROBE_EXT_ZACAS (1ULL << 34)
@@ -9187,6 +9288,9 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
fd_trans_unregister(ret);
unlock_user(p, arg2, 0);
return ret;
+ case TARGET_NR_openat2:
+ ret = do_openat2(cpu_env, arg1, arg2, arg3, arg4);
+ return ret;
#if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE)
case TARGET_NR_name_to_handle_at:
ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5);
@@ -10474,7 +10578,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
case TARGET_NR_mmap:
#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || \
(defined(TARGET_ARM) && defined(TARGET_ABI32)) || \
- defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) \
+ defined(TARGET_M68K) || defined(TARGET_MICROBLAZE) \
|| defined(TARGET_S390X)
{
abi_ulong *v;
@@ -11516,7 +11620,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
return -TARGET_EFAULT;
}
}
- ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
+ ret = get_errno(pread(arg1, p, arg3, target_offset64(arg4, arg5)));
unlock_user(p, arg2, ret);
return ret;
case TARGET_NR_pwrite64:
@@ -11533,7 +11637,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
return -TARGET_EFAULT;
}
}
- ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
+ ret = get_errno(pwrite(arg1, p, arg3, target_offset64(arg4, arg5)));
unlock_user(p, arg2, 0);
return ret;
#endif
@@ -12393,7 +12497,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
case TARGET_NR_fcntl64:
{
int cmd;
- struct flock64 fl;
+ struct flock fl;
from_flock64_fn *copyfrom = copy_from_user_flock64;
to_flock64_fn *copyto = copy_to_user_flock64;
@@ -12628,14 +12732,6 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
#if defined(TARGET_MIPS)
cpu_env->active_tc.CP0_UserLocal = arg1;
return 0;
-#elif defined(TARGET_CRIS)
- if (arg1 & 0xff)
- ret = -TARGET_EINVAL;
- else {
- cpu_env->pregs[PR_PID] = arg1;
- ret = 0;
- }
- return ret;
#elif defined(TARGET_I386) && defined(TARGET_ABI32)
return do_set_thread_area(cpu_env, arg1);
#elif defined(TARGET_M68K)
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index a00b617..0e08dfa 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -62,7 +62,7 @@
#if (defined(TARGET_I386) && defined(TARGET_ABI32)) \
|| (defined(TARGET_ARM) && defined(TARGET_ABI32)) \
|| (defined(TARGET_SPARC) && defined(TARGET_ABI32)) \
- || defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS)
+ || defined(TARGET_M68K) || defined(TARGET_SH4)
/* 16 bit uid wrappers emulation */
#define USE_UID16
#define target_id uint16_t
@@ -71,7 +71,7 @@
#endif
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) \
- || defined(TARGET_M68K) || defined(TARGET_CRIS) \
+ || defined(TARGET_M68K) \
|| defined(TARGET_S390X) || defined(TARGET_OPENRISC) \
|| defined(TARGET_RISCV) \
|| defined(TARGET_XTENSA) || defined(TARGET_LOONGARCH64)
@@ -1234,8 +1234,7 @@ struct target_winsize {
#include "target_mman.h"
#if (defined(TARGET_I386) && defined(TARGET_ABI32)) \
- || (defined(TARGET_ARM) && defined(TARGET_ABI32)) \
- || defined(TARGET_CRIS)
+ || (defined(TARGET_ARM) && defined(TARGET_ABI32))
#define TARGET_STAT_HAVE_NSEC
struct target_stat {
abi_ushort st_dev;
@@ -1976,7 +1975,7 @@ struct target_stat64 {
};
#elif defined(TARGET_OPENRISC) \
- || defined(TARGET_RISCV) || defined(TARGET_HEXAGON)
+ || defined(TARGET_RISCV) || defined(TARGET_HEXAGON) || defined(TARGET_LOONGARCH)
/* These are the asm-generic versions of the stat and stat64 structures */
@@ -2086,11 +2085,6 @@ struct target_stat64 {
abi_uint target_st_ctime_nsec;
abi_ullong st_ino;
};
-
-#elif defined(TARGET_LOONGARCH64)
-
-/* LoongArch no newfstatat/fstat syscall. */
-
#else
#error unsupported CPU
#endif
@@ -2754,4 +2748,22 @@ struct target_sched_param {
abi_int sched_priority;
};
+/* from kernel's include/uapi/linux/openat2.h */
+struct open_how_ver0 {
+ uint64_t flags;
+ uint64_t mode;
+ uint64_t resolve;
+};
+struct target_open_how_ver0 {
+ abi_ullong flags;
+ abi_ullong mode;
+ abi_ullong resolve;
+};
+#ifndef RESOLVE_NO_MAGICLINKS
+#define RESOLVE_NO_MAGICLINKS 0x02
+#endif
+#ifndef RESOLVE_NO_SYMLINKS
+#define RESOLVE_NO_SYMLINKS 0x04
+#endif
+
#endif
diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h
index 5c7f173..46ffc09 100644
--- a/linux-user/user-internals.h
+++ b/linux-user/user-internals.h
@@ -102,7 +102,6 @@ int host_to_target_waitstatus(int status);
/* vm86.c */
void save_v86_state(CPUX86State *env);
void handle_vm86_trap(CPUX86State *env, int trapno);
-void handle_vm86_fault(CPUX86State *env);
int do_vm86(CPUX86State *env, long subfunction, abi_ulong v86_addr);
#elif defined(TARGET_SPARC64)
void sparc64_set_context(CPUSPARCState *env);
diff --git a/linux-user/vm86.c b/linux-user/vm86.c
index 9f512a2..5091d53 100644
--- a/linux-user/vm86.c
+++ b/linux-user/vm86.c
@@ -47,30 +47,6 @@ static inline void vm_putw(CPUX86State *env, uint32_t segptr,
cpu_stw_data(env, segptr + (reg16 & 0xffff), val);
}
-static inline void vm_putl(CPUX86State *env, uint32_t segptr,
- unsigned int reg16, unsigned int val)
-{
- cpu_stl_data(env, segptr + (reg16 & 0xffff), val);
-}
-
-static inline unsigned int vm_getb(CPUX86State *env,
- uint32_t segptr, unsigned int reg16)
-{
- return cpu_ldub_data(env, segptr + (reg16 & 0xffff));
-}
-
-static inline unsigned int vm_getw(CPUX86State *env,
- uint32_t segptr, unsigned int reg16)
-{
- return cpu_lduw_data(env, segptr + (reg16 & 0xffff));
-}
-
-static inline unsigned int vm_getl(CPUX86State *env,
- uint32_t segptr, unsigned int reg16)
-{
- return cpu_ldl_data(env, segptr + (reg16 & 0xffff));
-}
-
void save_v86_state(CPUX86State *env)
{
CPUState *cs = env_cpu(env);
@@ -131,19 +107,6 @@ static inline void return_to_32bit(CPUX86State *env, int retval)
env->regs[R_EAX] = retval;
}
-static inline int set_IF(CPUX86State *env)
-{
- CPUState *cs = env_cpu(env);
- TaskState *ts = get_task_state(cs);
-
- ts->v86flags |= VIF_MASK;
- if (ts->v86flags & VIP_MASK) {
- return_to_32bit(env, TARGET_VM86_STI);
- return 1;
- }
- return 0;
-}
-
static inline void clear_IF(CPUX86State *env)
{
CPUState *cs = env_cpu(env);
@@ -162,34 +125,6 @@ static inline void clear_AC(CPUX86State *env)
env->eflags &= ~AC_MASK;
}
-static inline int set_vflags_long(unsigned long eflags, CPUX86State *env)
-{
- CPUState *cs = env_cpu(env);
- TaskState *ts = get_task_state(cs);
-
- set_flags(ts->v86flags, eflags, ts->v86mask);
- set_flags(env->eflags, eflags, SAFE_MASK);
- if (eflags & IF_MASK)
- return set_IF(env);
- else
- clear_IF(env);
- return 0;
-}
-
-static inline int set_vflags_short(unsigned short flags, CPUX86State *env)
-{
- CPUState *cs = env_cpu(env);
- TaskState *ts = get_task_state(cs);
-
- set_flags(ts->v86flags, flags, ts->v86mask & 0xffff);
- set_flags(env->eflags, flags, SAFE_MASK);
- if (flags & IF_MASK)
- return set_IF(env);
- else
- clear_IF(env);
- return 0;
-}
-
static inline unsigned int get_vflags(CPUX86State *env)
{
CPUState *cs = env_cpu(env);
@@ -255,142 +190,6 @@ void handle_vm86_trap(CPUX86State *env, int trapno)
}
}
-#define CHECK_IF_IN_TRAP() \
- if ((ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) && \
- (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_TFpendig)) \
- newflags |= TF_MASK
-
-#define VM86_FAULT_RETURN \
- if ((ts->vm86plus.vm86plus.flags & TARGET_force_return_for_pic) && \
- (ts->v86flags & (IF_MASK | VIF_MASK))) \
- return_to_32bit(env, TARGET_VM86_PICRETURN); \
- return
-
-void handle_vm86_fault(CPUX86State *env)
-{
- CPUState *cs = env_cpu(env);
- TaskState *ts = get_task_state(cs);
- uint32_t csp, ssp;
- unsigned int ip, sp, newflags, newip, newcs, opcode, intno;
- int data32, pref_done;
-
- csp = env->segs[R_CS].selector << 4;
- ip = env->eip & 0xffff;
-
- ssp = env->segs[R_SS].selector << 4;
- sp = env->regs[R_ESP] & 0xffff;
-
- LOG_VM86("VM86 exception %04x:%08x\n",
- env->segs[R_CS].selector, env->eip);
-
- data32 = 0;
- pref_done = 0;
- do {
- opcode = vm_getb(env, csp, ip);
- ADD16(ip, 1);
- switch (opcode) {
- case 0x66: /* 32-bit data */ data32=1; break;
- case 0x67: /* 32-bit address */ break;
- case 0x2e: /* CS */ break;
- case 0x3e: /* DS */ break;
- case 0x26: /* ES */ break;
- case 0x36: /* SS */ break;
- case 0x65: /* GS */ break;
- case 0x64: /* FS */ break;
- case 0xf2: /* repnz */ break;
- case 0xf3: /* rep */ break;
- default: pref_done = 1;
- }
- } while (!pref_done);
-
- /* VM86 mode */
- switch(opcode) {
- case 0x9c: /* pushf */
- if (data32) {
- vm_putl(env, ssp, sp - 4, get_vflags(env));
- ADD16(env->regs[R_ESP], -4);
- } else {
- vm_putw(env, ssp, sp - 2, get_vflags(env));
- ADD16(env->regs[R_ESP], -2);
- }
- env->eip = ip;
- VM86_FAULT_RETURN;
-
- case 0x9d: /* popf */
- if (data32) {
- newflags = vm_getl(env, ssp, sp);
- ADD16(env->regs[R_ESP], 4);
- } else {
- newflags = vm_getw(env, ssp, sp);
- ADD16(env->regs[R_ESP], 2);
- }
- env->eip = ip;
- CHECK_IF_IN_TRAP();
- if (data32) {
- if (set_vflags_long(newflags, env))
- return;
- } else {
- if (set_vflags_short(newflags, env))
- return;
- }
- VM86_FAULT_RETURN;
-
- case 0xcd: /* int */
- intno = vm_getb(env, csp, ip);
- ADD16(ip, 1);
- env->eip = ip;
- if (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) {
- if ( (ts->vm86plus.vm86plus.vm86dbg_intxxtab[intno >> 3] >>
- (intno &7)) & 1) {
- return_to_32bit(env, TARGET_VM86_INTx + (intno << 8));
- return;
- }
- }
- do_int(env, intno);
- break;
-
- case 0xcf: /* iret */
- if (data32) {
- newip = vm_getl(env, ssp, sp) & 0xffff;
- newcs = vm_getl(env, ssp, sp + 4) & 0xffff;
- newflags = vm_getl(env, ssp, sp + 8);
- ADD16(env->regs[R_ESP], 12);
- } else {
- newip = vm_getw(env, ssp, sp);
- newcs = vm_getw(env, ssp, sp + 2);
- newflags = vm_getw(env, ssp, sp + 4);
- ADD16(env->regs[R_ESP], 6);
- }
- env->eip = newip;
- cpu_x86_load_seg(env, R_CS, newcs);
- CHECK_IF_IN_TRAP();
- if (data32) {
- if (set_vflags_long(newflags, env))
- return;
- } else {
- if (set_vflags_short(newflags, env))
- return;
- }
- VM86_FAULT_RETURN;
-
- case 0xfa: /* cli */
- env->eip = ip;
- clear_IF(env);
- VM86_FAULT_RETURN;
-
- case 0xfb: /* sti */
- env->eip = ip;
- if (set_IF(env))
- return;
- VM86_FAULT_RETURN;
-
- default:
- /* real VM86 GPF exception */
- return_to_32bit(env, TARGET_VM86_UNKNOWN);
- break;
- }
-}
-
int do_vm86(CPUX86State *env, long subfunction, abi_ulong vm86_addr)
{
CPUState *cs = env_cpu(env);
diff --git a/linux-user/x86_64/syscall_64.tbl b/linux-user/x86_64/syscall_64.tbl
index ce18119..7093ee2 100644
--- a/linux-user/x86_64/syscall_64.tbl
+++ b/linux-user/x86_64/syscall_64.tbl
@@ -1,8 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
#
# 64-bit system call numbers and entry vectors
#
# The format is:
-# <number> <abi> <name> <entry point>
+# <number> <abi> <name> <entry point> [<compat entry point> [noreturn]]
#
# The __x64_sys_*() stubs are created on-the-fly for sys_*() system calls
#
@@ -68,7 +69,7 @@
57 common fork sys_fork
58 common vfork sys_vfork
59 64 execve sys_execve
-60 common exit sys_exit
+60 common exit sys_exit - noreturn
61 common wait4 sys_wait4
62 common kill sys_kill
63 common uname sys_newuname
@@ -220,7 +221,7 @@
209 64 io_submit sys_io_submit
210 common io_cancel sys_io_cancel
211 64 get_thread_area
-212 common lookup_dcookie sys_lookup_dcookie
+212 common lookup_dcookie
213 common epoll_create sys_epoll_create
214 64 epoll_ctl_old
215 64 epoll_wait_old
@@ -239,7 +240,7 @@
228 common clock_gettime sys_clock_gettime
229 common clock_getres sys_clock_getres
230 common clock_nanosleep sys_clock_nanosleep
-231 common exit_group sys_exit_group
+231 common exit_group sys_exit_group - noreturn
232 common epoll_wait sys_epoll_wait
233 common epoll_ctl sys_epoll_ctl
234 common tgkill sys_tgkill
@@ -343,6 +344,7 @@
332 common statx sys_statx
333 common io_pgetevents sys_io_pgetevents
334 common rseq sys_rseq
+335 common uretprobe sys_uretprobe
# don't use numbers 387 through 423, add new calls after the last
# 'common' entry
424 common pidfd_send_signal sys_pidfd_send_signal
@@ -364,10 +366,26 @@
440 common process_madvise sys_process_madvise
441 common epoll_pwait2 sys_epoll_pwait2
442 common mount_setattr sys_mount_setattr
-# 443 reserved for quotactl_path
+443 common quotactl_fd sys_quotactl_fd
444 common landlock_create_ruleset sys_landlock_create_ruleset
445 common landlock_add_rule sys_landlock_add_rule
446 common landlock_restrict_self sys_landlock_restrict_self
+447 common memfd_secret sys_memfd_secret
+448 common process_mrelease sys_process_mrelease
+449 common futex_waitv sys_futex_waitv
+450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common cachestat sys_cachestat
+452 common fchmodat2 sys_fchmodat2
+453 common map_shadow_stack sys_map_shadow_stack
+454 common futex_wake sys_futex_wake
+455 common futex_wait sys_futex_wait
+456 common futex_requeue sys_futex_requeue
+457 common statmount sys_statmount
+458 common listmount sys_listmount
+459 common lsm_get_self_attr sys_lsm_get_self_attr
+460 common lsm_set_self_attr sys_lsm_set_self_attr
+461 common lsm_list_modules sys_lsm_list_modules
+462 common mseal sys_mseal
#
# Due to a historical design error, certain syscalls are numbered differently
@@ -396,7 +414,7 @@
530 x32 set_robust_list compat_sys_set_robust_list
531 x32 get_robust_list compat_sys_get_robust_list
532 x32 vmsplice sys_vmsplice
-533 x32 move_pages compat_sys_move_pages
+533 x32 move_pages sys_move_pages
534 x32 preadv compat_sys_preadv64
535 x32 pwritev compat_sys_pwritev64
536 x32 rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo
diff --git a/linux-user/x86_64/syscallhdr.sh b/linux-user/x86_64/syscallhdr.sh
index 182be52..988256b 100644
--- a/linux-user/x86_64/syscallhdr.sh
+++ b/linux-user/x86_64/syscallhdr.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
in="$1"
out="$2"
diff --git a/linux-user/xtensa/syscall.tbl b/linux-user/xtensa/syscall.tbl
index fd2f302..735a89b 100644
--- a/linux-user/xtensa/syscall.tbl
+++ b/linux-user/xtensa/syscall.tbl
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
#
# system call numbers and entry vectors for xtensa
#
@@ -223,7 +223,7 @@
# 205 was old nfsservctl
205 common nfsservctl sys_ni_syscall
206 common _sysctl sys_ni_syscall
-207 common bdflush sys_bdflush
+207 common bdflush sys_ni_syscall
208 common uname sys_newuname
209 common sysinfo sys_sysinfo
210 common init_module sys_init_module
@@ -273,7 +273,7 @@
252 common timer_getoverrun sys_timer_getoverrun
# System
253 common reserved253 sys_ni_syscall
-254 common lookup_dcookie sys_lookup_dcookie
+254 common lookup_dcookie sys_ni_syscall
255 common available255 sys_ni_syscall
256 common add_key sys_add_key
257 common request_key sys_request_key
@@ -413,7 +413,23 @@
440 common process_madvise sys_process_madvise
441 common epoll_pwait2 sys_epoll_pwait2
442 common mount_setattr sys_mount_setattr
-# 443 reserved for quotactl_path
+443 common quotactl_fd sys_quotactl_fd
444 common landlock_create_ruleset sys_landlock_create_ruleset
445 common landlock_add_rule sys_landlock_add_rule
446 common landlock_restrict_self sys_landlock_restrict_self
+# 447 reserved for memfd_secret
+448 common process_mrelease sys_process_mrelease
+449 common futex_waitv sys_futex_waitv
+450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common cachestat sys_cachestat
+452 common fchmodat2 sys_fchmodat2
+453 common map_shadow_stack sys_map_shadow_stack
+454 common futex_wake sys_futex_wake
+455 common futex_wait sys_futex_wait
+456 common futex_requeue sys_futex_requeue
+457 common statmount sys_statmount
+458 common listmount sys_listmount
+459 common lsm_get_self_attr sys_lsm_get_self_attr
+460 common lsm_set_self_attr sys_lsm_set_self_attr
+461 common lsm_list_modules sys_lsm_list_modules
+462 common mseal sys_mseal
diff --git a/linux-user/xtensa/syscallhdr.sh b/linux-user/xtensa/syscallhdr.sh
index eef0644..dc787fb 100644
--- a/linux-user/xtensa/syscallhdr.sh
+++ b/linux-user/xtensa/syscallhdr.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
in="$1"
out="$2"
diff --git a/meson.build b/meson.build
index a1e5127..92168b9 100644
--- a/meson.build
+++ b/meson.build
@@ -1,4 +1,4 @@
-project('qemu', ['c'], meson_version: '>=1.1.0',
+project('qemu', ['c'], meson_version: '>=1.5.0',
default_options: ['warning_level=1', 'c_std=gnu11', 'cpp_std=gnu++11', 'b_colorout=auto',
'b_staticpic=false', 'stdsplit=false', 'optimization=2', 'b_pie=true'],
version: files('VERSION'))
@@ -70,6 +70,20 @@ if host_os == 'darwin' and \
all_languages += ['objc']
objc = meson.get_compiler('objc')
endif
+have_rust = false
+if not get_option('rust').disabled() and add_languages('rust', required: get_option('rust'), native: false) \
+ and add_languages('rust', required: get_option('rust'), native: true)
+ rustc = meson.get_compiler('rust')
+ have_rust = true
+ if rustc.version().version_compare('<1.80.0')
+ if get_option('rust').enabled()
+ error('rustc version ' + rustc.version() + ' is unsupported: Please upgrade to at least 1.80.0')
+ else
+ warning('rustc version ' + rustc.version() + ' is unsupported: Disabling Rust compilation. Please upgrade to at least 1.80.0 to use Rust.')
+ have_rust = false
+ endif
+ endif
+endif
dtrace = not_found
stap = not_found
@@ -93,7 +107,7 @@ else
iasl = find_program(get_option('iasl'), required: true)
endif
-edk2_targets = [ 'arm-softmmu', 'aarch64-softmmu', 'i386-softmmu', 'x86_64-softmmu', 'riscv64-softmmu' ]
+edk2_targets = [ 'arm-softmmu', 'aarch64-softmmu', 'i386-softmmu', 'x86_64-softmmu', 'riscv64-softmmu', 'loongarch64-softmmu' ]
unpack_edk2_blobs = false
foreach target : edk2_targets
if target in target_dirs
@@ -315,8 +329,17 @@ elif host_os == 'sunos'
qemu_common_flags += '-D__EXTENSIONS__'
elif host_os == 'haiku'
qemu_common_flags += ['-DB_USE_POSITIVE_POSIX_ERRORS', '-D_BSD_SOURCE', '-fPIC']
+elif host_os == 'windows'
+ if not compiler.compiles('struct x { int y; } __attribute__((gcc_struct));',
+ args: '-Werror')
+ error('Your compiler does not support __attribute__((gcc_struct)) - please use GCC instead of Clang')
+ endif
endif
+# Choose instruction set (currently x86-only)
+
+qemu_isa_flags = []
+
# __sync_fetch_and_and requires at least -march=i486. Many toolchains
# use i686 as default anyway, but for those that don't, an explicit
# specification is necessary
@@ -333,7 +356,7 @@ if host_arch == 'i386' and not cc.links('''
sfaa(&val);
return val;
}''')
- qemu_common_flags = ['-march=i486'] + qemu_common_flags
+ qemu_isa_flags += ['-march=i486']
endif
# Pick x86-64 baseline version
@@ -349,29 +372,31 @@ if host_arch in ['i386', 'x86_64']
else
# present on basically all processors but technically not part of
# x86-64-v1, so only include -mneeded for x86-64 version 2 and above
- qemu_common_flags = ['-mcx16'] + qemu_common_flags
+ qemu_isa_flags += ['-mcx16']
endif
endif
if get_option('x86_version') >= '2'
- qemu_common_flags = ['-mpopcnt'] + qemu_common_flags
- qemu_common_flags = cc.get_supported_arguments('-mneeded') + qemu_common_flags
+ qemu_isa_flags += ['-mpopcnt']
+ qemu_isa_flags += cc.get_supported_arguments('-mneeded')
endif
if get_option('x86_version') >= '3'
- qemu_common_flags = ['-mmovbe', '-mabm', '-mbmi1', '-mbmi2', '-mfma', '-mf16c'] + qemu_common_flags
+ qemu_isa_flags += ['-mmovbe', '-mabm', '-mbmi', '-mbmi2', '-mfma', '-mf16c']
endif
# add required vector instruction set (each level implies those below)
if get_option('x86_version') == '1'
- qemu_common_flags = ['-msse2'] + qemu_common_flags
+ qemu_isa_flags += ['-msse2']
elif get_option('x86_version') == '2'
- qemu_common_flags = ['-msse4.2'] + qemu_common_flags
+ qemu_isa_flags += ['-msse4.2']
elif get_option('x86_version') == '3'
- qemu_common_flags = ['-mavx2'] + qemu_common_flags
+ qemu_isa_flags += ['-mavx2']
elif get_option('x86_version') == '4'
- qemu_common_flags = ['-mavx512f', '-mavx512bw', '-mavx512cd', '-mavx512dq', '-mavx512vl'] + qemu_common_flags
+ qemu_isa_flags += ['-mavx512f', '-mavx512bw', '-mavx512cd', '-mavx512dq', '-mavx512vl']
endif
endif
+qemu_common_flags = qemu_isa_flags + qemu_common_flags
+
if get_option('prefer_static')
qemu_ldflags += get_option('b_pie') ? '-static-pie' : '-static'
endif
@@ -474,24 +499,38 @@ if get_option('safe_stack') and coroutine_backend != 'ucontext'
error('SafeStack is only supported with the ucontext coroutine backend')
endif
-if get_option('sanitizers')
+if get_option('asan')
if cc.has_argument('-fsanitize=address')
qemu_cflags = ['-fsanitize=address'] + qemu_cflags
qemu_ldflags = ['-fsanitize=address'] + qemu_ldflags
+ else
+ error('Your compiler does not support -fsanitize=address')
endif
+endif
- # Detect static linking issue with ubsan - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84285
+if get_option('ubsan')
+ # Detect static linking issue with ubsan:
+ # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84285
if cc.links('int main(int argc, char **argv) { return argc + 1; }',
args: [qemu_ldflags, '-fsanitize=undefined'])
- qemu_cflags = ['-fsanitize=undefined'] + qemu_cflags
- qemu_ldflags = ['-fsanitize=undefined'] + qemu_ldflags
+ qemu_cflags += ['-fsanitize=undefined']
+ qemu_ldflags += ['-fsanitize=undefined']
+
+ # Suppress undefined behaviour from function call to mismatched type.
+ # In addition, tcg prologue does not emit function type prefix
+ # required by function call sanitizer.
+ if cc.has_argument('-fno-sanitize=function')
+ qemu_cflags += ['-fno-sanitize=function']
+ endif
+ else
+ error('Your compiler does not support -fsanitize=undefined')
endif
endif
# Thread sanitizer is, for now, much noisier than the other sanitizers;
# keep it separate until that is not the case.
if get_option('tsan')
- if get_option('sanitizers')
+ if get_option('asan') or get_option('ubsan')
error('TSAN is not supported with other sanitizers')
endif
if not cc.has_function('__tsan_create_fiber',
@@ -499,7 +538,15 @@ if get_option('tsan')
prefix: '#include <sanitizer/tsan_interface.h>')
error('Cannot enable TSAN due to missing fiber annotation interface')
endif
- qemu_cflags = ['-fsanitize=thread'] + qemu_cflags
+ tsan_warn_suppress = []
+ # gcc (>=11) will report constructions not supported by tsan:
+ # "error: ā€˜atomic_thread_fenceā€™ is not supported with ā€˜-fsanitize=threadā€™"
+ # https://gcc.gnu.org/gcc-11/changes.html
+ # However, clang does not support this warning and this triggers an error.
+ if cc.has_argument('-Wno-tsan')
+ tsan_warn_suppress = ['-Wno-tsan']
+ endif
+ qemu_cflags = ['-fsanitize=thread'] + tsan_warn_suppress + qemu_cflags
qemu_ldflags = ['-fsanitize=thread'] + qemu_ldflags
endif
@@ -649,7 +696,19 @@ warn_flags = [
]
if host_os != 'darwin'
- warn_flags += ['-Wthread-safety']
+ tsa_has_cleanup = cc.compiles('''
+ struct __attribute__((capability("mutex"))) mutex {};
+ void lock(struct mutex *m) __attribute__((acquire_capability(m)));
+ void unlock(struct mutex *m) __attribute__((release_capability(m)));
+
+ void test(void) {
+ struct mutex __attribute__((cleanup(unlock))) m;
+ lock(&m);
+ }
+ ''', args: ['-Wthread-safety', '-Werror'])
+ if tsa_has_cleanup
+ warn_flags += ['-Wthread-safety']
+ endif
endif
# Set up C++ compiler flags
@@ -904,7 +963,9 @@ have_xen_pci_passthrough = get_option('xen_pci_passthrough') \
################
# When bumping glib minimum version, please check also whether to increase
-# the _WIN32_WINNT setting in osdep.h according to the value from glib
+# the _WIN32_WINNT setting in osdep.h according to the value from glib.
+# You should also check if any of the glib.version() checks
+# below can also be removed.
glib_req_ver = '>=2.66.0'
glib_pc = dependency('glib-2.0', version: glib_req_ver, required: true,
method: 'pkg-config')
@@ -954,6 +1015,9 @@ glib = declare_dependency(dependencies: [glib_pc, gmodule],
# TODO: remove this check and the corresponding workaround (qtree) when
# the minimum supported glib is >= 2.75.3
glib_has_gslice = glib.version().version_compare('<2.75.3')
+# Check whether glib has the aligned_alloc family of functions.
+# <https://docs.gtk.org/glib/func.aligned_alloc.html>
+glib_has_aligned_alloc = glib.version().version_compare('>=2.72.0')
# override glib dep to include the above refinements
meson.override_dependency('glib-2.0', glib)
@@ -981,7 +1045,7 @@ if not get_option('gio').auto() or have_system
gio = not_found
endif
if gio.found()
- gdbus_codegen = find_program(gio.get_variable('gdbus_codegen'),
+ gdbus_codegen = find_program('gdbus-codegen',
required: get_option('gio'))
gio_unix = dependency('gio-unix-2.0', required: get_option('gio'),
method: 'pkg-config')
@@ -1245,6 +1309,14 @@ if not get_option('uadk').auto() or have_system
uadk = declare_dependency(dependencies: [libwd, libwd_comp])
endif
endif
+
+qatzip = not_found
+if not get_option('qatzip').auto() or have_system
+ qatzip = dependency('qatzip', version: '>=1.1.2',
+ required: get_option('qatzip'),
+ method: 'pkg-config')
+endif
+
virgl = not_found
have_vhost_user_gpu = have_tools and host_os == 'linux' and pixman.found()
@@ -1335,7 +1407,7 @@ iconv = not_found
curses = not_found
if have_system and get_option('curses').allowed()
curses_test = '''
- #if defined(__APPLE__) || defined(__OpenBSD__)
+ #ifdef __APPLE__
#define _XOPEN_SOURCE_EXTENDED 1
#endif
#include <locale.h>
@@ -1696,7 +1768,6 @@ endif
if not gnutls_crypto.found()
if (not get_option('gcrypt').auto() or have_system) and not get_option('nettle').enabled()
gcrypt = dependency('libgcrypt', version: '>=1.8',
- method: 'config-tool',
required: get_option('gcrypt'))
# Debian has removed -lgpg-error from libgcrypt-config
# as it "spreads unnecessary dependencies" which in
@@ -1979,6 +2050,7 @@ endif
tasn1 = not_found
if gnutls.found()
tasn1 = dependency('libtasn1',
+ required: false,
method: 'pkg-config')
endif
keyutils = not_found
@@ -2100,8 +2172,14 @@ endif
# libxdp
libxdp = not_found
if not get_option('af_xdp').auto() or have_system
- libxdp = dependency('libxdp', required: get_option('af_xdp'),
- version: '>=1.4.0', method: 'pkg-config')
+ if libbpf.found()
+ libxdp = dependency('libxdp', required: get_option('af_xdp'),
+ version: '>=1.4.0', method: 'pkg-config')
+ else
+ if get_option('af_xdp').enabled()
+ error('libxdp requested, but libbpf is not available')
+ endif
+ endif
endif
# libdw
@@ -2119,6 +2197,7 @@ endif
config_host_data = configuration_data()
+config_host_data.set('CONFIG_HAVE_RUST', have_rust)
audio_drivers_selected = []
if have_system
audio_drivers_available = {
@@ -2180,12 +2259,18 @@ have_virtfs = get_option('virtfs') \
.disable_auto_if(not have_tools and not have_system) \
.allowed()
-have_virtfs_proxy_helper = get_option('virtfs_proxy_helper') \
- .require(host_os != 'darwin', error_message: 'the virtfs proxy helper is incompatible with macOS') \
- .require(have_virtfs, error_message: 'the virtfs proxy helper requires that virtfs is enabled') \
- .disable_auto_if(not have_tools) \
- .require(libcap_ng.found(), error_message: 'the virtfs proxy helper requires libcap-ng') \
- .allowed()
+qga_fsfreeze = false
+qga_fstrim = false
+if host_os == 'linux'
+ if cc.has_header_symbol('linux/fs.h', 'FIFREEZE')
+ qga_fsfreeze = true
+ endif
+ if cc.has_header_symbol('linux/fs.h', 'FITRIM')
+ qga_fstrim = true
+ endif
+elif host_os == 'freebsd' and cc.has_header_symbol('ufs/ffs/fs.h', 'UFSSUSPEND')
+ qga_fsfreeze = true
+endif
if get_option('block_drv_ro_whitelist') == ''
config_host_data.set('CONFIG_BDRV_RO_WHITELIST', '')
@@ -2263,6 +2348,7 @@ config_host_data.set('CONFIG_ATTR', libattr.found())
config_host_data.set('CONFIG_BDRV_WHITELIST_TOOLS', get_option('block_drv_whitelist_in_tools'))
config_host_data.set('CONFIG_BRLAPI', brlapi.found())
config_host_data.set('CONFIG_BSD', host_os in bsd_oses)
+config_host_data.set('CONFIG_FREEBSD', host_os == 'freebsd')
config_host_data.set('CONFIG_CAPSTONE', capstone.found())
config_host_data.set('CONFIG_COCOA', cocoa.found())
config_host_data.set('CONFIG_DARWIN', host_os == 'darwin')
@@ -2279,6 +2365,8 @@ config_host_data.set('CONFIG_BLKIO', blkio.found())
if blkio.found()
config_host_data.set('CONFIG_BLKIO_VHOST_VDPA_FD',
blkio.version().version_compare('>=1.3.0'))
+ config_host_data.set('CONFIG_BLKIO_WRITE_ZEROS_FUA',
+ blkio.version().version_compare('>=1.4.0'))
endif
config_host_data.set('CONFIG_CURL', curl.found())
config_host_data.set('CONFIG_CURSES', curses.found())
@@ -2355,10 +2443,7 @@ config_host_data.set('CONFIG_VNC', vnc.found())
config_host_data.set('CONFIG_VNC_JPEG', jpeg.found())
config_host_data.set('CONFIG_VNC_SASL', sasl.found())
if virgl.found()
- config_host_data.set('HAVE_VIRGL_D3D_INFO_EXT',
- cc.has_member('struct virgl_renderer_resource_info_ext', 'd3d_tex2d',
- prefix: '#include <virglrenderer.h>',
- dependencies: virgl))
+ config_host_data.set('VIRGL_VERSION_MAJOR', virgl.version().split('.')[0])
endif
config_host_data.set('CONFIG_VIRTFS', have_virtfs)
config_host_data.set('CONFIG_VTE', vte.found())
@@ -2379,6 +2464,7 @@ config_host_data.set('CONFIG_STATX_MNT_ID', has_statx_mnt_id)
config_host_data.set('CONFIG_ZSTD', zstd.found())
config_host_data.set('CONFIG_QPL', qpl.found())
config_host_data.set('CONFIG_UADK', uadk.found())
+config_host_data.set('CONFIG_QATZIP', qatzip.found())
config_host_data.set('CONFIG_FUSE', fuse.found())
config_host_data.set('CONFIG_FUSE_LSEEK', fuse_lseek.found())
config_host_data.set('CONFIG_SPICE_PROTOCOL', spice_protocol.found())
@@ -2423,6 +2509,8 @@ config_host_data.set('CONFIG_DEBUG_TCG', get_option('debug_tcg'))
config_host_data.set('CONFIG_DEBUG_REMAP', get_option('debug_remap'))
config_host_data.set('CONFIG_QOM_CAST_DEBUG', get_option('qom_cast_debug'))
config_host_data.set('CONFIG_REPLICATION', get_option('replication').allowed())
+config_host_data.set('CONFIG_FSFREEZE', qga_fsfreeze)
+config_host_data.set('CONFIG_FSTRIM', qga_fstrim)
# has_header
config_host_data.set('CONFIG_EPOLL', cc.has_header('sys/epoll.h'))
@@ -2430,6 +2518,7 @@ config_host_data.set('CONFIG_LINUX_MAGIC_H', cc.has_header('linux/magic.h'))
config_host_data.set('CONFIG_VALGRIND_H', cc.has_header('valgrind/valgrind.h'))
config_host_data.set('HAVE_BTRFS_H', cc.has_header('linux/btrfs.h'))
config_host_data.set('HAVE_DRM_H', cc.has_header('libdrm/drm.h'))
+config_host_data.set('HAVE_OPENAT2_H', cc.has_header('linux/openat2.h'))
config_host_data.set('HAVE_PTY_H', cc.has_header('pty.h'))
config_host_data.set('HAVE_SYS_DISK_H', cc.has_header('sys/disk.h'))
config_host_data.set('HAVE_SYS_IOCCOM_H', cc.has_header('sys/ioccom.h'))
@@ -2464,6 +2553,7 @@ config_host_data.set('CONFIG_TIMERFD', cc.has_function('timerfd_create'))
config_host_data.set('HAVE_COPY_FILE_RANGE', cc.has_function('copy_file_range'))
config_host_data.set('HAVE_GETIFADDRS', cc.has_function('getifaddrs'))
config_host_data.set('HAVE_GLIB_WITH_SLICE_ALLOCATOR', glib_has_gslice)
+config_host_data.set('HAVE_GLIB_WITH_ALIGNED_ALLOC', glib_has_aligned_alloc)
config_host_data.set('HAVE_OPENPTY', cc.has_function('openpty', dependencies: util))
config_host_data.set('HAVE_STRCHRNUL', cc.has_function('strchrnul'))
config_host_data.set('HAVE_SYSTEM_FUNCTION', cc.has_function('system', prefix: '#include <stdlib.h>'))
@@ -2481,7 +2571,7 @@ if rdma.found()
endif
have_asan_fiber = false
-if get_option('sanitizers') and \
+if get_option('asan') and \
not cc.has_function('__sanitizer_start_switch_fiber',
args: '-fsanitize=address',
prefix: '#include <sanitizer/asan_interface.h>')
@@ -2754,7 +2844,7 @@ config_host_data.set('CONFIG_ATOMIC64', cc.links('''
__atomic_exchange_n(&x, y, __ATOMIC_RELAXED);
__atomic_fetch_add(&x, y, __ATOMIC_RELAXED);
return 0;
- }'''))
+ }''', args: qemu_isa_flags))
has_int128_type = cc.compiles('''
__int128_t a;
@@ -2788,7 +2878,7 @@ if has_int128_type
__atomic_compare_exchange_n(&p[4], &p[5], p[6], 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
return 0;
}'''
- has_atomic128 = cc.links(atomic_test_128)
+ has_atomic128 = cc.links(atomic_test_128, args: qemu_isa_flags)
config_host_data.set('CONFIG_ATOMIC128', has_atomic128)
@@ -2797,7 +2887,8 @@ if has_int128_type
# without optimization enabled. Try again with optimizations locally
# enabled for the function. See
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107389
- has_atomic128_opt = cc.links('__attribute__((optimize("O1")))' + atomic_test_128)
+ has_atomic128_opt = cc.links('__attribute__((optimize("O1")))' + atomic_test_128,
+ args: qemu_isa_flags)
config_host_data.set('CONFIG_ATOMIC128_OPT', has_atomic128_opt)
if not has_atomic128_opt
@@ -2808,7 +2899,7 @@ if has_int128_type
__sync_val_compare_and_swap_16(&x, y, x);
return 0;
}
- '''))
+ ''', args: qemu_isa_flags))
endif
endif
endif
@@ -2819,6 +2910,14 @@ config_host_data.set('CONFIG_GETAUXVAL', cc.links(gnu_source_prefix + '''
return getauxval(AT_HWCAP) == 0;
}'''))
+config_host_data.set('CONFIG_ELF_AUX_INFO', cc.links(gnu_source_prefix + '''
+ #include <sys/auxv.h>
+ int main(void) {
+ unsigned long hwcap = 0;
+ elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap));
+ return hwcap;
+ }'''))
+
config_host_data.set('CONFIG_USBFS', have_linux_user and cc.compiles('''
#include <linux/usbdevice_fs.h>
@@ -3002,7 +3101,6 @@ config_target_mak = {}
disassemblers = {
'alpha' : ['CONFIG_ALPHA_DIS'],
'avr' : ['CONFIG_AVR_DIS'],
- 'cris' : ['CONFIG_CRIS_DIS'],
'hexagon' : ['CONFIG_HEXAGON_DIS'],
'hppa' : ['CONFIG_HPPA_DIS'],
'i386' : ['CONFIG_I386_DIS'],
@@ -3038,7 +3136,8 @@ host_kconfig = \
(host_os == 'linux' ? ['CONFIG_LINUX=y'] : []) + \
(multiprocess_allowed ? ['CONFIG_MULTIPROCESS_ALLOWED=y'] : []) + \
(vfio_user_server_allowed ? ['CONFIG_VFIO_USER_SERVER_ALLOWED=y'] : []) + \
- (hv_balloon ? ['CONFIG_HV_BALLOON_POSSIBLE=y'] : [])
+ (hv_balloon ? ['CONFIG_HV_BALLOON_POSSIBLE=y'] : []) + \
+ (have_rust ? ['CONFIG_HAVE_RUST=y'] : [])
ignored = [ 'TARGET_XML_FILES', 'TARGET_ABI_DIR', 'TARGET_ARCH' ]
@@ -3327,6 +3426,7 @@ if have_block
trace_events_subdirs += [
'authz',
'block',
+ 'chardev',
'io',
'nbd',
'scsi',
@@ -3338,7 +3438,6 @@ if have_system
'audio',
'backends',
'backends/tpm',
- 'chardev',
'ebpf',
'hw/9pfs',
'hw/acpi',
@@ -3432,6 +3531,7 @@ qom_ss = ss.source_set()
system_ss = ss.source_set()
specific_fuzz_ss = ss.source_set()
specific_ss = ss.source_set()
+rust_devices_ss = ss.source_set()
stub_ss = ss.source_set()
trace_ss = ss.source_set()
user_ss = ss.source_set()
@@ -3818,6 +3918,74 @@ common_all = static_library('common',
implicit_include_directories: false,
dependencies: common_ss.all_dependencies())
+if have_rust and have_system
+ rustc_args = run_command(
+ find_program('scripts/rust/rustc_args.py'),
+ '--config-headers', meson.project_build_root() / 'config-host.h',
+ capture : true,
+ check: true).stdout().strip().split()
+ rustc_args += ['-D', 'unsafe_op_in_unsafe_fn']
+ bindgen_args = [
+ '--disable-header-comment',
+ '--raw-line', '// @generated',
+ '--ctypes-prefix', 'core::ffi',
+ '--formatter', 'rustfmt',
+ '--generate-block',
+ '--generate-cstr',
+ '--impl-debug',
+ '--merge-extern-blocks',
+ '--no-doc-comments',
+ '--use-core',
+ '--with-derive-default',
+ '--no-size_t-is-usize',
+ '--no-layout-tests',
+ '--no-prepend-enum-name',
+ '--allowlist-file', meson.project_source_root() + '/include/.*',
+ '--allowlist-file', meson.project_source_root() + '/.*',
+ '--allowlist-file', meson.project_build_root() + '/.*'
+ ]
+ c_enums = [
+ 'DeviceCategory',
+ 'GpioPolarity',
+ 'MachineInitPhase',
+ 'MemoryDeviceInfoKind',
+ 'MigrationPolicy',
+ 'MigrationPriority',
+ 'QEMUChrEvent',
+ 'QEMUClockType',
+ 'device_endian',
+ 'module_init_type',
+ ]
+ foreach enum : c_enums
+ bindgen_args += ['--rustified-enum', enum]
+ endforeach
+ c_bitfields = [
+ 'ClockEvent',
+ 'VMStateFlags',
+ ]
+ foreach enum : c_bitfields
+ bindgen_args += ['--bitfield-enum', enum]
+ endforeach
+
+ # TODO: Remove this comment when the clang/libclang mismatch issue is solved.
+ #
+ # Rust bindings generation with `bindgen` might fail in some cases where the
+ # detected `libclang` does not match the expected `clang` version/target. In
+ # this case you must pass the path to `clang` and `libclang` to your build
+ # command invocation using the environment variables CLANG_PATH and
+ # LIBCLANG_PATH
+ bindings_rs = import('rust').bindgen(
+ input: 'rust/wrapper.h',
+ dependencies: common_ss.all_dependencies(),
+ output: 'bindings.rs',
+ include_directories: include_directories('.', 'include'),
+ bindgen_version: ['>=0.69.4'],
+ args: bindgen_args,
+ )
+ subdir('rust')
+endif
+
+
feature_to_c = find_program('scripts/feature_to_c.py')
if host_os == 'darwin'
@@ -3911,6 +4079,29 @@ foreach target : target_dirs
arch_srcs += target_specific.sources()
arch_deps += target_specific.dependencies()
+ if have_rust and have_system
+ target_rust = rust_devices_ss.apply(config_target, strict: false)
+ crates = []
+ foreach dep : target_rust.dependencies()
+ crates += dep.get_variable('crate')
+ endforeach
+ if crates.length() > 0
+ rlib_rs = custom_target('rust_' + target.underscorify() + '.rs',
+ output: 'rust_' + target.underscorify() + '.rs',
+ command: [find_program('scripts/rust/rust_root_crate.sh')] + crates,
+ capture: true,
+ build_by_default: true,
+ build_always_stale: true)
+ rlib = static_library('rust_' + target.underscorify(),
+ rlib_rs,
+ dependencies: target_rust.dependencies(),
+ override_options: ['rust_std=2021', 'build.rust_std=2021'],
+ rust_args: rustc_args,
+ rust_abi: 'c')
+ arch_deps += declare_dependency(link_whole: [rlib])
+ endif
+ endif
+
# allow using headers from the dependencies but do not include the sources,
# because this emulator only needs those in "objects". For external
# dependencies, the full dependency is included below in the executable.
@@ -4073,6 +4264,13 @@ if have_tools
dependencies: [authz, crypto, io, qom, qemuutil,
libcap_ng, mpathpersist],
install: true)
+
+ if cpu in ['x86', 'x86_64']
+ executable('qemu-vmsr-helper', files('tools/i386/qemu-vmsr-helper.c'),
+ dependencies: [authz, crypto, io, qom, qemuutil,
+ libcap_ng, mpathpersist],
+ install: true)
+ endif
endif
if have_ivshmem
@@ -4242,6 +4440,12 @@ if 'objc' in all_languages
else
summary_info += {'Objective-C compiler': false}
endif
+summary_info += {'Rust support': have_rust}
+if have_rust
+ summary_info += {'rustc version': rustc.version()}
+ summary_info += {'rustc': ' '.join(rustc.cmd_array())}
+ summary_info += {'Rust target': config_host['RUST_TARGET_TRIPLE']}
+endif
option_cflags = (get_option('debug') ? ['-g'] : [])
if get_option('optimization') != 'plain'
option_cflags += ['-O' + get_option('optimization')]
@@ -4347,7 +4551,6 @@ if have_block
summary_info += {'Block whitelist (ro)': get_option('block_drv_ro_whitelist')}
summary_info += {'Use block whitelist in tools': get_option('block_drv_whitelist_in_tools')}
summary_info += {'VirtFS (9P) support': have_virtfs}
- summary_info += {'VirtFS (9P) Proxy Helper support (deprecated)': have_virtfs_proxy_helper}
summary_info += {'replication support': config_host_data.get('CONFIG_REPLICATION')}
summary_info += {'bochs support': get_option('bochs').allowed()}
summary_info += {'cloop support': get_option('cloop').allowed()}
@@ -4485,6 +4688,7 @@ summary_info += {'lzfse support': liblzfse}
summary_info += {'zstd support': zstd}
summary_info += {'Query Processing Library support': qpl}
summary_info += {'UADK Library support': uadk}
+summary_info += {'qatzip support': qatzip}
summary_info += {'NUMA host support': numa}
summary_info += {'capstone': capstone}
summary_info += {'libpmem support': libpmem}
diff --git a/meson_options.txt b/meson_options.txt
index 0269fa0..0ee4d7b 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -91,8 +91,10 @@ option('tcg_interpreter', type: 'boolean', value: false,
description: 'TCG with bytecode interpreter (slow)')
option('safe_stack', type: 'boolean', value: false,
description: 'SafeStack Stack Smash Protection (requires clang/llvm and coroutine backend ucontext)')
-option('sanitizers', type: 'boolean', value: false,
- description: 'enable default sanitizers')
+option('asan', type: 'boolean', value: false,
+ description: 'enable address sanitizer')
+option('ubsan', type: 'boolean', value: false,
+ description: 'enable undefined behaviour sanitizer')
option('tsan', type: 'boolean', value: false,
description: 'enable thread sanitizer')
option('stack_protector', type: 'feature', value: 'auto',
@@ -261,6 +263,8 @@ option('qpl', type : 'feature', value : 'auto',
description: 'Query Processing Library support')
option('uadk', type : 'feature', value : 'auto',
description: 'UADK Library support')
+option('qatzip', type: 'feature', value: 'auto',
+ description: 'QATzip compression support')
option('fuse', type: 'feature', value: 'auto',
description: 'FUSE block device export')
option('fuse_lseek', type : 'feature', value : 'auto',
@@ -301,8 +305,6 @@ option('vhost_user_blk_server', type: 'feature', value: 'auto',
description: 'build vhost-user-blk server')
option('virtfs', type: 'feature', value: 'auto',
description: 'virtio-9p support')
-option('virtfs_proxy_helper', type: 'feature', value: 'auto',
- description: 'virtio-9p proxy helper support')
option('libvduse', type: 'feature', value: 'auto',
description: 'build VDUSE Library')
option('vduse_blk_export', type: 'feature', value: 'auto',
@@ -371,3 +373,6 @@ option('hexagon_idef_parser', type : 'boolean', value : true,
option('x86_version', type : 'combo', choices : ['0', '1', '2', '3', '4'], value: '1',
description: 'tweak required x86_64 architecture version beyond compiler default')
+
+option('rust', type: 'feature', value: 'disabled',
+ description: 'Rust support')
diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c
index 1d9db81..233acb0 100644
--- a/migration/dirtyrate.c
+++ b/migration/dirtyrate.c
@@ -149,12 +149,12 @@ int64_t vcpu_calculate_dirtyrate(int64_t calc_time_ms,
unsigned int flag,
bool one_shot)
{
- DirtyPageRecord *records;
+ DirtyPageRecord *records = NULL;
int64_t init_time_ms;
int64_t duration;
int64_t dirtyrate;
int i = 0;
- unsigned int gen_id;
+ unsigned int gen_id = 0;
retry:
init_time_ms = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
@@ -228,8 +228,7 @@ static int time_unit_to_power(TimeUnit time_unit)
case TIME_UNIT_MILLISECOND:
return -3;
default:
- assert(false); /* unreachable */
- return 0;
+ g_assert_not_reached();
}
}
diff --git a/migration/file.c b/migration/file.c
index db870f2..7f11e26 100644
--- a/migration/file.c
+++ b/migration/file.c
@@ -112,7 +112,6 @@ void file_start_outgoing_migration(MigrationState *s,
error_setg_errno(errp, errno,
"failed to truncate migration file to offset %" PRIx64,
offset);
- object_unref(OBJECT(fioc));
return;
}
@@ -120,7 +119,6 @@ void file_start_outgoing_migration(MigrationState *s,
ioc = QIO_CHANNEL(fioc);
if (offset && qio_channel_io_seek(ioc, offset, SEEK_SET, errp) < 0) {
- object_unref(OBJECT(fioc));
return;
}
qio_channel_set_name(ioc, "migration-file-outgoing");
@@ -198,12 +196,13 @@ void file_start_incoming_migration(FileMigrationArgs *file_args, Error **errp)
}
int file_write_ramblock_iov(QIOChannel *ioc, const struct iovec *iov,
- int niov, RAMBlock *block, Error **errp)
+ int niov, MultiFDPages_t *pages, Error **errp)
{
ssize_t ret = 0;
int i, slice_idx, slice_num;
uintptr_t base, next, offset;
size_t len;
+ RAMBlock *block = pages->block;
slice_idx = 0;
slice_num = 1;
diff --git a/migration/file.h b/migration/file.h
index 9f71e87..1a1115f 100644
--- a/migration/file.h
+++ b/migration/file.h
@@ -21,6 +21,6 @@ int file_parse_offset(char *filespec, uint64_t *offsetp, Error **errp);
void file_cleanup_outgoing_migration(void);
bool file_send_channel_create(gpointer opaque, Error **errp);
int file_write_ramblock_iov(QIOChannel *ioc, const struct iovec *iov,
- int niov, RAMBlock *block, Error **errp);
+ int niov, MultiFDPages_t *pages, Error **errp);
int multifd_file_recv_data(MultiFDRecvParams *p, Error **errp);
#endif
diff --git a/migration/meson.build b/migration/meson.build
index 5ce2acb4..66d3de8 100644
--- a/migration/meson.build
+++ b/migration/meson.build
@@ -21,6 +21,7 @@ system_ss.add(files(
'migration-hmp-cmds.c',
'migration.c',
'multifd.c',
+ 'multifd-nocomp.c',
'multifd-zlib.c',
'multifd-zero-page.c',
'options.c',
@@ -41,6 +42,7 @@ system_ss.add(when: rdma, if_true: files('rdma.c'))
system_ss.add(when: zstd, if_true: files('multifd-zstd.c'))
system_ss.add(when: qpl, if_true: files('multifd-qpl.c'))
system_ss.add(when: uadk, if_true: files('multifd-uadk.c'))
+system_ss.add(when: qatzip, if_true: files('multifd-qatzip.c'))
specific_ss.add(when: 'CONFIG_SYSTEM_ONLY',
if_true: files('ram.c',
diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c
index 7d608d2..20d1a6e 100644
--- a/migration/migration-hmp-cmds.c
+++ b/migration/migration-hmp-cmds.c
@@ -576,6 +576,10 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
p->has_multifd_zlib_level = true;
visit_type_uint8(v, param, &p->multifd_zlib_level, &err);
break;
+ case MIGRATION_PARAMETER_MULTIFD_QATZIP_LEVEL:
+ p->has_multifd_qatzip_level = true;
+ visit_type_uint8(v, param, &p->multifd_qatzip_level, &err);
+ break;
case MIGRATION_PARAMETER_MULTIFD_ZSTD_LEVEL:
p->has_multifd_zstd_level = true;
visit_type_uint8(v, param, &p->multifd_zstd_level, &err);
@@ -636,7 +640,7 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
visit_type_bool(v, param, &p->direct_io, &err);
break;
default:
- assert(0);
+ g_assert_not_reached();
}
if (err) {
diff --git a/migration/migration.c b/migration/migration.c
index 3dea06d..021faee 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -378,6 +378,11 @@ void migration_incoming_state_destroy(void)
struct MigrationIncomingState *mis = migration_incoming_get_current();
multifd_recv_cleanup();
+ /*
+ * RAM state cleanup needs to happen after multifd cleanup, because
+ * multifd threads can use some of its states (receivedmap).
+ */
+ qemu_loadvm_state_cleanup();
if (mis->to_src_file) {
/* Tell source that we are done */
@@ -2273,7 +2278,7 @@ static bool migrate_handle_rp_resume_ack(MigrationState *s,
*/
static void migration_release_dst_files(MigrationState *ms)
{
- QEMUFile *file;
+ QEMUFile *file = NULL;
WITH_QEMU_LOCK_GUARD(&ms->qemu_file_lock) {
/*
diff --git a/migration/multifd-nocomp.c b/migration/multifd-nocomp.c
new file mode 100644
index 0000000..5519115
--- /dev/null
+++ b/migration/multifd-nocomp.c
@@ -0,0 +1,391 @@
+/*
+ * Multifd RAM migration without compression
+ *
+ * Copyright (c) 2019-2020 Red Hat Inc
+ *
+ * Authors:
+ * Juan Quintela <quintela@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 "exec/ramblock.h"
+#include "exec/target_page.h"
+#include "file.h"
+#include "multifd.h"
+#include "options.h"
+#include "qapi/error.h"
+#include "qemu/cutils.h"
+#include "qemu/error-report.h"
+#include "trace.h"
+
+static MultiFDSendData *multifd_ram_send;
+
+size_t multifd_ram_payload_size(void)
+{
+ uint32_t n = multifd_ram_page_count();
+
+ /*
+ * We keep an array of page offsets at the end of MultiFDPages_t,
+ * add space for it in the allocation.
+ */
+ return sizeof(MultiFDPages_t) + n * sizeof(ram_addr_t);
+}
+
+void multifd_ram_save_setup(void)
+{
+ multifd_ram_send = multifd_send_data_alloc();
+}
+
+void multifd_ram_save_cleanup(void)
+{
+ g_free(multifd_ram_send);
+ multifd_ram_send = NULL;
+}
+
+static void multifd_set_file_bitmap(MultiFDSendParams *p)
+{
+ MultiFDPages_t *pages = &p->data->u.ram;
+
+ assert(pages->block);
+
+ for (int i = 0; i < pages->normal_num; i++) {
+ ramblock_set_file_bmap_atomic(pages->block, pages->offset[i], true);
+ }
+
+ for (int i = pages->normal_num; i < pages->num; i++) {
+ ramblock_set_file_bmap_atomic(pages->block, pages->offset[i], false);
+ }
+}
+
+static int multifd_nocomp_send_setup(MultiFDSendParams *p, Error **errp)
+{
+ uint32_t page_count = multifd_ram_page_count();
+
+ if (migrate_zero_copy_send()) {
+ p->write_flags |= QIO_CHANNEL_WRITE_FLAG_ZERO_COPY;
+ }
+
+ if (!migrate_mapped_ram()) {
+ /* We need one extra place for the packet header */
+ p->iov = g_new0(struct iovec, page_count + 1);
+ } else {
+ p->iov = g_new0(struct iovec, page_count);
+ }
+
+ return 0;
+}
+
+static void multifd_nocomp_send_cleanup(MultiFDSendParams *p, Error **errp)
+{
+ g_free(p->iov);
+ p->iov = NULL;
+ return;
+}
+
+static void multifd_send_prepare_iovs(MultiFDSendParams *p)
+{
+ MultiFDPages_t *pages = &p->data->u.ram;
+ uint32_t page_size = multifd_ram_page_size();
+
+ for (int i = 0; i < pages->normal_num; i++) {
+ p->iov[p->iovs_num].iov_base = pages->block->host + pages->offset[i];
+ p->iov[p->iovs_num].iov_len = page_size;
+ p->iovs_num++;
+ }
+
+ p->next_packet_size = pages->normal_num * page_size;
+}
+
+static int multifd_nocomp_send_prepare(MultiFDSendParams *p, Error **errp)
+{
+ bool use_zero_copy_send = migrate_zero_copy_send();
+ int ret;
+
+ multifd_send_zero_page_detect(p);
+
+ if (migrate_mapped_ram()) {
+ multifd_send_prepare_iovs(p);
+ multifd_set_file_bitmap(p);
+
+ return 0;
+ }
+
+ if (!use_zero_copy_send) {
+ /*
+ * Only !zerocopy needs the header in IOV; zerocopy will
+ * send it separately.
+ */
+ multifd_send_prepare_header(p);
+ }
+
+ multifd_send_prepare_iovs(p);
+ p->flags |= MULTIFD_FLAG_NOCOMP;
+
+ multifd_send_fill_packet(p);
+
+ if (use_zero_copy_send) {
+ /* Send header first, without zerocopy */
+ ret = qio_channel_write_all(p->c, (void *)p->packet,
+ p->packet_len, errp);
+ if (ret != 0) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int multifd_nocomp_recv_setup(MultiFDRecvParams *p, Error **errp)
+{
+ p->iov = g_new0(struct iovec, multifd_ram_page_count());
+ return 0;
+}
+
+static void multifd_nocomp_recv_cleanup(MultiFDRecvParams *p)
+{
+ g_free(p->iov);
+ p->iov = NULL;
+}
+
+static int multifd_nocomp_recv(MultiFDRecvParams *p, Error **errp)
+{
+ uint32_t flags;
+
+ if (migrate_mapped_ram()) {
+ return multifd_file_recv_data(p, errp);
+ }
+
+ flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK;
+
+ if (flags != MULTIFD_FLAG_NOCOMP) {
+ error_setg(errp, "multifd %u: flags received %x flags expected %x",
+ p->id, flags, MULTIFD_FLAG_NOCOMP);
+ return -1;
+ }
+
+ multifd_recv_zero_page_process(p);
+
+ if (!p->normal_num) {
+ return 0;
+ }
+
+ for (int i = 0; i < p->normal_num; i++) {
+ p->iov[i].iov_base = p->host + p->normal[i];
+ p->iov[i].iov_len = multifd_ram_page_size();
+ ramblock_recv_bitmap_set_offset(p->block, p->normal[i]);
+ }
+ return qio_channel_readv_all(p->c, p->iov, p->normal_num, errp);
+}
+
+static void multifd_pages_reset(MultiFDPages_t *pages)
+{
+ /*
+ * We don't need to touch offset[] array, because it will be
+ * overwritten later when reused.
+ */
+ pages->num = 0;
+ pages->normal_num = 0;
+ pages->block = NULL;
+}
+
+void multifd_ram_fill_packet(MultiFDSendParams *p)
+{
+ MultiFDPacket_t *packet = p->packet;
+ MultiFDPages_t *pages = &p->data->u.ram;
+ uint32_t zero_num = pages->num - pages->normal_num;
+
+ packet->pages_alloc = cpu_to_be32(multifd_ram_page_count());
+ packet->normal_pages = cpu_to_be32(pages->normal_num);
+ packet->zero_pages = cpu_to_be32(zero_num);
+
+ if (pages->block) {
+ pstrcpy(packet->ramblock, sizeof(packet->ramblock),
+ pages->block->idstr);
+ }
+
+ for (int i = 0; i < pages->num; i++) {
+ /* there are architectures where ram_addr_t is 32 bit */
+ uint64_t temp = pages->offset[i];
+
+ packet->offset[i] = cpu_to_be64(temp);
+ }
+
+ trace_multifd_send_ram_fill(p->id, pages->normal_num,
+ zero_num);
+}
+
+int multifd_ram_unfill_packet(MultiFDRecvParams *p, Error **errp)
+{
+ MultiFDPacket_t *packet = p->packet;
+ uint32_t page_count = multifd_ram_page_count();
+ uint32_t page_size = multifd_ram_page_size();
+ uint32_t pages_per_packet = be32_to_cpu(packet->pages_alloc);
+ int i;
+
+ if (pages_per_packet > page_count) {
+ error_setg(errp, "multifd: received packet with %u pages, expected %u",
+ pages_per_packet, page_count);
+ return -1;
+ }
+
+ p->normal_num = be32_to_cpu(packet->normal_pages);
+ if (p->normal_num > pages_per_packet) {
+ error_setg(errp, "multifd: received packet with %u non-zero pages, "
+ "which exceeds maximum expected pages %u",
+ p->normal_num, pages_per_packet);
+ return -1;
+ }
+
+ p->zero_num = be32_to_cpu(packet->zero_pages);
+ if (p->zero_num > pages_per_packet - p->normal_num) {
+ error_setg(errp,
+ "multifd: received packet with %u zero pages, expected maximum %u",
+ p->zero_num, pages_per_packet - p->normal_num);
+ return -1;
+ }
+
+ if (p->normal_num == 0 && p->zero_num == 0) {
+ return 0;
+ }
+
+ /* make sure that ramblock is 0 terminated */
+ packet->ramblock[255] = 0;
+ p->block = qemu_ram_block_by_name(packet->ramblock);
+ if (!p->block) {
+ error_setg(errp, "multifd: unknown ram block %s",
+ packet->ramblock);
+ return -1;
+ }
+
+ p->host = p->block->host;
+ for (i = 0; i < p->normal_num; i++) {
+ uint64_t offset = be64_to_cpu(packet->offset[i]);
+
+ if (offset > (p->block->used_length - page_size)) {
+ error_setg(errp, "multifd: offset too long %" PRIu64
+ " (max " RAM_ADDR_FMT ")",
+ offset, p->block->used_length);
+ return -1;
+ }
+ p->normal[i] = offset;
+ }
+
+ for (i = 0; i < p->zero_num; i++) {
+ uint64_t offset = be64_to_cpu(packet->offset[p->normal_num + i]);
+
+ if (offset > (p->block->used_length - page_size)) {
+ error_setg(errp, "multifd: offset too long %" PRIu64
+ " (max " RAM_ADDR_FMT ")",
+ offset, p->block->used_length);
+ return -1;
+ }
+ p->zero[i] = offset;
+ }
+
+ return 0;
+}
+
+static inline bool multifd_queue_empty(MultiFDPages_t *pages)
+{
+ return pages->num == 0;
+}
+
+static inline bool multifd_queue_full(MultiFDPages_t *pages)
+{
+ return pages->num == multifd_ram_page_count();
+}
+
+static inline void multifd_enqueue(MultiFDPages_t *pages, ram_addr_t offset)
+{
+ pages->offset[pages->num++] = offset;
+}
+
+/* Returns true if enqueue successful, false otherwise */
+bool multifd_queue_page(RAMBlock *block, ram_addr_t offset)
+{
+ MultiFDPages_t *pages;
+
+retry:
+ pages = &multifd_ram_send->u.ram;
+
+ if (multifd_payload_empty(multifd_ram_send)) {
+ multifd_pages_reset(pages);
+ multifd_set_payload_type(multifd_ram_send, MULTIFD_PAYLOAD_RAM);
+ }
+
+ /* If the queue is empty, we can already enqueue now */
+ if (multifd_queue_empty(pages)) {
+ pages->block = block;
+ multifd_enqueue(pages, offset);
+ return true;
+ }
+
+ /*
+ * Not empty, meanwhile we need a flush. It can because of either:
+ *
+ * (1) The page is not on the same ramblock of previous ones, or,
+ * (2) The queue is full.
+ *
+ * After flush, always retry.
+ */
+ if (pages->block != block || multifd_queue_full(pages)) {
+ if (!multifd_send(&multifd_ram_send)) {
+ return false;
+ }
+ goto retry;
+ }
+
+ /* Not empty, and we still have space, do it! */
+ multifd_enqueue(pages, offset);
+ return true;
+}
+
+int multifd_ram_flush_and_sync(void)
+{
+ if (!migrate_multifd()) {
+ return 0;
+ }
+
+ if (!multifd_payload_empty(multifd_ram_send)) {
+ if (!multifd_send(&multifd_ram_send)) {
+ error_report("%s: multifd_send fail", __func__);
+ return -1;
+ }
+ }
+
+ return multifd_send_sync_main();
+}
+
+bool multifd_send_prepare_common(MultiFDSendParams *p)
+{
+ MultiFDPages_t *pages = &p->data->u.ram;
+ multifd_send_zero_page_detect(p);
+
+ if (!pages->normal_num) {
+ p->next_packet_size = 0;
+ return false;
+ }
+
+ multifd_send_prepare_header(p);
+
+ return true;
+}
+
+static const MultiFDMethods multifd_nocomp_ops = {
+ .send_setup = multifd_nocomp_send_setup,
+ .send_cleanup = multifd_nocomp_send_cleanup,
+ .send_prepare = multifd_nocomp_send_prepare,
+ .recv_setup = multifd_nocomp_recv_setup,
+ .recv_cleanup = multifd_nocomp_recv_cleanup,
+ .recv = multifd_nocomp_recv
+};
+
+static void multifd_nocomp_register(void)
+{
+ multifd_register_ops(MULTIFD_COMPRESSION_NONE, &multifd_nocomp_ops);
+}
+
+migration_init(multifd_nocomp_register);
diff --git a/migration/multifd-qatzip.c b/migration/multifd-qatzip.c
new file mode 100644
index 0000000..7b68397
--- /dev/null
+++ b/migration/multifd-qatzip.c
@@ -0,0 +1,394 @@
+/*
+ * Multifd QATzip compression implementation
+ *
+ * Copyright (c) Bytedance
+ *
+ * Authors:
+ * Bryan Zhang <bryan.zhang@bytedance.com>
+ * Hao Xiang <hao.xiang@bytedance.com>
+ * Yichen Wang <yichen.wang@bytedance.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 "exec/ramblock.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qapi/qapi-types-migration.h"
+#include "options.h"
+#include "multifd.h"
+#include <qatzip.h>
+
+typedef struct {
+ /*
+ * Unique session for use with QATzip API
+ */
+ QzSession_T sess;
+
+ /*
+ * For compression: Buffer for pages to compress
+ * For decompression: Buffer for data to decompress
+ */
+ uint8_t *in_buf;
+ uint32_t in_len;
+
+ /*
+ * For compression: Output buffer of compressed data
+ * For decompression: Output buffer of decompressed data
+ */
+ uint8_t *out_buf;
+ uint32_t out_len;
+} QatzipData;
+
+/**
+ * qatzip_send_setup: Set up QATzip session and private buffers.
+ *
+ * @param p Multifd channel params
+ * @param errp Pointer to error, which will be set in case of error
+ * @return 0 on success, -1 on error (and *errp will be set)
+ */
+static int qatzip_send_setup(MultiFDSendParams *p, Error **errp)
+{
+ QatzipData *q;
+ QzSessionParamsDeflate_T params;
+ const char *err_msg;
+ int ret;
+
+ q = g_new0(QatzipData, 1);
+ p->compress_data = q;
+ /* We need one extra place for the packet header */
+ p->iov = g_new0(struct iovec, 2);
+
+ /*
+ * Initialize QAT device with software fallback by default. This allows
+ * QATzip to use CPU path when QAT hardware reaches maximum throughput.
+ */
+ ret = qzInit(&q->sess, true);
+ if (ret != QZ_OK && ret != QZ_DUPLICATE) {
+ err_msg = "qzInit failed";
+ goto err;
+ }
+
+ ret = qzGetDefaultsDeflate(&params);
+ if (ret != QZ_OK) {
+ err_msg = "qzGetDefaultsDeflate failed";
+ goto err;
+ }
+
+ /* Make sure to use configured QATzip compression level. */
+ params.common_params.comp_lvl = migrate_multifd_qatzip_level();
+ ret = qzSetupSessionDeflate(&q->sess, &params);
+ if (ret != QZ_OK && ret != QZ_DUPLICATE) {
+ err_msg = "qzSetupSessionDeflate failed";
+ goto err;
+ }
+
+ if (MULTIFD_PACKET_SIZE > UINT32_MAX) {
+ err_msg = "packet size too large for QAT";
+ goto err;
+ }
+
+ q->in_len = MULTIFD_PACKET_SIZE;
+ /*
+ * PINNED_MEM is an enum from qatzip headers, which means to use
+ * kzalloc_node() to allocate memory for QAT DMA purposes. When QAT device
+ * is not available or software fallback is used, the malloc flag needs to
+ * be set as COMMON_MEM.
+ */
+ q->in_buf = qzMalloc(q->in_len, 0, PINNED_MEM);
+ if (!q->in_buf) {
+ q->in_buf = qzMalloc(q->in_len, 0, COMMON_MEM);
+ if (!q->in_buf) {
+ err_msg = "qzMalloc failed";
+ goto err;
+ }
+ }
+
+ q->out_len = qzMaxCompressedLength(MULTIFD_PACKET_SIZE, &q->sess);
+ q->out_buf = qzMalloc(q->out_len, 0, PINNED_MEM);
+ if (!q->out_buf) {
+ q->out_buf = qzMalloc(q->out_len, 0, COMMON_MEM);
+ if (!q->out_buf) {
+ err_msg = "qzMalloc failed";
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ error_setg(errp, "multifd %u: [sender] %s", p->id, err_msg);
+ return -1;
+}
+
+/**
+ * qatzip_send_cleanup: Tear down QATzip session and release private buffers.
+ *
+ * @param p Multifd channel params
+ * @param errp Pointer to error, which will be set in case of error
+ * @return None
+ */
+static void qatzip_send_cleanup(MultiFDSendParams *p, Error **errp)
+{
+ QatzipData *q = p->compress_data;
+
+ if (q) {
+ if (q->in_buf) {
+ qzFree(q->in_buf);
+ }
+ if (q->out_buf) {
+ qzFree(q->out_buf);
+ }
+ (void)qzTeardownSession(&q->sess);
+ (void)qzClose(&q->sess);
+ g_free(q);
+ }
+
+ g_free(p->iov);
+ p->iov = NULL;
+ p->compress_data = NULL;
+}
+
+/**
+ * qatzip_send_prepare: Compress pages and update IO channel info.
+ *
+ * @param p Multifd channel params
+ * @param errp Pointer to error, which will be set in case of error
+ * @return 0 on success, -1 on error (and *errp will be set)
+ */
+static int qatzip_send_prepare(MultiFDSendParams *p, Error **errp)
+{
+ uint32_t page_size = multifd_ram_page_size();
+ MultiFDPages_t *pages = &p->data->u.ram;
+ QatzipData *q = p->compress_data;
+ int ret;
+ unsigned int in_len, out_len;
+
+ if (!multifd_send_prepare_common(p)) {
+ goto out;
+ }
+
+ /*
+ * Unlike other multifd compression implementations, we use a non-streaming
+ * API and place all the data into one buffer, rather than sending each
+ * page to the compression API at a time. Based on initial benchmarks, the
+ * non-streaming API outperforms the streaming API. Plus, the logic in QEMU
+ * is friendly to using the non-streaming API anyway. If either of these
+ * statements becomes no longer true, we can revisit adding a streaming
+ * implementation.
+ */
+ for (int i = 0; i < pages->normal_num; i++) {
+ memcpy(q->in_buf + (i * page_size),
+ pages->block->host + pages->offset[i],
+ page_size);
+ }
+
+ in_len = pages->normal_num * page_size;
+ if (in_len > q->in_len) {
+ error_setg(errp, "multifd %u: unexpectedly large input", p->id);
+ return -1;
+ }
+ out_len = q->out_len;
+
+ ret = qzCompress(&q->sess, q->in_buf, &in_len, q->out_buf, &out_len, 1);
+ if (ret != QZ_OK) {
+ error_setg(errp, "multifd %u: QATzip returned %d instead of QZ_OK",
+ p->id, ret);
+ return -1;
+ }
+ if (in_len != pages->normal_num * page_size) {
+ error_setg(errp, "multifd %u: QATzip failed to compress all input",
+ p->id);
+ return -1;
+ }
+
+ p->iov[p->iovs_num].iov_base = q->out_buf;
+ p->iov[p->iovs_num].iov_len = out_len;
+ p->iovs_num++;
+ p->next_packet_size = out_len;
+
+out:
+ p->flags |= MULTIFD_FLAG_QATZIP;
+ multifd_send_fill_packet(p);
+ return 0;
+}
+
+/**
+ * qatzip_recv_setup: Set up QATzip session and allocate private buffers.
+ *
+ * @param p Multifd channel params
+ * @param errp Pointer to error, which will be set in case of error
+ * @return 0 on success, -1 on error (and *errp will be set)
+ */
+static int qatzip_recv_setup(MultiFDRecvParams *p, Error **errp)
+{
+ QatzipData *q;
+ QzSessionParamsDeflate_T params;
+ const char *err_msg;
+ int ret;
+
+ q = g_new0(QatzipData, 1);
+ p->compress_data = q;
+
+ /*
+ * Initialize QAT device with software fallback by default. This allows
+ * QATzip to use CPU path when QAT hardware reaches maximum throughput.
+ */
+ ret = qzInit(&q->sess, true);
+ if (ret != QZ_OK && ret != QZ_DUPLICATE) {
+ err_msg = "qzInit failed";
+ goto err;
+ }
+
+ ret = qzGetDefaultsDeflate(&params);
+ if (ret != QZ_OK) {
+ err_msg = "qzGetDefaultsDeflate failed";
+ goto err;
+ }
+
+ ret = qzSetupSessionDeflate(&q->sess, &params);
+ if (ret != QZ_OK && ret != QZ_DUPLICATE) {
+ err_msg = "qzSetupSessionDeflate failed";
+ goto err;
+ }
+
+ /*
+ * Reserve extra spaces for the incoming packets. Current implementation
+ * doesn't send uncompressed pages in case the compression gets too big.
+ */
+ q->in_len = MULTIFD_PACKET_SIZE * 2;
+ /*
+ * PINNED_MEM is an enum from qatzip headers, which means to use
+ * kzalloc_node() to allocate memory for QAT DMA purposes. When QAT device
+ * is not available or software fallback is used, the malloc flag needs to
+ * be set as COMMON_MEM.
+ */
+ q->in_buf = qzMalloc(q->in_len, 0, PINNED_MEM);
+ if (!q->in_buf) {
+ q->in_buf = qzMalloc(q->in_len, 0, COMMON_MEM);
+ if (!q->in_buf) {
+ err_msg = "qzMalloc failed";
+ goto err;
+ }
+ }
+
+ q->out_len = MULTIFD_PACKET_SIZE;
+ q->out_buf = qzMalloc(q->out_len, 0, PINNED_MEM);
+ if (!q->out_buf) {
+ q->out_buf = qzMalloc(q->out_len, 0, COMMON_MEM);
+ if (!q->out_buf) {
+ err_msg = "qzMalloc failed";
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ error_setg(errp, "multifd %u: [receiver] %s", p->id, err_msg);
+ return -1;
+}
+
+/**
+ * qatzip_recv_cleanup: Tear down QATzip session and release private buffers.
+ *
+ * @param p Multifd channel params
+ * @return None
+ */
+static void qatzip_recv_cleanup(MultiFDRecvParams *p)
+{
+ QatzipData *q = p->compress_data;
+
+ if (q) {
+ if (q->in_buf) {
+ qzFree(q->in_buf);
+ }
+ if (q->out_buf) {
+ qzFree(q->out_buf);
+ }
+ (void)qzTeardownSession(&q->sess);
+ (void)qzClose(&q->sess);
+ g_free(q);
+ }
+ p->compress_data = NULL;
+}
+
+
+/**
+ * qatzip_recv: Decompress pages and copy them to the appropriate
+ * locations.
+ *
+ * @param p Multifd channel params
+ * @param errp Pointer to error, which will be set in case of error
+ * @return 0 on success, -1 on error (and *errp will be set)
+ */
+static int qatzip_recv(MultiFDRecvParams *p, Error **errp)
+{
+ QatzipData *q = p->compress_data;
+ int ret;
+ unsigned int in_len, out_len;
+ uint32_t in_size = p->next_packet_size;
+ uint32_t page_size = multifd_ram_page_size();
+ uint32_t expected_size = p->normal_num * page_size;
+ uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK;
+
+ if (in_size > q->in_len) {
+ error_setg(errp, "multifd %u: received unexpectedly large packet",
+ p->id);
+ return -1;
+ }
+
+ if (flags != MULTIFD_FLAG_QATZIP) {
+ error_setg(errp, "multifd %u: flags received %x flags expected %x",
+ p->id, flags, MULTIFD_FLAG_QATZIP);
+ return -1;
+ }
+
+ multifd_recv_zero_page_process(p);
+ if (!p->normal_num) {
+ assert(in_size == 0);
+ return 0;
+ }
+
+ ret = qio_channel_read_all(p->c, (void *)q->in_buf, in_size, errp);
+ if (ret != 0) {
+ return ret;
+ }
+
+ in_len = in_size;
+ out_len = q->out_len;
+ ret = qzDecompress(&q->sess, q->in_buf, &in_len, q->out_buf, &out_len);
+ if (ret != QZ_OK) {
+ error_setg(errp, "multifd %u: qzDecompress failed", p->id);
+ return -1;
+ }
+ if (out_len != expected_size) {
+ error_setg(errp, "multifd %u: packet size received %u size expected %u",
+ p->id, out_len, expected_size);
+ return -1;
+ }
+
+ /* Copy each page to its appropriate location. */
+ for (int i = 0; i < p->normal_num; i++) {
+ memcpy(p->host + p->normal[i], q->out_buf + page_size * i, page_size);
+ }
+ return 0;
+}
+
+static MultiFDMethods multifd_qatzip_ops = {
+ .send_setup = qatzip_send_setup,
+ .send_cleanup = qatzip_send_cleanup,
+ .send_prepare = qatzip_send_prepare,
+ .recv_setup = qatzip_recv_setup,
+ .recv_cleanup = qatzip_recv_cleanup,
+ .recv = qatzip_recv
+};
+
+static void multifd_qatzip_register(void)
+{
+ multifd_register_ops(MULTIFD_COMPRESSION_QATZIP, &multifd_qatzip_ops);
+}
+
+migration_init(multifd_qatzip_register);
diff --git a/migration/multifd-qpl.c b/migration/multifd-qpl.c
index 9265098..bbe4666 100644
--- a/migration/multifd-qpl.c
+++ b/migration/multifd-qpl.c
@@ -220,21 +220,13 @@ static void multifd_qpl_deinit(QplData *qpl)
}
}
-/**
- * multifd_qpl_send_setup: set up send side
- *
- * Set up the channel with QPL compression.
- *
- * Returns 0 on success or -1 on error
- *
- * @p: Params for the channel being used
- * @errp: pointer to an error
- */
static int multifd_qpl_send_setup(MultiFDSendParams *p, Error **errp)
{
QplData *qpl;
+ uint32_t page_size = multifd_ram_page_size();
+ uint32_t page_count = multifd_ram_page_count();
- qpl = multifd_qpl_init(p->page_count, p->page_size, errp);
+ qpl = multifd_qpl_init(page_count, page_size, errp);
if (!qpl) {
return -1;
}
@@ -245,18 +237,10 @@ static int multifd_qpl_send_setup(MultiFDSendParams *p, Error **errp)
* additional two IOVs are used to store packet header and compressed data
* length
*/
- p->iov = g_new0(struct iovec, p->page_count + 2);
+ p->iov = g_new0(struct iovec, page_count + 2);
return 0;
}
-/**
- * multifd_qpl_send_cleanup: clean up send side
- *
- * Close the channel and free memory.
- *
- * @p: Params for the channel being used
- * @errp: pointer to an error
- */
static void multifd_qpl_send_cleanup(MultiFDSendParams *p, Error **errp)
{
multifd_qpl_deinit(p->compress_data);
@@ -404,13 +388,14 @@ retry:
static void multifd_qpl_compress_pages_slow_path(MultiFDSendParams *p)
{
QplData *qpl = p->compress_data;
- uint32_t size = p->page_size;
+ MultiFDPages_t *pages = &p->data->u.ram;
+ uint32_t size = multifd_ram_page_size();
qpl_job *job = qpl->sw_job;
uint8_t *zbuf = qpl->zbuf;
uint8_t *buf;
- for (int i = 0; i < p->pages->normal_num; i++) {
- buf = p->pages->block->host + p->pages->offset[i];
+ for (int i = 0; i < pages->normal_num; i++) {
+ buf = pages->block->host + pages->offset[i];
multifd_qpl_prepare_comp_job(job, buf, zbuf, size);
if (qpl_execute_job(job) == QPL_STS_OK) {
multifd_qpl_fill_packet(i, p, zbuf, job->total_out);
@@ -434,8 +419,8 @@ static void multifd_qpl_compress_pages_slow_path(MultiFDSendParams *p)
static void multifd_qpl_compress_pages(MultiFDSendParams *p)
{
QplData *qpl = p->compress_data;
- MultiFDPages_t *pages = p->pages;
- uint32_t size = p->page_size;
+ MultiFDPages_t *pages = &p->data->u.ram;
+ uint32_t size = multifd_ram_page_size();
QplHwJob *hw_job;
uint8_t *buf;
uint8_t *zbuf;
@@ -484,20 +469,10 @@ static void multifd_qpl_compress_pages(MultiFDSendParams *p)
}
}
-/**
- * multifd_qpl_send_prepare: prepare data to be able to send
- *
- * Create a compressed buffer with all the pages that we are going to
- * send.
- *
- * Returns 0 on success or -1 on error
- *
- * @p: Params for the channel being used
- * @errp: pointer to an error
- */
static int multifd_qpl_send_prepare(MultiFDSendParams *p, Error **errp)
{
QplData *qpl = p->compress_data;
+ MultiFDPages_t *pages = &p->data->u.ram;
uint32_t len = 0;
if (!multifd_send_prepare_common(p)) {
@@ -505,7 +480,7 @@ static int multifd_qpl_send_prepare(MultiFDSendParams *p, Error **errp)
}
/* The first IOV is used to store the compressed page lengths */
- len = p->pages->normal_num * sizeof(uint32_t);
+ len = pages->normal_num * sizeof(uint32_t);
multifd_qpl_fill_iov(p, (uint8_t *) qpl->zlen, len);
if (qpl->hw_avail) {
multifd_qpl_compress_pages(p);
@@ -519,21 +494,13 @@ out:
return 0;
}
-/**
- * multifd_qpl_recv_setup: set up receive side
- *
- * Create the compressed channel and buffer.
- *
- * Returns 0 on success or -1 on error
- *
- * @p: Params for the channel being used
- * @errp: pointer to an error
- */
static int multifd_qpl_recv_setup(MultiFDRecvParams *p, Error **errp)
{
QplData *qpl;
+ uint32_t page_size = multifd_ram_page_size();
+ uint32_t page_count = multifd_ram_page_count();
- qpl = multifd_qpl_init(p->page_count, p->page_size, errp);
+ qpl = multifd_qpl_init(page_count, page_size, errp);
if (!qpl) {
return -1;
}
@@ -541,13 +508,6 @@ static int multifd_qpl_recv_setup(MultiFDRecvParams *p, Error **errp)
return 0;
}
-/**
- * multifd_qpl_recv_cleanup: set up receive side
- *
- * Close the channel and free memory.
- *
- * @p: Params for the channel being used
- */
static void multifd_qpl_recv_cleanup(MultiFDRecvParams *p)
{
multifd_qpl_deinit(p->compress_data);
@@ -600,7 +560,7 @@ static int multifd_qpl_decompress_pages_slow_path(MultiFDRecvParams *p,
Error **errp)
{
QplData *qpl = p->compress_data;
- uint32_t size = p->page_size;
+ uint32_t size = multifd_ram_page_size();
qpl_job *job = qpl->sw_job;
uint8_t *zbuf = qpl->zbuf;
uint8_t *addr;
@@ -638,7 +598,7 @@ static int multifd_qpl_decompress_pages_slow_path(MultiFDRecvParams *p,
static int multifd_qpl_decompress_pages(MultiFDRecvParams *p, Error **errp)
{
QplData *qpl = p->compress_data;
- uint32_t size = p->page_size;
+ uint32_t size = multifd_ram_page_size();
uint8_t *zbuf = qpl->zbuf;
uint8_t *addr;
uint32_t len;
@@ -688,17 +648,6 @@ static int multifd_qpl_decompress_pages(MultiFDRecvParams *p, Error **errp)
}
return 0;
}
-/**
- * multifd_qpl_recv: read the data from the channel into actual pages
- *
- * Read the compressed buffer, and uncompress it into the actual
- * pages.
- *
- * Returns 0 on success or -1 on error
- *
- * @p: Params for the channel being used
- * @errp: pointer to an error
- */
static int multifd_qpl_recv(MultiFDRecvParams *p, Error **errp)
{
QplData *qpl = p->compress_data;
@@ -728,7 +677,7 @@ static int multifd_qpl_recv(MultiFDRecvParams *p, Error **errp)
}
for (int i = 0; i < p->normal_num; i++) {
qpl->zlen[i] = be32_to_cpu(qpl->zlen[i]);
- assert(qpl->zlen[i] <= p->page_size);
+ assert(qpl->zlen[i] <= multifd_ram_page_size());
zbuf_len += qpl->zlen[i];
}
@@ -745,7 +694,7 @@ static int multifd_qpl_recv(MultiFDRecvParams *p, Error **errp)
return multifd_qpl_decompress_pages_slow_path(p, errp);
}
-static MultiFDMethods multifd_qpl_ops = {
+static const MultiFDMethods multifd_qpl_ops = {
.send_setup = multifd_qpl_send_setup,
.send_cleanup = multifd_qpl_send_cleanup,
.send_prepare = multifd_qpl_send_prepare,
diff --git a/migration/multifd-uadk.c b/migration/multifd-uadk.c
index d12353f..6e6a290 100644
--- a/migration/multifd-uadk.c
+++ b/migration/multifd-uadk.c
@@ -103,19 +103,13 @@ static void multifd_uadk_uninit_sess(struct wd_data *wd)
g_free(wd);
}
-/**
- * multifd_uadk_send_setup: setup send side
- *
- * Returns 0 for success or -1 for error
- *
- * @p: Params for the channel that we are using
- * @errp: pointer to an error
- */
static int multifd_uadk_send_setup(MultiFDSendParams *p, Error **errp)
{
struct wd_data *wd;
+ uint32_t page_size = multifd_ram_page_size();
+ uint32_t page_count = multifd_ram_page_count();
- wd = multifd_uadk_init_sess(p->page_count, p->page_size, true, errp);
+ wd = multifd_uadk_init_sess(page_count, page_size, true, errp);
if (!wd) {
return -1;
}
@@ -128,24 +122,18 @@ static int multifd_uadk_send_setup(MultiFDSendParams *p, Error **errp)
* length
*/
- p->iov = g_new0(struct iovec, p->page_count + 2);
+ p->iov = g_new0(struct iovec, page_count + 2);
return 0;
}
-/**
- * multifd_uadk_send_cleanup: cleanup send side
- *
- * Close the channel and return memory.
- *
- * @p: Params for the channel that we are using
- * @errp: pointer to an error
- */
static void multifd_uadk_send_cleanup(MultiFDSendParams *p, Error **errp)
{
struct wd_data *wd = p->compress_data;
multifd_uadk_uninit_sess(wd);
p->compress_data = NULL;
+ g_free(p->iov);
+ p->iov = NULL;
}
static inline void prepare_next_iov(MultiFDSendParams *p, void *base,
@@ -157,37 +145,28 @@ static inline void prepare_next_iov(MultiFDSendParams *p, void *base,
p->iovs_num++;
}
-/**
- * multifd_uadk_send_prepare: prepare data to be able to send
- *
- * Create a compressed buffer with all the pages that we are going to
- * send.
- *
- * Returns 0 for success or -1 for error
- *
- * @p: Params for the channel that we are using
- * @errp: pointer to an error
- */
static int multifd_uadk_send_prepare(MultiFDSendParams *p, Error **errp)
{
struct wd_data *uadk_data = p->compress_data;
uint32_t hdr_size;
+ uint32_t page_size = multifd_ram_page_size();
uint8_t *buf = uadk_data->buf;
int ret = 0;
+ MultiFDPages_t *pages = &p->data->u.ram;
if (!multifd_send_prepare_common(p)) {
goto out;
}
- hdr_size = p->pages->normal_num * sizeof(uint32_t);
+ hdr_size = pages->normal_num * sizeof(uint32_t);
/* prepare the header that stores the lengths of all compressed data */
prepare_next_iov(p, uadk_data->buf_hdr, hdr_size);
- for (int i = 0; i < p->pages->normal_num; i++) {
+ for (int i = 0; i < pages->normal_num; i++) {
struct wd_comp_req creq = {
.op_type = WD_DIR_COMPRESS,
- .src = p->pages->block->host + p->pages->offset[i],
- .src_len = p->page_size,
+ .src = pages->block->host + pages->offset[i],
+ .src_len = page_size,
.dst = buf,
/* Set dst_len to double the src in case compressed out >= page_size */
.dst_len = p->page_size * 2,
@@ -200,7 +179,7 @@ static int multifd_uadk_send_prepare(MultiFDSendParams *p, Error **errp)
p->id, ret, creq.status);
return -1;
}
- if (creq.dst_len < p->page_size) {
+ if (creq.dst_len < page_size) {
uadk_data->buf_hdr[i] = cpu_to_be32(creq.dst_len);
prepare_next_iov(p, buf, creq.dst_len);
buf += creq.dst_len;
@@ -212,11 +191,11 @@ static int multifd_uadk_send_prepare(MultiFDSendParams *p, Error **errp)
* than page_size as well because at the receive end we can skip the
* decompression. But it is tricky to find the right number here.
*/
- if (!uadk_data->handle || creq.dst_len >= p->page_size) {
- uadk_data->buf_hdr[i] = cpu_to_be32(p->page_size);
- prepare_next_iov(p, p->pages->block->host + p->pages->offset[i],
- p->page_size);
- buf += p->page_size;
+ if (!uadk_data->handle || creq.dst_len >= page_size) {
+ uadk_data->buf_hdr[i] = cpu_to_be32(page_size);
+ prepare_next_iov(p, pages->block->host + pages->offset[i],
+ page_size);
+ buf += page_size;
}
}
out:
@@ -225,21 +204,13 @@ out:
return 0;
}
-/**
- * multifd_uadk_recv_setup: setup receive side
- *
- * Create the compressed channel and buffer.
- *
- * Returns 0 for success or -1 for error
- *
- * @p: Params for the channel that we are using
- * @errp: pointer to an error
- */
static int multifd_uadk_recv_setup(MultiFDRecvParams *p, Error **errp)
{
struct wd_data *wd;
+ uint32_t page_size = multifd_ram_page_size();
+ uint32_t page_count = multifd_ram_page_count();
- wd = multifd_uadk_init_sess(p->page_count, p->page_size, false, errp);
+ wd = multifd_uadk_init_sess(page_count, page_size, false, errp);
if (!wd) {
return -1;
}
@@ -247,13 +218,6 @@ static int multifd_uadk_recv_setup(MultiFDRecvParams *p, Error **errp)
return 0;
}
-/**
- * multifd_uadk_recv_cleanup: cleanup receive side
- *
- * Close the channel and return memory.
- *
- * @p: Params for the channel that we are using
- */
static void multifd_uadk_recv_cleanup(MultiFDRecvParams *p)
{
struct wd_data *wd = p->compress_data;
@@ -262,17 +226,6 @@ static void multifd_uadk_recv_cleanup(MultiFDRecvParams *p)
p->compress_data = NULL;
}
-/**
- * multifd_uadk_recv: read the data from the channel into actual pages
- *
- * Read the compressed buffer, and uncompress it into the actual
- * pages.
- *
- * Returns 0 for success or -1 for error
- *
- * @p: Params for the channel that we are using
- * @errp: pointer to an error
- */
static int multifd_uadk_recv(MultiFDRecvParams *p, Error **errp)
{
struct wd_data *uadk_data = p->compress_data;
@@ -280,6 +233,7 @@ static int multifd_uadk_recv(MultiFDRecvParams *p, Error **errp)
uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK;
uint32_t hdr_len = p->normal_num * sizeof(uint32_t);
uint32_t data_len = 0;
+ uint32_t page_size = multifd_ram_page_size();
uint8_t *buf = uadk_data->buf;
int ret = 0;
@@ -306,7 +260,7 @@ static int multifd_uadk_recv(MultiFDRecvParams *p, Error **errp)
for (int i = 0; i < p->normal_num; i++) {
uadk_data->buf_hdr[i] = be32_to_cpu(uadk_data->buf_hdr[i]);
data_len += uadk_data->buf_hdr[i];
- assert(uadk_data->buf_hdr[i] <= p->page_size);
+ assert(uadk_data->buf_hdr[i] <= page_size);
}
/* read compressed data */
@@ -322,12 +276,12 @@ static int multifd_uadk_recv(MultiFDRecvParams *p, Error **errp)
.src = buf,
.src_len = uadk_data->buf_hdr[i],
.dst = p->host + p->normal[i],
- .dst_len = p->page_size,
+ .dst_len = page_size,
};
- if (uadk_data->buf_hdr[i] == p->page_size) {
- memcpy(p->host + p->normal[i], buf, p->page_size);
- buf += p->page_size;
+ if (uadk_data->buf_hdr[i] == page_size) {
+ memcpy(p->host + p->normal[i], buf, page_size);
+ buf += page_size;
continue;
}
@@ -343,7 +297,7 @@ static int multifd_uadk_recv(MultiFDRecvParams *p, Error **errp)
p->id, ret, creq.status);
return -1;
}
- if (creq.dst_len != p->page_size) {
+ if (creq.dst_len != page_size) {
error_setg(errp, "multifd %u: decompressed length error", p->id);
return -1;
}
@@ -353,7 +307,7 @@ static int multifd_uadk_recv(MultiFDRecvParams *p, Error **errp)
return 0;
}
-static MultiFDMethods multifd_uadk_ops = {
+static const MultiFDMethods multifd_uadk_ops = {
.send_setup = multifd_uadk_send_setup,
.send_cleanup = multifd_uadk_send_cleanup,
.send_prepare = multifd_uadk_send_prepare,
diff --git a/migration/multifd-zero-page.c b/migration/multifd-zero-page.c
index e1b8370..f1e988a 100644
--- a/migration/multifd-zero-page.c
+++ b/migration/multifd-zero-page.c
@@ -14,6 +14,7 @@
#include "qemu/cutils.h"
#include "exec/ramblock.h"
#include "migration.h"
+#include "migration-stats.h"
#include "multifd.h"
#include "options.h"
#include "ram.h"
@@ -46,14 +47,14 @@ static void swap_page_offset(ram_addr_t *pages_offset, int a, int b)
*/
void multifd_send_zero_page_detect(MultiFDSendParams *p)
{
- MultiFDPages_t *pages = p->pages;
+ MultiFDPages_t *pages = &p->data->u.ram;
RAMBlock *rb = pages->block;
int i = 0;
int j = pages->num - 1;
if (!multifd_zero_page_enabled()) {
pages->normal_num = pages->num;
- return;
+ goto out;
}
/*
@@ -63,7 +64,7 @@ void multifd_send_zero_page_detect(MultiFDSendParams *p)
while (i <= j) {
uint64_t offset = pages->offset[i];
- if (!buffer_is_zero(rb->host + offset, p->page_size)) {
+ if (!buffer_is_zero(rb->host + offset, multifd_ram_page_size())) {
i++;
continue;
}
@@ -74,6 +75,10 @@ void multifd_send_zero_page_detect(MultiFDSendParams *p)
}
pages->normal_num = i;
+
+out:
+ stat64_add(&mig_stats.normal_pages, pages->normal_num);
+ stat64_add(&mig_stats.zero_pages, pages->num - pages->normal_num);
}
void multifd_recv_zero_page_process(MultiFDRecvParams *p)
@@ -81,7 +86,7 @@ void multifd_recv_zero_page_process(MultiFDRecvParams *p)
for (int i = 0; i < p->zero_num; i++) {
void *page = p->host + p->zero[i];
if (ramblock_recv_bitmap_test_byte_offset(p->block, p->zero[i])) {
- memset(page, 0, p->page_size);
+ memset(page, 0, multifd_ram_page_size());
} else {
ramblock_recv_bitmap_set_offset(p->block, p->zero[i]);
}
diff --git a/migration/multifd-zlib.c b/migration/multifd-zlib.c
index 2ced694..8cf8a26 100644
--- a/migration/multifd-zlib.c
+++ b/migration/multifd-zlib.c
@@ -34,17 +34,7 @@ struct zlib_data {
/* Multifd zlib compression */
-/**
- * zlib_send_setup: setup send side
- *
- * Setup each channel with zlib compression.
- *
- * Returns 0 for success or -1 for error
- *
- * @p: Params for the channel that we are using
- * @errp: pointer to an error
- */
-static int zlib_send_setup(MultiFDSendParams *p, Error **errp)
+static int multifd_zlib_send_setup(MultiFDSendParams *p, Error **errp)
{
struct zlib_data *z = g_new0(struct zlib_data, 1);
z_stream *zs = &z->zs;
@@ -86,15 +76,7 @@ err_free_z:
return -1;
}
-/**
- * zlib_send_cleanup: cleanup send side
- *
- * Close the channel and return memory.
- *
- * @p: Params for the channel that we are using
- * @errp: pointer to an error
- */
-static void zlib_send_cleanup(MultiFDSendParams *p, Error **errp)
+static void multifd_zlib_send_cleanup(MultiFDSendParams *p, Error **errp)
{
struct zlib_data *z = p->compress_data;
@@ -110,23 +92,13 @@ static void zlib_send_cleanup(MultiFDSendParams *p, Error **errp)
p->iov = NULL;
}
-/**
- * zlib_send_prepare: prepare date to be able to send
- *
- * Create a compressed buffer with all the pages that we are going to
- * send.
- *
- * Returns 0 for success or -1 for error
- *
- * @p: Params for the channel that we are using
- * @errp: pointer to an error
- */
-static int zlib_send_prepare(MultiFDSendParams *p, Error **errp)
+static int multifd_zlib_send_prepare(MultiFDSendParams *p, Error **errp)
{
- MultiFDPages_t *pages = p->pages;
+ MultiFDPages_t *pages = &p->data->u.ram;
struct zlib_data *z = p->compress_data;
z_stream *zs = &z->zs;
uint32_t out_size = 0;
+ uint32_t page_size = multifd_ram_page_size();
int ret;
uint32_t i;
@@ -147,8 +119,8 @@ static int zlib_send_prepare(MultiFDSendParams *p, Error **errp)
* with compression. zlib does not guarantee that this is safe,
* therefore copy the page before calling deflate().
*/
- memcpy(z->buf, p->pages->block->host + pages->offset[i], p->page_size);
- zs->avail_in = p->page_size;
+ memcpy(z->buf, pages->block->host + pages->offset[i], page_size);
+ zs->avail_in = page_size;
zs->next_in = z->buf;
zs->avail_out = available;
@@ -188,17 +160,7 @@ out:
return 0;
}
-/**
- * zlib_recv_setup: setup receive side
- *
- * Create the compressed channel and buffer.
- *
- * Returns 0 for success or -1 for error
- *
- * @p: Params for the channel that we are using
- * @errp: pointer to an error
- */
-static int zlib_recv_setup(MultiFDRecvParams *p, Error **errp)
+static int multifd_zlib_recv_setup(MultiFDRecvParams *p, Error **errp)
{
struct zlib_data *z = g_new0(struct zlib_data, 1);
z_stream *zs = &z->zs;
@@ -224,14 +186,7 @@ static int zlib_recv_setup(MultiFDRecvParams *p, Error **errp)
return 0;
}
-/**
- * zlib_recv_cleanup: setup receive side
- *
- * For no compression this function does nothing.
- *
- * @p: Params for the channel that we are using
- */
-static void zlib_recv_cleanup(MultiFDRecvParams *p)
+static void multifd_zlib_recv_cleanup(MultiFDRecvParams *p)
{
struct zlib_data *z = p->compress_data;
@@ -242,25 +197,15 @@ static void zlib_recv_cleanup(MultiFDRecvParams *p)
p->compress_data = NULL;
}
-/**
- * zlib_recv: read the data from the channel into actual pages
- *
- * Read the compressed buffer, and uncompress it into the actual
- * pages.
- *
- * Returns 0 for success or -1 for error
- *
- * @p: Params for the channel that we are using
- * @errp: pointer to an error
- */
-static int zlib_recv(MultiFDRecvParams *p, Error **errp)
+static int multifd_zlib_recv(MultiFDRecvParams *p, Error **errp)
{
struct zlib_data *z = p->compress_data;
z_stream *zs = &z->zs;
uint32_t in_size = p->next_packet_size;
/* we measure the change of total_out */
uint32_t out_size = zs->total_out;
- uint32_t expected_size = p->normal_num * p->page_size;
+ uint32_t page_size = multifd_ram_page_size();
+ uint32_t expected_size = p->normal_num * page_size;
uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK;
int ret;
int i;
@@ -296,7 +241,7 @@ static int zlib_recv(MultiFDRecvParams *p, Error **errp)
flush = Z_SYNC_FLUSH;
}
- zs->avail_out = p->page_size;
+ zs->avail_out = page_size;
zs->next_out = p->host + p->normal[i];
/*
@@ -310,8 +255,8 @@ static int zlib_recv(MultiFDRecvParams *p, Error **errp)
do {
ret = inflate(zs, flush);
} while (ret == Z_OK && zs->avail_in
- && (zs->total_out - start) < p->page_size);
- if (ret == Z_OK && (zs->total_out - start) < p->page_size) {
+ && (zs->total_out - start) < page_size);
+ if (ret == Z_OK && (zs->total_out - start) < page_size) {
error_setg(errp, "multifd %u: inflate generated too few output",
p->id);
return -1;
@@ -332,13 +277,13 @@ static int zlib_recv(MultiFDRecvParams *p, Error **errp)
return 0;
}
-static MultiFDMethods multifd_zlib_ops = {
- .send_setup = zlib_send_setup,
- .send_cleanup = zlib_send_cleanup,
- .send_prepare = zlib_send_prepare,
- .recv_setup = zlib_recv_setup,
- .recv_cleanup = zlib_recv_cleanup,
- .recv = zlib_recv
+static const MultiFDMethods multifd_zlib_ops = {
+ .send_setup = multifd_zlib_send_setup,
+ .send_cleanup = multifd_zlib_send_cleanup,
+ .send_prepare = multifd_zlib_send_prepare,
+ .recv_setup = multifd_zlib_recv_setup,
+ .recv_cleanup = multifd_zlib_recv_cleanup,
+ .recv = multifd_zlib_recv
};
static void multifd_zlib_register(void)
diff --git a/migration/multifd-zstd.c b/migration/multifd-zstd.c
index ca17b7e..abed140 100644
--- a/migration/multifd-zstd.c
+++ b/migration/multifd-zstd.c
@@ -37,17 +37,7 @@ struct zstd_data {
/* Multifd zstd compression */
-/**
- * zstd_send_setup: setup send side
- *
- * Setup each channel with zstd compression.
- *
- * Returns 0 for success or -1 for error
- *
- * @p: Params for the channel that we are using
- * @errp: pointer to an error
- */
-static int zstd_send_setup(MultiFDSendParams *p, Error **errp)
+static int multifd_zstd_send_setup(MultiFDSendParams *p, Error **errp)
{
struct zstd_data *z = g_new0(struct zstd_data, 1);
int res;
@@ -83,15 +73,7 @@ static int zstd_send_setup(MultiFDSendParams *p, Error **errp)
return 0;
}
-/**
- * zstd_send_cleanup: cleanup send side
- *
- * Close the channel and return memory.
- *
- * @p: Params for the channel that we are using
- * @errp: pointer to an error
- */
-static void zstd_send_cleanup(MultiFDSendParams *p, Error **errp)
+static void multifd_zstd_send_cleanup(MultiFDSendParams *p, Error **errp)
{
struct zstd_data *z = p->compress_data;
@@ -106,20 +88,9 @@ static void zstd_send_cleanup(MultiFDSendParams *p, Error **errp)
p->iov = NULL;
}
-/**
- * zstd_send_prepare: prepare date to be able to send
- *
- * Create a compressed buffer with all the pages that we are going to
- * send.
- *
- * Returns 0 for success or -1 for error
- *
- * @p: Params for the channel that we are using
- * @errp: pointer to an error
- */
-static int zstd_send_prepare(MultiFDSendParams *p, Error **errp)
+static int multifd_zstd_send_prepare(MultiFDSendParams *p, Error **errp)
{
- MultiFDPages_t *pages = p->pages;
+ MultiFDPages_t *pages = &p->data->u.ram;
struct zstd_data *z = p->compress_data;
int ret;
uint32_t i;
@@ -138,8 +109,8 @@ static int zstd_send_prepare(MultiFDSendParams *p, Error **errp)
if (i == pages->normal_num - 1) {
flush = ZSTD_e_flush;
}
- z->in.src = p->pages->block->host + pages->offset[i];
- z->in.size = p->page_size;
+ z->in.src = pages->block->host + pages->offset[i];
+ z->in.size = multifd_ram_page_size();
z->in.pos = 0;
/*
@@ -152,9 +123,9 @@ static int zstd_send_prepare(MultiFDSendParams *p, Error **errp)
*/
do {
ret = ZSTD_compressStream2(z->zcs, &z->out, &z->in, flush);
- } while (ret > 0 && (z->in.size - z->in.pos > 0)
- && (z->out.size - z->out.pos > 0));
- if (ret > 0 && (z->in.size - z->in.pos > 0)) {
+ } while (ret > 0 && (z->in.size > z->in.pos)
+ && (z->out.size > z->out.pos));
+ if (ret > 0 && (z->in.size > z->in.pos)) {
error_setg(errp, "multifd %u: compressStream buffer too small",
p->id);
return -1;
@@ -176,17 +147,7 @@ out:
return 0;
}
-/**
- * zstd_recv_setup: setup receive side
- *
- * Create the compressed channel and buffer.
- *
- * Returns 0 for success or -1 for error
- *
- * @p: Params for the channel that we are using
- * @errp: pointer to an error
- */
-static int zstd_recv_setup(MultiFDRecvParams *p, Error **errp)
+static int multifd_zstd_recv_setup(MultiFDRecvParams *p, Error **errp)
{
struct zstd_data *z = g_new0(struct zstd_data, 1);
int ret;
@@ -220,14 +181,7 @@ static int zstd_recv_setup(MultiFDRecvParams *p, Error **errp)
return 0;
}
-/**
- * zstd_recv_cleanup: setup receive side
- *
- * For no compression this function does nothing.
- *
- * @p: Params for the channel that we are using
- */
-static void zstd_recv_cleanup(MultiFDRecvParams *p)
+static void multifd_zstd_recv_cleanup(MultiFDRecvParams *p)
{
struct zstd_data *z = p->compress_data;
@@ -239,22 +193,12 @@ static void zstd_recv_cleanup(MultiFDRecvParams *p)
p->compress_data = NULL;
}
-/**
- * zstd_recv: read the data from the channel into actual pages
- *
- * Read the compressed buffer, and uncompress it into the actual
- * pages.
- *
- * Returns 0 for success or -1 for error
- *
- * @p: Params for the channel that we are using
- * @errp: pointer to an error
- */
-static int zstd_recv(MultiFDRecvParams *p, Error **errp)
+static int multifd_zstd_recv(MultiFDRecvParams *p, Error **errp)
{
uint32_t in_size = p->next_packet_size;
uint32_t out_size = 0;
- uint32_t expected_size = p->normal_num * p->page_size;
+ uint32_t page_size = multifd_ram_page_size();
+ uint32_t expected_size = p->normal_num * page_size;
uint32_t flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK;
struct zstd_data *z = p->compress_data;
int ret;
@@ -286,7 +230,7 @@ static int zstd_recv(MultiFDRecvParams *p, Error **errp)
for (i = 0; i < p->normal_num; i++) {
ramblock_recv_bitmap_set_offset(p->block, p->normal[i]);
z->out.dst = p->host + p->normal[i];
- z->out.size = p->page_size;
+ z->out.size = page_size;
z->out.pos = 0;
/*
@@ -299,9 +243,9 @@ static int zstd_recv(MultiFDRecvParams *p, Error **errp)
*/
do {
ret = ZSTD_decompressStream(z->zds, &z->out, &z->in);
- } while (ret > 0 && (z->in.size - z->in.pos > 0)
- && (z->out.pos < p->page_size));
- if (ret > 0 && (z->out.pos < p->page_size)) {
+ } while (ret > 0 && (z->in.size > z->in.pos)
+ && (z->out.pos < page_size));
+ if (ret > 0 && (z->out.pos < page_size)) {
error_setg(errp, "multifd %u: decompressStream buffer too small",
p->id);
return -1;
@@ -321,13 +265,13 @@ static int zstd_recv(MultiFDRecvParams *p, Error **errp)
return 0;
}
-static MultiFDMethods multifd_zstd_ops = {
- .send_setup = zstd_send_setup,
- .send_cleanup = zstd_send_cleanup,
- .send_prepare = zstd_send_prepare,
- .recv_setup = zstd_recv_setup,
- .recv_cleanup = zstd_recv_cleanup,
- .recv = zstd_recv
+static const MultiFDMethods multifd_zstd_ops = {
+ .send_setup = multifd_zstd_send_setup,
+ .send_cleanup = multifd_zstd_send_cleanup,
+ .send_prepare = multifd_zstd_send_prepare,
+ .recv_setup = multifd_zstd_recv_setup,
+ .recv_cleanup = multifd_zstd_recv_cleanup,
+ .recv = multifd_zstd_recv
};
static void multifd_zstd_register(void)
diff --git a/migration/multifd.c b/migration/multifd.c
index 0b4cbad..9b200f4 100644
--- a/migration/multifd.c
+++ b/migration/multifd.c
@@ -49,8 +49,6 @@ typedef struct {
struct {
MultiFDSendParams *params;
- /* array of pages to sent */
- MultiFDPages_t *pages;
/*
* Global number of generated multifd packets.
*
@@ -78,7 +76,7 @@ struct {
*/
int exiting;
/* multifd ops */
- MultiFDMethods *ops;
+ const MultiFDMethods *ops;
} *multifd_send_state;
struct {
@@ -95,236 +93,50 @@ struct {
uint64_t packet_num;
int exiting;
/* multifd ops */
- MultiFDMethods *ops;
+ const MultiFDMethods *ops;
} *multifd_recv_state;
-static bool multifd_use_packets(void)
-{
- return !migrate_mapped_ram();
-}
-
-void multifd_send_channel_created(void)
-{
- qemu_sem_post(&multifd_send_state->channels_created);
-}
-
-static void multifd_set_file_bitmap(MultiFDSendParams *p)
-{
- MultiFDPages_t *pages = p->pages;
-
- assert(pages->block);
-
- for (int i = 0; i < p->pages->normal_num; i++) {
- ramblock_set_file_bmap_atomic(pages->block, pages->offset[i], true);
- }
-
- for (int i = p->pages->normal_num; i < p->pages->num; i++) {
- ramblock_set_file_bmap_atomic(pages->block, pages->offset[i], false);
- }
-}
-
-/* Multifd without compression */
-
-/**
- * nocomp_send_setup: setup send side
- *
- * @p: Params for the channel that we are using
- * @errp: pointer to an error
- */
-static int nocomp_send_setup(MultiFDSendParams *p, Error **errp)
-{
- if (migrate_zero_copy_send()) {
- p->write_flags |= QIO_CHANNEL_WRITE_FLAG_ZERO_COPY;
- }
-
- if (multifd_use_packets()) {
- /* We need one extra place for the packet header */
- p->iov = g_new0(struct iovec, p->page_count + 1);
- } else {
- p->iov = g_new0(struct iovec, p->page_count);
- }
-
- return 0;
-}
-
-/**
- * nocomp_send_cleanup: cleanup send side
- *
- * For no compression this function does nothing.
- *
- * @p: Params for the channel that we are using
- * @errp: pointer to an error
- */
-static void nocomp_send_cleanup(MultiFDSendParams *p, Error **errp)
-{
- g_free(p->iov);
- p->iov = NULL;
- return;
-}
-
-static void multifd_send_prepare_iovs(MultiFDSendParams *p)
+MultiFDSendData *multifd_send_data_alloc(void)
{
- MultiFDPages_t *pages = p->pages;
-
- for (int i = 0; i < pages->normal_num; i++) {
- p->iov[p->iovs_num].iov_base = pages->block->host + pages->offset[i];
- p->iov[p->iovs_num].iov_len = p->page_size;
- p->iovs_num++;
- }
+ size_t max_payload_size, size_minus_payload;
- p->next_packet_size = pages->normal_num * p->page_size;
-}
-
-/**
- * nocomp_send_prepare: prepare date to be able to send
- *
- * For no compression we just have to calculate the size of the
- * packet.
- *
- * Returns 0 for success or -1 for error
- *
- * @p: Params for the channel that we are using
- * @errp: pointer to an error
- */
-static int nocomp_send_prepare(MultiFDSendParams *p, Error **errp)
-{
- bool use_zero_copy_send = migrate_zero_copy_send();
- int ret;
-
- multifd_send_zero_page_detect(p);
-
- if (!multifd_use_packets()) {
- multifd_send_prepare_iovs(p);
- multifd_set_file_bitmap(p);
-
- return 0;
- }
-
- if (!use_zero_copy_send) {
- /*
- * Only !zerocopy needs the header in IOV; zerocopy will
- * send it separately.
- */
- multifd_send_prepare_header(p);
- }
-
- multifd_send_prepare_iovs(p);
- p->flags |= MULTIFD_FLAG_NOCOMP;
-
- multifd_send_fill_packet(p);
+ /*
+ * MultiFDPages_t has a flexible array at the end, account for it
+ * when allocating MultiFDSendData. Use max() in case other types
+ * added to the union in the future are larger than
+ * (MultiFDPages_t + flex array).
+ */
+ max_payload_size = MAX(multifd_ram_payload_size(), sizeof(MultiFDPayload));
- if (use_zero_copy_send) {
- /* Send header first, without zerocopy */
- ret = qio_channel_write_all(p->c, (void *)p->packet,
- p->packet_len, errp);
- if (ret != 0) {
- return -1;
- }
- }
+ /*
+ * Account for any holes the compiler might insert. We can't pack
+ * the structure because that misaligns the members and triggers
+ * Waddress-of-packed-member.
+ */
+ size_minus_payload = sizeof(MultiFDSendData) - sizeof(MultiFDPayload);
- return 0;
+ return g_malloc0(size_minus_payload + max_payload_size);
}
-/**
- * nocomp_recv_setup: setup receive side
- *
- * For no compression this function does nothing.
- *
- * Returns 0 for success or -1 for error
- *
- * @p: Params for the channel that we are using
- * @errp: pointer to an error
- */
-static int nocomp_recv_setup(MultiFDRecvParams *p, Error **errp)
-{
- p->iov = g_new0(struct iovec, p->page_count);
- return 0;
-}
-
-/**
- * nocomp_recv_cleanup: setup receive side
- *
- * For no compression this function does nothing.
- *
- * @p: Params for the channel that we are using
- */
-static void nocomp_recv_cleanup(MultiFDRecvParams *p)
+static bool multifd_use_packets(void)
{
- g_free(p->iov);
- p->iov = NULL;
+ return !migrate_mapped_ram();
}
-/**
- * nocomp_recv: read the data from the channel
- *
- * For no compression we just need to read things into the correct place.
- *
- * Returns 0 for success or -1 for error
- *
- * @p: Params for the channel that we are using
- * @errp: pointer to an error
- */
-static int nocomp_recv(MultiFDRecvParams *p, Error **errp)
+void multifd_send_channel_created(void)
{
- uint32_t flags;
-
- if (!multifd_use_packets()) {
- return multifd_file_recv_data(p, errp);
- }
-
- flags = p->flags & MULTIFD_FLAG_COMPRESSION_MASK;
-
- if (flags != MULTIFD_FLAG_NOCOMP) {
- error_setg(errp, "multifd %u: flags received %x flags expected %x",
- p->id, flags, MULTIFD_FLAG_NOCOMP);
- return -1;
- }
-
- multifd_recv_zero_page_process(p);
-
- if (!p->normal_num) {
- return 0;
- }
-
- for (int i = 0; i < p->normal_num; i++) {
- p->iov[i].iov_base = p->host + p->normal[i];
- p->iov[i].iov_len = p->page_size;
- ramblock_recv_bitmap_set_offset(p->block, p->normal[i]);
- }
- return qio_channel_readv_all(p->c, p->iov, p->normal_num, errp);
+ qemu_sem_post(&multifd_send_state->channels_created);
}
-static MultiFDMethods multifd_nocomp_ops = {
- .send_setup = nocomp_send_setup,
- .send_cleanup = nocomp_send_cleanup,
- .send_prepare = nocomp_send_prepare,
- .recv_setup = nocomp_recv_setup,
- .recv_cleanup = nocomp_recv_cleanup,
- .recv = nocomp_recv
-};
+static const MultiFDMethods *multifd_ops[MULTIFD_COMPRESSION__MAX] = {};
-static MultiFDMethods *multifd_ops[MULTIFD_COMPRESSION__MAX] = {
- [MULTIFD_COMPRESSION_NONE] = &multifd_nocomp_ops,
-};
-
-void multifd_register_ops(int method, MultiFDMethods *ops)
+void multifd_register_ops(int method, const MultiFDMethods *ops)
{
- assert(0 < method && method < MULTIFD_COMPRESSION__MAX);
+ assert(0 <= method && method < MULTIFD_COMPRESSION__MAX);
+ assert(!multifd_ops[method]);
multifd_ops[method] = ops;
}
-/* Reset a MultiFDPages_t* object for the next use */
-static void multifd_pages_reset(MultiFDPages_t *pages)
-{
- /*
- * We don't need to touch offset[] array, because it will be
- * overwritten later when reused.
- */
- pages->num = 0;
- pages->normal_num = 0;
- pages->block = NULL;
-}
-
static int multifd_send_initial_packet(MultiFDSendParams *p, Error **errp)
{
MultiFDInit_t msg = {};
@@ -389,160 +201,65 @@ static int multifd_recv_initial_packet(QIOChannel *c, Error **errp)
return msg.id;
}
-static MultiFDPages_t *multifd_pages_init(uint32_t n)
-{
- MultiFDPages_t *pages = g_new0(MultiFDPages_t, 1);
-
- pages->allocated = n;
- pages->offset = g_new0(ram_addr_t, n);
-
- return pages;
-}
-
-static void multifd_pages_clear(MultiFDPages_t *pages)
-{
- multifd_pages_reset(pages);
- pages->allocated = 0;
- g_free(pages->offset);
- pages->offset = NULL;
- g_free(pages);
-}
-
void multifd_send_fill_packet(MultiFDSendParams *p)
{
MultiFDPacket_t *packet = p->packet;
- MultiFDPages_t *pages = p->pages;
uint64_t packet_num;
- uint32_t zero_num = pages->num - pages->normal_num;
- int i;
+ bool sync_packet = p->flags & MULTIFD_FLAG_SYNC;
+
+ memset(packet, 0, p->packet_len);
+
+ packet->magic = cpu_to_be32(MULTIFD_MAGIC);
+ packet->version = cpu_to_be32(MULTIFD_VERSION);
packet->flags = cpu_to_be32(p->flags);
- packet->pages_alloc = cpu_to_be32(p->pages->allocated);
- packet->normal_pages = cpu_to_be32(pages->normal_num);
- packet->zero_pages = cpu_to_be32(zero_num);
packet->next_packet_size = cpu_to_be32(p->next_packet_size);
packet_num = qatomic_fetch_inc(&multifd_send_state->packet_num);
packet->packet_num = cpu_to_be64(packet_num);
- if (pages->block) {
- strncpy(packet->ramblock, pages->block->idstr, 256);
- }
-
- for (i = 0; i < pages->num; i++) {
- /* there are architectures where ram_addr_t is 32 bit */
- uint64_t temp = pages->offset[i];
+ p->packets_sent++;
- packet->offset[i] = cpu_to_be64(temp);
+ if (!sync_packet) {
+ multifd_ram_fill_packet(p);
}
- p->packets_sent++;
- p->total_normal_pages += pages->normal_num;
- p->total_zero_pages += zero_num;
-
- trace_multifd_send(p->id, packet_num, pages->normal_num, zero_num,
- p->flags, p->next_packet_size);
+ trace_multifd_send_fill(p->id, packet_num,
+ p->flags, p->next_packet_size);
}
static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp)
{
- MultiFDPacket_t *packet = p->packet;
- int i;
+ const MultiFDPacket_t *packet = p->packet;
+ uint32_t magic = be32_to_cpu(packet->magic);
+ uint32_t version = be32_to_cpu(packet->version);
+ int ret = 0;
- packet->magic = be32_to_cpu(packet->magic);
- if (packet->magic != MULTIFD_MAGIC) {
- error_setg(errp, "multifd: received packet "
- "magic %x and expected magic %x",
- packet->magic, MULTIFD_MAGIC);
+ if (magic != MULTIFD_MAGIC) {
+ error_setg(errp, "multifd: received packet magic %x, expected %x",
+ magic, MULTIFD_MAGIC);
return -1;
}
- packet->version = be32_to_cpu(packet->version);
- if (packet->version != MULTIFD_VERSION) {
- error_setg(errp, "multifd: received packet "
- "version %u and expected version %u",
- packet->version, MULTIFD_VERSION);
+ if (version != MULTIFD_VERSION) {
+ error_setg(errp, "multifd: received packet version %u, expected %u",
+ version, MULTIFD_VERSION);
return -1;
}
p->flags = be32_to_cpu(packet->flags);
-
- packet->pages_alloc = be32_to_cpu(packet->pages_alloc);
- /*
- * If we received a packet that is 100 times bigger than expected
- * just stop migration. It is a magic number.
- */
- if (packet->pages_alloc > p->page_count) {
- error_setg(errp, "multifd: received packet "
- "with size %u and expected a size of %u",
- packet->pages_alloc, p->page_count) ;
- return -1;
- }
-
- p->normal_num = be32_to_cpu(packet->normal_pages);
- if (p->normal_num > packet->pages_alloc) {
- error_setg(errp, "multifd: received packet "
- "with %u normal pages and expected maximum pages are %u",
- p->normal_num, packet->pages_alloc) ;
- return -1;
- }
-
- p->zero_num = be32_to_cpu(packet->zero_pages);
- if (p->zero_num > packet->pages_alloc - p->normal_num) {
- error_setg(errp, "multifd: received packet "
- "with %u zero pages and expected maximum zero pages are %u",
- p->zero_num, packet->pages_alloc - p->normal_num) ;
- return -1;
- }
-
p->next_packet_size = be32_to_cpu(packet->next_packet_size);
p->packet_num = be64_to_cpu(packet->packet_num);
p->packets_recved++;
- p->total_normal_pages += p->normal_num;
- p->total_zero_pages += p->zero_num;
-
- trace_multifd_recv(p->id, p->packet_num, p->normal_num, p->zero_num,
- p->flags, p->next_packet_size);
-
- if (p->normal_num == 0 && p->zero_num == 0) {
- return 0;
- }
-
- /* make sure that ramblock is 0 terminated */
- packet->ramblock[255] = 0;
- p->block = qemu_ram_block_by_name(packet->ramblock);
- if (!p->block) {
- error_setg(errp, "multifd: unknown ram block %s",
- packet->ramblock);
- return -1;
- }
-
- p->host = p->block->host;
- for (i = 0; i < p->normal_num; i++) {
- uint64_t offset = be64_to_cpu(packet->offset[i]);
- if (offset > (p->block->used_length - p->page_size)) {
- error_setg(errp, "multifd: offset too long %" PRIu64
- " (max " RAM_ADDR_FMT ")",
- offset, p->block->used_length);
- return -1;
- }
- p->normal[i] = offset;
+ if (!(p->flags & MULTIFD_FLAG_SYNC)) {
+ ret = multifd_ram_unfill_packet(p, errp);
}
- for (i = 0; i < p->zero_num; i++) {
- uint64_t offset = be64_to_cpu(packet->offset[p->normal_num + i]);
+ trace_multifd_recv_unfill(p->id, p->packet_num, p->flags,
+ p->next_packet_size);
- if (offset > (p->block->used_length - p->page_size)) {
- error_setg(errp, "multifd: offset too long %" PRIu64
- " (max " RAM_ADDR_FMT ")",
- offset, p->block->used_length);
- return -1;
- }
- p->zero[i] = offset;
- }
-
- return 0;
+ return ret;
}
static bool multifd_send_should_exit(void)
@@ -568,30 +285,25 @@ static void multifd_send_kick_main(MultiFDSendParams *p)
}
/*
- * How we use multifd_send_state->pages and channel->pages?
+ * multifd_send() works by exchanging the MultiFDSendData object
+ * provided by the caller with an unused MultiFDSendData object from
+ * the next channel that is found to be idle.
*
- * We create a pages for each channel, and a main one. Each time that
- * we need to send a batch of pages we interchange the ones between
- * multifd_send_state and the channel that is sending it. There are
- * two reasons for that:
- * - to not have to do so many mallocs during migration
- * - to make easier to know what to free at the end of migration
+ * The channel owns the data until it finishes transmitting and the
+ * caller owns the empty object until it fills it with data and calls
+ * this function again. No locking necessary.
*
- * This way we always know who is the owner of each "pages" struct,
- * and we don't need any locking. It belongs to the migration thread
- * or to the channel thread. Switching is safe because the migration
- * thread is using the channel mutex when changing it, and the channel
- * have to had finish with its own, otherwise pending_job can't be
- * false.
+ * Switching is safe because both the migration thread and the channel
+ * thread have barriers in place to serialize access.
*
* Returns true if succeed, false otherwise.
*/
-static bool multifd_send_pages(void)
+bool multifd_send(MultiFDSendData **send_data)
{
int i;
static int next_channel;
MultiFDSendParams *p = NULL; /* make happy gcc */
- MultiFDPages_t *pages = multifd_send_state->pages;
+ MultiFDSendData *tmp;
if (multifd_send_should_exit()) {
return false;
@@ -626,66 +338,24 @@ static bool multifd_send_pages(void)
* qatomic_store_release() in multifd_send_thread().
*/
smp_mb_acquire();
- assert(!p->pages->num);
- multifd_send_state->pages = p->pages;
- p->pages = pages;
- /*
- * Making sure p->pages is setup before marking pending_job=true. Pairs
- * with the qatomic_load_acquire() in multifd_send_thread().
- */
- qatomic_store_release(&p->pending_job, true);
- qemu_sem_post(&p->sem);
-
- return true;
-}
-static inline bool multifd_queue_empty(MultiFDPages_t *pages)
-{
- return pages->num == 0;
-}
+ assert(multifd_payload_empty(p->data));
-static inline bool multifd_queue_full(MultiFDPages_t *pages)
-{
- return pages->num == pages->allocated;
-}
-
-static inline void multifd_enqueue(MultiFDPages_t *pages, ram_addr_t offset)
-{
- pages->offset[pages->num++] = offset;
-}
-
-/* Returns true if enqueue successful, false otherwise */
-bool multifd_queue_page(RAMBlock *block, ram_addr_t offset)
-{
- MultiFDPages_t *pages;
-
-retry:
- pages = multifd_send_state->pages;
-
- /* If the queue is empty, we can already enqueue now */
- if (multifd_queue_empty(pages)) {
- pages->block = block;
- multifd_enqueue(pages, offset);
- return true;
- }
+ /*
+ * Swap the pointers. The channel gets the client data for
+ * transferring and the client gets back an unused data slot.
+ */
+ tmp = *send_data;
+ *send_data = p->data;
+ p->data = tmp;
/*
- * Not empty, meanwhile we need a flush. It can because of either:
- *
- * (1) The page is not on the same ramblock of previous ones, or,
- * (2) The queue is full.
- *
- * After flush, always retry.
+ * Making sure p->data is setup before marking pending_job=true. Pairs
+ * with the qatomic_load_acquire() in multifd_send_thread().
*/
- if (pages->block != block || multifd_queue_full(pages)) {
- if (!multifd_send_pages()) {
- return false;
- }
- goto retry;
- }
+ qatomic_store_release(&p->pending_job, true);
+ qemu_sem_post(&p->sem);
- /* Not empty, and we still have space, do it! */
- multifd_enqueue(pages, offset);
return true;
}
@@ -790,12 +460,13 @@ static bool multifd_send_cleanup_channel(MultiFDSendParams *p, Error **errp)
qemu_sem_destroy(&p->sem_sync);
g_free(p->name);
p->name = NULL;
- multifd_pages_clear(p->pages);
- p->pages = NULL;
+ g_free(p->data);
+ p->data = NULL;
p->packet_len = 0;
g_free(p->packet);
p->packet = NULL;
multifd_send_state->ops->send_cleanup(p, errp);
+ assert(!p->iov);
return *errp == NULL;
}
@@ -808,8 +479,6 @@ static void multifd_send_cleanup_state(void)
qemu_sem_destroy(&multifd_send_state->channels_ready);
g_free(multifd_send_state->params);
multifd_send_state->params = NULL;
- multifd_pages_clear(multifd_send_state->pages);
- multifd_send_state->pages = NULL;
g_free(multifd_send_state);
multifd_send_state = NULL;
}
@@ -859,16 +528,6 @@ int multifd_send_sync_main(void)
int i;
bool flush_zero_copy;
- if (!migrate_multifd()) {
- return 0;
- }
- if (multifd_send_state->pages->num) {
- if (!multifd_send_pages()) {
- error_report("%s: multifd_send_pages fail", __func__);
- return -1;
- }
- }
-
flush_zero_copy = migrate_zero_copy_send();
for (i = 0; i < migrate_multifd_channels(); i++) {
@@ -937,14 +596,12 @@ static void *multifd_send_thread(void *opaque)
}
/*
- * Read pending_job flag before p->pages. Pairs with the
- * qatomic_store_release() in multifd_send_pages().
+ * Read pending_job flag before p->data. Pairs with the
+ * qatomic_store_release() in multifd_send().
*/
if (qatomic_load_acquire(&p->pending_job)) {
- MultiFDPages_t *pages = p->pages;
-
p->iovs_num = 0;
- assert(pages->num);
+ assert(!multifd_payload_empty(p->data));
ret = multifd_send_state->ops->send_prepare(p, &local_err);
if (ret != 0) {
@@ -953,7 +610,7 @@ static void *multifd_send_thread(void *opaque)
if (migrate_mapped_ram()) {
ret = file_write_ramblock_iov(p->c, p->iov, p->iovs_num,
- p->pages->block, &local_err);
+ &p->data->u.ram, &local_err);
} else {
ret = qio_channel_writev_full_all(p->c, p->iov, p->iovs_num,
NULL, 0, p->write_flags,
@@ -966,16 +623,14 @@ static void *multifd_send_thread(void *opaque)
stat64_add(&mig_stats.multifd_bytes,
p->next_packet_size + p->packet_len);
- stat64_add(&mig_stats.normal_pages, pages->normal_num);
- stat64_add(&mig_stats.zero_pages, pages->num - pages->normal_num);
- multifd_pages_reset(p->pages);
p->next_packet_size = 0;
+ multifd_set_payload_type(p->data, MULTIFD_PAYLOAD_NONE);
/*
- * Making sure p->pages is published before saying "we're
+ * Making sure p->data is published before saying "we're
* free". Pairs with the smp_mb_acquire() in
- * multifd_send_pages().
+ * multifd_send().
*/
qatomic_store_release(&p->pending_job, false);
} else {
@@ -1015,8 +670,7 @@ out:
rcu_unregister_thread();
migration_threads_remove(thread);
- trace_multifd_send_thread_end(p->id, p->packets_sent, p->total_normal_pages,
- p->total_zero_pages);
+ trace_multifd_send_thread_end(p->id, p->packets_sent);
return NULL;
}
@@ -1156,9 +810,8 @@ static bool multifd_new_send_channel_create(gpointer opaque, Error **errp)
bool multifd_send_setup(void)
{
MigrationState *s = migrate_get_current();
- Error *local_err = NULL;
int thread_count, ret = 0;
- uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size();
+ uint32_t page_count = multifd_ram_page_count();
bool use_packets = multifd_use_packets();
uint8_t i;
@@ -1169,7 +822,6 @@ bool multifd_send_setup(void)
thread_count = migrate_multifd_channels();
multifd_send_state = g_malloc0(sizeof(*multifd_send_state));
multifd_send_state->params = g_new0(MultiFDSendParams, thread_count);
- multifd_send_state->pages = multifd_pages_init(page_count);
qemu_sem_init(&multifd_send_state->channels_created, 0);
qemu_sem_init(&multifd_send_state->channels_ready, 0);
qatomic_set(&multifd_send_state->exiting, 0);
@@ -1177,26 +829,24 @@ bool multifd_send_setup(void)
for (i = 0; i < thread_count; i++) {
MultiFDSendParams *p = &multifd_send_state->params[i];
+ Error *local_err = NULL;
qemu_sem_init(&p->sem, 0);
qemu_sem_init(&p->sem_sync, 0);
p->id = i;
- p->pages = multifd_pages_init(page_count);
+ p->data = multifd_send_data_alloc();
if (use_packets) {
p->packet_len = sizeof(MultiFDPacket_t)
+ sizeof(uint64_t) * page_count;
p->packet = g_malloc0(p->packet_len);
- p->packet->magic = cpu_to_be32(MULTIFD_MAGIC);
- p->packet->version = cpu_to_be32(MULTIFD_VERSION);
}
p->name = g_strdup_printf("mig/src/send_%d", i);
- p->page_size = qemu_target_page_size();
- p->page_count = page_count;
p->write_flags = 0;
if (!multifd_new_send_channel_create(p, &local_err)) {
- return false;
+ migrate_set_error(s, local_err);
+ ret = -1;
}
}
@@ -1209,24 +859,28 @@ bool multifd_send_setup(void)
qemu_sem_wait(&multifd_send_state->channels_created);
}
+ if (ret) {
+ goto err;
+ }
+
for (i = 0; i < thread_count; i++) {
MultiFDSendParams *p = &multifd_send_state->params[i];
+ Error *local_err = NULL;
ret = multifd_send_state->ops->send_setup(p, &local_err);
if (ret) {
- break;
+ migrate_set_error(s, local_err);
+ goto err;
}
- }
-
- if (ret) {
- migrate_set_error(s, local_err);
- error_report_err(local_err);
- migrate_set_state(&s->state, MIGRATION_STATUS_SETUP,
- MIGRATION_STATUS_FAILED);
- return false;
+ assert(p->iov);
}
return true;
+
+err:
+ migrate_set_state(&s->state, MIGRATION_STATUS_SETUP,
+ MIGRATION_STATUS_FAILED);
+ return false;
}
bool multifd_recv(void)
@@ -1353,6 +1007,8 @@ static void multifd_recv_cleanup_channel(MultiFDRecvParams *p)
qemu_mutex_destroy(&p->mutex);
qemu_sem_destroy(&p->sem_sync);
qemu_sem_destroy(&p->sem);
+ g_free(p->data);
+ p->data = NULL;
g_free(p->name);
p->name = NULL;
p->packet_len = 0;
@@ -1495,7 +1151,9 @@ static void *multifd_recv_thread(void *opaque)
flags = p->flags;
/* recv methods don't know how to handle the SYNC flag */
p->flags &= ~MULTIFD_FLAG_SYNC;
- has_data = p->normal_num || p->zero_num;
+ if (!(flags & MULTIFD_FLAG_SYNC)) {
+ has_data = p->normal_num || p->zero_num;
+ }
qemu_mutex_unlock(&p->mutex);
} else {
/*
@@ -1536,7 +1194,6 @@ static void *multifd_recv_thread(void *opaque)
qemu_sem_wait(&p->sem_sync);
}
} else {
- p->total_normal_pages += p->data->size / qemu_target_page_size();
p->data->size = 0;
/*
* Order data->size update before clearing
@@ -1553,9 +1210,7 @@ static void *multifd_recv_thread(void *opaque)
}
rcu_unregister_thread();
- trace_multifd_recv_thread_end(p->id, p->packets_recved,
- p->total_normal_pages,
- p->total_zero_pages);
+ trace_multifd_recv_thread_end(p->id, p->packets_recved);
return NULL;
}
@@ -1563,7 +1218,7 @@ static void *multifd_recv_thread(void *opaque)
int multifd_recv_setup(Error **errp)
{
int thread_count;
- uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size();
+ uint32_t page_count = multifd_ram_page_count();
bool use_packets = multifd_use_packets();
uint8_t i;
@@ -1607,8 +1262,6 @@ int multifd_recv_setup(Error **errp)
p->name = g_strdup_printf("mig/dst/recv_%d", i);
p->normal = g_new0(ram_addr_t, page_count);
p->zero = g_new0(ram_addr_t, page_count);
- p->page_count = page_count;
- p->page_size = qemu_target_page_size();
}
for (i = 0; i < thread_count; i++) {
@@ -1681,17 +1334,3 @@ void multifd_recv_new_channel(QIOChannel *ioc, Error **errp)
QEMU_THREAD_JOINABLE);
qatomic_inc(&multifd_recv_state->count);
}
-
-bool multifd_send_prepare_common(MultiFDSendParams *p)
-{
- multifd_send_zero_page_detect(p);
-
- if (!p->pages->normal_num) {
- p->next_packet_size = 0;
- return false;
- }
-
- multifd_send_prepare_header(p);
-
- return true;
-}
diff --git a/migration/multifd.h b/migration/multifd.h
index 0ecd6f4..50d58c0 100644
--- a/migration/multifd.h
+++ b/migration/multifd.h
@@ -13,9 +13,11 @@
#ifndef QEMU_MIGRATION_MULTIFD_H
#define QEMU_MIGRATION_MULTIFD_H
+#include "exec/target_page.h"
#include "ram.h"
typedef struct MultiFDRecvData MultiFDRecvData;
+typedef struct MultiFDSendData MultiFDSendData;
bool multifd_send_setup(void);
void multifd_send_shutdown(void);
@@ -34,14 +36,15 @@ MultiFDRecvData *multifd_get_recv_data(void);
/* Multifd Compression flags */
#define MULTIFD_FLAG_SYNC (1 << 0)
-/* We reserve 4 bits for compression methods */
-#define MULTIFD_FLAG_COMPRESSION_MASK (0xf << 1)
+/* We reserve 5 bits for compression methods */
+#define MULTIFD_FLAG_COMPRESSION_MASK (0x1f << 1)
/* we need to be compatible. Before compression value was 0 */
#define MULTIFD_FLAG_NOCOMP (0 << 1)
#define MULTIFD_FLAG_ZLIB (1 << 1)
#define MULTIFD_FLAG_ZSTD (2 << 1)
#define MULTIFD_FLAG_QPL (4 << 1)
#define MULTIFD_FLAG_UADK (8 << 1)
+#define MULTIFD_FLAG_QATZIP (16 << 1)
/* This value needs to be a multiple of qemu_target_page_size() */
#define MULTIFD_PACKET_SIZE (512 * 1024)
@@ -75,11 +78,9 @@ typedef struct {
uint32_t num;
/* number of normal pages */
uint32_t normal_num;
- /* number of allocated pages */
- uint32_t allocated;
- /* offset of each page */
- ram_addr_t *offset;
RAMBlock *block;
+ /* offset of each page */
+ ram_addr_t offset[];
} MultiFDPages_t;
struct MultiFDRecvData {
@@ -89,6 +90,31 @@ struct MultiFDRecvData {
off_t file_offset;
};
+typedef enum {
+ MULTIFD_PAYLOAD_NONE,
+ MULTIFD_PAYLOAD_RAM,
+} MultiFDPayloadType;
+
+typedef union MultiFDPayload {
+ MultiFDPages_t ram;
+} MultiFDPayload;
+
+struct MultiFDSendData {
+ MultiFDPayloadType type;
+ MultiFDPayload u;
+};
+
+static inline bool multifd_payload_empty(MultiFDSendData *data)
+{
+ return data->type == MULTIFD_PAYLOAD_NONE;
+}
+
+static inline void multifd_set_payload_type(MultiFDSendData *data,
+ MultiFDPayloadType type)
+{
+ data->type = type;
+}
+
typedef struct {
/* Fields are only written at creating/deletion time */
/* No lock required for them, they are read only */
@@ -106,10 +132,6 @@ typedef struct {
QIOChannel *c;
/* packet allocated len */
uint32_t packet_len;
- /* guest page size */
- uint32_t page_size;
- /* number of pages in a full packet */
- uint32_t page_count;
/* multifd flags for sending ram */
int write_flags;
@@ -131,12 +153,7 @@ typedef struct {
*/
bool pending_job;
bool pending_sync;
- /* array of pages to sent.
- * The owner of 'pages' depends of 'pending_job' value:
- * pending_job == 0 -> migration_thread can use it.
- * pending_job != 0 -> multifd_channel can use it.
- */
- MultiFDPages_t *pages;
+ MultiFDSendData *data;
/* thread local variables. No locking required */
@@ -146,10 +163,6 @@ typedef struct {
uint32_t next_packet_size;
/* packets sent through this channel */
uint64_t packets_sent;
- /* non zero pages sent through this channel */
- uint64_t total_normal_pages;
- /* zero pages sent through this channel */
- uint64_t total_zero_pages;
/* buffers to send */
struct iovec *iov;
/* number of iovs used */
@@ -173,10 +186,6 @@ typedef struct {
QIOChannel *c;
/* packet allocated len */
uint32_t packet_len;
- /* guest page size */
- uint32_t page_size;
- /* number of pages in a full packet */
- uint32_t page_count;
/* syncs main thread and channels */
QemuSemaphore sem_sync;
@@ -206,10 +215,6 @@ typedef struct {
RAMBlock *block;
/* ramblock host address */
uint8_t *host;
- /* non zero pages recv through this channel */
- uint64_t total_normal_pages;
- /* zero pages recv through this channel */
- uint64_t total_zero_pages;
/* buffers to recv */
struct iovec *iov;
/* Pages that are not zero */
@@ -225,21 +230,85 @@ typedef struct {
} MultiFDRecvParams;
typedef struct {
- /* Setup for sending side */
+ /*
+ * The send_setup, send_cleanup, send_prepare are only called on
+ * the QEMU instance at the migration source.
+ */
+
+ /*
+ * Setup for sending side. Called once per channel during channel
+ * setup phase.
+ *
+ * Must allocate p->iov. If packets are in use (default), one
+ * extra iovec must be allocated for the packet header. Any memory
+ * allocated in this hook must be released at send_cleanup.
+ *
+ * p->write_flags may be used for passing flags to the QIOChannel.
+ *
+ * p->compression_data may be used by compression methods to store
+ * compression data.
+ */
int (*send_setup)(MultiFDSendParams *p, Error **errp);
- /* Cleanup for sending side */
+
+ /*
+ * Cleanup for sending side. Called once per channel during
+ * channel cleanup phase.
+ */
void (*send_cleanup)(MultiFDSendParams *p, Error **errp);
- /* Prepare the send packet */
+
+ /*
+ * Prepare the send packet. Called as a result of multifd_send()
+ * on the client side, with p pointing to the MultiFDSendParams of
+ * a channel that is currently idle.
+ *
+ * Must populate p->iov with the data to be sent, increment
+ * p->iovs_num to match the amount of iovecs used and set
+ * p->next_packet_size with the amount of data currently present
+ * in p->iov.
+ *
+ * Must indicate whether this is a compression packet by setting
+ * p->flags.
+ *
+ * As a last step, if packets are in use (default), must prepare
+ * the packet by calling multifd_send_fill_packet().
+ */
int (*send_prepare)(MultiFDSendParams *p, Error **errp);
- /* Setup for receiving side */
+
+ /*
+ * The recv_setup, recv_cleanup, recv are only called on the QEMU
+ * instance at the migration destination.
+ */
+
+ /*
+ * Setup for receiving side. Called once per channel during
+ * channel setup phase. May be empty.
+ *
+ * May allocate data structures for the receiving of data. May use
+ * p->iov. Compression methods may use p->compress_data.
+ */
int (*recv_setup)(MultiFDRecvParams *p, Error **errp);
- /* Cleanup for receiving side */
+
+ /*
+ * Cleanup for receiving side. Called once per channel during
+ * channel cleanup phase. May be empty.
+ */
void (*recv_cleanup)(MultiFDRecvParams *p);
- /* Read all data */
+
+ /*
+ * Data receive method. Called as a result of multifd_recv() on
+ * the client side, with p pointing to the MultiFDRecvParams of a
+ * channel that is currently idle. Only called if there is data
+ * available to receive.
+ *
+ * Must validate p->flags according to what was set at
+ * send_prepare.
+ *
+ * Must read the data from the QIOChannel p->c.
+ */
int (*recv)(MultiFDRecvParams *p, Error **errp);
} MultiFDMethods;
-void multifd_register_ops(int method, MultiFDMethods *ops);
+void multifd_register_ops(int method, const MultiFDMethods *ops);
void multifd_send_fill_packet(MultiFDSendParams *p);
bool multifd_send_prepare_common(MultiFDSendParams *p);
void multifd_send_zero_page_detect(MultiFDSendParams *p);
@@ -253,5 +322,23 @@ static inline void multifd_send_prepare_header(MultiFDSendParams *p)
}
void multifd_channel_connect(MultiFDSendParams *p, QIOChannel *ioc);
+bool multifd_send(MultiFDSendData **send_data);
+MultiFDSendData *multifd_send_data_alloc(void);
+
+static inline uint32_t multifd_ram_page_size(void)
+{
+ return qemu_target_page_size();
+}
+
+static inline uint32_t multifd_ram_page_count(void)
+{
+ return MULTIFD_PACKET_SIZE / qemu_target_page_size();
+}
+void multifd_ram_save_setup(void);
+void multifd_ram_save_cleanup(void);
+int multifd_ram_flush_and_sync(void);
+size_t multifd_ram_payload_size(void);
+void multifd_ram_fill_packet(MultiFDSendParams *p);
+int multifd_ram_unfill_packet(MultiFDRecvParams *p, Error **errp);
#endif
diff --git a/migration/options.c b/migration/options.c
index 645f550..ad8d698 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -55,6 +55,13 @@
#define DEFAULT_MIGRATE_MULTIFD_COMPRESSION MULTIFD_COMPRESSION_NONE
/* 0: means nocompress, 1: best speed, ... 9: best compress ratio */
#define DEFAULT_MIGRATE_MULTIFD_ZLIB_LEVEL 1
+/*
+ * 1: best speed, ... 9: best compress ratio
+ * There is some nuance here. Refer to QATzip documentation to understand
+ * the mapping of QATzip levels to standard deflate levels.
+ */
+#define DEFAULT_MIGRATE_MULTIFD_QATZIP_LEVEL 1
+
/* 0: means nocompress, 1: best speed, ... 20: best compress ratio */
#define DEFAULT_MIGRATE_MULTIFD_ZSTD_LEVEL 1
@@ -123,6 +130,9 @@ Property migration_properties[] = {
DEFINE_PROP_UINT8("multifd-zlib-level", MigrationState,
parameters.multifd_zlib_level,
DEFAULT_MIGRATE_MULTIFD_ZLIB_LEVEL),
+ DEFINE_PROP_UINT8("multifd-qatzip-level", MigrationState,
+ parameters.multifd_qatzip_level,
+ DEFAULT_MIGRATE_MULTIFD_QATZIP_LEVEL),
DEFINE_PROP_UINT8("multifd-zstd-level", MigrationState,
parameters.multifd_zstd_level,
DEFAULT_MIGRATE_MULTIFD_ZSTD_LEVEL),
@@ -329,13 +339,6 @@ bool migrate_xbzrle(void)
return s->capabilities[MIGRATION_CAPABILITY_XBZRLE];
}
-bool migrate_zero_blocks(void)
-{
- MigrationState *s = migrate_get_current();
-
- return s->capabilities[MIGRATION_CAPABILITY_ZERO_BLOCKS];
-}
-
bool migrate_zero_copy_send(void)
{
MigrationState *s = migrate_get_current();
@@ -447,6 +450,10 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
ERRP_GUARD();
MigrationIncomingState *mis = migration_incoming_get_current();
+ if (new_caps[MIGRATION_CAPABILITY_ZERO_BLOCKS]) {
+ warn_report("zero-blocks capability is deprecated");
+ }
+
#ifndef CONFIG_REPLICATION
if (new_caps[MIGRATION_CAPABILITY_X_COLO]) {
error_setg(errp, "QEMU compiled without replication module"
@@ -595,26 +602,6 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
return true;
}
-bool migrate_cap_set(int cap, bool value, Error **errp)
-{
- MigrationState *s = migrate_get_current();
- bool new_caps[MIGRATION_CAPABILITY__MAX];
-
- if (migration_is_running()) {
- error_setg(errp, "There's a migration process in progress");
- return false;
- }
-
- memcpy(new_caps, s->capabilities, sizeof(new_caps));
- new_caps[cap] = value;
-
- if (!migrate_caps_check(s->capabilities, new_caps, errp)) {
- return false;
- }
- s->capabilities[cap] = value;
- return true;
-}
-
MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp)
{
MigrationCapabilityStatusList *head = NULL, **tail = &head;
@@ -787,6 +774,13 @@ int migrate_multifd_zlib_level(void)
return s->parameters.multifd_zlib_level;
}
+int migrate_multifd_qatzip_level(void)
+{
+ MigrationState *s = migrate_get_current();
+
+ return s->parameters.multifd_qatzip_level;
+}
+
int migrate_multifd_zstd_level(void)
{
MigrationState *s = migrate_get_current();
@@ -892,6 +886,8 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
params->multifd_compression = s->parameters.multifd_compression;
params->has_multifd_zlib_level = true;
params->multifd_zlib_level = s->parameters.multifd_zlib_level;
+ params->has_multifd_qatzip_level = true;
+ params->multifd_qatzip_level = s->parameters.multifd_qatzip_level;
params->has_multifd_zstd_level = true;
params->multifd_zstd_level = s->parameters.multifd_zstd_level;
params->has_xbzrle_cache_size = true;
@@ -946,6 +942,7 @@ void migrate_params_init(MigrationParameters *params)
params->has_multifd_channels = true;
params->has_multifd_compression = true;
params->has_multifd_zlib_level = true;
+ params->has_multifd_qatzip_level = true;
params->has_multifd_zstd_level = true;
params->has_xbzrle_cache_size = true;
params->has_max_postcopy_bandwidth = true;
@@ -1038,6 +1035,14 @@ bool migrate_params_check(MigrationParameters *params, Error **errp)
return false;
}
+ if (params->has_multifd_qatzip_level &&
+ ((params->multifd_qatzip_level > 9) ||
+ (params->multifd_qatzip_level < 1))) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_qatzip_level",
+ "a value between 1 and 9");
+ return false;
+ }
+
if (params->has_multifd_zstd_level &&
(params->multifd_zstd_level > 20)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_zstd_level",
@@ -1195,6 +1200,9 @@ static void migrate_params_test_apply(MigrateSetParameters *params,
if (params->has_multifd_compression) {
dest->multifd_compression = params->multifd_compression;
}
+ if (params->has_multifd_qatzip_level) {
+ dest->multifd_qatzip_level = params->multifd_qatzip_level;
+ }
if (params->has_multifd_zlib_level) {
dest->multifd_zlib_level = params->multifd_zlib_level;
}
@@ -1315,6 +1323,9 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
if (params->has_multifd_compression) {
s->parameters.multifd_compression = params->multifd_compression;
}
+ if (params->has_multifd_qatzip_level) {
+ s->parameters.multifd_qatzip_level = params->multifd_qatzip_level;
+ }
if (params->has_multifd_zlib_level) {
s->parameters.multifd_zlib_level = params->multifd_zlib_level;
}
diff --git a/migration/options.h b/migration/options.h
index a239702..79084ee 100644
--- a/migration/options.h
+++ b/migration/options.h
@@ -40,7 +40,6 @@ bool migrate_release_ram(void);
bool migrate_return_path(void);
bool migrate_validate_uuid(void);
bool migrate_xbzrle(void);
-bool migrate_zero_blocks(void);
bool migrate_zero_copy_send(void);
/*
@@ -58,7 +57,6 @@ bool migrate_tls(void);
/* capabilities helpers */
bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp);
-bool migrate_cap_set(int cap, bool value, Error **errp);
/* parameters */
@@ -78,6 +76,7 @@ uint64_t migrate_max_postcopy_bandwidth(void);
int migrate_multifd_channels(void);
MultiFDCompression migrate_multifd_compression(void);
int migrate_multifd_zlib_level(void);
+int migrate_multifd_qatzip_level(void);
int migrate_multifd_zstd_level(void);
uint8_t migrate_throttle_trigger_threshold(void);
const char *migrate_tls_authz(void);
diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c
index 1c374b7..83f6160 100644
--- a/migration/postcopy-ram.c
+++ b/migration/postcopy-ram.c
@@ -746,18 +746,10 @@ int postcopy_wake_shared(struct PostCopyFD *pcfd,
RAMBlock *rb)
{
size_t pagesize = qemu_ram_pagesize(rb);
- struct uffdio_range range;
- int ret;
trace_postcopy_wake_shared(client_addr, qemu_ram_get_idstr(rb));
- range.start = ROUND_DOWN(client_addr, pagesize);
- range.len = pagesize;
- ret = ioctl(pcfd->fd, UFFDIO_WAKE, &range);
- if (ret) {
- error_report("%s: Failed to wake: %zx in %s (%s)",
- __func__, (size_t)client_addr, qemu_ram_get_idstr(rb),
- strerror(errno));
- }
- return ret;
+ return uffd_wakeup(pcfd->fd,
+ (void *)(uintptr_t)ROUND_DOWN(client_addr, pagesize),
+ pagesize);
}
static int postcopy_request_page(MigrationIncomingState *mis, RAMBlock *rb,
@@ -1275,18 +1267,10 @@ static int qemu_ufd_copy_ioctl(MigrationIncomingState *mis, void *host_addr,
int ret;
if (from_addr) {
- struct uffdio_copy copy_struct;
- copy_struct.dst = (uint64_t)(uintptr_t)host_addr;
- copy_struct.src = (uint64_t)(uintptr_t)from_addr;
- copy_struct.len = pagesize;
- copy_struct.mode = 0;
- ret = ioctl(userfault_fd, UFFDIO_COPY, &copy_struct);
+ ret = uffd_copy_page(userfault_fd, host_addr, from_addr, pagesize,
+ false);
} else {
- struct uffdio_zeropage zero_struct;
- zero_struct.range.start = (uint64_t)(uintptr_t)host_addr;
- zero_struct.range.len = pagesize;
- zero_struct.mode = 0;
- ret = ioctl(userfault_fd, UFFDIO_ZEROPAGE, &zero_struct);
+ ret = uffd_zero_page(userfault_fd, host_addr, pagesize, false);
}
if (!ret) {
qemu_mutex_lock(&mis->page_request_mutex);
@@ -1343,18 +1327,16 @@ int postcopy_place_page(MigrationIncomingState *mis, void *host, void *from,
RAMBlock *rb)
{
size_t pagesize = qemu_ram_pagesize(rb);
+ int e;
/* copy also acks to the kernel waking the stalled thread up
* TODO: We can inhibit that ack and only do it if it was requested
* which would be slightly cheaper, but we'd have to be careful
* of the order of updating our page state.
*/
- if (qemu_ufd_copy_ioctl(mis, host, from, pagesize, rb)) {
- int e = errno;
- error_report("%s: %s copy host: %p from: %p (size: %zd)",
- __func__, strerror(e), host, from, pagesize);
-
- return -e;
+ e = qemu_ufd_copy_ioctl(mis, host, from, pagesize, rb);
+ if (e) {
+ return e;
}
trace_postcopy_place_page(host);
@@ -1376,12 +1358,10 @@ int postcopy_place_page_zero(MigrationIncomingState *mis, void *host,
* but it's not available for everything (e.g. hugetlbpages)
*/
if (qemu_ram_is_uf_zeroable(rb)) {
- if (qemu_ufd_copy_ioctl(mis, host, NULL, pagesize, rb)) {
- int e = errno;
- error_report("%s: %s zero host: %p",
- __func__, strerror(e), host);
-
- return -e;
+ int e;
+ e = qemu_ufd_copy_ioctl(mis, host, NULL, pagesize, rb);
+ if (e) {
+ return e;
}
return postcopy_notify_shared_wake(rb,
qemu_ram_block_host_offset(rb,
@@ -1411,49 +1391,42 @@ int postcopy_ram_incoming_init(MigrationIncomingState *mis)
int postcopy_ram_incoming_cleanup(MigrationIncomingState *mis)
{
- assert(0);
- return -1;
+ g_assert_not_reached();
}
int postcopy_ram_prepare_discard(MigrationIncomingState *mis)
{
- assert(0);
- return -1;
+ g_assert_not_reached();
}
int postcopy_request_shared_page(struct PostCopyFD *pcfd, RAMBlock *rb,
uint64_t client_addr, uint64_t rb_offset)
{
- assert(0);
- return -1;
+ g_assert_not_reached();
}
int postcopy_ram_incoming_setup(MigrationIncomingState *mis)
{
- assert(0);
- return -1;
+ g_assert_not_reached();
}
int postcopy_place_page(MigrationIncomingState *mis, void *host, void *from,
RAMBlock *rb)
{
- assert(0);
- return -1;
+ g_assert_not_reached();
}
int postcopy_place_page_zero(MigrationIncomingState *mis, void *host,
RAMBlock *rb)
{
- assert(0);
- return -1;
+ g_assert_not_reached();
}
int postcopy_wake_shared(struct PostCopyFD *pcfd,
uint64_t client_addr,
RAMBlock *rb)
{
- assert(0);
- return -1;
+ g_assert_not_reached();
}
#endif
diff --git a/migration/ram.c b/migration/ram.c
index edec1a2..326ce7e 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -1326,7 +1326,7 @@ static int find_dirty_block(RAMState *rs, PageSearchStatus *pss)
(!migrate_multifd_flush_after_each_section() ||
migrate_mapped_ram())) {
QEMUFile *f = rs->pss[RAM_CHANNEL_PRECOPY].pss_channel;
- int ret = multifd_send_sync_main();
+ int ret = multifd_ram_flush_and_sync();
if (ret < 0) {
return ret;
}
@@ -1765,19 +1765,17 @@ bool ram_write_tracking_available(void)
bool ram_write_tracking_compatible(void)
{
- assert(0);
- return false;
+ g_assert_not_reached();
}
int ram_write_tracking_start(void)
{
- assert(0);
- return -1;
+ g_assert_not_reached();
}
void ram_write_tracking_stop(void)
{
- assert(0);
+ g_assert_not_reached();
}
#endif /* defined(__linux__) */
@@ -1795,7 +1793,7 @@ static bool get_queued_page(RAMState *rs, PageSearchStatus *pss)
{
RAMBlock *block;
ram_addr_t offset;
- bool dirty;
+ bool dirty = false;
do {
block = unqueue_page(rs, &offset);
@@ -2387,6 +2385,7 @@ static void ram_save_cleanup(void *opaque)
ram_bitmaps_destroy();
xbzrle_cleanup();
+ multifd_ram_save_cleanup();
ram_state_cleanup(rsp);
g_free(migration_ops);
migration_ops = NULL;
@@ -3058,13 +3057,14 @@ static int ram_save_setup(QEMUFile *f, void *opaque, Error **errp)
migration_ops = g_malloc0(sizeof(MigrationOps));
if (migrate_multifd()) {
+ multifd_ram_save_setup();
migration_ops->ram_save_target_page = ram_save_target_page_multifd;
} else {
migration_ops->ram_save_target_page = ram_save_target_page_legacy;
}
bql_unlock();
- ret = multifd_send_sync_main();
+ ret = multifd_ram_flush_and_sync();
bql_lock();
if (ret < 0) {
error_setg(errp, "%s: multifd synchronization failed", __func__);
@@ -3211,7 +3211,7 @@ out:
&& migration_is_setup_or_active()) {
if (migrate_multifd() && migrate_multifd_flush_after_each_section() &&
!migrate_mapped_ram()) {
- ret = multifd_send_sync_main();
+ ret = multifd_ram_flush_and_sync();
if (ret < 0) {
return ret;
}
@@ -3283,7 +3283,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
}
}
- ret = multifd_send_sync_main();
+ ret = multifd_ram_flush_and_sync();
if (ret < 0) {
return ret;
}
diff --git a/migration/savevm.c b/migration/savevm.c
index deb5783..7e1e271 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -874,6 +874,8 @@ int vmstate_replace_hack_for_ppc(VMStateIf *obj, int instance_id,
if (se) {
savevm_state_handler_remove(se);
+ g_free(se->compat);
+ g_free(se);
}
return vmstate_register(obj, instance_id, vmsd, opaque);
}
@@ -2576,8 +2578,7 @@ static bool check_section_footer(QEMUFile *f, SaveStateEntry *se)
}
static int
-qemu_loadvm_section_start_full(QEMUFile *f, MigrationIncomingState *mis,
- uint8_t type)
+qemu_loadvm_section_start_full(QEMUFile *f, uint8_t type)
{
bool trace_downtime = (type == QEMU_VM_SECTION_FULL);
uint32_t instance_id, version_id, section_id;
@@ -2655,8 +2656,7 @@ qemu_loadvm_section_start_full(QEMUFile *f, MigrationIncomingState *mis,
}
static int
-qemu_loadvm_section_part_end(QEMUFile *f, MigrationIncomingState *mis,
- uint8_t type)
+qemu_loadvm_section_part_end(QEMUFile *f, uint8_t type)
{
bool trace_downtime = (type == QEMU_VM_SECTION_END);
int64_t start_ts, end_ts;
@@ -2732,13 +2732,11 @@ static int qemu_loadvm_state_header(QEMUFile *f)
if (migrate_get_current()->send_configuration) {
if (qemu_get_byte(f) != QEMU_VM_CONFIGURATION) {
error_report("Configuration section missing");
- qemu_loadvm_state_cleanup();
return -EINVAL;
}
ret = vmstate_load_state(f, &vmstate_configuration, &savevm_state, 0);
if (ret) {
- qemu_loadvm_state_cleanup();
return ret;
}
}
@@ -2891,14 +2889,14 @@ retry:
switch (section_type) {
case QEMU_VM_SECTION_START:
case QEMU_VM_SECTION_FULL:
- ret = qemu_loadvm_section_start_full(f, mis, section_type);
+ ret = qemu_loadvm_section_start_full(f, section_type);
if (ret < 0) {
goto out;
}
break;
case QEMU_VM_SECTION_PART:
case QEMU_VM_SECTION_END:
- ret = qemu_loadvm_section_part_end(f, mis, section_type);
+ ret = qemu_loadvm_section_part_end(f, section_type);
if (ret < 0) {
goto out;
}
@@ -2981,7 +2979,10 @@ int qemu_loadvm_state(QEMUFile *f)
trace_qemu_loadvm_state_post_main(ret);
if (mis->have_listen_thread) {
- /* Listen thread still going, can't clean up yet */
+ /*
+ * Postcopy listen thread still going, don't synchronize the
+ * cpus yet.
+ */
return ret;
}
@@ -3024,7 +3025,6 @@ int qemu_loadvm_state(QEMUFile *f)
}
}
- qemu_loadvm_state_cleanup();
cpu_synchronize_all_post_init();
return ret;
@@ -3286,6 +3286,7 @@ bool load_snapshot(const char *name, const char *vmstate,
/* Don't even try to load empty VM states */
ret = bdrv_snapshot_find(bs_vm_state, &sn, name);
if (ret < 0) {
+ error_setg(errp, "Snapshot can not be found");
return false;
} else if (sn.vm_state_size == 0) {
error_setg(errp, "This is a disk-only snapshot. Revert to it "
diff --git a/migration/socket.c b/migration/socket.c
index 9ab89b1..5ec65b8 100644
--- a/migration/socket.c
+++ b/migration/socket.c
@@ -42,24 +42,6 @@ void socket_send_channel_create(QIOTaskFunc f, void *data)
f, data, NULL, NULL);
}
-QIOChannel *socket_send_channel_create_sync(Error **errp)
-{
- QIOChannelSocket *sioc = qio_channel_socket_new();
-
- if (!outgoing_args.saddr) {
- object_unref(OBJECT(sioc));
- error_setg(errp, "Initial sock address not set!");
- return NULL;
- }
-
- if (qio_channel_socket_connect_sync(sioc, outgoing_args.saddr, errp) < 0) {
- object_unref(OBJECT(sioc));
- return NULL;
- }
-
- return QIO_CHANNEL(sioc);
-}
-
struct SocketConnectData {
MigrationState *s;
char *hostname;
diff --git a/migration/socket.h b/migration/socket.h
index 46c233e..04ebbe9 100644
--- a/migration/socket.h
+++ b/migration/socket.h
@@ -22,7 +22,6 @@
#include "qemu/sockets.h"
void socket_send_channel_create(QIOTaskFunc f, void *data);
-QIOChannel *socket_send_channel_create_sync(Error **errp);
void socket_start_incoming_migration(SocketAddress *saddr, Error **errp);
diff --git a/migration/trace-events b/migration/trace-events
index 0b7c332..c65902f 100644
--- a/migration/trace-events
+++ b/migration/trace-events
@@ -128,21 +128,22 @@ postcopy_preempt_reset_channel(void) ""
# multifd.c
multifd_new_send_channel_async(uint8_t id) "channel %u"
multifd_new_send_channel_async_error(uint8_t id, void *err) "channel=%u err=%p"
-multifd_recv(uint8_t id, uint64_t packet_num, uint32_t normal, uint32_t zero, uint32_t flags, uint32_t next_packet_size) "channel %u packet_num %" PRIu64 " normal pages %u zero pages %u flags 0x%x next packet size %u"
+multifd_recv_unfill(uint8_t id, uint64_t packet_num, uint32_t flags, uint32_t next_packet_size) "channel %u packet_num %" PRIu64 " flags 0x%x next packet size %u"
multifd_recv_new_channel(uint8_t id) "channel %u"
multifd_recv_sync_main(long packet_num) "packet num %ld"
multifd_recv_sync_main_signal(uint8_t id) "channel %u"
multifd_recv_sync_main_wait(uint8_t id) "iter %u"
multifd_recv_terminate_threads(bool error) "error %d"
-multifd_recv_thread_end(uint8_t id, uint64_t packets, uint64_t normal_pages, uint64_t zero_pages) "channel %u packets %" PRIu64 " normal pages %" PRIu64 " zero pages %" PRIu64
+multifd_recv_thread_end(uint8_t id, uint64_t packets) "channel %u packets %" PRIu64
multifd_recv_thread_start(uint8_t id) "%u"
-multifd_send(uint8_t id, uint64_t packet_num, uint32_t normal_pages, uint32_t zero_pages, uint32_t flags, uint32_t next_packet_size) "channel %u packet_num %" PRIu64 " normal pages %u zero pages %u flags 0x%x next packet size %u"
+multifd_send_fill(uint8_t id, uint64_t packet_num, uint32_t flags, uint32_t next_packet_size) "channel %u packet_num %" PRIu64 " flags 0x%x next packet size %u"
+multifd_send_ram_fill(uint8_t id, uint32_t normal, uint32_t zero) "channel %u normal pages %u zero pages %u"
multifd_send_error(uint8_t id) "channel %u"
multifd_send_sync_main(long packet_num) "packet num %ld"
multifd_send_sync_main_signal(uint8_t id) "channel %u"
multifd_send_sync_main_wait(uint8_t id) "channel %u"
multifd_send_terminate_threads(void) ""
-multifd_send_thread_end(uint8_t id, uint64_t packets, uint64_t normal_pages, uint64_t zero_pages) "channel %u packets %" PRIu64 " normal pages %" PRIu64 " zero pages %" PRIu64
+multifd_send_thread_end(uint8_t id, uint64_t packets) "channel %u packets %" PRIu64
multifd_send_thread_start(uint8_t id) "%u"
multifd_tls_outgoing_handshake_start(void *ioc, void *tioc, const char *hostname) "ioc=%p tioc=%p hostname=%s"
multifd_tls_outgoing_handshake_error(void *ioc, const char *err) "ioc=%p err=%s"
diff --git a/monitor/monitor.c b/monitor/monitor.c
index db52a9c..56786c0 100644
--- a/monitor/monitor.c
+++ b/monitor/monitor.c
@@ -308,6 +308,7 @@ int error_printf_unless_qmp(const char *fmt, ...)
static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = {
/* Limit guest-triggerable events to 1 per second */
[QAPI_EVENT_RTC_CHANGE] = { 1000 * SCALE_MS },
+ [QAPI_EVENT_BLOCK_IO_ERROR] = { 1000 * SCALE_MS },
[QAPI_EVENT_WATCHDOG] = { 1000 * SCALE_MS },
[QAPI_EVENT_BALLOON_CHANGE] = { 1000 * SCALE_MS },
[QAPI_EVENT_QUORUM_REPORT_BAD] = { 1000 * SCALE_MS },
@@ -493,7 +494,8 @@ static unsigned int qapi_event_throttle_hash(const void *key)
hash += g_str_hash(qdict_get_str(evstate->data, "node-name"));
}
- if (evstate->event == QAPI_EVENT_MEMORY_DEVICE_SIZE_CHANGE) {
+ if (evstate->event == QAPI_EVENT_MEMORY_DEVICE_SIZE_CHANGE ||
+ evstate->event == QAPI_EVENT_BLOCK_IO_ERROR) {
hash += g_str_hash(qdict_get_str(evstate->data, "qom-path"));
}
@@ -519,7 +521,8 @@ static gboolean qapi_event_throttle_equal(const void *a, const void *b)
qdict_get_str(evb->data, "node-name"));
}
- if (eva->event == QAPI_EVENT_MEMORY_DEVICE_SIZE_CHANGE) {
+ if (eva->event == QAPI_EVENT_MEMORY_DEVICE_SIZE_CHANGE ||
+ eva->event == QAPI_EVENT_BLOCK_IO_ERROR) {
return !strcmp(qdict_get_str(eva->data, "qom-path"),
qdict_get_str(evb->data, "qom-path"));
}
diff --git a/nbd/client-connection.c b/nbd/client-connection.c
index f9da67c..b11e266 100644
--- a/nbd/client-connection.c
+++ b/nbd/client-connection.c
@@ -410,7 +410,7 @@ nbd_co_establish_connection(NBDClientConnection *conn, NBDExportInfo *info,
*/
void nbd_co_establish_connection_cancel(NBDClientConnection *conn)
{
- Coroutine *wait_co;
+ Coroutine *wait_co = NULL;
WITH_QEMU_LOCK_GUARD(&conn->mutex) {
wait_co = g_steal_pointer(&conn->wait_co);
diff --git a/nbd/server.c b/nbd/server.c
index 892797b..c30e687 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -124,12 +124,14 @@ struct NBDMetaContexts {
struct NBDClient {
int refcount; /* atomic */
void (*close_fn)(NBDClient *client, bool negotiated);
+ void *owner;
QemuMutex lock;
NBDExport *exp;
QCryptoTLSCreds *tlscreds;
char *tlsauthz;
+ uint32_t handshake_max_secs;
QIOChannelSocket *sioc; /* The underlying data channel */
QIOChannel *ioc; /* The current I/O channel which may differ (eg TLS) */
@@ -1972,7 +1974,7 @@ static void nbd_export_request_shutdown(BlockExport *blk_exp)
blk_exp_ref(&exp->common);
/*
- * TODO: Should we expand QMP NbdServerRemoveNode enum to allow a
+ * TODO: Should we expand QMP BlockExportRemoveMode enum to allow a
* close mode that stops advertising the export to new clients but
* still permits existing clients to run to completion? Because of
* that possibility, nbd_export_close() can be called more than
@@ -3184,35 +3186,65 @@ static void nbd_client_receive_next_request(NBDClient *client)
}
}
+static void nbd_handshake_timer_cb(void *opaque)
+{
+ QIOChannel *ioc = opaque;
+
+ trace_nbd_handshake_timer_cb();
+ qio_channel_shutdown(ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
+}
+
static coroutine_fn void nbd_co_client_start(void *opaque)
{
NBDClient *client = opaque;
Error *local_err = NULL;
+ QEMUTimer *handshake_timer = NULL;
qemu_co_mutex_init(&client->send_lock);
+ /*
+ * Create a timer to bound the time spent in negotiation. If the
+ * timer expires, it is likely nbd_negotiate will fail because the
+ * socket was shutdown.
+ */
+ if (client->handshake_max_secs > 0) {
+ handshake_timer = aio_timer_new(qemu_get_aio_context(),
+ QEMU_CLOCK_REALTIME,
+ SCALE_NS,
+ nbd_handshake_timer_cb,
+ client->sioc);
+ timer_mod(handshake_timer,
+ qemu_clock_get_ns(QEMU_CLOCK_REALTIME) +
+ client->handshake_max_secs * NANOSECONDS_PER_SECOND);
+ }
+
if (nbd_negotiate(client, &local_err)) {
if (local_err) {
error_report_err(local_err);
}
+ timer_free(handshake_timer);
client_close(client, false);
return;
}
+ timer_free(handshake_timer);
WITH_QEMU_LOCK_GUARD(&client->lock) {
nbd_client_receive_next_request(client);
}
}
/*
- * Create a new client listener using the given channel @sioc.
+ * Create a new client listener using the given channel @sioc and @owner.
* Begin servicing it in a coroutine. When the connection closes, call
- * @close_fn with an indication of whether the client completed negotiation.
+ * @close_fn with an indication of whether the client completed negotiation
+ * within @handshake_max_secs seconds (0 for unbounded).
*/
void nbd_client_new(QIOChannelSocket *sioc,
+ uint32_t handshake_max_secs,
QCryptoTLSCreds *tlscreds,
const char *tlsauthz,
- void (*close_fn)(NBDClient *, bool))
+ void (*close_fn)(NBDClient *, bool),
+ void *owner)
{
NBDClient *client;
Coroutine *co;
@@ -3225,13 +3257,21 @@ void nbd_client_new(QIOChannelSocket *sioc,
object_ref(OBJECT(client->tlscreds));
}
client->tlsauthz = g_strdup(tlsauthz);
+ client->handshake_max_secs = handshake_max_secs;
client->sioc = sioc;
qio_channel_set_delay(QIO_CHANNEL(sioc), false);
object_ref(OBJECT(client->sioc));
client->ioc = QIO_CHANNEL(sioc);
object_ref(OBJECT(client->ioc));
client->close_fn = close_fn;
+ client->owner = owner;
co = qemu_coroutine_create(nbd_co_client_start, client);
qemu_coroutine_enter(co);
}
+
+void *
+nbd_client_owner(NBDClient *client)
+{
+ return client->owner;
+}
diff --git a/nbd/trace-events b/nbd/trace-events
index 00ae321..cbd0a4a 100644
--- a/nbd/trace-events
+++ b/nbd/trace-events
@@ -76,6 +76,7 @@ nbd_co_receive_request_payload_received(uint64_t cookie, uint64_t len) "Payload
nbd_co_receive_ext_payload_compliance(uint64_t from, uint64_t len) "client sent non-compliant write without payload flag: from=0x%" PRIx64 ", len=0x%" PRIx64
nbd_co_receive_align_compliance(const char *op, uint64_t from, uint64_t len, uint32_t align) "client sent non-compliant unaligned %s request: from=0x%" PRIx64 ", len=0x%" PRIx64 ", align=0x%" PRIx32
nbd_trip(void) "Reading request"
+nbd_handshake_timer_cb(void) "client took too long to negotiate"
# client-connection.c
nbd_connect_thread_sleep(uint64_t timeout) "timeout %" PRIu64
diff --git a/net/colo-compare.c b/net/colo-compare.c
index c4ad0ab..39f90c4 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -412,8 +412,7 @@ static void colo_compare_tcp(CompareState *s, Connection *conn)
* can ensure that the packet's payload is acknowledged by
* primary and secondary.
*/
- uint32_t min_ack = conn->pack - conn->sack > 0 ?
- conn->sack : conn->pack;
+ uint32_t min_ack = MIN(conn->pack, conn->sack);
pri:
if (g_queue_is_empty(&conn->primary_list)) {
diff --git a/net/hub.c b/net/hub.c
index 4c8a469..496a3d3 100644
--- a/net/hub.c
+++ b/net/hub.c
@@ -194,31 +194,6 @@ NetClientState *net_hub_add_port(int hub_id, const char *name,
}
/**
- * Find a available port on a hub; otherwise create one new port
- */
-NetClientState *net_hub_port_find(int hub_id)
-{
- NetHub *hub;
- NetHubPort *port;
- NetClientState *nc;
-
- QLIST_FOREACH(hub, &hubs, next) {
- if (hub->id == hub_id) {
- QLIST_FOREACH(port, &hub->ports, next) {
- nc = port->nc.peer;
- if (!nc) {
- return &(port->nc);
- }
- }
- break;
- }
- }
-
- nc = net_hub_add_port(hub_id, NULL, NULL);
- return nc;
-}
-
-/**
* Print hub configuration
*/
void net_hub_info(Monitor *mon)
diff --git a/net/meson.build b/net/meson.build
index e0cd714..bb97b4d 100644
--- a/net/meson.build
+++ b/net/meson.build
@@ -39,7 +39,7 @@ if have_netmap
system_ss.add(files('netmap.c'))
endif
-system_ss.add(when: libxdp, if_true: files('af-xdp.c'))
+system_ss.add(when: [libxdp, libbpf], if_true: files('af-xdp.c'))
if have_vhost_net_user
system_ss.add(when: 'CONFIG_VIRTIO_NET', if_true: files('vhost-user.c'), if_false: files('vhost-user-stub.c'))
diff --git a/net/net.c b/net/net.c
index 6938da0..7ef6885 100644
--- a/net/net.c
+++ b/net/net.c
@@ -542,6 +542,10 @@ void qemu_set_offload(NetClientState *nc, int csum, int tso4, int tso6,
int qemu_get_vnet_hdr_len(NetClientState *nc)
{
+ if (!nc) {
+ return 0;
+ }
+
return nc->vnet_hdr_len;
}
@@ -750,16 +754,6 @@ ssize_t qemu_receive_packet(NetClientState *nc, const uint8_t *buf, int size)
return qemu_net_queue_receive(nc->incoming_queue, buf, size);
}
-ssize_t qemu_receive_packet_iov(NetClientState *nc, const struct iovec *iov,
- int iovcnt)
-{
- if (!qemu_can_receive_packet(nc)) {
- return 0;
- }
-
- return qemu_net_queue_receive_iov(nc->incoming_queue, iov, iovcnt);
-}
-
ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size)
{
return qemu_send_packet_async_with_flags(nc, QEMU_NET_PACKET_FLAG_RAW,
@@ -1139,6 +1133,21 @@ NICInfo *qemu_find_nic_info(const char *typename, bool match_default,
return NULL;
}
+static bool is_nic_model_help_option(const char *model)
+{
+ if (model && is_help_option(model)) {
+ /*
+ * Trigger the help output by instantiating the hash table which
+ * will gather tha available models as they get registered.
+ */
+ if (!nic_model_help) {
+ nic_model_help = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, NULL);
+ }
+ return true;
+ }
+ return false;
+}
/* "I have created a device. Please configure it if you can" */
bool qemu_configure_nic_device(DeviceState *dev, bool match_default,
@@ -1722,6 +1731,12 @@ void net_check_clients(void)
static int net_init_client(void *dummy, QemuOpts *opts, Error **errp)
{
+ const char *model = qemu_opt_get(opts, "model");
+
+ if (is_nic_model_help_option(model)) {
+ return 0;
+ }
+
return net_client_init(opts, false, errp);
}
@@ -1778,9 +1793,7 @@ static int net_param_nic(void *dummy, QemuOpts *opts, Error **errp)
memset(ni, 0, sizeof(*ni));
ni->model = qemu_opt_get_del(opts, "model");
- if (!nic_model_help && !g_strcmp0(ni->model, "help")) {
- nic_model_help = g_hash_table_new_full(g_str_hash, g_str_equal,
- g_free, NULL);
+ if (is_nic_model_help_option(ni->model)) {
return 0;
}
diff --git a/net/queue.c b/net/queue.c
index c872d51..fb33856 100644
--- a/net/queue.c
+++ b/net/queue.c
@@ -193,17 +193,6 @@ ssize_t qemu_net_queue_receive(NetQueue *queue,
return qemu_net_queue_deliver(queue, NULL, 0, data, size);
}
-ssize_t qemu_net_queue_receive_iov(NetQueue *queue,
- const struct iovec *iov,
- int iovcnt)
-{
- if (queue->delivering) {
- return 0;
- }
-
- return qemu_net_queue_deliver_iov(queue, NULL, 0, iov, iovcnt);
-}
-
ssize_t qemu_net_queue_send(NetQueue *queue,
NetClientState *sender,
unsigned flags,
diff --git a/net/stream.c b/net/stream.c
index 97e6ec6..4de5613 100644
--- a/net/stream.c
+++ b/net/stream.c
@@ -51,7 +51,7 @@ typedef struct NetStreamState {
guint ioc_write_tag;
SocketReadState rs;
unsigned int send_index; /* number of bytes sent*/
- uint32_t reconnect;
+ uint32_t reconnect_ms;
guint timer_tag;
SocketAddress *addr;
} NetStreamState;
@@ -387,10 +387,9 @@ static gboolean net_stream_reconnect(gpointer data)
static void net_stream_arm_reconnect(NetStreamState *s)
{
- if (s->reconnect && s->timer_tag == 0) {
+ if (s->reconnect_ms && s->timer_tag == 0) {
qemu_set_info_str(&s->nc, "connecting");
- s->timer_tag = g_timeout_add_seconds(s->reconnect,
- net_stream_reconnect, s);
+ s->timer_tag = g_timeout_add(s->reconnect_ms, net_stream_reconnect, s);
}
}
@@ -398,7 +397,7 @@ static int net_stream_client_init(NetClientState *peer,
const char *model,
const char *name,
SocketAddress *addr,
- uint32_t reconnect,
+ uint32_t reconnect_ms,
Error **errp)
{
NetStreamState *s;
@@ -412,8 +411,8 @@ static int net_stream_client_init(NetClientState *peer,
s->ioc = QIO_CHANNEL(sioc);
s->nc.link_down = true;
- s->reconnect = reconnect;
- if (reconnect) {
+ s->reconnect_ms = reconnect_ms;
+ if (reconnect_ms) {
s->addr = QAPI_CLONE(SocketAddress, addr);
}
qio_channel_socket_connect_async(sioc, addr,
@@ -432,13 +431,24 @@ int net_init_stream(const Netdev *netdev, const char *name,
sock = &netdev->u.stream;
if (!sock->has_server || !sock->server) {
+ uint32_t reconnect_ms = 0;
+
+ if (sock->has_reconnect && sock->has_reconnect_ms) {
+ error_setg(errp, "'reconnect' and 'reconnect-ms' are mutually "
+ "exclusive");
+ return -1;
+ } else if (sock->has_reconnect_ms) {
+ reconnect_ms = sock->reconnect_ms;
+ } else if (sock->has_reconnect) {
+ reconnect_ms = sock->reconnect * 1000u;
+ }
+
return net_stream_client_init(peer, "stream", name, sock->addr,
- sock->has_reconnect ? sock->reconnect : 0,
- errp);
+ reconnect_ms, errp);
}
- if (sock->has_reconnect) {
- error_setg(errp, "'reconnect' option is incompatible with "
- "socket in server mode");
+ if (sock->has_reconnect || sock->has_reconnect_ms) {
+ error_setg(errp, "'reconnect' and 'reconnect-ms' options are "
+ "incompatible with socket in server mode");
return -1;
}
return net_stream_server_init(peer, "stream", name, sock->addr, errp);
diff --git a/net/tap-win32.c b/net/tap-win32.c
index 7edbd71..671dee9 100644
--- a/net/tap-win32.c
+++ b/net/tap-win32.c
@@ -214,7 +214,7 @@ static int is_tap_win32_dev(const char *guid)
for (;;) {
char enum_name[256];
- char unit_string[256];
+ g_autofree char *unit_string = NULL;
HKEY unit_key;
char component_id_string[] = "ComponentId";
char component_id[256];
@@ -239,8 +239,7 @@ static int is_tap_win32_dev(const char *guid)
return FALSE;
}
- snprintf (unit_string, sizeof(unit_string), "%s\\%s",
- ADAPTER_KEY, enum_name);
+ unit_string = g_strdup_printf("%s\\%s", ADAPTER_KEY, enum_name);
status = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
@@ -315,7 +314,7 @@ static int get_device_guid(
while (!stop)
{
char enum_name[256];
- char connection_string[256];
+ g_autofree char *connection_string = NULL;
HKEY connection_key;
char name_data[256];
DWORD name_type;
@@ -338,9 +337,7 @@ static int get_device_guid(
return -1;
}
- snprintf(connection_string,
- sizeof(connection_string),
- "%s\\%s\\Connection",
+ connection_string = g_strdup_printf("%s\\%s\\Connection",
NETWORK_CONNECTIONS_KEY, enum_name);
status = RegOpenKeyEx(
@@ -595,7 +592,7 @@ static void tap_win32_free_buffer(tap_win32_overlapped_t *overlapped,
static int tap_win32_open(tap_win32_overlapped_t **phandle,
const char *preferred_name)
{
- char device_path[256];
+ g_autofree char *device_path = NULL;
char device_guid[0x100];
int rc;
HANDLE handle;
@@ -617,7 +614,7 @@ static int tap_win32_open(tap_win32_overlapped_t **phandle,
if (rc)
return -1;
- snprintf (device_path, sizeof(device_path), "%s%s%s",
+ device_path = g_strdup_printf("%s%s%s",
USERMODEDEVICEDIR,
device_guid,
TAPSUFFIX);
diff --git a/net/tap.c b/net/tap.c
index 51f7aec..3f90022 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -385,6 +385,24 @@ static TAPState *net_tap_fd_init(NetClientState *peer,
return s;
}
+static void close_all_fds_after_fork(int excluded_fd)
+{
+ const int skip_fd[] = {STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO,
+ excluded_fd};
+ unsigned int nskip = ARRAY_SIZE(skip_fd);
+
+ /*
+ * skip_fd must be an ordered array of distinct fds, exclude
+ * excluded_fd if already included in the [STDIN_FILENO - STDERR_FILENO]
+ * range
+ */
+ if (excluded_fd <= STDERR_FILENO) {
+ nskip--;
+ }
+
+ qemu_close_all_open_fd(skip_fd, nskip);
+}
+
static void launch_script(const char *setup_script, const char *ifname,
int fd, Error **errp)
{
@@ -400,13 +418,7 @@ static void launch_script(const char *setup_script, const char *ifname,
return;
}
if (pid == 0) {
- int open_max = sysconf(_SC_OPEN_MAX), i;
-
- for (i = 3; i < open_max; i++) {
- if (i != fd) {
- close(i);
- }
- }
+ close_all_fds_after_fork(fd);
parg = args;
*parg++ = (char *)setup_script;
*parg++ = (char *)ifname;
@@ -490,17 +502,11 @@ static int net_bridge_run_helper(const char *helper, const char *bridge,
return -1;
}
if (pid == 0) {
- int open_max = sysconf(_SC_OPEN_MAX), i;
char *fd_buf = NULL;
char *br_buf = NULL;
char *helper_cmd = NULL;
- for (i = 3; i < open_max; i++) {
- if (i != sv[1]) {
- close(i);
- }
- }
-
+ close_all_fds_after_fork(sv[1]);
fd_buf = g_strdup_printf("%s%d", "--fd=", sv[1]);
if (strrchr(helper, ' ') || strrchr(helper, '\t')) {
diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
index daa3842..46b02c5 100644
--- a/net/vhost-vdpa.c
+++ b/net/vhost-vdpa.c
@@ -62,6 +62,7 @@ const int vdpa_feature_bits[] = {
VIRTIO_F_RING_PACKED,
VIRTIO_F_RING_RESET,
VIRTIO_F_VERSION_1,
+ VIRTIO_F_IN_ORDER,
VIRTIO_F_NOTIFICATION_DATA,
VIRTIO_NET_F_CSUM,
VIRTIO_NET_F_CTRL_GUEST_OFFLOADS,
@@ -87,6 +88,7 @@ const int vdpa_feature_bits[] = {
VIRTIO_NET_F_MQ,
VIRTIO_NET_F_MRG_RXBUF,
VIRTIO_NET_F_MTU,
+ VIRTIO_NET_F_RSC_EXT,
VIRTIO_NET_F_RSS,
VIRTIO_NET_F_STATUS,
VIRTIO_RING_F_EVENT_IDX,
diff --git a/pc-bios/descriptors/60-edk2-loongarch64.json b/pc-bios/descriptors/60-edk2-loongarch64.json
new file mode 100644
index 0000000..f174a1f
--- /dev/null
+++ b/pc-bios/descriptors/60-edk2-loongarch64.json
@@ -0,0 +1,31 @@
+{
+ "description": "UEFI firmware for loongarch64",
+ "interface-types": [
+ "uefi"
+ ],
+ "mapping": {
+ "device": "flash",
+ "executable": {
+ "filename": "@DATADIR@/edk2-loongarch64-code.fd",
+ "format": "raw"
+ },
+ "nvram-template": {
+ "filename": "@DATADIR@/edk2-loongarch64-vars.fd",
+ "format": "raw"
+ }
+ },
+ "targets": [
+ {
+ "architecture": "loongarch64",
+ "machines": [
+ "virt*"
+ ]
+ }
+ ],
+ "features": [
+
+ ],
+ "tags": [
+
+ ]
+}
diff --git a/pc-bios/descriptors/meson.build b/pc-bios/descriptors/meson.build
index 66f85d0..afb5a95 100644
--- a/pc-bios/descriptors/meson.build
+++ b/pc-bios/descriptors/meson.build
@@ -5,7 +5,8 @@ if unpack_edk2_blobs and get_option('install_blobs')
'60-edk2-aarch64.json',
'60-edk2-arm.json',
'60-edk2-i386.json',
- '60-edk2-x86_64.json'
+ '60-edk2-x86_64.json',
+ '60-edk2-loongarch64.json'
]
configure_file(input: files(f),
output: f,
diff --git a/pc-bios/edk2-aarch64-code.fd.bz2 b/pc-bios/edk2-aarch64-code.fd.bz2
index e763982..2ce728c 100644
--- a/pc-bios/edk2-aarch64-code.fd.bz2
+++ b/pc-bios/edk2-aarch64-code.fd.bz2
Binary files differ
diff --git a/pc-bios/edk2-arm-code.fd.bz2 b/pc-bios/edk2-arm-code.fd.bz2
index 329646d..9b98490 100644
--- a/pc-bios/edk2-arm-code.fd.bz2
+++ b/pc-bios/edk2-arm-code.fd.bz2
Binary files differ
diff --git a/pc-bios/edk2-i386-code.fd.bz2 b/pc-bios/edk2-i386-code.fd.bz2
index 271ce65..50c9869 100644
--- a/pc-bios/edk2-i386-code.fd.bz2
+++ b/pc-bios/edk2-i386-code.fd.bz2
Binary files differ
diff --git a/pc-bios/edk2-i386-secure-code.fd.bz2 b/pc-bios/edk2-i386-secure-code.fd.bz2
index 00335cd..d58c16f 100644
--- a/pc-bios/edk2-i386-secure-code.fd.bz2
+++ b/pc-bios/edk2-i386-secure-code.fd.bz2
Binary files differ
diff --git a/pc-bios/edk2-loongarch64-code.fd.bz2 b/pc-bios/edk2-loongarch64-code.fd.bz2
new file mode 100644
index 0000000..ba12bc9
--- /dev/null
+++ b/pc-bios/edk2-loongarch64-code.fd.bz2
Binary files differ
diff --git a/pc-bios/edk2-loongarch64-vars.fd.bz2 b/pc-bios/edk2-loongarch64-vars.fd.bz2
new file mode 100644
index 0000000..8a13571
--- /dev/null
+++ b/pc-bios/edk2-loongarch64-vars.fd.bz2
Binary files differ
diff --git a/pc-bios/edk2-riscv-code.fd.bz2 b/pc-bios/edk2-riscv-code.fd.bz2
index f3a98d6..f4e243d 100644
--- a/pc-bios/edk2-riscv-code.fd.bz2
+++ b/pc-bios/edk2-riscv-code.fd.bz2
Binary files differ
diff --git a/pc-bios/edk2-x86_64-code.fd.bz2 b/pc-bios/edk2-x86_64-code.fd.bz2
index a1a8c05..cf043fc 100644
--- a/pc-bios/edk2-x86_64-code.fd.bz2
+++ b/pc-bios/edk2-x86_64-code.fd.bz2
Binary files differ
diff --git a/pc-bios/edk2-x86_64-microvm.fd.bz2 b/pc-bios/edk2-x86_64-microvm.fd.bz2
index 6b7cd54..c2b04f8 100644
--- a/pc-bios/edk2-x86_64-microvm.fd.bz2
+++ b/pc-bios/edk2-x86_64-microvm.fd.bz2
Binary files differ
diff --git a/pc-bios/edk2-x86_64-secure-code.fd.bz2 b/pc-bios/edk2-x86_64-secure-code.fd.bz2
index ef40a8b..50f5b36 100644
--- a/pc-bios/edk2-x86_64-secure-code.fd.bz2
+++ b/pc-bios/edk2-x86_64-secure-code.fd.bz2
Binary files differ
diff --git a/pc-bios/meson.build b/pc-bios/meson.build
index 8602b45..4823dff 100644
--- a/pc-bios/meson.build
+++ b/pc-bios/meson.build
@@ -11,6 +11,8 @@ if unpack_edk2_blobs
'edk2-i386-vars.fd',
'edk2-x86_64-code.fd',
'edk2-x86_64-secure-code.fd',
+ 'edk2-loongarch64-code.fd',
+ 'edk2-loongarch64-vars.fd',
]
foreach f : fds
@@ -66,7 +68,6 @@ blobs = [
'kvmvapic.bin',
'pvh.bin',
's390-ccw.img',
- 's390-netboot.img',
'slof.bin',
'skiboot.lid',
'palcode-clipper',
diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc
index 4af6002..6f472d4 100644
--- a/pc-bios/openbios-ppc
+++ b/pc-bios/openbios-ppc
Binary files differ
diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32
index 41b6a60..9679248 100644
--- a/pc-bios/openbios-sparc32
+++ b/pc-bios/openbios-sparc32
Binary files differ
diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64
index 902b4b3..0a13453 100644
--- a/pc-bios/openbios-sparc64
+++ b/pc-bios/openbios-sparc64
Binary files differ
diff --git a/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin b/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin
index 60ca116..b2e7400 100644
--- a/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin
+++ b/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin
Binary files differ
diff --git a/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin b/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin
index bae158d..018b473 100644
--- a/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin
+++ b/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin
Binary files differ
diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img
index f0d9ef6..f9bac25 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 6207911..dc69dd4 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -3,7 +3,8 @@ all: build-all
@true
include config-host.mak
-CFLAGS = -O2 -g
+CFLAGS = -O2 -g -I $(SRC_PATH)/../../include/hw/s390x/ipl
+LDFLAGS ?=
MAKEFLAGS += -rR
GIT_SUBMODULES = roms/SLOF
@@ -32,15 +33,21 @@ QEMU_DGFLAGS = -MMD -MP -MT $@ -MF $(@D)/$(*F).d
.PHONY : all clean build-all distclean
-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
+OBJECTS = start.o main.o bootmap.o jump2ipl.o sclp.o menu.o netmain.o \
+ virtio.o virtio-net.o virtio-scsi.o virtio-blkdev.o cio.o dasd-ipl.o
+
+SLOF_DIR := $(SRC_PATH)/../../roms/SLOF
+
+LIBC_INC := -nostdinc -I$(SLOF_DIR)/lib/libc/include
+LIBNET_INC := -I$(SLOF_DIR)/lib/libnet
EXTRA_CFLAGS += -Wall
EXTRA_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -fno-common -fPIE
EXTRA_CFLAGS += -fwrapv -fno-strict-aliasing -fno-asynchronous-unwind-tables
EXTRA_CFLAGS += -msoft-float
EXTRA_CFLAGS += -std=gnu99
-LDFLAGS += -Wl,-pie -nostdlib -z noexecstack
+EXTRA_CFLAGS += $(LIBC_INC) $(LIBNET_INC)
+EXTRA_LDFLAGS += -Wl,-pie -nostdlib -z noexecstack -z text
cc-test = $(CC) -Werror $1 -c -o /dev/null -xc /dev/null >/dev/null 2>/dev/null
cc-option = if $(call cc-test, $1); then \
@@ -55,19 +62,64 @@ config-cc.mak: Makefile
$(call cc-option,-march=z900,-march=z10)) 3> config-cc.mak
-include config-cc.mak
-build-all: s390-ccw.img s390-netboot.img
+# libc files:
+
+LIBC_CFLAGS = $(EXTRA_CFLAGS) $(CFLAGS) $(LIBC_INC) $(LIBNET_INC) \
+ -MMD -MP -MT $@ -MF $(@:%.o=%.d)
+
+CTYPE_OBJS = isdigit.o isxdigit.o toupper.o
+%.o : $(SLOF_DIR)/lib/libc/ctype/%.c
+ $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling)
+
+STRING_OBJS = strcat.o strchr.o strrchr.o strcpy.o strlen.o strncpy.o \
+ strcmp.o strncmp.o strcasecmp.o strncasecmp.o strstr.o \
+ memset.o memcpy.o memmove.o memcmp.o
+%.o : $(SLOF_DIR)/lib/libc/string/%.c
+ $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling)
+
+STDLIB_OBJS = atoi.o atol.o strtoul.o strtol.o rand.o malloc.o free.o
+%.o : $(SLOF_DIR)/lib/libc/stdlib/%.c
+ $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling)
+
+STDIO_OBJS = sprintf.o snprintf.o vfprintf.o vsnprintf.o vsprintf.o fprintf.o \
+ printf.o putc.o puts.o putchar.o stdchnls.o fileno.o
+%.o : $(SLOF_DIR)/lib/libc/stdio/%.c
+ $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling)
+
+sbrk.o: $(SLOF_DIR)/slof/sbrk.c
+ $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling)
+
+LIBCOBJS := $(STRING_OBJS) $(CTYPE_OBJS) $(STDLIB_OBJS) $(STDIO_OBJS) sbrk.o
-s390-ccw.elf: $(OBJECTS)
- $(call quiet-command,$(CC) $(LDFLAGS) -o $@ $(OBJECTS),Linking)
+libc.a: $(LIBCOBJS)
+ $(call quiet-command,$(AR) -rc $@ $^,Creating static library)
+
+# libnet files:
+
+LIBNETOBJS := args.o dhcp.o dns.o icmpv6.o ipv6.o tcp.o udp.o bootp.o \
+ dhcpv6.o ethernet.o ipv4.o ndp.o tftp.o pxelinux.o
+LIBNETCFLAGS = $(EXTRA_CFLAGS) $(CFLAGS) $(LIBC_INC) $(LIBNET_INC) \
+ -DDHCPARCH=0x1F -MMD -MP -MT $@ -MF $(@:%.o=%.d)
+
+%.o : $(SLOF_DIR)/lib/libnet/%.c
+ $(call quiet-command,$(CC) $(LIBNETCFLAGS) -c -o $@ $<,Compiling)
+
+libnet.a: $(LIBNETOBJS)
+ $(call quiet-command,$(AR) -rc $@ $^,Creating static library)
+
+# Main targets:
+
+build-all: s390-ccw.img
+
+s390-ccw.elf: $(OBJECTS) libnet.a libc.a
+ $(call quiet-command,$(CC) $(EXTRA_LDFLAGS) $(LDFLAGS) -o $@ $^,Linking)
s390-ccw.img: s390-ccw.elf
$(call quiet-command,$(STRIP) --strip-unneeded $< -o $@,Stripping $< into)
$(OBJECTS): Makefile
-include $(SRC_PATH)/netboot.mak
-
-ALL_OBJS = $(sort $(OBJECTS) $(NETOBJS) $(LIBCOBJS) $(LIBNETOBJS))
+ALL_OBJS = $(sort $(OBJECTS) $(LIBCOBJS) $(LIBNETOBJS))
-include $(ALL_OBJS:%.o=%.d)
clean:
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index a213744..56f2f75 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -8,7 +8,8 @@
* directory.
*/
-#include "libc.h"
+#include <string.h>
+#include <stdio.h>
#include "s390-ccw.h"
#include "s390-arch.h"
#include "bootmap.h"
@@ -21,7 +22,7 @@
#ifdef DEBUG_FALLBACK
#define dputs(txt) \
- do { sclp_print("zipl: " txt); } while (0)
+ do { printf("zipl: " txt); } while (0)
#else
#define dputs(fmt, ...) \
do { } while (0)
@@ -61,15 +62,34 @@ static void *s2_prev_blk = _s2;
static void *s2_cur_blk = _s2 + MAX_SECTOR_SIZE;
static void *s2_next_blk = _s2 + MAX_SECTOR_SIZE * 2;
-static inline void verify_boot_info(BootInfo *bip)
+static inline int verify_boot_info(BootInfo *bip)
{
- IPL_assert(magic_match(bip->magic, ZIPL_MAGIC), "No zIPL sig in BootInfo");
- IPL_assert(bip->version == BOOT_INFO_VERSION, "Wrong zIPL version");
- IPL_assert(bip->bp_type == BOOT_INFO_BP_TYPE_IPL, "DASD is not for IPL");
- IPL_assert(bip->dev_type == BOOT_INFO_DEV_TYPE_ECKD, "DASD is not ECKD");
- IPL_assert(bip->flags == BOOT_INFO_FLAGS_ARCH, "Not for this arch");
- IPL_assert(block_size_ok(bip->bp.ipl.bm_ptr.eckd.bptr.size),
- "Bad block size in zIPL section of the 1st record.");
+ if (!magic_match(bip->magic, ZIPL_MAGIC)) {
+ puts("No zIPL sig in BootInfo");
+ return -EINVAL;
+ }
+ if (bip->version != BOOT_INFO_VERSION) {
+ puts("Wrong zIPL version");
+ return -EINVAL;
+ }
+ if (bip->bp_type != BOOT_INFO_BP_TYPE_IPL) {
+ puts("DASD is not for IPL");
+ return -ENODEV;
+ }
+ if (bip->dev_type != BOOT_INFO_DEV_TYPE_ECKD) {
+ puts("DASD is not ECKD");
+ return -ENODEV;
+ }
+ if (bip->flags != BOOT_INFO_FLAGS_ARCH) {
+ puts("Not for this arch");
+ return -EINVAL;
+ }
+ if (!block_size_ok(bip->bp.ipl.bm_ptr.eckd.bptr.size)) {
+ puts("Bad block size in zIPL section of 1st record");
+ return -EINVAL;
+ }
+
+ return 0;
}
static void eckd_format_chs(ExtEckdBlockPtr *ptr, bool ldipl,
@@ -144,14 +164,17 @@ static block_number_t load_eckd_segments(block_number_t blk, bool ldipl,
bool more_data;
memset(_bprs, FREE_SPACE_FILLER, sizeof(_bprs));
- read_block(blk, bprs, "BPRS read failed");
+ if (virtio_read(blk, bprs)) {
+ puts("BPRS read failed");
+ return ERROR_BLOCK_NR;
+ }
do {
more_data = false;
for (j = 0;; j++) {
block_nr = gen_eckd_block_num(&bprs[j].xeckd, ldipl);
if (is_null_block_number(block_nr)) { /* end of chunk */
- break;
+ return NULL_BLOCK_NR;
}
/* we need the updated blockno for the next indirect entry
@@ -162,15 +185,20 @@ static block_number_t load_eckd_segments(block_number_t blk, bool ldipl,
}
/* List directed pointer does not store block size */
- IPL_assert(ldipl || block_size_ok(bprs[j].xeckd.bptr.size),
- "bad chunk block size");
+ if (!ldipl && !block_size_ok(bprs[j].xeckd.bptr.size)) {
+ puts("Bad chunk block size");
+ return ERROR_BLOCK_NR;
+ }
if (!eckd_valid_address(&bprs[j].xeckd, ldipl)) {
/*
* If an invalid address is found during LD-IPL then break and
- * retry as CCW
+ * retry as CCW-IPL, otherwise abort on error
*/
- IPL_assert(ldipl, "bad chunk ECKD addr");
+ if (!ldipl) {
+ puts("Bad chunk ECKD address");
+ return ERROR_BLOCK_NR;
+ }
break;
}
@@ -188,7 +216,10 @@ static block_number_t load_eckd_segments(block_number_t blk, bool ldipl,
* I.e. the next ptr must point to the unused memory area
*/
memset(_bprs, FREE_SPACE_FILLER, sizeof(_bprs));
- read_block(block_nr, bprs, "BPRS continuation read failed");
+ if (virtio_read(block_nr, bprs)) {
+ puts("BPRS continuation read failed");
+ return ERROR_BLOCK_NR;
+ }
more_data = true;
break;
}
@@ -197,7 +228,10 @@ static block_number_t load_eckd_segments(block_number_t blk, bool ldipl,
* to memory (address).
*/
rc = virtio_read_many(block_nr, (void *)(*address), count + 1);
- IPL_assert(rc == 0, "code chunk read failed");
+ if (rc != 0) {
+ puts("Code chunk read failed");
+ return ERROR_BLOCK_NR;
+ }
*address += (count + 1) * virtio_get_block_size();
}
@@ -231,7 +265,10 @@ static int eckd_get_boot_menu_index(block_number_t s1b_block_nr)
/* Get Stage1b data */
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
- read_block(s1b_block_nr, s1b, "Cannot read stage1b boot loader");
+ if (virtio_read(s1b_block_nr, s1b)) {
+ puts("Cannot read stage1b boot loader");
+ return -EIO;
+ }
memset(_s2, FREE_SPACE_FILLER, sizeof(_s2));
@@ -243,7 +280,10 @@ static int eckd_get_boot_menu_index(block_number_t s1b_block_nr)
break;
}
- read_block(cur_block_nr, s2_cur_blk, "Cannot read stage2 boot loader");
+ if (virtio_read(cur_block_nr, s2_cur_blk)) {
+ puts("Cannot read stage2 boot loader");
+ return -EIO;
+ }
if (find_zipl_boot_menu_banner(&banner_offset)) {
/*
@@ -251,8 +291,10 @@ static int eckd_get_boot_menu_index(block_number_t s1b_block_nr)
* possibility of menu data spanning multiple blocks.
*/
if (prev_block_nr) {
- read_block(prev_block_nr, s2_prev_blk,
- "Cannot read stage2 boot loader");
+ if (virtio_read(prev_block_nr, s2_prev_blk)) {
+ puts("Cannot read stage2 boot loader");
+ return -EIO;
+ }
}
if (i + 1 < STAGE2_BLK_CNT_MAX) {
@@ -260,8 +302,10 @@ static int eckd_get_boot_menu_index(block_number_t s1b_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");
+ if (virtio_read(next_block_nr, s2_next_blk)) {
+ puts("Cannot read stage2 boot loader");
+ return -EIO;
+ }
}
return menu_get_zipl_boot_index(s2_cur_blk + banner_offset);
@@ -270,11 +314,11 @@ static int eckd_get_boot_menu_index(block_number_t s1b_block_nr)
prev_block_nr = cur_block_nr;
}
- sclp_print("No zipl boot menu data found. Booting default entry.");
+ printf("No zipl boot menu data found. Booting default entry.");
return 0;
}
-static void run_eckd_boot_script(block_number_t bmt_block_nr,
+static int run_eckd_boot_script(block_number_t bmt_block_nr,
block_number_t s1b_block_nr)
{
int i;
@@ -291,17 +335,28 @@ static void run_eckd_boot_script(block_number_t bmt_block_nr,
}
debug_print_int("loadparm", loadparm);
- IPL_assert(loadparm < MAX_BOOT_ENTRIES, "loadparm value greater than"
- " maximum number of boot entries allowed");
+ if (loadparm >= MAX_BOOT_ENTRIES) {
+ puts("loadparm value greater than max number of boot entries allowed");
+ return -EINVAL;
+ }
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
- read_block(bmt_block_nr, sec, "Cannot read Boot Map Table");
+ if (virtio_read(bmt_block_nr, sec)) {
+ puts("Cannot read Boot Map Table");
+ return -EIO;
+ }
block_nr = gen_eckd_block_num(&bmt->entry[loadparm].xeckd, ldipl);
- IPL_assert(block_nr != -1, "Cannot find Boot Map Table Entry");
+ if (block_nr == NULL_BLOCK_NR) {
+ puts("Cannot find Boot Map Table Entry");
+ return -EIO;
+ }
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
- read_block(block_nr, sec, "Cannot read Boot Map Script");
+ if (virtio_read(block_nr, sec)) {
+ puts("Cannot read Boot Map Script");
+ return -EIO;
+ }
for (i = 0; bms->entry[i].type == BOOT_SCRIPT_LOAD ||
bms->entry[i].type == BOOT_SCRIPT_SIGNATURE; i++) {
@@ -316,21 +371,27 @@ static void run_eckd_boot_script(block_number_t bmt_block_nr,
do {
block_nr = load_eckd_segments(block_nr, ldipl, &address);
- } while (block_nr != -1);
+ if (block_nr == ERROR_BLOCK_NR) {
+ return ldipl ? 0 : -EIO;
+ }
+ } while (block_nr != NULL_BLOCK_NR);
}
if (ldipl && bms->entry[i].type != BOOT_SCRIPT_EXEC) {
/* Abort LD-IPL and retry as CCW-IPL */
- return;
+ return 0;
}
- IPL_assert(bms->entry[i].type == BOOT_SCRIPT_EXEC,
- "Unknown script entry type");
- write_reset_psw(bms->entry[i].address.load_address); /* no return */
- jump_to_IPL_code(0); /* no return */
+ if (bms->entry[i].type != BOOT_SCRIPT_EXEC) {
+ puts("Unknown script entry type");
+ return -EINVAL;
+ }
+ write_reset_psw(bms->entry[i].address.load_address);
+ jump_to_IPL_code(0);
+ return -1;
}
-static void ipl_eckd_cdl(void)
+static int ipl_eckd_cdl(void)
{
XEckdMbr *mbr;
EckdCdlIpl2 *ipl2 = (void *)sec;
@@ -338,23 +399,26 @@ static void ipl_eckd_cdl(void)
block_number_t bmt_block_nr, s1b_block_nr;
/* we have just read the block #0 and recognized it as "IPL1" */
- sclp_print("CDL\n");
+ puts("CDL");
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
- read_block(1, ipl2, "Cannot read IPL2 record at block 1");
+ if (virtio_read(1, ipl2)) {
+ puts("Cannot read IPL2 record at block 1");
+ return -EIO;
+ }
mbr = &ipl2->mbr;
if (!magic_match(mbr, ZIPL_MAGIC)) {
- sclp_print("No zIPL section in IPL2 record.\n");
- return;
+ puts("No zIPL section in IPL2 record.");
+ return 0;
}
if (!block_size_ok(mbr->blockptr.xeckd.bptr.size)) {
- sclp_print("Bad block size in zIPL section of IPL2 record.\n");
- return;
+ puts("Bad block size in zIPL section of IPL2 record.");
+ return 0;
}
if (mbr->dev_type != DEV_TYPE_ECKD) {
- sclp_print("Non-ECKD device type in zIPL section of IPL2 record.\n");
- return;
+ puts("Non-ECKD device type in zIPL section of IPL2 record.");
+ return 0;
}
/* save pointer to Boot Map Table */
@@ -364,19 +428,21 @@ static void ipl_eckd_cdl(void)
s1b_block_nr = eckd_block_num(&ipl2->stage1.seek[0].chs);
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
- read_block(2, vlbl, "Cannot read Volume Label at block 2");
+ if (virtio_read(2, vlbl)) {
+ puts("Cannot read Volume Label at block 2");
+ return -EIO;
+ }
if (!magic_match(vlbl->key, VOL1_MAGIC)) {
- sclp_print("Invalid magic of volume label block.\n");
- return;
+ puts("Invalid magic of volume label block.");
+ return 0;
}
if (!magic_match(vlbl->f.key, VOL1_MAGIC)) {
- sclp_print("Invalid magic of volser block.\n");
- return;
+ puts("Invalid magic of volser block.");
+ return 0;
}
print_volser(vlbl->f.volser);
- run_eckd_boot_script(bmt_block_nr, s1b_block_nr);
- /* no return */
+ return run_eckd_boot_script(bmt_block_nr, s1b_block_nr);
}
static void print_eckd_ldl_msg(ECKD_IPL_mode_t mode)
@@ -384,8 +450,8 @@ static void print_eckd_ldl_msg(ECKD_IPL_mode_t mode)
LDL_VTOC *vlbl = (void *)sec; /* already read, 3rd block */
char msg[4] = { '?', '.', '\n', '\0' };
- sclp_print((mode == ECKD_CMS) ? "CMS" : "LDL");
- sclp_print(" version ");
+ printf((mode == ECKD_CMS) ? "CMS" : "LDL");
+ printf(" version ");
switch (vlbl->LDL_version) {
case LDL1_VERSION:
msg[0] = '1';
@@ -398,11 +464,11 @@ static void print_eckd_ldl_msg(ECKD_IPL_mode_t mode)
msg[1] = '?';
break;
}
- sclp_print(msg);
+ printf("%s", msg);
print_volser(vlbl->volser);
}
-static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
+static int ipl_eckd_ldl(ECKD_IPL_mode_t mode)
{
block_number_t bmt_block_nr, s1b_block_nr;
EckdLdlIpl1 *ipl1 = (void *)sec;
@@ -414,12 +480,15 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
/* DO NOT read BootMap pointer (only one, xECKD) at block #2 */
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
- read_block(0, sec, "Cannot read block 0 to grab boot info.");
+ if (virtio_read(0, sec)) {
+ puts("Cannot read block 0 to grab boot info.");
+ return -EIO;
+ }
if (mode == ECKD_LDL_UNLABELED) {
if (!magic_match(ipl1->bip.magic, ZIPL_MAGIC)) {
- return; /* not applicable layout */
+ return 0; /* not applicable layout */
}
- sclp_print("unlabeled LDL.\n");
+ puts("unlabeled LDL.");
}
verify_boot_info(&ipl1->bip);
@@ -429,8 +498,7 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode)
/* save pointer to Stage1b Data */
s1b_block_nr = eckd_block_num(&ipl1->stage1.seek[0].chs);
- run_eckd_boot_script(bmt_block_nr, s1b_block_nr);
- /* no return */
+ return run_eckd_boot_script(bmt_block_nr, s1b_block_nr);
}
static block_number_t eckd_find_bmt(ExtEckdBlockPtr *ptr)
@@ -440,7 +508,10 @@ static block_number_t eckd_find_bmt(ExtEckdBlockPtr *ptr)
BootRecord *br;
blockno = gen_eckd_block_num(ptr, 0);
- read_block(blockno, tmp_sec, "Cannot read boot record");
+ if (virtio_read(blockno, tmp_sec)) {
+ puts("Cannot read boot record");
+ return ERROR_BLOCK_NR;
+ }
br = (BootRecord *)tmp_sec;
if (!magic_match(br->magic, ZIPL_MAGIC)) {
/* If the boot record is invalid, return and try CCW-IPL instead */
@@ -466,10 +537,10 @@ static void print_eckd_msg(void)
*p-- = ' ';
}
}
- sclp_print(msg);
+ printf("%s", msg);
}
-static void ipl_eckd(void)
+static int ipl_eckd(void)
{
IplVolumeLabel *vlbl = (void *)sec;
LDL_VTOC *vtoc = (void *)sec;
@@ -479,7 +550,10 @@ static void ipl_eckd(void)
/* Block 2 can contain either the CDL VOL1 label or the LDL VTOC */
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
- read_block(2, vlbl, "Cannot read block 2");
+ if (virtio_read(2, vlbl)) {
+ puts("Cannot read block 2");
+ return -EIO;
+ }
/*
* First check for a list-directed-format pointer which would
@@ -487,43 +561,60 @@ static void ipl_eckd(void)
*/
if (eckd_valid_address((ExtEckdBlockPtr *)&vlbl->f.br, 0)) {
ldipl_bmt = eckd_find_bmt((ExtEckdBlockPtr *)&vlbl->f.br);
- if (ldipl_bmt) {
- sclp_print("List-Directed\n");
- /* LD-IPL does not use the S1B bock, just make it NULL */
- run_eckd_boot_script(ldipl_bmt, NULL_BLOCK_NR);
- /* Only return in error, retry as CCW-IPL */
- sclp_print("Retrying IPL ");
+ switch (ldipl_bmt) {
+ case ERROR_BLOCK_NR:
+ return -EIO;
+ case NULL_BLOCK_NR:
+ break; /* Invalid BMT but the device may still boot with CCW-IPL */
+ default:
+ puts("List-Directed");
+ /*
+ * LD-IPL does not use the S1B bock, just make it NULL_BLOCK_NR.
+ * In some failure cases retry IPL before aborting.
+ */
+ if (run_eckd_boot_script(ldipl_bmt, NULL_BLOCK_NR)) {
+ return -EIO;
+ }
+ /* Non-fatal error, retry as CCW-IPL */
+ printf("Retrying IPL ");
print_eckd_msg();
}
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
- read_block(2, vtoc, "Cannot read block 2");
+ if (virtio_read(2, vtoc)) {
+ puts("Cannot read block 2");
+ return -EIO;
+ }
}
/* Not list-directed */
if (magic_match(vtoc->magic, VOL1_MAGIC)) {
- ipl_eckd_cdl(); /* may return in error */
+ if (ipl_eckd_cdl()) {
+ return -1;
+ }
}
if (magic_match(vtoc->magic, CMS1_MAGIC)) {
- ipl_eckd_ldl(ECKD_CMS); /* no return */
+ return ipl_eckd_ldl(ECKD_CMS);
}
if (magic_match(vtoc->magic, LNX1_MAGIC)) {
- ipl_eckd_ldl(ECKD_LDL); /* no return */
+ return ipl_eckd_ldl(ECKD_LDL);
}
- ipl_eckd_ldl(ECKD_LDL_UNLABELED); /* it still may return */
+ if (ipl_eckd_ldl(ECKD_LDL_UNLABELED)) {
+ return -1;
+ }
/*
* Ok, it is not a LDL by any means.
* It still might be a CDL with zero record keys for IPL1 and IPL2
*/
- ipl_eckd_cdl();
+ return ipl_eckd_cdl();
}
/***********************************************************************
* IPL a SCSI disk
*/
-static void zipl_load_segment(ComponentEntry *entry)
+static int zipl_load_segment(ComponentEntry *entry)
{
const int max_entries = (MAX_SECTOR_SIZE / sizeof(ScsiBlockPtr));
ScsiBlockPtr *bprs = (void *)sec;
@@ -543,7 +634,10 @@ static void zipl_load_segment(ComponentEntry *entry)
do {
memset(bprs, FREE_SPACE_FILLER, bprs_size);
fill_hex_val(blk_no, &blockno, sizeof(blockno));
- read_block(blockno, bprs, err_msg);
+ if (virtio_read(blockno, bprs)) {
+ puts(err_msg);
+ return -EIO;
+ }
for (i = 0;; i++) {
uint64_t *cur_desc = (void *)&bprs[i];
@@ -571,23 +665,37 @@ static void zipl_load_segment(ComponentEntry *entry)
}
address = virtio_load_direct(cur_desc[0], cur_desc[1], 0,
(void *)address);
- IPL_assert(address != -1, "zIPL load segment failed");
+ if (!address) {
+ puts("zIPL load segment failed");
+ return -EIO;
+ }
}
} while (blockno);
+
+ return 0;
}
/* Run a zipl program */
-static void zipl_run(ScsiBlockPtr *pte)
+static int zipl_run(ScsiBlockPtr *pte)
{
ComponentHeader *header;
ComponentEntry *entry;
uint8_t tmp_sec[MAX_SECTOR_SIZE];
- read_block(pte->blockno, tmp_sec, "Cannot read header");
+ if (virtio_read(pte->blockno, tmp_sec)) {
+ puts("Cannot read header");
+ return -EIO;
+ }
header = (ComponentHeader *)tmp_sec;
- IPL_assert(magic_match(tmp_sec, ZIPL_MAGIC), "No zIPL magic in header");
- IPL_assert(header->type == ZIPL_COMP_HEADER_IPL, "Bad header type");
+ if (!magic_match(tmp_sec, ZIPL_MAGIC)) {
+ puts("No zIPL magic in header");
+ return -EINVAL;
+ }
+ if (header->type != ZIPL_COMP_HEADER_IPL) {
+ puts("Bad header type");
+ return -EINVAL;
+ }
dputs("start loading images\n");
@@ -602,22 +710,30 @@ static void zipl_run(ScsiBlockPtr *pte)
continue;
}
- zipl_load_segment(entry);
+ if (zipl_load_segment(entry)) {
+ return -1;
+ }
entry++;
- IPL_assert((uint8_t *)(&entry[1]) <= (tmp_sec + MAX_SECTOR_SIZE),
- "Wrong entry value");
+ if ((uint8_t *)(&entry[1]) > (tmp_sec + MAX_SECTOR_SIZE)) {
+ puts("Wrong entry value");
+ return -EINVAL;
+ }
}
- IPL_assert(entry->component_type == ZIPL_COMP_ENTRY_EXEC, "No EXEC entry");
+ if (entry->component_type != ZIPL_COMP_ENTRY_EXEC) {
+ puts("No EXEC entry");
+ return -EINVAL;
+ }
/* should not return */
write_reset_psw(entry->compdat.load_psw);
jump_to_IPL_code(0);
+ return -1;
}
-static void ipl_scsi(void)
+static int ipl_scsi(void)
{
ScsiMbr *mbr = (void *)sec;
int program_table_entries = 0;
@@ -628,22 +744,34 @@ static void ipl_scsi(void)
/* Grab the MBR */
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
- read_block(0, mbr, "Cannot read block 0");
+ if (virtio_read(0, mbr)) {
+ puts("Cannot read block 0");
+ return -EIO;
+ }
if (!magic_match(mbr->magic, ZIPL_MAGIC)) {
- return;
+ return 0;
}
- sclp_print("Using SCSI scheme.\n");
+ puts("Using SCSI scheme.");
debug_print_int("MBR Version", mbr->version_id);
IPL_check(mbr->version_id == 1,
"Unknown MBR layout version, assuming version 1");
debug_print_int("program table", mbr->pt.blockno);
- IPL_assert(mbr->pt.blockno, "No Program Table");
+ if (!mbr->pt.blockno) {
+ puts("No Program Table");
+ return -EINVAL;
+ }
/* Parse the program table */
- read_block(mbr->pt.blockno, sec, "Error reading Program Table");
- IPL_assert(magic_match(sec, ZIPL_MAGIC), "No zIPL magic in PT");
+ if (virtio_read(mbr->pt.blockno, sec)) {
+ puts("Error reading Program Table");
+ return -EIO;
+ }
+ if (!magic_match(sec, ZIPL_MAGIC)) {
+ puts("No zIPL magic in Program Table");
+ return -EINVAL;
+ }
for (i = 0; i < MAX_BOOT_ENTRIES; i++) {
if (prog_table->entry[i].scsi.blockno) {
@@ -653,17 +781,22 @@ static void ipl_scsi(void)
}
debug_print_int("program table entries", program_table_entries);
- IPL_assert(program_table_entries != 0, "Empty Program Table");
+ if (program_table_entries == 0) {
+ puts("Empty Program Table");
+ return -EINVAL;
+ }
if (menu_is_enabled_enum()) {
loadparm = menu_get_enum_boot_index(valid_entries);
}
debug_print_int("loadparm", loadparm);
- IPL_assert(loadparm < MAX_BOOT_ENTRIES, "loadparm value greater than"
- " maximum number of boot entries allowed");
+ if (loadparm >= MAX_BOOT_ENTRIES) {
+ puts("loadparm value greater than max number of boot entries allowed");
+ return -EINVAL;
+ }
- zipl_run(&prog_table->entry[loadparm].scsi); /* no return */
+ return zipl_run(&prog_table->entry[loadparm].scsi);
}
/***********************************************************************
@@ -677,8 +810,10 @@ static bool is_iso_bc_entry_compatible(IsoBcSection *s)
if (s->unused || !s->sector_count) {
return false;
}
- read_iso_sector(bswap32(s->load_rba), magic_sec,
- "Failed to read image sector 0");
+ if (virtio_read(bswap32(s->load_rba), magic_sec)) {
+ puts("Failed to read image sector 0");
+ return false;
+ }
/* Checking bytes 8 - 32 for S390 Linux magic */
return !memcmp(magic_sec + 8, linux_s390_magic, 24);
@@ -691,28 +826,35 @@ static uint32_t sec_offset[ISO9660_MAX_DIR_DEPTH];
/* Remained directory space in bytes */
static uint32_t dir_rem[ISO9660_MAX_DIR_DEPTH];
-static inline uint32_t iso_get_file_size(uint32_t load_rba)
+static inline long iso_get_file_size(uint32_t load_rba)
{
IsoVolDesc *vd = (IsoVolDesc *)sec;
IsoDirHdr *cur_record = &vd->vd.primary.rootdir;
uint8_t *temp = sec + ISO_SECTOR_SIZE;
int level = 0;
- read_iso_sector(ISO_PRIMARY_VD_SECTOR, sec,
- "Failed to read ISO primary descriptor");
+ if (virtio_read(ISO_PRIMARY_VD_SECTOR, sec)) {
+ puts("Failed to read ISO primary descriptor");
+ return -EIO;
+ }
+
sec_loc[0] = iso_733_to_u32(cur_record->ext_loc);
dir_rem[0] = 0;
sec_offset[0] = 0;
while (level >= 0) {
- IPL_assert(sec_offset[level] <= ISO_SECTOR_SIZE,
- "Directory tree structure violation");
+ if (sec_offset[level] > ISO_SECTOR_SIZE) {
+ puts("Directory tree structure violation");
+ return -EIO;
+ }
cur_record = (IsoDirHdr *)(temp + sec_offset[level]);
if (sec_offset[level] == 0) {
- read_iso_sector(sec_loc[level], temp,
- "Failed to read ISO directory");
+ if (virtio_read(sec_loc[level], temp)) {
+ puts("Failed to read ISO directory");
+ return -EIO;
+ }
if (dir_rem[level] == 0) {
/* Skip self and parent records */
dir_rem[level] = iso_733_to_u32(cur_record->data_len) -
@@ -743,7 +885,7 @@ static inline uint32_t iso_get_file_size(uint32_t load_rba)
if (cur_record->file_flags & 0x2) {
/* Subdirectory */
if (level == ISO9660_MAX_DIR_DEPTH - 1) {
- sclp_print("ISO-9660 directory depth limit exceeded\n");
+ puts("ISO-9660 directory depth limit exceeded");
} else {
level++;
sec_loc[level] = iso_733_to_u32(cur_record->ext_loc);
@@ -757,8 +899,10 @@ static inline uint32_t iso_get_file_size(uint32_t load_rba)
if (dir_rem[level] == 0) {
/* Nothing remaining */
level--;
- read_iso_sector(sec_loc[level], temp,
- "Failed to read ISO directory");
+ if (virtio_read(sec_loc[level], temp)) {
+ puts("Failed to read ISO directory");
+ return -EIO;
+ }
}
}
@@ -773,19 +917,24 @@ static void load_iso_bc_entry(IsoBcSection *load)
* is padded and ISO_SECTOR_SIZE bytes aligned
*/
uint32_t blks_to_load = bswap16(s.sector_count) >> ET_SECTOR_SHIFT;
- uint32_t real_size = iso_get_file_size(bswap32(s.load_rba));
+ long real_size = iso_get_file_size(bswap32(s.load_rba));
- if (real_size) {
+ if (real_size > 0) {
/* Round up blocks to load */
blks_to_load = (real_size + ISO_SECTOR_SIZE - 1) / ISO_SECTOR_SIZE;
- sclp_print("ISO boot image size verified\n");
+ puts("ISO boot image size verified");
} else {
- sclp_print("ISO boot image size could not be verified\n");
+ puts("ISO boot image size could not be verified");
+ if (real_size < 0) {
+ return;
+ }
}
- read_iso_boot_image(bswap32(s.load_rba),
+ if (read_iso_boot_image(bswap32(s.load_rba),
(void *)((uint64_t)bswap16(s.load_segment)),
- blks_to_load);
+ blks_to_load)) {
+ return;
+ }
jump_to_low_kernel();
}
@@ -808,17 +957,18 @@ static uint32_t find_iso_bc(void)
return bswap32(et->bc_offset);
}
}
- read_iso_sector(block_num++, sec,
- "Failed to read ISO volume descriptor");
+ if (virtio_read(block_num++, sec)) {
+ puts("Failed to read ISO volume descriptor");
+ return 0;
+ }
}
return 0;
}
-static IsoBcSection *find_iso_bc_entry(void)
+static IsoBcSection *find_iso_bc_entry(uint32_t offset)
{
IsoBcEntry *e = (IsoBcEntry *)sec;
- uint32_t offset = find_iso_bc();
int i;
unsigned int loadparm = get_loadparm_index();
@@ -826,11 +976,13 @@ static IsoBcSection *find_iso_bc_entry(void)
return NULL;
}
- read_iso_sector(offset, sec, "Failed to read El Torito boot catalog");
+ if (virtio_read(offset, sec)) {
+ puts("Failed to read El Torito boot catalog");
+ return NULL;
+ }
if (!is_iso_bc_valid(e)) {
/* The validation entry is mandatory */
- panic("No valid boot catalog found!\n");
return NULL;
}
@@ -850,19 +1002,25 @@ static IsoBcSection *find_iso_bc_entry(void)
}
}
- panic("No suitable boot entry found on ISO-9660 media!\n");
-
return NULL;
}
-static void ipl_iso_el_torito(void)
+static int ipl_iso_el_torito(void)
{
- IsoBcSection *s = find_iso_bc_entry();
+ uint32_t offset = find_iso_bc();
+ if (!offset) {
+ return 0;
+ }
+
+ IsoBcSection *s = find_iso_bc_entry(offset);
if (s) {
- load_iso_bc_entry(s);
- /* no return */
+ load_iso_bc_entry(s); /* only return in error */
+ return -1;
}
+
+ puts("No suitable boot entry found on ISO-9660 media!");
+ return -EIO;
}
/**
@@ -884,7 +1042,7 @@ static bool has_iso_signature(void)
* Bus specific IPL sequences
*/
-static void zipl_load_vblk(void)
+static int zipl_load_vblk(void)
{
int blksize = virtio_get_block_size();
@@ -892,26 +1050,30 @@ static void zipl_load_vblk(void)
if (blksize != VIRTIO_ISO_BLOCK_SIZE) {
virtio_assume_iso9660();
}
- ipl_iso_el_torito();
+ if (ipl_iso_el_torito()) {
+ return 0;
+ }
}
if (blksize != VIRTIO_DASD_DEFAULT_BLOCK_SIZE) {
- sclp_print("Using guessed DASD geometry.\n");
+ puts("Using guessed DASD geometry.");
virtio_assume_eckd();
}
- ipl_eckd();
+ return ipl_eckd();
}
-static void zipl_load_vscsi(void)
+static int zipl_load_vscsi(void)
{
if (virtio_get_block_size() == VIRTIO_ISO_BLOCK_SIZE) {
/* Is it an ISO image in non-CD drive? */
- ipl_iso_el_torito();
+ if (ipl_iso_el_torito()) {
+ return 0;
+ }
}
- sclp_print("Using guessed DASD geometry.\n");
+ puts("Using guessed DASD geometry.");
virtio_assume_eckd();
- ipl_eckd();
+ return ipl_eckd();
}
/***********************************************************************
@@ -924,14 +1086,20 @@ void zipl_load(void)
if (vdev->is_cdrom) {
ipl_iso_el_torito();
- panic("\n! Cannot IPL this ISO image !\n");
+ puts("Failed to IPL this ISO image!");
+ return;
}
if (virtio_get_device_type() == VIRTIO_ID_NET) {
- jump_to_IPL_code(vdev->netboot_start_addr);
+ netmain();
+ puts("Failed to IPL from this network!");
+ return;
}
- ipl_scsi();
+ if (ipl_scsi()) {
+ puts("Failed to IPL from this SCSI device!");
+ return;
+ }
switch (virtio_get_device_type()) {
case VIRTIO_ID_BLOCK:
@@ -941,8 +1109,9 @@ void zipl_load(void)
zipl_load_vscsi();
break;
default:
- panic("\n! Unknown IPL device type !\n");
+ puts("Unknown IPL device type!");
+ return;
}
- sclp_print("zIPL load failed.\n");
+ puts("zIPL load failed!");
}
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index d4690a8..9594344 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -16,6 +16,7 @@
typedef uint64_t block_number_t;
#define NULL_BLOCK_NR 0xffffffffffffffffULL
+#define ERROR_BLOCK_NR 0xfffffffffffffffeULL
#define FREE_SPACE_FILLER '\xAA'
@@ -336,9 +337,7 @@ static inline void print_volser(const void *volser)
ebcdic_to_ascii((char *)volser, ascii, 6);
ascii[6] = '\0';
- sclp_print("VOLSER=[");
- sclp_print(ascii);
- sclp_print("]\n");
+ printf("VOLSER=[%s]\n", ascii);
}
static inline bool unused_space(const void *p, size_t size)
@@ -387,17 +386,14 @@ static inline uint32_t iso_733_to_u32(uint64_t x)
#define ISO_PRIMARY_VD_SECTOR 16
-static inline void read_iso_sector(uint32_t block_offset, void *buf,
- const char *errmsg)
-{
- IPL_assert(virtio_read_many(block_offset, buf, 1) == 0, errmsg);
-}
-
-static inline void read_iso_boot_image(uint32_t block_offset, void *load_addr,
+static inline int read_iso_boot_image(uint32_t block_offset, void *load_addr,
uint32_t blks_to_load)
{
- IPL_assert(virtio_read_many(block_offset, load_addr, blks_to_load) == 0,
- "Failed to read boot image!");
+ if (virtio_read_many(block_offset, load_addr, blks_to_load)) {
+ puts("Failed to read boot image!");
+ return -1;
+ }
+ return 0;
}
#define ISO9660_MAX_DIR_DEPTH 8
diff --git a/pc-bios/s390-ccw/cio.c b/pc-bios/s390-ccw/cio.c
index 83ca27a..5d543da 100644
--- a/pc-bios/s390-ccw/cio.c
+++ b/pc-bios/s390-ccw/cio.c
@@ -11,7 +11,8 @@
* directory.
*/
-#include "libc.h"
+#include <string.h>
+#include <stdio.h>
#include "s390-ccw.h"
#include "s390-arch.h"
#include "helper.h"
@@ -58,7 +59,8 @@ uint16_t cu_type(SubChannelId schid)
};
if (do_cio(schid, CU_TYPE_UNKNOWN, ptr2u32(&sense_id_ccw), CCW_FMT1)) {
- panic("Failed to run SenseID CCw\n");
+ puts("Failed to run SenseID CCW");
+ return CU_TYPE_UNKNOWN;
}
return sense_data.cu_type;
@@ -90,9 +92,9 @@ static void print_eckd_dasd_sense_data(SenseDataEckdDasd *sd)
char msgline[512];
if (sd->config_info & 0x8000) {
- sclp_print("Eckd Dasd Sense Data (fmt 24-bytes):\n");
+ puts("Eckd Dasd Sense Data (fmt 24-bytes):");
} else {
- sclp_print("Eckd Dasd Sense Data (fmt 32-bytes):\n");
+ puts("Eckd Dasd Sense Data (fmt 32-bytes):");
}
strcat(msgline, " Sense Condition Flags :");
@@ -158,22 +160,21 @@ static void print_eckd_dasd_sense_data(SenseDataEckdDasd *sd)
if (sd->status[1] & SNS_STAT2_IMPRECISE_END) {
strcat(msgline, " [Imprecise-End]");
}
- strcat(msgline, "\n");
- sclp_print(msgline);
-
- print_int(" Residual Count =", sd->res_count);
- print_int(" Phys Drive ID =", sd->phys_drive_id);
- print_int(" low cyl address =", sd->low_cyl_addr);
- print_int(" head addr & hi cyl =", sd->head_high_cyl_addr);
- print_int(" format/message =", sd->fmt_msg);
- print_int(" fmt-dependent[0-7] =", sd->fmt_dependent_info[0]);
- print_int(" fmt-dependent[8-15]=", sd->fmt_dependent_info[1]);
- print_int(" prog action code =", sd->program_action_code);
- print_int(" Configuration info =", sd->config_info);
- print_int(" mcode / hi-cyl =", sd->mcode_hicyl);
- print_int(" cyl & head addr [0]=", sd->cyl_head_addr[0]);
- print_int(" cyl & head addr [1]=", sd->cyl_head_addr[1]);
- print_int(" cyl & head addr [2]=", sd->cyl_head_addr[2]);
+ puts(msgline);
+
+ printf(" Residual Count = 0x%X\n", sd->res_count);
+ printf(" Phys Drive ID = 0x%X\n", sd->phys_drive_id);
+ printf(" low cyl address = 0x%X\n", sd->low_cyl_addr);
+ printf(" head addr & hi cyl = 0x%X\n", sd->head_high_cyl_addr);
+ printf(" format/message = 0x%X\n", sd->fmt_msg);
+ printf(" fmt-dependent[0-7] = 0x%llX\n", sd->fmt_dependent_info[0]);
+ printf(" fmt-dependent[8-15]= 0x%llX\n", sd->fmt_dependent_info[1]);
+ printf(" prog action code = 0x%X\n", sd->program_action_code);
+ printf(" Configuration info = 0x%X\n", sd->config_info);
+ printf(" mcode / hi-cyl = 0x%X\n", sd->mcode_hicyl);
+ printf(" cyl & head addr [0]= 0x%X\n", sd->cyl_head_addr[0]);
+ printf(" cyl & head addr [1]= 0x%X\n", sd->cyl_head_addr[1]);
+ printf(" cyl & head addr [2]= 0x%X\n", sd->cyl_head_addr[2]);
}
static void print_irb_err(Irb *irb)
@@ -182,7 +183,7 @@ static void print_irb_err(Irb *irb)
uint64_t prev_ccw = *(uint64_t *)u32toptr(irb->scsw.cpa - 8);
char msgline[256];
- sclp_print("Interrupt Response Block Data:\n");
+ puts("Interrupt Response Block Data:");
strcat(msgline, " Function Ctrl :");
if (irb->scsw.ctrl & SCSW_FCTL_START_FUNC) {
@@ -194,8 +195,7 @@ static void print_irb_err(Irb *irb)
if (irb->scsw.ctrl & SCSW_FCTL_CLEAR_FUNC) {
strcat(msgline, " [Clear]");
}
- strcat(msgline, "\n");
- sclp_print(msgline);
+ puts(msgline);
msgline[0] = '\0';
strcat(msgline, " Activity Ctrl :");
@@ -220,8 +220,7 @@ static void print_irb_err(Irb *irb)
if (irb->scsw.ctrl & SCSW_ACTL_SUSPENDED) {
strcat(msgline, " [Suspended]");
}
- strcat(msgline, "\n");
- sclp_print(msgline);
+ puts(msgline);
msgline[0] = '\0';
strcat(msgline, " Status Ctrl :");
@@ -240,9 +239,7 @@ static void print_irb_err(Irb *irb)
if (irb->scsw.ctrl & SCSW_SCTL_STATUS_PEND) {
strcat(msgline, " [Status-Pending]");
}
-
- strcat(msgline, "\n");
- sclp_print(msgline);
+ puts(msgline);
msgline[0] = '\0';
strcat(msgline, " Device Status :");
@@ -270,8 +267,7 @@ static void print_irb_err(Irb *irb)
if (irb->scsw.dstat & SCSW_DSTAT_UEXCP) {
strcat(msgline, " [Unit-Exception]");
}
- strcat(msgline, "\n");
- sclp_print(msgline);
+ puts(msgline);
msgline[0] = '\0';
strcat(msgline, " Channel Status :");
@@ -299,12 +295,11 @@ static void print_irb_err(Irb *irb)
if (irb->scsw.cstat & SCSW_CSTAT_CHAINCHK) {
strcat(msgline, " [Chaining-Check]");
}
- strcat(msgline, "\n");
- sclp_print(msgline);
+ puts(msgline);
- print_int(" cpa=", irb->scsw.cpa);
- print_int(" prev_ccw=", prev_ccw);
- print_int(" this_ccw=", this_ccw);
+ printf(" cpa= 0x%X\n", irb->scsw.cpa);
+ printf(" prev_ccw= 0x%llX\n", prev_ccw);
+ printf(" this_ccw= 0x%llX\n", this_ccw);
}
/*
@@ -341,7 +336,7 @@ static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb)
return -1;
}
if (rc) {
- print_int("ssch failed with cc=", rc);
+ printf("ssch failed with cc= 0x%x\n", rc);
return rc;
}
@@ -350,7 +345,7 @@ static int __do_cio(SubChannelId schid, uint32_t ccw_addr, int fmt, Irb *irb)
/* collect status */
rc = tsch(schid, irb);
if (rc) {
- print_int("tsch failed with cc=", rc);
+ printf("tsch failed with cc= 0x%X\n", rc);
}
return rc;
@@ -406,12 +401,12 @@ int do_cio(SubChannelId schid, uint16_t cutype, uint32_t ccw_addr, int fmt)
continue;
}
- sclp_print("cio device error\n");
- print_int(" ssid ", schid.ssid);
- print_int(" cssid ", schid.cssid);
- print_int(" sch_no", schid.sch_no);
- print_int(" ctrl-unit type", cutype);
- sclp_print("\n");
+ printf("cio device error\n");
+ printf(" ssid 0x%X\n", schid.ssid);
+ printf(" cssid 0x%X\n", schid.cssid);
+ printf(" sch_no 0x%X\n", schid.sch_no);
+ printf(" ctrl-unit type 0x%X\n", cutype);
+ printf("\n");
print_irb_err(&irb);
if (cutype == CU_TYPE_DASD_3990 || cutype == CU_TYPE_DASD_2107 ||
cutype == CU_TYPE_UNKNOWN) {
diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h
index 8b18153..6a5e86b 100644
--- a/pc-bios/s390-ccw/cio.h
+++ b/pc-bios/s390-ccw/cio.h
@@ -361,6 +361,8 @@ typedef struct CcwSearchIdData {
uint8_t record;
} __attribute__((packed)) CcwSearchIdData;
+extern SubChannelId net_schid;
+
int enable_mss_facility(void);
void enable_subchannel(SubChannelId schid);
uint16_t cu_type(SubChannelId schid);
diff --git a/pc-bios/s390-ccw/dasd-ipl.c b/pc-bios/s390-ccw/dasd-ipl.c
index 254bb1a..babece9 100644
--- a/pc-bios/s390-ccw/dasd-ipl.c
+++ b/pc-bios/s390-ccw/dasd-ipl.c
@@ -8,7 +8,8 @@
* directory.
*/
-#include "libc.h"
+#include <string.h>
+#include <stdio.h>
#include "s390-ccw.h"
#include "s390-arch.h"
#include "dasd-ipl.h"
@@ -82,7 +83,7 @@ static int run_dynamic_ccw_program(SubChannelId schid, uint16_t cutype,
do {
has_next = dynamic_cp_fixup(cpa, &next_cpa);
- print_int("executing ccw chain at ", cpa);
+ printf("executing ccw chain at 0x%X\n", cpa);
enable_prefixing();
rc = do_cio(schid, cutype, cpa, CCW_FMT0);
disable_prefixing();
@@ -110,38 +111,29 @@ static void make_readipl(void)
ccwIplRead->count = 0x18; /* Read 0x18 bytes of data */
}
-static void run_readipl(SubChannelId schid, uint16_t cutype)
+static int run_readipl(SubChannelId schid, uint16_t cutype)
{
- if (do_cio(schid, cutype, 0x00, CCW_FMT0)) {
- panic("dasd-ipl: Failed to run Read IPL channel program\n");
- }
+ return do_cio(schid, cutype, 0x00, CCW_FMT0);
}
/*
* The architecture states that IPL1 data should consist of a psw followed by
* format-0 READ and TIC CCWs. Let's sanity check.
*/
-static void check_ipl1(void)
+static bool check_ipl1(void)
{
Ccw0 *ccwread = (Ccw0 *)0x08;
Ccw0 *ccwtic = (Ccw0 *)0x10;
- if (ccwread->cmd_code != CCW_CMD_DASD_READ ||
- ccwtic->cmd_code != CCW_CMD_TIC) {
- panic("dasd-ipl: IPL1 data invalid. Is this disk really bootable?\n");
- }
+ return (ccwread->cmd_code == CCW_CMD_DASD_READ &&
+ ccwtic->cmd_code == CCW_CMD_TIC);
}
-static void check_ipl2(uint32_t ipl2_addr)
+static bool check_ipl2(uint32_t ipl2_addr)
{
Ccw0 *ccw = u32toptr(ipl2_addr);
- if (ipl2_addr == 0x00) {
- panic("IPL2 address invalid. Is this disk really bootable?\n");
- }
- if (ccw->cmd_code == 0x00) {
- panic("IPL2 ccw data invalid. Is this disk really bootable?\n");
- }
+ return (ipl2_addr != 0x00 && ccw->cmd_code != 0x00);
}
static uint32_t read_ipl2_addr(void)
@@ -187,52 +179,67 @@ static void ipl1_fixup(void)
ccwSearchTic->cda = ptr2u32(ccwSearchID);
}
-static void run_ipl1(SubChannelId schid, uint16_t cutype)
+static int run_ipl1(SubChannelId schid, uint16_t cutype)
{
uint32_t startAddr = 0x08;
- if (do_cio(schid, cutype, startAddr, CCW_FMT0)) {
- panic("dasd-ipl: Failed to run IPL1 channel program\n");
- }
+ return do_cio(schid, cutype, startAddr, CCW_FMT0);
}
-static void run_ipl2(SubChannelId schid, uint16_t cutype, uint32_t addr)
+static int run_ipl2(SubChannelId schid, uint16_t cutype, uint32_t addr)
{
- if (run_dynamic_ccw_program(schid, cutype, addr)) {
- panic("dasd-ipl: Failed to run IPL2 channel program\n");
- }
+ return run_dynamic_ccw_program(schid, cutype, addr);
}
/*
* Limitations in vfio-ccw support complicate the IPL process. Details can
* be found in docs/devel/s390-dasd-ipl.rst
*/
-void dasd_ipl(SubChannelId schid, uint16_t cutype)
+int dasd_ipl(SubChannelId schid, uint16_t cutype)
{
PSWLegacy *pswl = (PSWLegacy *) 0x00;
uint32_t ipl2_addr;
/* Construct Read IPL CCW and run it to read IPL1 from boot disk */
make_readipl();
- run_readipl(schid, cutype);
+ if (run_readipl(schid, cutype)) {
+ puts("Failed to run Read IPL channel program");
+ return -EIO;
+ }
+
ipl2_addr = read_ipl2_addr();
- check_ipl1();
+
+ if (!check_ipl1()) {
+ puts("IPL1 invalid for DASD-IPL");
+ return -EINVAL;
+ }
/*
* Fixup IPL1 channel program to account for vfio-ccw limitations, then run
* it to read IPL2 channel program from boot disk.
*/
ipl1_fixup();
- run_ipl1(schid, cutype);
- check_ipl2(ipl2_addr);
+ if (run_ipl1(schid, cutype)) {
+ puts("Failed to run IPL1 channel program");
+ return -EIO;
+ }
+
+ if (!check_ipl2(ipl2_addr)) {
+ puts("IPL2 invalid for DASD-IPL");
+ return -EINVAL;
+ }
/*
* Run IPL2 channel program to read operating system code from boot disk
*/
- run_ipl2(schid, cutype, ipl2_addr);
+ if (run_ipl2(schid, cutype, ipl2_addr)) {
+ puts("Failed to run IPL2 channel program");
+ return -EIO;
+ }
/* Transfer control to the guest operating system */
pswl->mask |= PSW_MASK_EAMODE; /* Force z-mode */
pswl->addr |= PSW_MASK_BAMODE; /* ... */
jump_to_low_kernel();
+ return -1;
}
diff --git a/pc-bios/s390-ccw/dasd-ipl.h b/pc-bios/s390-ccw/dasd-ipl.h
index c394828..eb1898c 100644
--- a/pc-bios/s390-ccw/dasd-ipl.h
+++ b/pc-bios/s390-ccw/dasd-ipl.h
@@ -11,6 +11,6 @@
#ifndef DASD_IPL_H
#define DASD_IPL_H
-void dasd_ipl(SubChannelId schid, uint16_t cutype);
+int dasd_ipl(SubChannelId schid, uint16_t cutype);
#endif /* DASD_IPL_H */
diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h
index cb6ac8a..08f259f 100644
--- a/pc-bios/s390-ccw/iplb.h
+++ b/pc-bios/s390-ccw/iplb.h
@@ -12,88 +12,16 @@
#ifndef IPLB_H
#define IPLB_H
-#define LOADPARM_LEN 8
-
-struct IplBlockCcw {
- uint8_t reserved0[85];
- uint8_t ssid;
- uint16_t devno;
- uint8_t vm_flags;
- uint8_t reserved3[3];
- uint32_t vm_parm_len;
- uint8_t nss_name[8];
- uint8_t vm_parm[64];
- uint8_t reserved4[8];
-} __attribute__ ((packed));
-typedef struct IplBlockCcw IplBlockCcw;
-
-struct IplBlockFcp {
- uint8_t reserved1[305 - 1];
- uint8_t opt;
- uint8_t reserved2[3];
- uint16_t reserved3;
- uint16_t devno;
- uint8_t reserved4[4];
- uint64_t wwpn;
- uint64_t lun;
- uint32_t bootprog;
- uint8_t reserved5[12];
- uint64_t br_lba;
- uint32_t scp_data_len;
- uint8_t reserved6[260];
- uint8_t scp_data[];
-} __attribute__ ((packed));
-typedef struct IplBlockFcp IplBlockFcp;
-
-struct IplBlockQemuScsi {
- uint32_t lun;
- uint16_t target;
- uint16_t channel;
- uint8_t reserved0[77];
- uint8_t ssid;
- uint16_t devno;
-} __attribute__ ((packed));
-typedef struct IplBlockQemuScsi IplBlockQemuScsi;
-
-struct IplParameterBlock {
- uint32_t len;
- uint8_t reserved0[3];
- uint8_t version;
- uint32_t blk0_len;
- uint8_t pbt;
- uint8_t flags;
- uint16_t reserved01;
- uint8_t loadparm[LOADPARM_LEN];
- union {
- IplBlockCcw ccw;
- IplBlockFcp fcp;
- IplBlockQemuScsi scsi;
- };
-} __attribute__ ((packed));
-typedef struct IplParameterBlock IplParameterBlock;
+#ifndef QEMU_PACKED
+#define QEMU_PACKED __attribute__((packed))
+#endif
-extern IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
-
-#define QIPL_ADDRESS 0xcc
-
-/* Boot Menu flags */
-#define QIPL_FLAG_BM_OPTS_CMD 0x80
-#define QIPL_FLAG_BM_OPTS_ZIPL 0x40
-
-/*
- * This definition must be kept in sync with the definition
- * in hw/s390x/ipl.h
- */
-struct QemuIplParameters {
- uint8_t qipl_flags;
- uint8_t reserved1[3];
- uint64_t netboot_start_addr;
- uint32_t boot_menu_timeout;
- uint8_t reserved2[12];
-} __attribute__ ((packed));
-typedef struct QemuIplParameters QemuIplParameters;
+#include <qipl.h>
+#include <string.h>
extern QemuIplParameters qipl;
+extern IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
+extern bool have_iplb;
#define S390_IPL_TYPE_FCP 0x00
#define S390_IPL_TYPE_CCW 0x02
@@ -123,4 +51,26 @@ static inline bool set_iplb(IplParameterBlock *iplb)
return manage_iplb(iplb, false);
}
+/*
+ * The IPL started on the device, but failed in some way. If the IPLB chain
+ * still has more devices left to try, use the next device in order.
+ */
+static inline bool load_next_iplb(void)
+{
+ IplParameterBlock *next_iplb;
+
+ if (qipl.chain_len < 1) {
+ return false;
+ }
+
+ qipl.index++;
+ next_iplb = (IplParameterBlock *) qipl.next_iplb;
+ memcpy(&iplb, next_iplb, sizeof(IplParameterBlock));
+
+ qipl.chain_len--;
+ qipl.next_iplb = qipl.next_iplb + sizeof(IplParameterBlock);
+
+ return true;
+}
+
#endif /* IPLB_H */
diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
index 78f5f46..86321d0 100644
--- a/pc-bios/s390-ccw/jump2ipl.c
+++ b/pc-bios/s390-ccw/jump2ipl.c
@@ -6,7 +6,8 @@
* directory.
*/
-#include "libc.h"
+#include <string.h>
+#include <stdio.h>
#include "s390-ccw.h"
#include "s390-arch.h"
@@ -32,16 +33,22 @@ static void jump_to_IPL_addr(void)
/* should not return */
}
-void jump_to_IPL_code(uint64_t address)
+int jump_to_IPL_code(uint64_t address)
{
/* store the subsystem information _after_ the bootmap was loaded */
write_subsystem_identification();
write_iplb_location();
- /* prevent unknown IPL types in the guest */
+ /*
+ * The IPLB for QEMU SCSI type devices must be rebuilt during re-ipl. The
+ * iplb.devno is set to the boot position of the target SCSI device.
+ */
if (iplb.pbt == S390_IPL_TYPE_QEMU_SCSI) {
- iplb.pbt = S390_IPL_TYPE_CCW;
- set_iplb(&iplb);
+ iplb.devno = qipl.index;
+ }
+
+ if (have_iplb && !set_iplb(&iplb)) {
+ panic("Failed to set IPLB");
}
/*
@@ -57,7 +64,7 @@ void jump_to_IPL_code(uint64_t address)
debug_print_int("set IPL addr to", address ?: *reset_psw & PSW_MASK_SHORT_ADDR);
/* Ensure the guest output starts fresh */
- sclp_print("\n");
+ printf("\n");
/*
* HACK ALERT.
@@ -67,7 +74,8 @@ void jump_to_IPL_code(uint64_t address)
asm volatile("lghi %%r1,1\n\t"
"diag %%r1,%%r1,0x308\n\t"
: : : "1", "memory");
- panic("\n! IPL returns !\n");
+ puts("IPL code jump failed");
+ return -1;
}
void jump_to_low_kernel(void)
diff --git a/pc-bios/s390-ccw/libc.c b/pc-bios/s390-ccw/libc.c
deleted file mode 100644
index 3187923..0000000
--- a/pc-bios/s390-ccw/libc.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * libc-style definitions and functions
- *
- * Copyright 2018 IBM Corp.
- * Author(s): Collin L. Walling <walling@linux.vnet.ibm.com>
- *
- * This code 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.
- */
-
-#include "libc.h"
-#include "s390-ccw.h"
-
-/**
- * atoui:
- * @str: the string to be converted.
- *
- * Given a string @str, convert it to an integer. Leading spaces are
- * ignored. Any other non-numerical value will terminate the conversion
- * and return 0. This function only handles numbers between 0 and
- * UINT64_MAX inclusive.
- *
- * Returns: an integer converted from the string @str, or the number 0
- * if an error occurred.
- */
-uint64_t atoui(const char *str)
-{
- int val = 0;
-
- if (!str || !str[0]) {
- return 0;
- }
-
- while (*str == ' ') {
- str++;
- }
-
- while (*str) {
- if (!isdigit(*(unsigned char *)str)) {
- break;
- }
- val = val * 10 + *str - '0';
- str++;
- }
-
- return val;
-}
-
-/**
- * uitoa:
- * @num: an integer (base 10) to be converted.
- * @str: a pointer to a string to store the conversion.
- * @len: the length of the passed string.
- *
- * Given an integer @num, convert it to a string. The string @str must be
- * allocated beforehand. The resulting string will be null terminated and
- * returned. This function only handles numbers between 0 and UINT64_MAX
- * inclusive.
- *
- * Returns: the string @str of the converted integer @num
- */
-char *uitoa(uint64_t num, char *str, size_t len)
-{
- long num_idx = 1; /* account for NUL */
- uint64_t tmp = num;
-
- IPL_assert(str != NULL, "uitoa: no space allocated to store string");
-
- /* Count indices of num */
- while ((tmp /= 10) != 0) {
- num_idx++;
- }
-
- /* Check if we have enough space for num and NUL */
- IPL_assert(len > num_idx, "uitoa: array too small for conversion");
-
- str[num_idx--] = '\0';
-
- /* Convert int to string */
- while (num_idx >= 0) {
- str[num_idx--] = num % 10 + '0';
- num /= 10;
- }
-
- return str;
-}
diff --git a/pc-bios/s390-ccw/libc.h b/pc-bios/s390-ccw/libc.h
deleted file mode 100644
index bcdc457..0000000
--- a/pc-bios/s390-ccw/libc.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * libc-style definitions and functions
- *
- * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
- *
- * This code 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.
- */
-
-#ifndef S390_CCW_LIBC_H
-#define S390_CCW_LIBC_H
-
-typedef unsigned long size_t;
-typedef int bool;
-typedef unsigned char uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned int uint32_t;
-typedef unsigned long long uint64_t;
-
-static inline void *memset(void *s, int c, size_t n)
-{
- size_t i;
- unsigned char *p = s;
-
- for (i = 0; i < n; i++) {
- p[i] = c;
- }
-
- return s;
-}
-
-static inline void *memcpy(void *s1, const void *s2, size_t n)
-{
- uint8_t *dest = s1;
- const uint8_t *src = s2;
- size_t i;
-
- for (i = 0; i < n; i++) {
- dest[i] = src[i];
- }
-
- return s1;
-}
-
-static inline int memcmp(const void *s1, const void *s2, size_t n)
-{
- size_t i;
- const uint8_t *p1 = s1, *p2 = s2;
-
- for (i = 0; i < n; i++) {
- if (p1[i] != p2[i]) {
- return p1[i] > p2[i] ? 1 : -1;
- }
- }
-
- return 0;
-}
-
-static inline size_t strlen(const char *str)
-{
- size_t i;
- for (i = 0; *str; i++) {
- str++;
- }
- return i;
-}
-
-static inline char *strcat(char *dest, const char *src)
-{
- int i;
- char *dest_end = dest + strlen(dest);
-
- for (i = 0; i <= strlen(src); i++) {
- dest_end[i] = src[i];
- }
- return dest;
-}
-
-static inline int isdigit(int c)
-{
- return (c >= '0') && (c <= '9');
-}
-
-uint64_t atoui(const char *str);
-char *uitoa(uint64_t num, char *str, size_t len);
-
-#endif
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 5506798..a4d1c05 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -8,7 +8,9 @@
* directory.
*/
-#include "libc.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
#include "helper.h"
#include "s390-arch.h"
#include "s390-ccw.h"
@@ -21,7 +23,7 @@ static SubChannelId blk_schid = { .one = 1 };
static char loadparm_str[LOADPARM_LEN + 1];
QemuIplParameters qipl;
IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
-static bool have_iplb;
+bool have_iplb;
static uint16_t cutype;
LowCore *lowcore; /* Yes, this *is* a pointer to address 0 */
@@ -36,8 +38,13 @@ LowCore *lowcore; /* Yes, this *is* a pointer to address 0 */
*/
void write_subsystem_identification(void)
{
- lowcore->subchannel_id = blk_schid.sch_id;
- lowcore->subchannel_nr = blk_schid.sch_no;
+ if (cutype == CU_TYPE_VIRTIO && virtio_get_device_type() == VIRTIO_ID_NET) {
+ lowcore->subchannel_id = net_schid.sch_id;
+ lowcore->subchannel_nr = net_schid.sch_no;
+ } else {
+ lowcore->subchannel_id = blk_schid.sch_id;
+ lowcore->subchannel_nr = blk_schid.sch_no;
+ }
lowcore->io_int_parm = 0;
}
@@ -48,9 +55,15 @@ void write_iplb_location(void)
}
}
+static void copy_qipl(void)
+{
+ QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
+ memcpy(&qipl, early_qipl, sizeof(QemuIplParameters));
+}
+
unsigned int get_loadparm_index(void)
{
- return atoui(loadparm_str);
+ return atoi(loadparm_str);
}
static int is_dev_possibly_bootable(int dev_no, int sch_no)
@@ -70,6 +83,9 @@ static int is_dev_possibly_bootable(int dev_no, int sch_no)
enable_subchannel(blk_schid);
cutype = cu_type(blk_schid);
+ if (cutype == CU_TYPE_UNKNOWN) {
+ return -EIO;
+ }
/*
* Note: we always have to run virtio_is_supported() here to make
@@ -142,6 +158,7 @@ static void menu_setup(void)
/* If loadparm was set to any other value, then do not enable menu */
if (memcmp(loadparm_str, LOADPARM_EMPTY, LOADPARM_LEN) != 0) {
+ menu_set_parms(qipl.qipl_flags & ~BOOT_MENU_FLAG_MASK, 0);
return;
}
@@ -174,26 +191,34 @@ static void boot_setup(void)
{
char lpmsg[] = "LOADPARM=[________]\n";
- sclp_get_loadparm_ascii(loadparm_str);
+ if (memcmp(iplb.loadparm, NO_LOADPARM, LOADPARM_LEN) != 0) {
+ ebcdic_to_ascii((char *) iplb.loadparm, loadparm_str, LOADPARM_LEN);
+ } else {
+ sclp_get_loadparm_ascii(loadparm_str);
+ }
+
+ if (have_iplb) {
+ menu_setup();
+ }
+
memcpy(lpmsg + 10, loadparm_str, 8);
- sclp_print(lpmsg);
+ puts(lpmsg);
/*
* Clear out any potential S390EP magic (see jump_to_low_kernel()),
* so we don't taint our decision-making process during a reboot.
*/
memset((char *)S390EP, 0, 6);
-
- have_iplb = store_iplb(&iplb);
}
-static void find_boot_device(void)
+static bool find_boot_device(void)
{
VDev *vdev = virtio_get_device();
- bool found;
+ bool found = false;
switch (iplb.pbt) {
case S390_IPL_TYPE_CCW:
+ vdev->scsi_device_selected = false;
debug_print_int("device no. ", iplb.ccw.devno);
blk_schid.ssid = iplb.ccw.ssid & 0x3;
debug_print_int("ssid ", blk_schid.ssid);
@@ -208,28 +233,20 @@ static void find_boot_device(void)
found = find_subch(iplb.scsi.devno);
break;
default:
- panic("List-directed IPL not supported yet!\n");
+ puts("Unsupported IPLB");
}
- IPL_assert(found, "Boot device not found\n");
+ return found;
}
static int virtio_setup(void)
{
VDev *vdev = virtio_get_device();
- QemuIplParameters *early_qipl = (QemuIplParameters *)QIPL_ADDRESS;
int ret;
- memcpy(&qipl, early_qipl, sizeof(QemuIplParameters));
-
- if (have_iplb) {
- menu_setup();
- }
-
switch (vdev->senseid.cu_model) {
case VIRTIO_ID_NET:
- sclp_print("Network boot device detected\n");
- vdev->netboot_start_addr = qipl.netboot_start_addr;
+ puts("Network boot device detected");
return 0;
case VIRTIO_ID_BLOCK:
ret = virtio_blk_setup_device(blk_schid);
@@ -238,11 +255,13 @@ static int virtio_setup(void)
ret = virtio_scsi_setup_device(blk_schid);
break;
default:
- panic("\n! No IPL device available !\n");
+ puts("\n! No IPL device available !\n");
+ return -1;
}
- if (!ret) {
- IPL_assert(virtio_ipl_disk_is_valid(), "No valid IPL device detected");
+ if (!ret && !virtio_ipl_disk_is_valid()) {
+ puts("No valid IPL device detected");
+ return -ENODEV;
}
return ret;
@@ -253,16 +272,15 @@ static void ipl_boot_device(void)
switch (cutype) {
case CU_TYPE_DASD_3990:
case CU_TYPE_DASD_2107:
- dasd_ipl(blk_schid, cutype); /* no return */
+ dasd_ipl(blk_schid, cutype);
break;
case CU_TYPE_VIRTIO:
if (virtio_setup() == 0) {
- zipl_load(); /* Only returns in case of errors */
+ zipl_load();
}
break;
default:
- print_int("Attempting to boot from unexpected device type", cutype);
- panic("\nBoot failed.\n");
+ printf("Attempting to boot from unexpected device type 0x%X\n", cutype);
}
}
@@ -287,20 +305,27 @@ static void probe_boot_device(void)
}
}
- sclp_print("Could not find a suitable boot device (none specified)\n");
+ puts("Could not find a suitable boot device (none specified)");
}
void main(void)
{
+ copy_qipl();
sclp_setup();
css_setup();
- boot_setup();
- if (have_iplb) {
- find_boot_device();
- ipl_boot_device();
- } else {
+ have_iplb = store_iplb(&iplb);
+ if (!have_iplb) {
probe_boot_device();
}
- panic("Failed to load OS from hard disk\n");
+ while (have_iplb) {
+ boot_setup();
+ if (have_iplb && find_boot_device()) {
+ ipl_boot_device();
+ }
+ have_iplb = load_next_iplb();
+ }
+
+ panic("No suitable device for IPL. Halting...");
+
}
diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c
index d601952..84062e9 100644
--- a/pc-bios/s390-ccw/menu.c
+++ b/pc-bios/s390-ccw/menu.c
@@ -9,7 +9,10 @@
* directory.
*/
-#include "libc.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include "s390-ccw.h"
#include "sclp.h"
#include "s390-time.h"
@@ -93,7 +96,7 @@ static int read_prompt(char *buf, size_t len)
case KEYCODE_BACKSP:
if (idx > 0) {
buf[--idx] = 0;
- sclp_print("\b \b");
+ printf("\b \b");
}
continue;
case KEYCODE_ENTER:
@@ -103,7 +106,7 @@ static int read_prompt(char *buf, size_t len)
/* Echo input and add to buffer */
if (idx < len) {
buf[idx++] = inp[0];
- sclp_print(inp);
+ printf("%s", inp);
}
}
}
@@ -140,22 +143,19 @@ static int get_index(void)
}
}
- return atoui(buf);
+ return atoi(buf);
}
static void boot_menu_prompt(bool retry)
{
- char tmp[11];
-
if (retry) {
- sclp_print("\nError: undefined configuration"
+ printf("\nError: undefined configuration"
"\nPlease choose:\n");
} else if (timeout > 0) {
- sclp_print("Please choose (default will boot in ");
- sclp_print(uitoa(timeout / 1000, tmp, sizeof(tmp)));
- sclp_print(" seconds):\n");
+ printf("Please choose (default will boot in %d seconds):\n",
+ (int)(timeout / 1000));
} else {
- sclp_print("Please choose:\n");
+ puts("Please choose:");
}
}
@@ -163,7 +163,6 @@ static int get_boot_index(bool *valid_entries)
{
int boot_index;
bool retry = false;
- char tmp[5];
do {
boot_menu_prompt(retry);
@@ -172,8 +171,7 @@ static int get_boot_index(bool *valid_entries)
} while (boot_index < 0 || boot_index >= MAX_BOOT_ENTRIES ||
!valid_entries[boot_index]);
- sclp_print("\nBooting entry #");
- sclp_print(uitoa(boot_index, tmp, sizeof(tmp)));
+ printf("\nBooting entry #%d", boot_index);
return boot_index;
}
@@ -187,9 +185,9 @@ static int zipl_print_entry(const char *data, size_t len)
buf[len] = '\n';
buf[len + 1] = '\0';
- sclp_print(buf);
+ printf("%s", buf);
- return buf[0] == ' ' ? atoui(buf + 1) : atoui(buf);
+ return buf[0] == ' ' ? atoi(buf + 1) : atoi(buf);
}
int menu_get_zipl_boot_index(const char *menu_data)
@@ -209,7 +207,7 @@ int menu_get_zipl_boot_index(const char *menu_data)
}
/* Print banner */
- sclp_print("s390-ccw zIPL Boot Menu\n\n");
+ puts("s390-ccw zIPL Boot Menu\n");
menu_data += strlen(menu_data) + 1;
/* Print entries */
@@ -221,37 +219,34 @@ int menu_get_zipl_boot_index(const char *menu_data)
valid_entries[entry] = true;
if (entry == 0) {
- sclp_print("\n");
+ printf("\n");
}
}
- sclp_print("\n");
+ printf("\n");
return get_boot_index(valid_entries);
}
int menu_get_enum_boot_index(bool *valid_entries)
{
- char tmp[3];
int i;
- sclp_print("s390-ccw Enumerated Boot Menu.\n\n");
+ puts("s390-ccw Enumerated Boot Menu.\n");
for (i = 0; i < MAX_BOOT_ENTRIES; i++) {
if (valid_entries[i]) {
if (i < 10) {
- sclp_print(" ");
+ printf(" ");
}
- sclp_print("[");
- sclp_print(uitoa(i, tmp, sizeof(tmp)));
- sclp_print("]");
+ printf("[%d]", i);
if (i == 0) {
- sclp_print(" default\n");
+ printf(" default\n");
}
- sclp_print("\n");
+ printf("\n");
}
}
- sclp_print("\n");
+ printf("\n");
return get_boot_index(valid_entries);
}
diff --git a/pc-bios/s390-ccw/netboot.mak b/pc-bios/s390-ccw/netboot.mak
deleted file mode 100644
index 046aa35..0000000
--- a/pc-bios/s390-ccw/netboot.mak
+++ /dev/null
@@ -1,62 +0,0 @@
-
-SLOF_DIR := $(SRC_PATH)/../../roms/SLOF
-
-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) -Wl,-Ttext=0x7800000
-
-$(NETOBJS): EXTRA_CFLAGS += $(LIBC_INC) $(LIBNET_INC)
-
-s390-netboot.elf: $(NETOBJS) libnet.a libc.a
- $(call quiet-command,$(CC) $(NETLDFLAGS) -o $@ $^,Linking)
-
-s390-netboot.img: s390-netboot.elf
- $(call quiet-command,$(STRIP) --strip-unneeded $< -o $@,Stripping $< into)
-
-# libc files:
-
-LIBC_CFLAGS = $(EXTRA_CFLAGS) $(CFLAGS) $(LIBC_INC) $(LIBNET_INC) \
- -MMD -MP -MT $@ -MF $(@:%.o=%.d)
-
-CTYPE_OBJS = isdigit.o isxdigit.o toupper.o
-%.o : $(SLOF_DIR)/lib/libc/ctype/%.c
- $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling)
-
-STRING_OBJS = strcat.o strchr.o strrchr.o strcpy.o strlen.o strncpy.o \
- strcmp.o strncmp.o strcasecmp.o strncasecmp.o strstr.o \
- memset.o memcpy.o memmove.o memcmp.o
-%.o : $(SLOF_DIR)/lib/libc/string/%.c
- $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling)
-
-STDLIB_OBJS = atoi.o atol.o strtoul.o strtol.o rand.o malloc.o free.o
-%.o : $(SLOF_DIR)/lib/libc/stdlib/%.c
- $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling)
-
-STDIO_OBJS = sprintf.o snprintf.o vfprintf.o vsnprintf.o vsprintf.o fprintf.o \
- printf.o putc.o puts.o putchar.o stdchnls.o fileno.o
-%.o : $(SLOF_DIR)/lib/libc/stdio/%.c
- $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling)
-
-sbrk.o: $(SLOF_DIR)/slof/sbrk.c
- $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,Compiling)
-
-LIBCOBJS := $(STRING_OBJS) $(CTYPE_OBJS) $(STDLIB_OBJS) $(STDIO_OBJS) sbrk.o
-
-libc.a: $(LIBCOBJS)
- $(call quiet-command,$(AR) -rc $@ $^,Creating static library)
-
-# libnet files:
-
-LIBNETOBJS := args.o dhcp.o dns.o icmpv6.o ipv6.o tcp.o udp.o bootp.o \
- dhcpv6.o ethernet.o ipv4.o ndp.o tftp.o pxelinux.o
-LIBNETCFLAGS = $(EXTRA_CFLAGS) $(CFLAGS) $(LIBC_INC) $(LIBNET_INC) \
- -DDHCPARCH=0x1F -MMD -MP -MT $@ -MF $(@:%.o=%.d)
-
-%.o : $(SLOF_DIR)/lib/libnet/%.c
- $(call quiet-command,$(CC) $(LIBNETCFLAGS) -c -o $@ $<,Compiling)
-
-libnet.a: $(LIBNETOBJS)
- $(call quiet-command,$(AR) -rc $@ $^,Creating static library)
diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c
index 5cd619b..e46e470 100644
--- a/pc-bios/s390-ccw/netmain.c
+++ b/pc-bios/s390-ccw/netmain.c
@@ -41,7 +41,6 @@
#define DEFAULT_TFTP_RETRIES 20
extern char _start[];
-void write_iplb_location(void) {}
#define KERNEL_ADDR ((void *)0L)
#define KERNEL_MAX_SIZE ((long)_start)
@@ -50,10 +49,9 @@ void write_iplb_location(void) {}
/* STSI 3.2.2 offset of first vmdb + offset of uuid inside vmdb */
#define STSI322_VMDB_UUID_OFFSET ((8 + 12) * 4)
-IplParameterBlock iplb __attribute__((aligned(PAGE_SIZE)));
static char cfgbuf[2048];
-static SubChannelId net_schid = { .one = 1 };
+SubChannelId net_schid = { .one = 1 };
static uint8_t mac[6];
static uint64_t dest_timer;
@@ -293,7 +291,7 @@ static int load_kernel_with_initrd(filename_ip_t *fn_ip,
printf("Loading pxelinux.cfg entry '%s'\n", entry->label);
if (!entry->kernel) {
- printf("Kernel entry is missing!\n");
+ puts("Kernel entry is missing!\n");
return -1;
}
@@ -438,15 +436,6 @@ static int net_try_direct_tftp_load(filename_ip_t *fn_ip)
return rc;
}
-void write_subsystem_identification(void)
-{
- SubChannelId *schid = (SubChannelId *) 184;
- uint32_t *zeroes = (uint32_t *) 188;
-
- *schid = net_schid;
- *zeroes = 0;
-}
-
static bool find_net_dev(Schib *schib, int dev_no)
{
int i, r;
@@ -475,7 +464,7 @@ static bool find_net_dev(Schib *schib, int dev_no)
return false;
}
-static void virtio_setup(void)
+static bool virtio_setup(void)
{
Schib schib;
int ssid;
@@ -489,7 +478,7 @@ static void virtio_setup(void)
*/
enable_mss_facility();
- if (store_iplb(&iplb)) {
+ if (have_iplb || store_iplb(&iplb)) {
IPL_assert(iplb.pbt == S390_IPL_TYPE_CCW, "IPL_TYPE_CCW expected");
dev_no = iplb.ccw.devno;
debug_print_int("device no. ", dev_no);
@@ -506,22 +495,26 @@ static void virtio_setup(void)
}
}
- IPL_assert(found, "No virtio net device found");
+ return found;
}
-void main(void)
+int netmain(void)
{
filename_ip_t fn_ip;
int rc, fnlen;
sclp_setup();
- sclp_print("Network boot starting...\n");
+ puts("Network boot starting...");
- virtio_setup();
+ if (!virtio_setup()) {
+ puts("No virtio net device found.");
+ return -1;
+ }
rc = net_init(&fn_ip);
if (rc) {
- panic("Network initialization failed. Halting.\n");
+ puts("Network initialization failed.");
+ return -1;
}
fnlen = strlen(fn_ip.filename);
@@ -535,9 +528,10 @@ void main(void)
net_release(&fn_ip);
if (rc > 0) {
- sclp_print("Network loading done, starting kernel...\n");
+ puts("Network loading done, starting kernel...");
jump_to_low_kernel();
}
- panic("Failed to load OS from network\n");
+ puts("Failed to load OS from network.");
+ return -1;
}
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index c977a52..6cdce3e 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -13,6 +13,11 @@
/* #define DEBUG */
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
@@ -25,10 +30,8 @@ typedef unsigned long long u64;
#define EIO 1
#define EBUSY 2
#define ENODEV 3
+#define EINVAL 4
-#ifndef NULL
-#define NULL 0
-#endif
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
@@ -53,6 +56,9 @@ void write_iplb_location(void);
unsigned int get_loadparm_index(void);
void main(void);
+/* netmain.c */
+int netmain(void);
+
/* sclp.c */
void sclp_print(const char *string);
void sclp_set_write_mask(uint32_t receive_mask, uint32_t send_mask);
@@ -72,7 +78,7 @@ void zipl_load(void);
/* jump2ipl.c */
void write_reset_psw(uint64_t psw);
-void jump_to_IPL_code(uint64_t address);
+int jump_to_IPL_code(uint64_t address);
void jump_to_low_kernel(void);
/* menu.c */
@@ -87,7 +93,7 @@ bool menu_is_enabled_enum(void);
__attribute__ ((__noreturn__))
static inline void panic(const char *string)
{
- sclp_print(string);
+ printf("ERROR: %s\n ", string);
disabled_wait();
}
@@ -109,20 +115,10 @@ static inline void fill_hex_val(char *out, void *ptr, unsigned size)
}
}
-static inline void print_int(const char *desc, u64 addr)
-{
- char out[] = ": 0xffffffffffffffff\n";
-
- fill_hex_val(&out[4], &addr, sizeof(addr));
-
- sclp_print(desc);
- sclp_print(out);
-}
-
static inline void debug_print_int(const char *desc, u64 addr)
{
#ifdef DEBUG
- print_int(desc, addr);
+ printf("%s 0x%X\n", desc, addr);
#endif
}
@@ -147,18 +143,14 @@ static inline void debug_print_addr(const char *desc, void *p)
static inline void IPL_assert(bool term, const char *message)
{
if (!term) {
- sclp_print("\n! ");
- sclp_print(message);
- panic(" !\n"); /* no return */
+ panic(message); /* no return */
}
}
static inline void IPL_check(bool term, const char *message)
{
if (!term) {
- sclp_print("\n! WARNING: ");
- sclp_print(message);
- sclp_print(" !\n");
+ printf("WARNING: %s\n", message);
}
}
diff --git a/pc-bios/s390-ccw/sclp.c b/pc-bios/s390-ccw/sclp.c
index 7251f9a..4a07de0 100644
--- a/pc-bios/s390-ccw/sclp.c
+++ b/pc-bios/s390-ccw/sclp.c
@@ -8,7 +8,7 @@
* directory.
*/
-#include "libc.h"
+#include <string.h>
#include "s390-ccw.h"
#include "sclp.h"
@@ -101,11 +101,6 @@ long write(int fd, const void *str, size_t len)
return len;
}
-void sclp_print(const char *str)
-{
- write(1, str, strlen(str));
-}
-
void sclp_get_loadparm_ascii(char *loadparm)
{
diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S
index 061b065..b70213e 100644
--- a/pc-bios/s390-ccw/start.S
+++ b/pc-bios/s390-ccw/start.S
@@ -112,9 +112,7 @@ io_new_code:
lctlg %c6,%c6,0(%r15)
br %r14
- .align 8
-bss_start_literal:
- .quad __bss_start
+ .balign 8
disabled_wait_psw:
.quad 0x0002000180000000,0x0000000000000000
enabled_wait_psw:
@@ -124,8 +122,13 @@ external_new_mask:
io_new_mask:
.quad 0x0000000180000000
+.data
+ .balign 8
+bss_start_literal:
+ .quad __bss_start
+
.bss
- .align 8
+ .balign 8
stack:
.space STACK_SIZE
.size stack,STACK_SIZE
diff --git a/pc-bios/s390-ccw/virtio-blkdev.c b/pc-bios/s390-ccw/virtio-blkdev.c
index a81207b..7b2d1e2 100644
--- a/pc-bios/s390-ccw/virtio-blkdev.c
+++ b/pc-bios/s390-ccw/virtio-blkdev.c
@@ -8,7 +8,7 @@
* directory.
*/
-#include "libc.h"
+#include <stdio.h>
#include "s390-ccw.h"
#include "virtio.h"
#include "virtio-scsi.h"
@@ -59,7 +59,7 @@ int virtio_read_many(unsigned long sector, void *load_addr, int sec_num)
case VIRTIO_ID_SCSI:
return virtio_scsi_read_many(vdev, sector, load_addr, sec_num);
}
- panic("\n! No readable IPL device !\n");
+
return -1;
}
@@ -73,13 +73,13 @@ unsigned long virtio_load_direct(unsigned long rec_list1, unsigned long rec_list
unsigned long addr = (unsigned long)load_addr;
if (sec_len != virtio_get_block_size()) {
- return -1;
+ return 0;
}
- sclp_print(".");
+ printf(".");
status = virtio_read_many(sec, (void *)addr, sec_num);
if (status) {
- panic("I/O Error");
+ return 0;
}
addr += sec_num * virtio_get_block_size();
@@ -230,7 +230,7 @@ int virtio_blk_setup_device(SubChannelId schid)
vdev->schid = schid;
virtio_setup_ccw(vdev);
- sclp_print("Using virtio-blk.\n");
+ puts("Using virtio-blk.");
return 0;
}
diff --git a/pc-bios/s390-ccw/virtio-net.c b/pc-bios/s390-ccw/virtio-net.c
index 2fcb0a5..f9854a2 100644
--- a/pc-bios/s390-ccw/virtio-net.c
+++ b/pc-bios/s390-ccw/virtio-net.c
@@ -54,8 +54,11 @@ int virtio_net_init(void *mac_addr)
vdev->guest_features[0] = VIRTIO_NET_F_MAC_BIT;
virtio_setup_ccw(vdev);
- IPL_assert(vdev->guest_features[0] & VIRTIO_NET_F_MAC_BIT,
- "virtio-net device does not support the MAC address feature");
+ if (!(vdev->guest_features[0] & VIRTIO_NET_F_MAC_BIT)) {
+ puts("virtio-net device does not support the MAC address feature");
+ return -1;
+ }
+
memcpy(mac_addr, vdev->config.net.mac, ETH_ALEN);
for (i = 0; i < 64; i++) {
diff --git a/pc-bios/s390-ccw/virtio-scsi.c b/pc-bios/s390-ccw/virtio-scsi.c
index d1a84b9..71db75c 100644
--- a/pc-bios/s390-ccw/virtio-scsi.c
+++ b/pc-bios/s390-ccw/virtio-scsi.c
@@ -9,7 +9,8 @@
* directory.
*/
-#include "libc.h"
+#include <string.h>
+#include <stdio.h>
#include "s390-ccw.h"
#include "virtio.h"
#include "scsi.h"
@@ -25,20 +26,22 @@ static uint8_t scsi_inquiry_std_response[256];
static ScsiInquiryEvpdPages scsi_inquiry_evpd_pages_response;
static ScsiInquiryEvpdBl scsi_inquiry_evpd_bl_response;
-static inline void vs_assert(bool term, const char **msgs)
+static inline bool vs_assert(bool term, const char **msgs)
{
if (!term) {
int i = 0;
- sclp_print("\n! ");
+ printf("\n! ");
while (msgs[i]) {
- sclp_print(msgs[i++]);
+ printf("%s", msgs[i++]);
}
- panic(" !\n");
+ puts(" !");
}
+
+ return term;
}
-static void virtio_scsi_verify_response(VirtioScsiCmdResp *resp,
+static bool virtio_scsi_verify_response(VirtioScsiCmdResp *resp,
const char *title)
{
const char *mr[] = {
@@ -55,8 +58,8 @@ static void virtio_scsi_verify_response(VirtioScsiCmdResp *resp,
0
};
- vs_assert(resp->response == VIRTIO_SCSI_S_OK, mr);
- vs_assert(resp->status == CDB_STATUS_GOOD, ms);
+ return vs_assert(resp->response == VIRTIO_SCSI_S_OK, mr) &&
+ vs_assert(resp->status == CDB_STATUS_GOOD, ms);
}
static void prepare_request(VDev *vdev, const void *cdb, int cdb_size,
@@ -77,24 +80,31 @@ static void prepare_request(VDev *vdev, const void *cdb, int cdb_size,
}
}
-static inline void vs_io_assert(bool term, const char *msg)
+static inline bool vs_io_assert(bool term, const char *msg)
{
- if (!term) {
- virtio_scsi_verify_response(&resp, msg);
+ if (!term && !virtio_scsi_verify_response(&resp, msg)) {
+ return false;
}
+
+ return true;
}
-static void vs_run(const char *title, VirtioCmd *cmd, VDev *vdev,
+static int vs_run(const char *title, VirtioCmd *cmd, VDev *vdev,
const void *cdb, int cdb_size,
void *data, uint32_t data_size)
{
prepare_request(vdev, cdb, cdb_size, data, data_size);
- vs_io_assert(virtio_run(vdev, VR_REQUEST, cmd) == 0, title);
+ if (!vs_io_assert(virtio_run(vdev, VR_REQUEST, cmd) == 0, title)) {
+ puts(title);
+ return -EIO;
+ }
+
+ return 0;
}
/* SCSI protocol implementation routines */
-static bool scsi_inquiry(VDev *vdev, uint8_t evpd, uint8_t page,
+static int scsi_inquiry(VDev *vdev, uint8_t evpd, uint8_t page,
void *data, uint32_t data_size)
{
ScsiCdbInquiry cdb = {
@@ -109,12 +119,13 @@ static bool scsi_inquiry(VDev *vdev, uint8_t evpd, uint8_t page,
{ data, data_size, VRING_DESC_F_WRITE },
};
- vs_run("inquiry", inquiry, vdev, &cdb, sizeof(cdb), data, data_size);
+ int ret = vs_run("inquiry", inquiry,
+ vdev, &cdb, sizeof(cdb), data, data_size);
- return virtio_scsi_response_ok(&resp);
+ return ret ? ret : virtio_scsi_response_ok(&resp);
}
-static bool scsi_test_unit_ready(VDev *vdev)
+static int scsi_test_unit_ready(VDev *vdev)
{
ScsiCdbTestUnitReady cdb = {
.command = 0x00,
@@ -130,7 +141,7 @@ static bool scsi_test_unit_ready(VDev *vdev)
return virtio_scsi_response_ok(&resp);
}
-static bool scsi_report_luns(VDev *vdev, void *data, uint32_t data_size)
+static int scsi_report_luns(VDev *vdev, void *data, uint32_t data_size)
{
ScsiCdbReportLuns cdb = {
.command = 0xa0,
@@ -143,13 +154,13 @@ static bool scsi_report_luns(VDev *vdev, void *data, uint32_t data_size)
{ data, data_size, VRING_DESC_F_WRITE },
};
- vs_run("report luns", report_luns,
+ int ret = vs_run("report luns", report_luns,
vdev, &cdb, sizeof(cdb), data, data_size);
- return virtio_scsi_response_ok(&resp);
+ return ret ? ret : virtio_scsi_response_ok(&resp);
}
-static bool scsi_read_10(VDev *vdev,
+static int scsi_read_10(VDev *vdev,
unsigned long sector, int sectors, void *data,
unsigned int data_size)
{
@@ -167,12 +178,13 @@ static bool scsi_read_10(VDev *vdev,
debug_print_int("read_10 sector", sector);
debug_print_int("read_10 sectors", sectors);
- vs_run("read(10)", read_10, vdev, &cdb, sizeof(cdb), data, data_size);
+ int ret = vs_run("read(10)", read_10,
+ vdev, &cdb, sizeof(cdb), data, data_size);
- return virtio_scsi_response_ok(&resp);
+ return ret ? ret : virtio_scsi_response_ok(&resp);
}
-static bool scsi_read_capacity(VDev *vdev,
+static int scsi_read_capacity(VDev *vdev,
void *data, uint32_t data_size)
{
ScsiCdbReadCapacity16 cdb = {
@@ -186,10 +198,10 @@ static bool scsi_read_capacity(VDev *vdev,
{ data, data_size, VRING_DESC_F_WRITE },
};
- vs_run("read capacity", read_capacity_16,
+ int ret = vs_run("read capacity", read_capacity_16,
vdev, &cdb, sizeof(cdb), data, data_size);
- return virtio_scsi_response_ok(&resp);
+ return ret ? ret : virtio_scsi_response_ok(&resp);
}
/* virtio-scsi routines */
@@ -206,7 +218,7 @@ static int virtio_scsi_locate_device(VDev *vdev)
static uint8_t data[16 + 8 * 63];
ScsiLunReport *r = (void *) data;
ScsiDevice *sdev = vdev->scsi_device;
- int i, luns;
+ int i, ret, luns;
/* QEMU has hardcoded channel #0 in many places.
* If this hardcoded value is ever changed, we'll need to add code for
@@ -232,15 +244,23 @@ static int virtio_scsi_locate_device(VDev *vdev)
sdev->channel = channel;
sdev->target = target;
sdev->lun = 0; /* LUN has to be 0 for REPORT LUNS */
- if (!scsi_report_luns(vdev, data, sizeof(data))) {
+ ret = scsi_report_luns(vdev, data, sizeof(data));
+ if (ret < 0) {
+ return ret;
+ }
+
+ else if (ret == 0) {
if (resp.response == VIRTIO_SCSI_S_BAD_TARGET) {
continue;
}
- print_int("target", target);
- virtio_scsi_verify_response(&resp, "SCSI cannot report LUNs");
+ printf("target 0x%X\n", target);
+ if (!virtio_scsi_verify_response(&resp, "SCSI cannot report LUNs")) {
+ return -EIO;
+ }
}
+
if (r->lun_list_len == 0) {
- print_int("no LUNs for target", target);
+ printf("no LUNs for target 0x%X\n", target);
continue;
}
luns = r->lun_list_len / 8;
@@ -264,7 +284,7 @@ static int virtio_scsi_locate_device(VDev *vdev)
}
}
- sclp_print("Warning: Could not locate a usable virtio-scsi device\n");
+ puts("Warning: Could not locate a usable virtio-scsi device");
return -ENODEV;
}
@@ -282,7 +302,9 @@ int virtio_scsi_read_many(VDev *vdev,
data_size = sector_count * virtio_get_block_size() * f;
if (!scsi_read_10(vdev, sector * f, sector_count * f, load_addr,
data_size)) {
- virtio_scsi_verify_response(&resp, "virtio-scsi:read_many");
+ if (!virtio_scsi_verify_response(&resp, "virtio-scsi:read_many")) {
+ return -1;
+ }
}
load_addr += data_size;
sector += sector_count;
@@ -351,11 +373,16 @@ static int virtio_scsi_setup(VDev *vdev)
uint8_t code = resp.sense[0] & SCSI_SENSE_CODE_MASK;
uint8_t sense_key = resp.sense[2] & SCSI_SENSE_KEY_MASK;
- IPL_assert(resp.sense_len != 0, "virtio-scsi:setup: no SENSE data");
+ if (resp.sense_len == 0) {
+ puts("virtio-scsi: setup: no SENSE data");
+ return -EINVAL;
+ }
- IPL_assert(retry_test_unit_ready && code == 0x70 &&
- sense_key == SCSI_SENSE_KEY_UNIT_ATTENTION,
- "virtio-scsi:setup: cannot retry");
+ if (!retry_test_unit_ready || code != 0x70 ||
+ sense_key != SCSI_SENSE_KEY_UNIT_ATTENTION) {
+ puts("virtio-scsi:setup: cannot retry");
+ return -EIO;
+ }
/* retry on CHECK_CONDITION/UNIT_ATTENTION as it
* may not designate a real error, but it may be
@@ -366,30 +393,40 @@ static int virtio_scsi_setup(VDev *vdev)
continue;
}
- virtio_scsi_verify_response(&resp, "virtio-scsi:setup");
+ if (!virtio_scsi_verify_response(&resp, "virtio-scsi:setup")) {
+ return -1;
+ }
}
/* read and cache SCSI INQUIRY response */
- if (!scsi_inquiry(vdev,
+ ret = scsi_inquiry(vdev,
SCSI_INQUIRY_STANDARD,
SCSI_INQUIRY_STANDARD_NONE,
scsi_inquiry_std_response,
- sizeof(scsi_inquiry_std_response))) {
- virtio_scsi_verify_response(&resp, "virtio-scsi:setup:inquiry");
+ sizeof(scsi_inquiry_std_response));
+ if (ret < 1) {
+ if (ret != 0 || !virtio_scsi_verify_response(&resp,
+ "virtio-scsi:setup:inquiry")) {
+ return -1;
+ }
}
if (virtio_scsi_inquiry_response_is_cdrom(scsi_inquiry_std_response)) {
- sclp_print("SCSI CD-ROM detected.\n");
+ puts("SCSI CD-ROM detected.");
vdev->is_cdrom = true;
vdev->scsi_block_size = VIRTIO_ISO_BLOCK_SIZE;
}
- if (!scsi_inquiry(vdev,
+ ret = scsi_inquiry(vdev,
SCSI_INQUIRY_EVPD,
SCSI_INQUIRY_EVPD_SUPPORTED_PAGES,
evpd,
- sizeof(*evpd))) {
- virtio_scsi_verify_response(&resp, "virtio-scsi:setup:supported_pages");
+ sizeof(*evpd));
+ if (ret < 1) {
+ if (ret != 0 || !virtio_scsi_verify_response(&resp,
+ "virtio-scsi:setup:supported_pages")) {
+ return -1;
+ }
}
debug_print_int("EVPD length", evpd->page_length);
@@ -401,12 +438,16 @@ static int virtio_scsi_setup(VDev *vdev)
continue;
}
- if (!scsi_inquiry(vdev,
+ ret = scsi_inquiry(vdev,
SCSI_INQUIRY_EVPD,
SCSI_INQUIRY_EVPD_BLOCK_LIMITS,
evpd_bl,
- sizeof(*evpd_bl))) {
- virtio_scsi_verify_response(&resp, "virtio-scsi:setup:blocklimits");
+ sizeof(*evpd_bl));
+ if (ret < 1) {
+ if (ret != 0 || !virtio_scsi_verify_response(&resp,
+ "virtio-scsi:setup:blocklimits")) {
+ return -1;
+ }
}
debug_print_int("max transfer", evpd_bl->max_transfer);
@@ -422,8 +463,12 @@ static int virtio_scsi_setup(VDev *vdev)
vdev->max_transfer = MIN_NON_ZERO(VIRTIO_SCSI_MAX_SECTORS,
vdev->max_transfer);
- if (!scsi_read_capacity(vdev, data, data_size)) {
- virtio_scsi_verify_response(&resp, "virtio-scsi:setup:read_capacity");
+ ret = scsi_read_capacity(vdev, data, data_size);
+ if (ret < 1) {
+ if (ret != 0 || !virtio_scsi_verify_response(&resp,
+ "virtio-scsi:setup:read_capacity")) {
+ return -1;
+ }
}
scsi_parse_capacity_report(data, &vdev->scsi_last_block,
(uint32_t *) &vdev->scsi_block_size);
@@ -438,12 +483,17 @@ int virtio_scsi_setup_device(SubChannelId schid)
vdev->schid = schid;
virtio_setup_ccw(vdev);
- IPL_assert(vdev->config.scsi.sense_size == VIRTIO_SCSI_SENSE_SIZE,
- "Config: sense size mismatch");
- IPL_assert(vdev->config.scsi.cdb_size == VIRTIO_SCSI_CDB_SIZE,
- "Config: CDB size mismatch");
+ if (vdev->config.scsi.sense_size != VIRTIO_SCSI_SENSE_SIZE) {
+ puts("Config: sense size mismatch");
+ return -EINVAL;
+ }
+
+ if (vdev->config.scsi.cdb_size != VIRTIO_SCSI_CDB_SIZE) {
+ puts("Config: CDB size mismatch");
+ return -EINVAL;
+ }
- sclp_print("Using virtio-scsi.\n");
+ puts("Using virtio-scsi.");
return virtio_scsi_setup(vdev);
}
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 5edd058..8b5a370 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -8,7 +8,7 @@
* directory.
*/
-#include "libc.h"
+#include <string.h>
#include "s390-ccw.h"
#include "cio.h"
#include "virtio.h"
@@ -217,16 +217,19 @@ int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd)
return 0;
}
-void virtio_setup_ccw(VDev *vdev)
+int virtio_setup_ccw(VDev *vdev)
{
- int i, rc, cfg_size = 0;
+ int i, cfg_size = 0;
uint8_t status;
struct VirtioFeatureDesc {
uint32_t features;
uint8_t index;
} __attribute__((packed)) feats;
- IPL_assert(virtio_is_supported(vdev->schid), "PE");
+ if (!virtio_is_supported(vdev->schid)) {
+ puts("Virtio unsupported for this device ID");
+ return -ENODEV;
+ }
/* device ID has been established now */
vdev->config.blk.blk_size = 0; /* mark "illegal" - setup started... */
@@ -235,8 +238,10 @@ void virtio_setup_ccw(VDev *vdev)
run_ccw(vdev, CCW_CMD_VDEV_RESET, NULL, 0, false);
status = VIRTIO_CONFIG_S_ACKNOWLEDGE;
- rc = run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false);
- IPL_assert(rc == 0, "Could not write ACKNOWLEDGE status to host");
+ if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
+ puts("Could not write ACKNOWLEDGE status to host");
+ return -EIO;
+ }
switch (vdev->senseid.cu_model) {
case VIRTIO_ID_NET:
@@ -255,27 +260,37 @@ void virtio_setup_ccw(VDev *vdev)
cfg_size = sizeof(vdev->config.scsi);
break;
default:
- panic("Unsupported virtio device\n");
+ puts("Unsupported virtio device");
+ return -ENODEV;
}
status |= VIRTIO_CONFIG_S_DRIVER;
- rc = run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false);
- IPL_assert(rc == 0, "Could not write DRIVER status to host");
+ if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
+ puts("Could not write DRIVER status to host");
+ return -EIO;
+ }
/* Feature negotiation */
for (i = 0; i < ARRAY_SIZE(vdev->guest_features); i++) {
feats.features = 0;
feats.index = i;
- rc = run_ccw(vdev, CCW_CMD_READ_FEAT, &feats, sizeof(feats), false);
- IPL_assert(rc == 0, "Could not get features bits");
+ if (run_ccw(vdev, CCW_CMD_READ_FEAT, &feats, sizeof(feats), false)) {
+ puts("Could not get features bits");
+ return -EIO;
+ }
+
vdev->guest_features[i] &= bswap32(feats.features);
feats.features = bswap32(vdev->guest_features[i]);
- rc = run_ccw(vdev, CCW_CMD_WRITE_FEAT, &feats, sizeof(feats), false);
- IPL_assert(rc == 0, "Could not set features bits");
+ if (run_ccw(vdev, CCW_CMD_WRITE_FEAT, &feats, sizeof(feats), false)) {
+ puts("Could not set features bits");
+ return -EIO;
+ }
}
- rc = run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size, false);
- IPL_assert(rc == 0, "Could not get virtio device configuration");
+ if (run_ccw(vdev, CCW_CMD_READ_CONF, &vdev->config, cfg_size, false)) {
+ puts("Could not get virtio device configuration");
+ return -EIO;
+ }
for (i = 0; i < vdev->nr_vqs; i++) {
VqInfo info = {
@@ -289,19 +304,27 @@ void virtio_setup_ccw(VDev *vdev)
.num = 0,
};
- rc = run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config), false);
- IPL_assert(rc == 0, "Could not get virtio device VQ configuration");
+ if (run_ccw(vdev, CCW_CMD_READ_VQ_CONF, &config, sizeof(config),
+ false)) {
+ puts("Could not get virtio device VQ config");
+ return -EIO;
+ }
info.num = config.num;
vring_init(&vdev->vrings[i], &info);
vdev->vrings[i].schid = vdev->schid;
- IPL_assert(
- run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info), false) == 0,
- "Cannot set VQ info");
+ if (run_ccw(vdev, CCW_CMD_SET_VQ, &info, sizeof(info), false)) {
+ puts("Cannot set VQ info");
+ return -EIO;
+ }
}
status |= VIRTIO_CONFIG_S_DRIVER_OK;
- rc = run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false);
- IPL_assert(rc == 0, "Could not write DRIVER_OK status to host");
+ if (run_ccw(vdev, CCW_CMD_WRITE_STATUS, &status, sizeof(status), false)) {
+ puts("Could not write DRIVER_OK status to host");
+ return -EIO;
+ }
+
+ return 0;
}
bool virtio_is_supported(SubChannelId schid)
diff --git a/pc-bios/s390-ccw/virtio.h b/pc-bios/s390-ccw/virtio.h
index 85bd9d1..9faf398 100644
--- a/pc-bios/s390-ccw/virtio.h
+++ b/pc-bios/s390-ccw/virtio.h
@@ -253,7 +253,6 @@ struct VDev {
uint8_t scsi_dev_heads;
bool scsi_device_selected;
ScsiDevice selected_scsi_device;
- uint64_t netboot_start_addr;
uint32_t max_transfer;
uint32_t guest_features[2];
};
@@ -275,7 +274,7 @@ void vring_send_buf(VRing *vr, void *p, int len, int flags);
int vr_poll(VRing *vr);
int vring_wait_reply(void);
int virtio_run(VDev *vdev, int vqid, VirtioCmd *cmd);
-void virtio_setup_ccw(VDev *vdev);
+int virtio_setup_ccw(VDev *vdev);
int virtio_net_init(void *mac_addr);
diff --git a/pc-bios/s390-netboot.img b/pc-bios/s390-netboot.img
deleted file mode 100644
index 6908e49..0000000
--- a/pc-bios/s390-netboot.img
+++ /dev/null
Binary files differ
diff --git a/plugins/api.c b/plugins/api.c
index 2ff13d0..24ea64e 100644
--- a/plugins/api.c
+++ b/plugins/api.c
@@ -351,6 +351,39 @@ bool qemu_plugin_mem_is_store(qemu_plugin_meminfo_t info)
return get_plugin_meminfo_rw(info) & QEMU_PLUGIN_MEM_W;
}
+qemu_plugin_mem_value qemu_plugin_mem_get_value(qemu_plugin_meminfo_t info)
+{
+ uint64_t low = current_cpu->neg.plugin_mem_value_low;
+ qemu_plugin_mem_value value;
+
+ switch (qemu_plugin_mem_size_shift(info)) {
+ case 0:
+ value.type = QEMU_PLUGIN_MEM_VALUE_U8;
+ value.data.u8 = (uint8_t)low;
+ break;
+ case 1:
+ value.type = QEMU_PLUGIN_MEM_VALUE_U16;
+ value.data.u16 = (uint16_t)low;
+ break;
+ case 2:
+ value.type = QEMU_PLUGIN_MEM_VALUE_U32;
+ value.data.u32 = (uint32_t)low;
+ break;
+ case 3:
+ value.type = QEMU_PLUGIN_MEM_VALUE_U64;
+ value.data.u64 = low;
+ break;
+ case 4:
+ value.type = QEMU_PLUGIN_MEM_VALUE_U128;
+ value.data.u128.low = low;
+ value.data.u128.high = current_cpu->neg.plugin_mem_value_high;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ return value;
+}
+
/*
* Virtual Memory queries
*/
@@ -527,6 +560,26 @@ GArray *qemu_plugin_get_registers(void)
return create_register_handles(regs);
}
+bool qemu_plugin_read_memory_vaddr(vaddr addr, GByteArray *data, size_t len)
+{
+ g_assert(current_cpu);
+
+ if (len == 0) {
+ return false;
+ }
+
+ g_byte_array_set_size(data, len);
+
+ int result = cpu_memory_rw_debug(current_cpu, addr, data->data,
+ data->len, false);
+
+ if (result < 0) {
+ return false;
+ }
+
+ return true;
+}
+
int qemu_plugin_read_register(struct qemu_plugin_register *reg, GByteArray *buf)
{
g_assert(current_cpu);
diff --git a/plugins/core.c b/plugins/core.c
index 12c67b4..bb105e8 100644
--- a/plugins/core.c
+++ b/plugins/core.c
@@ -214,30 +214,49 @@ CPUPluginState *qemu_plugin_create_vcpu_state(void)
static void plugin_grow_scoreboards__locked(CPUState *cpu)
{
- if (cpu->cpu_index < plugin.scoreboard_alloc_size) {
+ size_t scoreboard_size = plugin.scoreboard_alloc_size;
+ bool need_realloc = false;
+
+ if (cpu->cpu_index < scoreboard_size) {
return;
}
- bool need_realloc = FALSE;
- while (cpu->cpu_index >= plugin.scoreboard_alloc_size) {
- plugin.scoreboard_alloc_size *= 2;
- need_realloc = TRUE;
+ while (cpu->cpu_index >= scoreboard_size) {
+ scoreboard_size *= 2;
+ need_realloc = true;
}
+ if (!need_realloc) {
+ return;
+ }
- if (!need_realloc || QLIST_EMPTY(&plugin.scoreboards)) {
- /* nothing to do, we just updated sizes for future scoreboards */
+ if (QLIST_EMPTY(&plugin.scoreboards)) {
+ /* just update size for future scoreboards */
+ plugin.scoreboard_alloc_size = scoreboard_size;
return;
}
+ /*
+ * A scoreboard creation/deletion might be in progress. If a new vcpu is
+ * initialized at the same time, we are safe, as the new
+ * plugin.scoreboard_alloc_size was not yet written.
+ */
+ qemu_rec_mutex_unlock(&plugin.lock);
+
/* cpus must be stopped, as tb might still use an existing scoreboard. */
start_exclusive();
- struct qemu_plugin_scoreboard *score;
- QLIST_FOREACH(score, &plugin.scoreboards, entry) {
- g_array_set_size(score->data, plugin.scoreboard_alloc_size);
+ /* re-acquire lock */
+ qemu_rec_mutex_lock(&plugin.lock);
+ /* in case another vcpu is created between unlock and exclusive section. */
+ if (scoreboard_size > plugin.scoreboard_alloc_size) {
+ struct qemu_plugin_scoreboard *score;
+ QLIST_FOREACH(score, &plugin.scoreboards, entry) {
+ g_array_set_size(score->data, scoreboard_size);
+ }
+ plugin.scoreboard_alloc_size = scoreboard_size;
+ /* force all tb to be flushed, as scoreboard pointers were changed. */
+ tb_flush(cpu);
}
- /* force all tb to be flushed, as scoreboard pointers were changed. */
- tb_flush(cpu);
end_exclusive();
}
@@ -583,6 +602,8 @@ void exec_inline_op(enum plugin_dyn_cb_type type,
}
void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr,
+ uint64_t value_low,
+ uint64_t value_high,
MemOpIdx oi, enum qemu_plugin_mem_rw rw)
{
GArray *arr = cpu->neg.plugin_mem_cbs;
@@ -591,6 +612,10 @@ void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr,
if (arr == NULL) {
return;
}
+
+ cpu->neg.plugin_mem_value_low = value_low;
+ cpu->neg.plugin_mem_value_high = value_high;
+
for (i = 0; i < arr->len; i++) {
struct qemu_plugin_dyn_cb *cb =
&g_array_index(arr, struct qemu_plugin_dyn_cb, i);
diff --git a/plugins/loader.c b/plugins/loader.c
index 513a429..ebc01da 100644
--- a/plugins/loader.c
+++ b/plugins/loader.c
@@ -18,6 +18,7 @@
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "qemu/config-file.h"
+#include "qemu/help_option.h"
#include "qapi/error.h"
#include "qemu/lockable.h"
#include "qemu/option.h"
@@ -98,7 +99,12 @@ static int plugin_add(void *opaque, const char *name, const char *value,
bool is_on;
char *fullarg;
- if (strcmp(name, "file") == 0) {
+ if (is_help_option(value)) {
+ printf("Plugin options\n");
+ printf(" file=<path/to/plugin.so>\n");
+ printf(" plugin specific arguments\n");
+ exit(0);
+ } else if (strcmp(name, "file") == 0) {
if (strcmp(value, "") == 0) {
error_setg(errp, "requires a non-empty argument");
return 1;
diff --git a/plugins/meson.build b/plugins/meson.build
index 18a0303..1cc039d 100644
--- a/plugins/meson.build
+++ b/plugins/meson.build
@@ -1,3 +1,7 @@
+if not get_option('plugins')
+ subdir_done()
+endif
+
# Modules need more symbols than just those in plugins/qemu-plugins.symbols
if not enable_modules
if host_os == 'darwin'
@@ -12,29 +16,27 @@ if not enable_modules
endif
endif
-if get_option('plugins')
- if host_os == 'windows'
- dlltool = find_program('dlltool', required: true)
+if host_os == 'windows'
+ dlltool = find_program('dlltool', required: true)
- # Generate a .lib file for plugins to link against.
- # First, create a .def file listing all the symbols a plugin should expect to have
- # available in qemu
- win32_plugin_def = configure_file(
- input: files('qemu-plugins.symbols'),
- output: 'qemu_plugin_api.def',
- capture: true,
- command: ['sed', '-e', '0,/^/s//EXPORTS/; s/[{};]//g', '@INPUT@'])
- # then use dlltool to assemble a delaylib.
- win32_qemu_plugin_api_lib = configure_file(
- input: win32_plugin_def,
- output: 'libqemu_plugin_api.a',
- command: [dlltool, '--input-def', '@INPUT@',
- '--output-delaylib', '@OUTPUT@', '--dllname', 'qemu.exe']
- )
- endif
- specific_ss.add(files(
- 'loader.c',
- 'core.c',
- 'api.c',
- ))
+ # Generate a .lib file for plugins to link against.
+ # First, create a .def file listing all the symbols a plugin should expect to have
+ # available in qemu
+ win32_plugin_def = configure_file(
+ input: files('qemu-plugins.symbols'),
+ output: 'qemu_plugin_api.def',
+ capture: true,
+ command: ['sed', '-e', '0,/^/s//EXPORTS/; s/[{};]//g', '@INPUT@'])
+ # then use dlltool to assemble a delaylib.
+ win32_qemu_plugin_api_lib = configure_file(
+ input: win32_plugin_def,
+ output: 'libqemu_plugin_api.a',
+ command: [dlltool, '--input-def', '@INPUT@',
+ '--output-delaylib', '@OUTPUT@', '--dllname', 'qemu.exe']
+ )
endif
+specific_ss.add(files(
+ 'loader.c',
+ 'core.c',
+ 'api.c',
+))
diff --git a/plugins/qemu-plugins.symbols b/plugins/qemu-plugins.symbols
index ca773d8..032661f 100644
--- a/plugins/qemu-plugins.symbols
+++ b/plugins/qemu-plugins.symbols
@@ -13,6 +13,7 @@
qemu_plugin_insn_size;
qemu_plugin_insn_symbol;
qemu_plugin_insn_vaddr;
+ qemu_plugin_mem_get_value;
qemu_plugin_mem_is_big_endian;
qemu_plugin_mem_is_sign_extended;
qemu_plugin_mem_is_store;
@@ -20,6 +21,7 @@
qemu_plugin_num_vcpus;
qemu_plugin_outs;
qemu_plugin_path_to_binary;
+ qemu_plugin_read_memory_vaddr;
qemu_plugin_read_register;
qemu_plugin_register_atexit_cb;
qemu_plugin_register_flush_cb;
diff --git a/po/it.po b/po/it.po
index c6d9517..363b9bd 100644
--- a/po/it.po
+++ b/po/it.po
@@ -65,7 +65,7 @@ msgid "Detach Tab"
msgstr "_Sposta in una nuova finestra"
msgid "Show Menubar"
-msgstr ""
+msgstr "Mostra _barra dei menu"
msgid "_Machine"
msgstr "_Macchina virtuale"
diff --git a/python/scripts/vendor.py b/python/scripts/vendor.py
index 07aff97..0405e91 100755
--- a/python/scripts/vendor.py
+++ b/python/scripts/vendor.py
@@ -41,8 +41,8 @@ def main() -> int:
parser.parse_args()
packages = {
- "meson==1.2.3":
- "4533a43c34548edd1f63a276a42690fce15bde9409bcf20c4b8fa3d7e4d7cac1",
+ "meson==1.5.0":
+ "52b34f4903b882df52ad0d533146d4b992c018ea77399f825579737672ae7b20",
}
vendor_dir = Path(__file__, "..", "..", "wheels").resolve()
diff --git a/python/wheels/meson-1.2.3-py3-none-any.whl b/python/wheels/meson-1.2.3-py3-none-any.whl
deleted file mode 100644
index a8b84e5..0000000
--- a/python/wheels/meson-1.2.3-py3-none-any.whl
+++ /dev/null
Binary files differ
diff --git a/python/wheels/meson-1.5.0-py3-none-any.whl b/python/wheels/meson-1.5.0-py3-none-any.whl
new file mode 100644
index 0000000..c7edeb3
--- /dev/null
+++ b/python/wheels/meson-1.5.0-py3-none-any.whl
Binary files differ
diff --git a/python/wheels/pycotap-1.3.1-py3-none-any.whl b/python/wheels/pycotap-1.3.1-py3-none-any.whl
new file mode 100644
index 0000000..9c2c7d2
--- /dev/null
+++ b/python/wheels/pycotap-1.3.1-py3-none-any.whl
Binary files differ
diff --git a/pythondeps.toml b/pythondeps.toml
index f6e590f..c03c9df 100644
--- a/pythondeps.toml
+++ b/pythondeps.toml
@@ -19,7 +19,8 @@
[meson]
# The install key should match the version in python/wheels/
-meson = { accepted = ">=1.1.0", installed = "1.2.3", canary = "meson" }
+meson = { accepted = ">=1.5.0", installed = "1.5.0", canary = "meson" }
+pycotap = { accepted = ">=1.1.0", installed = "1.3.1" }
[docs]
# Please keep the installed versions in sync with docs/requirements.txt
@@ -30,5 +31,5 @@ sphinx_rtd_theme = { accepted = ">=0.5", installed = "1.1.1" }
# Note that qemu.git/python/ is always implicitly installed.
# Prefer an LTS version when updating the accepted versions of
# avocado-framework, for example right now the limit is 92.x.
-avocado-framework = { accepted = "(>=88.1, <93.0)", installed = "88.1", canary = "avocado" }
+avocado-framework = { accepted = "(>=103.0, <104.0)", installed = "103.0", canary = "avocado" }
pycdlib = { accepted = ">=1.11.0" }
diff --git a/qapi/block-core.json b/qapi/block-core.json
index f400b33..fd3bcc1 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1158,11 +1158,11 @@
#
# @query-nodes: If true, the command will query all the block nodes
# that have a node name, in a list which will include "parent"
-# information, but not "backing". If false or omitted, the
+# information, but not "backing". If false or omitted, the
# behavior is as before - query all the device backends,
-# recursively including their "parent" and "backing". Filter nodes
-# that were created implicitly are skipped over in this mode.
-# (Since 2.3)
+# recursively including their "parent" and "backing". Filter
+# nodes that were created implicitly are skipped over in this
+# mode. (Since 2.3)
#
# Returns: A list of @BlockStats for each virtual block devices.
#
@@ -1286,7 +1286,7 @@
# jobs, cancel the job
#
# @ignore: ignore the error, only report a QMP event (BLOCK_IO_ERROR
-# or BLOCK_JOB_ERROR). The backup, mirror and commit block jobs
+# or BLOCK_JOB_ERROR). The backup, mirror and commit block jobs
# retry the failing request later and may still complete
# successfully. The stream block job continues to stream and will
# complete with an error.
@@ -1551,11 +1551,16 @@
# it should not be less than job cluster size which is calculated
# as maximum of target image cluster size and 64k. Default 0.
#
+# @min-cluster-size: Minimum size of blocks used by copy-before-write
+# and background copy operations. Has to be a power of 2. No
+# effect if smaller than the maximum of the target's cluster size
+# and 64 KiB. Default 0. (Since 9.2)
+#
# Since: 6.0
##
{ 'struct': 'BackupPerf',
- 'data': { '*use-copy-range': 'bool',
- '*max-workers': 'int', '*max-chunk': 'int64' } }
+ 'data': { '*use-copy-range': 'bool', '*max-workers': 'int',
+ '*max-chunk': 'int64', '*min-cluster-size': 'size' } }
##
# @BackupCommon:
@@ -1574,7 +1579,7 @@
# for unlimited.
#
# @bitmap: The name of a dirty bitmap to use. Must be present if sync
-# is "bitmap" or "incremental". Can be present if sync is "full"
+# is "bitmap" or "incremental". Can be present if sync is "full"
# or "top". Must not be present otherwise.
# (Since 2.4 (drive-backup), 3.1 (blockdev-backup))
#
@@ -1619,9 +1624,9 @@
#
# @unstable: Member @x-perf is experimental.
#
-# .. note:: @on-source-error and @on-target-error only affect background
-# I/O. If an error occurs during a guest write request, the device's
-# rerror/werror actions will be used.
+# .. note:: @on-source-error and @on-target-error only affect
+# background I/O. If an error occurs during a guest write request,
+# the device's rerror/werror actions will be used.
#
# Since: 4.2
##
@@ -1699,7 +1704,7 @@
# Takes a snapshot of a block device.
#
# Take a snapshot, by installing 'node' as the backing image of
-# 'overlay'. Additionally, if 'node' is associated with a block
+# 'overlay'. Additionally, if 'node' is associated with a block
# device, the block device changes to using 'overlay' as its new
# active image.
#
@@ -1738,7 +1743,7 @@
# Change the backing file in the image file metadata. This does not
# cause QEMU to reopen the image file to reparse the backing filename
# (it may, however, perform a reopen to change permissions from r/o ->
-# r/w -> r/o, if needed). The new backing file string is written into
+# r/w -> r/o, if needed). The new backing file string is written into
# the image file metadata, and the QEMU internal strings are updated.
#
# @image-node-name: The name of the block driver state node of the
@@ -1853,7 +1858,6 @@
#
# Errors:
# - If @device does not exist, DeviceNotFound
-# - Any other error returns a GenericError.
#
# Since: 1.3
#
@@ -1882,8 +1886,8 @@
# Start a point-in-time copy of a block device to a new destination.
# The status of ongoing drive-backup operations can be checked with
# query-block-jobs where the BlockJobInfo.type field has the value
-# 'backup'. The operation can be stopped before it has completed using
-# the block-job-cancel command.
+# 'backup'. The operation can be stopped before it has completed
+# using the block-job-cancel command.
#
# Features:
#
@@ -1913,8 +1917,8 @@
# Start a point-in-time copy of a block device to a new destination.
# The status of ongoing blockdev-backup operations can be checked with
# query-block-jobs where the BlockJobInfo.type field has the value
-# 'backup'. The operation can be stopped before it has completed using
-# the block-job-cancel command.
+# 'backup'. The operation can be stopped before it has completed
+# using the block-job-cancel command.
#
# Errors:
# - If @device is not a valid block device, DeviceNotFound
@@ -2299,7 +2303,7 @@
#
# Errors:
# - If @node is not a valid block device or node, DeviceNotFound
-# - If @name is already taken, GenericError with an explanation
+# - If @name is already taken, GenericError
#
# Since: 2.4
#
@@ -2322,7 +2326,7 @@
#
# Errors:
# - If @node is not a valid block device or node, DeviceNotFound
-# - If @name is not found, GenericError with an explanation
+# - If @name is not found, GenericError
# - if @name is frozen by an operation, GenericError
#
# Since: 2.4
@@ -2346,7 +2350,7 @@
#
# Errors:
# - If @node is not a valid block device, DeviceNotFound
-# - If @name is not found, GenericError with an explanation
+# - If @name is not found, GenericError
#
# Since: 2.4
#
@@ -2367,7 +2371,7 @@
#
# Errors:
# - If @node is not a valid block device, DeviceNotFound
-# - If @name is not found, GenericError with an explanation
+# - If @name is not found, GenericError
#
# Since: 4.0
#
@@ -2388,7 +2392,7 @@
#
# Errors:
# - If @node is not a valid block device, DeviceNotFound
-# - If @name is not found, GenericError with an explanation
+# - If @name is not found, GenericError
#
# Since: 4.0
#
@@ -2462,7 +2466,6 @@
# Errors:
# - If @node is not a valid block device, DeviceNotFound
# - If @name is not found or if hashing has failed, GenericError
-# with an explanation
#
# Since: 2.10
##
@@ -2832,7 +2835,7 @@
#
# @speed: the maximum speed, in bytes per second
#
-# @on-error: the action to take on an error (default report). 'stop'
+# @on-error: the action to take on an error (default report). 'stop'
# and 'enospc' can only be used if the block device supports
# io-status (see BlockInfo). (Since 1.3)
#
@@ -3034,8 +3037,8 @@
# semantics.
#
# This command will refuse to operate on any job that has not yet
-# reached its terminal state, JOB_STATUS_CONCLUDED. For jobs that make
-# use of the BLOCK_JOB_READY event, block-job-cancel or
+# reached its terminal state, JOB_STATUS_CONCLUDED. For jobs that
+# make use of the BLOCK_JOB_READY event, block-job-cancel or
# block-job-complete will still need to be used as appropriate.
#
# @id: The job identifier.
@@ -3187,12 +3190,18 @@
#
# @snapshot-access: Since 7.0
#
+# Features:
+#
+# @deprecated: Member @gluster is deprecated because GlusterFS
+# development ceased.
+#
# Since: 2.9
##
{ 'enum': 'BlockdevDriver',
'data': [ 'blkdebug', 'blklogwrites', 'blkreplay', 'blkverify', 'bochs',
'cloop', 'compress', 'copy-before-write', 'copy-on-read', 'dmg',
- 'file', 'snapshot-access', 'ftp', 'ftps', 'gluster',
+ 'file', 'snapshot-access', 'ftp', 'ftps',
+ {'name': 'gluster', 'features': [ 'deprecated' ] },
{'name': 'host_cdrom', 'if': 'HAVE_HOST_BLOCK_DEVICE' },
{'name': 'host_device', 'if': 'HAVE_HOST_BLOCK_DEVICE' },
'http', 'https',
@@ -3351,7 +3360,7 @@
# Driver specific block device options for LUKS.
#
# @key-secret: the ID of a QCryptoSecret object providing the
-# decryption key (since 2.6). Mandatory except when doing a
+# decryption key (since 2.6). Mandatory except when doing a
# metadata-only probe of the image.
#
# @header: block device holding a detached LUKS header. (since 9.0)
@@ -3746,7 +3755,7 @@
#
# Since: 4.1
##
-{ 'enum': 'BlkdebugIOType', 'prefix': 'BLKDEBUG_IO_TYPE',
+{ 'enum': 'BlkdebugIOType',
'data': [ 'read', 'write', 'write-zeroes', 'discard', 'flush',
'block-status' ] }
@@ -4050,6 +4059,7 @@
# @path: path to the vhost-vdpa character device.
#
# Features:
+#
# @fdset: Member @path supports the special "/dev/fdset/N" path
# (since 8.1)
#
@@ -4162,7 +4172,7 @@
##
{ 'struct': 'RbdEncryptionCreateOptionsLUKSBase',
'base': 'RbdEncryptionOptionsLUKSBase',
- 'data': { '*cipher-alg': 'QCryptoCipherAlgorithm' } }
+ 'data': { '*cipher-alg': 'QCryptoCipherAlgo' } }
##
# @RbdEncryptionOptionsLUKS:
@@ -4427,7 +4437,7 @@
# curl backend. URLs must start with "http://".
#
# @cookie: List of cookies to set; format is "name1=content1;
-# name2=content2;" as explained by CURLOPT_COOKIE(3). Defaults to
+# name2=content2;" as explained by CURLOPT_COOKIE(3). Defaults to
# no cookies.
#
# @cookie-secret: ID of a QCryptoSecret object providing the cookie
@@ -4447,7 +4457,7 @@
# curl backend. URLs must start with "https://".
#
# @cookie: List of cookies to set; format is "name1=content1;
-# name2=content2;" as explained by CURLOPT_COOKIE(3). Defaults to
+# name2=content2;" as explained by CURLOPT_COOKIE(3). Defaults to
# no cookies.
#
# @sslverify: Whether to verify the SSL certificate's validity
@@ -4638,12 +4648,18 @@
# @on-cbw-error parameter will decide how this failure is handled.
# Default 0. (Since 7.1)
#
+# @min-cluster-size: Minimum size of blocks used by copy-before-write
+# operations. Has to be a power of 2. No effect if smaller than
+# the maximum of the target's cluster size and 64 KiB. Default 0.
+# (Since 9.2)
+#
# Since: 6.2
##
{ 'struct': 'BlockdevOptionsCbw',
'base': 'BlockdevOptionsGenericFormat',
'data': { 'target': 'BlockdevRef', '*bitmap': 'BlockDirtyBitmap',
- '*on-cbw-error': 'OnCbwError', '*cbw-timeout': 'uint32' } }
+ '*on-cbw-error': 'OnCbwError', '*cbw-timeout': 'uint32',
+ '*min-cluster-size': 'size' } }
##
# @BlockdevOptions:
@@ -4653,10 +4669,10 @@
#
# @driver: block driver name
#
-# @node-name: the node name of the new node (Since 2.0). This option
+# @node-name: the node name of the new node (Since 2.0). This option
# is required on the top level of blockdev-add. Valid node names
# start with an alphabetic character and may contain only
-# alphanumeric characters, '-', '.' and '_'. Their maximum length
+# alphanumeric characters, '-', '.' and '_'. Their maximum length
# is 31 characters.
#
# @discard: discard-related options (default: ignore)
@@ -4664,7 +4680,7 @@
# @cache: cache-related options
#
# @read-only: whether the block device should be read-only (default:
-# false). Note that some block drivers support only read-only
+# false). Note that some block drivers support only read-only
# access, either generally or in certain configurations. In this
# case, the default value does not work and the option must be
# specified explicitly.
@@ -5231,8 +5247,8 @@
# monolithcFlat, twoGbMaxExtentSparse and twoGbMaxExtentFlat
# formats. For monolithicFlat, only one entry is required; for
# twoGbMaxExtent* formats, the number of entries required is
-# calculated as extent_number = virtual_size / 2GB. Providing more
-# extents than will be used is an error.
+# calculated as extent_number = virtual_size / 2GB. Providing
+# more extents than will be used is an error.
#
# @subformat: The subformat of the VMDK image. Default:
# "monolithicSparse".
@@ -5244,7 +5260,7 @@
# Default: ide.
#
# @hwversion: Hardware version. The meaningful options are "4" or
-# "6". Default: "4".
+# "6". Default: "4".
#
# @toolsversion: VMware guest tools version. Default: "2147483647"
# (Since 6.2)
@@ -5440,7 +5456,7 @@
##
# @BlockdevAmendOptionsQcow2:
#
-# Driver specific image amend options for qcow2. For now, only
+# Driver specific image amend options for qcow2. For now, only
# encryption options can be amended
#
# @encrypt: Encryption options to be amended
@@ -5543,8 +5559,8 @@
# after this event and must be repaired (Since 2.2; before, every
# BLOCK_IMAGE_CORRUPTED event was fatal)
#
-# .. note:: If action is "stop", a STOP event will eventually follow the
-# BLOCK_IO_ERROR event.
+# .. note:: If action is "stop", a STOP event will eventually follow
+# the BLOCK_IO_ERROR event.
#
# .. qmp-example::
#
@@ -5568,6 +5584,8 @@
#
# Emitted when a disk I/O error occurs
#
+# @qom-path: path to the device object in the QOM tree (since 9.2)
+#
# @device: device name. This is always present for compatibility
# reasons, but it can be empty ("") if the image does not have a
# device name associated.
@@ -5590,15 +5608,18 @@
# field is a debugging aid for humans, it should not be parsed by
# applications) (since: 2.2)
#
-# .. note:: If action is "stop", a STOP event will eventually follow the
-# BLOCK_IO_ERROR event.
+# .. note:: If action is "stop", a STOP event will eventually follow
+# the BLOCK_IO_ERROR event.
+#
+# .. note:: This event is rate-limited.
#
# Since: 0.13
#
# .. qmp-example::
#
# <- { "event": "BLOCK_IO_ERROR",
-# "data": { "device": "ide0-hd1",
+# "data": { "qom-path": "/machine/unattached/device[0]",
+# "device": "ide0-hd1",
# "node-name": "#block212",
# "operation": "write",
# "action": "stop",
@@ -5606,7 +5627,7 @@
# "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
##
{ 'event': 'BLOCK_IO_ERROR',
- 'data': { 'device': 'str', '*node-name': 'str',
+ 'data': { 'qom-path': 'str', 'device': 'str', '*node-name': 'str',
'operation': 'IoOperationType',
'action': 'BlockErrorAction', '*nospace': 'bool',
'reason': 'str' } }
@@ -6046,10 +6067,6 @@
#
# @name: the name of the internal snapshot to be created
#
-# .. note:: In a transaction, if @name is empty or any snapshot matching
-# @name exists, the operation will fail. Only some image formats
-# support it; for example, qcow2, and rbd.
-#
# Since: 1.7
##
{ 'struct': 'BlockdevSnapshotInternal',
@@ -6070,6 +6087,9 @@
# - If the format of the image used does not support it,
# GenericError
#
+# .. note:: Only some image formats such as qcow2 and rbd support
+# internal snapshots.
+#
# Since: 1.7
#
# .. qmp-example::
diff --git a/qapi/block-export.json b/qapi/block-export.json
index 3919a2d..ce33fe3 100644
--- a/qapi/block-export.json
+++ b/qapi/block-export.json
@@ -28,7 +28,7 @@
# @max-connections: The maximum number of connections to allow at the
# same time, 0 for unlimited. Setting this to 1 also stops the
# server from advertising multiple client support (since 5.2;
-# default: 0)
+# default: 100)
#
# Since: 4.2
##
@@ -63,7 +63,7 @@
# @max-connections: The maximum number of connections to allow at the
# same time, 0 for unlimited. Setting this to 1 also stops the
# server from advertising multiple client support (since 5.2;
-# default: 0).
+# default: 100).
#
# Errors:
# - if the server is already running
@@ -163,8 +163,8 @@
# Options for exporting a block graph node on some (file) mountpoint
# as a raw image.
#
-# @mountpoint: Path on which to export the block device via FUSE. This
-# must point to an existing regular file.
+# @mountpoint: Path on which to export the block device via FUSE.
+# This must point to an existing regular file.
#
# @growable: Whether writes beyond the EOF should grow the block node
# accordingly. (default: false)
@@ -172,7 +172,7 @@
# @allow-other: If this is off, only qemu's user is allowed access to
# this export. That cannot be changed even with chmod or chown.
# Enabling this option will allow other users access to the export
-# with the FUSE mount option "allow_other". Note that using
+# with the FUSE mount option "allow_other". Note that using
# allow_other as a non-root user requires user_allow_other to be
# enabled in the global fuse.conf configuration file. In auto
# mode (the default), the FUSE export driver will first attempt to
@@ -199,7 +199,7 @@
# @queue-size: the size of virtqueue. Defaults to 256.
#
# @logical-block-size: Logical block size in bytes. Range [512,
-# PAGE_SIZE] and must be power of 2. Defaults to 512 bytes.
+# PAGE_SIZE] and must be power of 2. Defaults to 512 bytes.
#
# @serial: the serial number of virtio block device. Defaults to
# empty string.
diff --git a/qapi/block.json b/qapi/block.json
index ce9490a..e66666f 100644
--- a/qapi/block.json
+++ b/qapi/block.json
@@ -454,8 +454,8 @@
# different group. In this case the limits specified in the
# parameters will be applied to the new group only.
#
-# I/O limits can be disabled by setting all of them to 0. In this case
-# the device will be removed from its group and the rest of its
+# I/O limits can be disabled by setting all of them to 0. In this
+# case the device will be removed from its group and the rest of its
# members will not be affected. The 'group' parameter is ignored.
#
# Errors:
@@ -519,10 +519,10 @@
# @id: The name or QOM path of the guest device.
#
# @boundaries: list of interval boundary values (see description in
-# BlockLatencyHistogramInfo definition). If specified, all latency
-# histograms are removed, and empty ones created for all io types
-# with intervals corresponding to @boundaries (except for io
-# types, for which specific boundaries are set through the
+# BlockLatencyHistogramInfo definition). If specified, all
+# latency histograms are removed, and empty ones created for all
+# io types with intervals corresponding to @boundaries (except for
+# io types, for which specific boundaries are set through the
# following parameters).
#
# @boundaries-read: list of interval boundary values for read latency
diff --git a/qapi/char.json b/qapi/char.json
index 5e4aeb9..e045354 100644
--- a/qapi/char.json
+++ b/qapi/char.json
@@ -258,7 +258,7 @@
# @server: create server socket (default: true)
#
# @wait: wait for incoming connection on server sockets (default:
-# false). Silently ignored with server: false. This use is
+# false). Silently ignored with server: false. This use is
# deprecated.
#
# @nodelay: set TCP_NODELAY socket option (default: false)
@@ -273,7 +273,19 @@
#
# @reconnect: For a client socket, if a socket is disconnected, then
# attempt a reconnect after the given number of seconds. Setting
-# this to zero disables this function. (default: 0) (Since: 2.2)
+# this to zero disables this function. The use of this member is
+# deprecated, use @reconnect-ms instead. (default: 0) (Since: 2.2)
+#
+# @reconnect-ms: For a client socket, if a socket is disconnected,
+# then attempt a reconnect after the given number of milliseconds.
+# Setting this to zero disables this function. This member is
+# mutually exclusive with @reconnect.
+# (default: 0) (Since: 9.2)
+#
+# Features:
+#
+# @deprecated: Member @reconnect is deprecated. Use @reconnect-ms
+# instead.
#
# Since: 1.4
##
@@ -287,7 +299,8 @@
'*telnet': 'bool',
'*tn3270': 'bool',
'*websocket': 'bool',
- '*reconnect': 'int' },
+ '*reconnect': { 'type': 'int', 'features': [ 'deprecated' ] },
+ '*reconnect-ms': 'int' },
'base': 'ChardevCommon' }
##
@@ -388,9 +401,9 @@
#
# @rows: console height, in chars
#
-# .. note:: The options are only effective when the VNC or SDL graphical
-# display backend is active. They are ignored with the GTK, Spice,
-# VNC and D-Bus display backends.
+# .. note:: The options are only effective when the VNC or SDL
+# graphical display backend is active. They are ignored with the
+# GTK, Spice, VNC and D-Bus display backends.
#
# Since: 1.5
##
@@ -432,39 +445,65 @@
'if': 'CONFIG_SPICE_PROTOCOL' }
##
+# @ChardevPty:
+#
+# Configuration info for pty implementation.
+#
+# @path: optional path to create a symbolic link that points to the
+# allocated PTY
+#
+# Since: 9.2
+##
+{ 'struct': 'ChardevPty',
+ 'data': { '*path': 'str' },
+ 'base': 'ChardevCommon' }
+
+##
# @ChardevBackendKind:
#
-# @pipe: Since 1.5
+# @file: regular files
+#
+# @serial: serial host device
#
-# @udp: Since 1.5
+# @parallel: parallel host device
#
-# @mux: Since 1.5
+# @pipe: pipes (since 1.5)
#
-# @msmouse: Since 1.5
+# @socket: stream socket
#
-# @wctablet: Since 2.9
+# @udp: datagram socket (since 1.5)
#
-# @braille: Since 1.5
+# @pty: pseudo-terminal
#
-# @testdev: Since 2.2
+# @null: provides no input, throws away output
#
-# @stdio: Since 1.5
+# @mux: (since 1.5)
#
-# @console: Since 1.5
+# @msmouse: emulated Microsoft serial mouse (since 1.5)
#
-# @spicevmc: Since 1.5
+# @wctablet: emulated Wacom Penpartner serial tablet (since 2.9)
#
-# @spiceport: Since 1.5
+# @braille: Baum Braille device (since 1.5)
#
-# @qemu-vdagent: Since 6.1
+# @testdev: device for test-suite control (since 2.2)
#
-# @dbus: Since 7.0
+# @stdio: standard I/O (since 1.5)
#
-# @vc: v1.5
+# @console: Windows console (since 1.5)
#
-# @ringbuf: Since 1.6
+# @spicevmc: spice vm channel (since 1.5)
#
-# @memory: Since 1.5
+# @spiceport: Spice port channel (since 1.5)
+#
+# @qemu-vdagent: Spice vdagent (since 6.1)
+#
+# @dbus: D-Bus channel (since 7.0)
+#
+# @vc: virtual console (since 1.5)
+#
+# @ringbuf: memory ring buffer (since 1.6)
+#
+# @memory: synonym for @ringbuf (since 1.5)
#
# Features:
#
@@ -630,6 +669,17 @@
{ 'struct': 'ChardevRingbufWrapper',
'data': { 'data': 'ChardevRingbuf' } }
+
+##
+# @ChardevPtyWrapper:
+#
+# @data: Configuration info for pty chardevs
+#
+# Since: 9.2
+##
+{ 'struct': 'ChardevPtyWrapper',
+ 'data': { 'data': 'ChardevPty' } }
+
##
# @ChardevBackend:
#
@@ -650,7 +700,7 @@
'pipe': 'ChardevHostdevWrapper',
'socket': 'ChardevSocketWrapper',
'udp': 'ChardevUdpWrapper',
- 'pty': 'ChardevCommonWrapper',
+ 'pty': 'ChardevPtyWrapper',
'null': 'ChardevCommonWrapper',
'mux': 'ChardevMuxWrapper',
'msmouse': 'ChardevCommonWrapper',
diff --git a/qapi/common.json b/qapi/common.json
index 7558ce5..6ffc7a3 100644
--- a/qapi/common.json
+++ b/qapi/common.json
@@ -183,7 +183,19 @@
##
# @GrabToggleKeys:
#
-# Keys to toggle input-linux between host and guest.
+# Key combinations to toggle input-linux between host and guest.
+#
+# @ctrl-ctrl: left and right control key
+#
+# @alt-alt: left and right alt key
+#
+# @shift-shift: left and right shift key
+#
+# @meta-meta: left and right meta key
+#
+# @scrolllock: scroll lock key
+#
+# @ctrl-scrolllock: either control key and scroll lock key
#
# Since: 4.0
##
diff --git a/qapi/control.json b/qapi/control.json
index 950443d..336386f 100644
--- a/qapi/control.json
+++ b/qapi/control.json
@@ -22,13 +22,14 @@
# "arguments": { "enable": [ "oob" ] } }
# <- { "return": {} }
#
-# .. note:: This command is valid exactly when first connecting: it must
-# be issued before any other command will be accepted, and will fail
-# once the monitor is accepting other commands.
-# (see :doc:`/interop/qmp-spec`)
+# .. note:: This command is valid exactly when first connecting: it
+# must be issued before any other command will be accepted, and
+# will fail once the monitor is accepting other commands. (see
+# :doc:`/interop/qmp-spec`)
#
-# .. note:: The QMP client needs to explicitly enable QMP capabilities,
-# otherwise all the QMP capabilities will be turned off by default.
+# .. note:: The QMP client needs to explicitly enable QMP
+# capabilities, otherwise all the QMP capabilities will be turned
+# off by default.
#
# Since: 0.13
##
@@ -150,7 +151,6 @@
# }
#
# This example has been shortened as the real response is too long.
-#
##
{ 'command': 'query-commands', 'returns': ['CommandInfo'],
'allow-preconfig': true }
diff --git a/qapi/crypto.json b/qapi/crypto.json
index e102be3..9431522 100644
--- a/qapi/crypto.json
+++ b/qapi/crypto.json
@@ -20,7 +20,6 @@
# Since: 2.5
##
{ 'enum': 'QCryptoTLSCredsEndpoint',
- 'prefix': 'QCRYPTO_TLS_CREDS_ENDPOINT',
'data': ['client', 'server']}
##
@@ -36,21 +35,20 @@
# Since: 2.6
##
{ 'enum': 'QCryptoSecretFormat',
- 'prefix': 'QCRYPTO_SECRET_FORMAT',
'data': ['raw', 'base64']}
##
-# @QCryptoHashAlgorithm:
+# @QCryptoHashAlgo:
#
# The supported algorithms for computing content digests
#
-# @md5: MD5. Should not be used in any new code, legacy compat only
+# @md5: MD5. Should not be used in any new code, legacy compat only
#
-# @sha1: SHA-1. Should not be used in any new code, legacy compat only
+# @sha1: SHA-1. Should not be used in any new code, legacy compat only
#
# @sha224: SHA-224. (since 2.7)
#
-# @sha256: SHA-256. Current recommended strong hash.
+# @sha256: SHA-256. Current recommended strong hash.
#
# @sha384: SHA-384. (since 2.7)
#
@@ -60,12 +58,11 @@
#
# Since: 2.6
##
-{ 'enum': 'QCryptoHashAlgorithm',
- 'prefix': 'QCRYPTO_HASH_ALG',
+{ 'enum': 'QCryptoHashAlgo',
'data': ['md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'ripemd160']}
##
-# @QCryptoCipherAlgorithm:
+# @QCryptoCipherAlgo:
#
# The supported algorithms for content encryption ciphers
#
@@ -98,8 +95,7 @@
#
# Since: 2.6
##
-{ 'enum': 'QCryptoCipherAlgorithm',
- 'prefix': 'QCRYPTO_CIPHER_ALG',
+{ 'enum': 'QCryptoCipherAlgo',
'data': ['aes-128', 'aes-192', 'aes-256',
'des', '3des',
'cast5-128',
@@ -123,11 +119,10 @@
# Since: 2.6
##
{ 'enum': 'QCryptoCipherMode',
- 'prefix': 'QCRYPTO_CIPHER_MODE',
'data': ['ecb', 'cbc', 'xts', 'ctr']}
##
-# @QCryptoIVGenAlgorithm:
+# @QCryptoIVGenAlgo:
#
# The supported algorithms for generating initialization vectors for
# full disk encryption. The 'plain' generator should not be used for
@@ -143,8 +138,7 @@
#
# Since: 2.6
##
-{ 'enum': 'QCryptoIVGenAlgorithm',
- 'prefix': 'QCRYPTO_IVGEN_ALG',
+{ 'enum': 'QCryptoIVGenAlgo',
'data': ['plain', 'plain64', 'essiv']}
##
@@ -160,7 +154,6 @@
# Since: 2.6
##
{ 'enum': 'QCryptoBlockFormat',
-# 'prefix': 'QCRYPTO_BLOCK_FORMAT',
'data': ['qcow', 'luks']}
##
@@ -226,19 +219,16 @@
# @iter-time: number of milliseconds to spend in PBKDF passphrase
# processing. Currently defaults to 2000. (since 2.8)
#
-# @detached-header: create a detached LUKS header. (since 9.0)
-#
# Since: 2.6
##
{ 'struct': 'QCryptoBlockCreateOptionsLUKS',
'base': 'QCryptoBlockOptionsLUKS',
- 'data': { '*cipher-alg': 'QCryptoCipherAlgorithm',
+ 'data': { '*cipher-alg': 'QCryptoCipherAlgo',
'*cipher-mode': 'QCryptoCipherMode',
- '*ivgen-alg': 'QCryptoIVGenAlgorithm',
- '*ivgen-hash-alg': 'QCryptoHashAlgorithm',
- '*hash-alg': 'QCryptoHashAlgorithm',
- '*iter-time': 'int',
- '*detached-header': 'bool'}}
+ '*ivgen-alg': 'QCryptoIVGenAlgo',
+ '*ivgen-hash-alg': 'QCryptoHashAlgo',
+ '*hash-alg': 'QCryptoHashAlgo',
+ '*iter-time': 'int' }}
##
# @QCryptoBlockOpenOptions:
@@ -330,11 +320,11 @@
# Since: 2.7
##
{ 'struct': 'QCryptoBlockInfoLUKS',
- 'data': {'cipher-alg': 'QCryptoCipherAlgorithm',
+ 'data': {'cipher-alg': 'QCryptoCipherAlgo',
'cipher-mode': 'QCryptoCipherMode',
- 'ivgen-alg': 'QCryptoIVGenAlgorithm',
- '*ivgen-hash-alg': 'QCryptoHashAlgorithm',
- 'hash-alg': 'QCryptoHashAlgorithm',
+ 'ivgen-alg': 'QCryptoIVGenAlgo',
+ '*ivgen-hash-alg': 'QCryptoHashAlgo',
+ 'hash-alg': 'QCryptoHashAlgo',
'detached-header': 'bool',
'payload-offset': 'int',
'master-key-iters': 'int',
@@ -443,7 +433,7 @@
#
# @iv: the random initialization vector used for encryption of this
# particular secret. Should be a base64 encrypted string of the
-# 16-byte IV. Mandatory if @keyid is given. Ignored if @keyid is
+# 16-byte IV. Mandatory if @keyid is given. Ignored if @keyid is
# absent.
#
# Features:
@@ -488,7 +478,8 @@
##
{ 'struct': 'SecretKeyringProperties',
'base': 'SecretCommonProperties',
- 'data': { 'serial': 'int32' } }
+ 'data': { 'serial': 'int32' },
+ 'if': 'CONFIG_SECRET_KEYRING' }
##
# @TlsCredsProperties:
@@ -595,7 +586,7 @@
'*sanity-check': 'bool',
'*passwordid': 'str' } }
##
-# @QCryptoAkCipherAlgorithm:
+# @QCryptoAkCipherAlgo:
#
# The supported algorithms for asymmetric encryption ciphers
#
@@ -603,8 +594,7 @@
#
# Since: 7.1
##
-{ 'enum': 'QCryptoAkCipherAlgorithm',
- 'prefix': 'QCRYPTO_AKCIPHER_ALG',
+{ 'enum': 'QCryptoAkCipherAlgo',
'data': ['rsa']}
##
@@ -612,14 +602,17 @@
#
# The type of asymmetric keys.
#
+# @public: public key
+#
+# @private: private key
+#
# Since: 7.1
##
{ 'enum': 'QCryptoAkCipherKeyType',
- 'prefix': 'QCRYPTO_AKCIPHER_KEY_TYPE',
'data': ['public', 'private']}
##
-# @QCryptoRSAPaddingAlgorithm:
+# @QCryptoRSAPaddingAlgo:
#
# The padding algorithm for RSA.
#
@@ -629,8 +622,7 @@
#
# Since: 7.1
##
-{ 'enum': 'QCryptoRSAPaddingAlgorithm',
- 'prefix': 'QCRYPTO_RSA_PADDING_ALG',
+{ 'enum': 'QCryptoRSAPaddingAlgo',
'data': ['raw', 'pkcs1']}
##
@@ -638,15 +630,15 @@
#
# Specific parameters for RSA algorithm.
#
-# @hash-alg: QCryptoHashAlgorithm
+# @hash-alg: QCryptoHashAlgo
#
-# @padding-alg: QCryptoRSAPaddingAlgorithm
+# @padding-alg: QCryptoRSAPaddingAlgo
#
# Since: 7.1
##
{ 'struct': 'QCryptoAkCipherOptionsRSA',
- 'data': { 'hash-alg':'QCryptoHashAlgorithm',
- 'padding-alg': 'QCryptoRSAPaddingAlgorithm'}}
+ 'data': { 'hash-alg':'QCryptoHashAlgo',
+ 'padding-alg': 'QCryptoRSAPaddingAlgo'}}
##
# @QCryptoAkCipherOptions:
@@ -659,6 +651,6 @@
# Since: 7.1
##
{ 'union': 'QCryptoAkCipherOptions',
- 'base': { 'alg': 'QCryptoAkCipherAlgorithm' },
+ 'base': { 'alg': 'QCryptoAkCipherAlgo' },
'discriminator': 'alg',
'data': { 'rsa': 'QCryptoAkCipherOptionsRSA' }}
diff --git a/qapi/cryptodev.json b/qapi/cryptodev.json
index 68289f4..04d0e21 100644
--- a/qapi/cryptodev.json
+++ b/qapi/cryptodev.json
@@ -9,7 +9,7 @@
##
##
-# @QCryptodevBackendAlgType:
+# @QCryptodevBackendAlgoType:
#
# The supported algorithm types of a crypto device.
#
@@ -19,8 +19,7 @@
#
# Since: 8.0
##
-{ 'enum': 'QCryptodevBackendAlgType',
- 'prefix': 'QCRYPTODEV_BACKEND_ALG',
+{ 'enum': 'QCryptodevBackendAlgoType',
'data': ['sym', 'asym']}
##
@@ -28,10 +27,19 @@
#
# The supported service types of a crypto device.
#
+# @cipher: Symmetric Key Cipher service
+#
+# @hash: Hash service
+#
+# @mac: Message Authentication Codes service
+#
+# @aead: Authenticated Encryption with Associated Data service
+#
+# @akcipher: Asymmetric Key Cipher service
+#
# Since: 8.0
##
{ 'enum': 'QCryptodevBackendServiceType',
- 'prefix': 'QCRYPTODEV_BACKEND_SERVICE',
'data': ['cipher', 'hash', 'mac', 'aead', 'akcipher']}
##
@@ -48,7 +56,6 @@
# Since: 8.0
##
{ 'enum': 'QCryptodevBackendType',
- 'prefix': 'QCRYPTODEV_BACKEND_TYPE',
'data': ['builtin', 'vhost-user', 'lkcf']}
##
diff --git a/qapi/cxl.json b/qapi/cxl.json
index bdfac67..9f65589 100644
--- a/qapi/cxl.json
+++ b/qapi/cxl.json
@@ -326,6 +326,9 @@
# @crc-threshold: Component specific and applicable to 68 byte Flit
# mode only.
#
+# @retry-threshold: Retry threshold hit in the Local Retry State
+# Machine, 68B Flits only.
+#
# @cache-poison-received: Received poison from a peer on CXL.cache.
#
# @mem-poison-received: Received poison from a peer on CXL.mem
@@ -369,8 +372,8 @@
# of memory by Device Physical Address within a single Dynamic
# Capacity Region on a CXL Type 3 Device.
#
-# @offset: The offset (in bytes) to the start of the region
-# where the extent belongs to.
+# @offset: The offset (in bytes) to the start of the region where the
+# extent belongs to.
#
# @len: The length of the extent in bytes.
#
@@ -404,16 +407,16 @@
#
# @enable-shared-access: Capacity has already been allocated to a
# different host using free, contiguous or prescriptive policy
-# with a known tag. This policy then instructs the device to
-# make the capacity with the specified tag available to an
-# additional host. Capacity is implicit as it matches that
-# already associated with the tag. Note that the extent list
-# (and hence Device Physical Addresses) used are per host, so
-# a device may use different representations on each host.
-# The ordering of the extents provided to each host is indicated
-# to the host using per extent sequence numbers generated by
-# the device. Has a similar meaning for temporal sharing, but
-# in that case there may be only one host involved.
+# with a known tag. This policy then instructs the device to make
+# the capacity with the specified tag available to an additional
+# host. Capacity is implicit as it matches that already
+# associated with the tag. Note that the extent list (and hence
+# Device Physical Addresses) used are per host, so a device may
+# use different representations on each host. The ordering of the
+# extents provided to each host is indicated to the host using per
+# extent sequence numbers generated by the device. Has a similar
+# meaning for temporal sharing, but in that case there may be only
+# one host involved.
#
# Since: 9.1
##
@@ -429,7 +432,7 @@
#
# Initiate adding dynamic capacity extents to a host. This simulates
# operations defined in Compute Express Link (CXL) Specification,
-# Revision 3.1, Section 7.6.7.6.5. Note that, currently, establishing
+# Revision 3.1, Section 7.6.7.6.5. Note that, currently, establishing
# success or failure of the full Add Dynamic Capacity flow requires
# out of band communication with the OS of the CXL host.
#
@@ -495,7 +498,7 @@
#
# Initiate release of dynamic capacity extents from a host. This
# simulates operations defined in Compute Express Link (CXL)
-# Specification, Revision 3.1, Section 7.6.7.6.6. Note that,
+# Specification, Revision 3.1, Section 7.6.7.6.6. Note that,
# currently, success or failure of the full Release Dynamic Capacity
# flow requires out of band communication with the OS of the CXL host.
#
@@ -514,13 +517,13 @@
# from the host. Instead, the host immediately looses access to
# the released capacity.
#
-# @sanitize-on-release: Bit[5] of the "Flags" field in Compute
-# Express Link (CXL) Specification, Revision 3.1, Table 7-71.
-# When set, the device should sanitize all released capacity as
-# a result of this request. This ensures that all user data
-# and metadata is made permanently unavailable by whatever
-# means is appropriate for the media type. Note that changing
-# encryption keys is not sufficient.
+# @sanitize-on-release: Bit[5] of the "Flags" field in Compute Express
+# Link (CXL) Specification, Revision 3.1, Table 7-71. When set,
+# the device should sanitize all released capacity as a result of
+# this request. This ensures that all user data and metadata is
+# made permanently unavailable by whatever means is appropriate
+# for the media type. Note that changing encryption keys is not
+# sufficient.
#
# @region: The "Region Number" field as defined in Compute Express
# Link Specification, Revision 3.1, Table 7-71. Valid range
diff --git a/qapi/dump.json b/qapi/dump.json
index d8145da..d7826c0 100644
--- a/qapi/dump.json
+++ b/qapi/dump.json
@@ -55,7 +55,7 @@
# allows using gdb to process the core file.
#
# IMPORTANT: this option can make QEMU allocate several gigabytes
-# of RAM. This can happen for a large guest, or a malicious guest
+# of RAM. This can happen for a large guest, or a malicious guest
# pretending to be large.
#
# Also, paging=true has the following limitations:
diff --git a/qapi/ebpf.json b/qapi/ebpf.json
index e500b5a..db19ae8 100644
--- a/qapi/ebpf.json
+++ b/qapi/ebpf.json
@@ -8,7 +8,7 @@
# = eBPF Objects
#
# eBPF object is an ELF binary that contains the eBPF program and eBPF
-# map description(BTF). Overall, eBPF object should contain the
+# map description(BTF). Overall, eBPF object should contain the
# program and enough metadata to create/load eBPF with libbpf. As the
# eBPF maps/program should correspond to QEMU, the eBPF can't be used
# from different QEMU build.
diff --git a/qapi/introspect.json b/qapi/introspect.json
index b15052e..01bb242 100644
--- a/qapi/introspect.json
+++ b/qapi/introspect.json
@@ -42,8 +42,8 @@
# with different meta-types).
#
# .. note:: The QAPI schema is also used to help define *internal*
-# interfaces, by defining QAPI types. These are not part of the QMP
-# wire ABI, and therefore not returned by this command.
+# interfaces, by defining QAPI types. These are not part of the
+# QMP wire ABI, and therefore not returned by this command.
#
# Since: 2.5
##
@@ -127,6 +127,22 @@
# section 1, plus 'int' (split off 'number'), plus the obvious top
# type 'value'.
#
+# @string: JSON string
+#
+# @number: JSON number
+#
+# @int: JSON number that is an integer
+#
+# @boolean: literal ``false`` or ``true``
+#
+# @null: literal ``null``
+#
+# @object: JSON object
+#
+# @array: JSON array
+#
+# @value: any JSON value
+#
# Since: 2.5
##
{ 'enum': 'JSONType',
diff --git a/qapi/job.json b/qapi/job.json
index b395720..cfc3bee 100644
--- a/qapi/job.json
+++ b/qapi/job.json
@@ -138,7 +138,7 @@
#
# The job will pause as soon as possible, which means transitioning
# into the PAUSED state if it was RUNNING, or into STANDBY if it was
-# READY. The corresponding JOB_STATUS_CHANGE event will be emitted.
+# READY. The corresponding JOB_STATUS_CHANGE event will be emitted.
#
# Cancelling a paused job automatically resumes it.
#
@@ -200,9 +200,9 @@
# dismiss enabled.
#
# This command will refuse to operate on any job that has not yet
-# reached its terminal state, JOB_STATUS_CONCLUDED. For jobs that make
-# use of JOB_READY event, job-cancel or job-complete will still need
-# to be used as appropriate.
+# reached its terminal state, JOB_STATUS_CONCLUDED. For jobs that
+# make use of JOB_READY event, job-cancel or job-complete will still
+# need to be used as appropriate.
#
# @id: The job identifier.
#
diff --git a/qapi/machine-common.json b/qapi/machine-common.json
index fa6bd71..b64e489 100644
--- a/qapi/machine-common.json
+++ b/qapi/machine-common.json
@@ -9,13 +9,12 @@
##
##
-# @CpuS390Entitlement:
+# @S390CpuEntitlement:
#
# An enumeration of CPU entitlements that can be assumed by a virtual
# S390 CPU
#
# Since: 8.2
##
-{ 'enum': 'CpuS390Entitlement',
- 'prefix': 'S390_CPU_ENTITLEMENT',
+{ 'enum': 'S390CpuEntitlement',
'data': [ 'auto', 'low', 'medium', 'high' ] }
diff --git a/qapi/machine-target.json b/qapi/machine-target.json
index 7edb876..541f93e 100644
--- a/qapi/machine-target.json
+++ b/qapi/machine-target.json
@@ -12,24 +12,20 @@
# Virtual CPU model.
#
# A CPU model consists of the name of a CPU definition, to which delta
-# changes are applied (e.g. features added/removed). Most magic values
-# that an architecture might require should be hidden behind the name.
-# However, if required, architectures can expose relevant properties.
+# changes are applied (e.g. features added/removed). Most magic
+# values that an architecture might require should be hidden behind
+# the name. However, if required, architectures can expose relevant
+# properties.
#
# @name: the name of the CPU definition the model is based on
#
# @props: a dictionary of QOM properties to be applied
#
-# @deprecated-props: a list of properties that are flagged as deprecated
-# by the CPU vendor. These props are a subset of the full model's
-# definition list of properties. (since 9.1)
-#
# Since: 2.8
##
{ 'struct': 'CpuModelInfo',
'data': { 'name': 'str',
- '*props': 'any',
- '*deprecated-props': ['str'] } }
+ '*props': 'any' } }
##
# @CpuModelExpansionType:
@@ -51,13 +47,13 @@
#
# .. note:: When a non-migration-safe CPU model is expanded in static
# mode, some features enabled by the CPU model may be omitted,
-# because they can't be implemented by a static CPU model definition
-# (e.g. cache info passthrough and PMU passthrough in x86). If you
-# need an accurate representation of the features enabled by a
-# non-migration-safe CPU model, use @full. If you need a static
-# representation that will keep ABI compatibility even when changing
-# QEMU version or machine-type, use @static (but keep in mind that
-# some features may be omitted).
+# because they can't be implemented by a static CPU model
+# definition (e.g. cache info passthrough and PMU passthrough in
+# x86). If you need an accurate representation of the features
+# enabled by a non-migration-safe CPU model, use @full. If you
+# need a static representation that will keep ABI compatibility
+# even when changing QEMU version or machine-type, use @static (but
+# keep in mind that some features may be omitted).
#
# Since: 2.8
##
@@ -160,11 +156,11 @@
# Some architectures may not support comparing CPU models. s390x
# supports comparing CPU models.
#
-# @modela: description of the first CPU model to compare, referred to as
-# "model A" in CpuModelCompareResult
+# @modela: description of the first CPU model to compare, referred to
+# as "model A" in CpuModelCompareResult
#
-# @modelb: description of the second CPU model to compare, referred to as
-# "model B" in CpuModelCompareResult
+# @modelb: description of the second CPU model to compare, referred to
+# as "model B" in CpuModelCompareResult
#
# Returns: a CpuModelCompareInfo describing how both CPU models
# compare
@@ -190,7 +186,8 @@
#
# Baseline two CPU models, @modela and @modelb, creating a compatible
# third model. The created model will always be a static,
-# migration-safe CPU model (see "static" CPU model expansion for details).
+# migration-safe CPU model (see "static" CPU model expansion for
+# details).
#
# This interface can be used by tooling to create a compatible CPU
# model out two CPU models. The created CPU model will be identical
@@ -247,10 +244,19 @@
#
# @model: the expanded CpuModelInfo.
#
+# @deprecated-props: a list of properties that are flagged as
+# deprecated by the CPU vendor. The list depends on the
+# CpuModelExpansionType: "static" properties are a subset of the
+# enabled-properties for the expanded model; "full" properties are
+# a set of properties that are deprecated across all models for
+# the architecture. (since: 9.1).
+#
# Since: 2.8
##
{ 'struct': 'CpuModelExpansionInfo',
- 'data': { 'model': 'CpuModelInfo' },
+ 'data': { 'model': 'CpuModelInfo',
+ 'deprecated-props' : { 'type': ['str'],
+ 'if': 'TARGET_S390X' } },
'if': { 'any': [ 'TARGET_S390X',
'TARGET_I386',
'TARGET_ARM',
@@ -261,9 +267,9 @@
# @query-cpu-model-expansion:
#
# Expands a given CPU model, @model, (or a combination of CPU model +
-# additional options) to different granularities, specified by
-# @type, allowing tooling to get an understanding what a specific
-# CPU model looks like in QEMU under a certain configuration.
+# additional options) to different granularities, specified by @type,
+# allowing tooling to get an understanding what a specific CPU model
+# looks like in QEMU under a certain configuration.
#
# This interface can be used to query the "host" CPU model.
#
@@ -284,7 +290,7 @@
# Using query-cpu-model-expansion while using these is not advised.
#
# Some architectures may not support all expansion types. s390x
-# supports "full" and "static". Arm only supports "full".
+# supports "full" and "static". Arm only supports "full".
#
# @model: description of the CPU model to expand
#
@@ -351,7 +357,7 @@
# CPU model attributes that prevent the CPU from running. If the QOM
# property is read-only, that means there's no known way to make the
# CPU model run in the current host. Implementations that choose not
-# to provide specific information return the property name "type". If
+# to provide specific information return the property name "type". If
# the property is read-write, it means that it MAY be possible to run
# the CPU model in the current host if that property is changed.
# Management software can use it as hints to suggest or choose an
@@ -399,15 +405,14 @@
'TARGET_RISCV' ] } }
##
-# @CpuS390Polarization:
+# @S390CpuPolarization:
#
# An enumeration of CPU polarization that can be assumed by a virtual
# S390 CPU
#
# Since: 8.2
##
-{ 'enum': 'CpuS390Polarization',
- 'prefix': 'S390_CPU_POLARIZATION',
+{ 'enum': 'S390CpuPolarization',
'data': [ 'horizontal', 'vertical' ],
'if': 'TARGET_S390X'
}
@@ -444,7 +449,7 @@
'*socket-id': 'uint16',
'*book-id': 'uint16',
'*drawer-id': 'uint16',
- '*entitlement': 'CpuS390Entitlement',
+ '*entitlement': 'S390CpuEntitlement',
'*dedicated': 'bool'
},
'features': [ 'unstable' ],
@@ -482,7 +487,7 @@
# "timestamp": { "seconds": 1401385907, "microseconds": 422329 } }
##
{ 'event': 'CPU_POLARIZATION_CHANGE',
- 'data': { 'polarization': 'CpuS390Polarization' },
+ 'data': { 'polarization': 'S390CpuPolarization' },
'features': [ 'unstable' ],
'if': { 'all': [ 'TARGET_S390X', 'CONFIG_KVM' ] }
}
@@ -497,7 +502,7 @@
# Since: 8.2
##
{ 'struct': 'CpuPolarizationInfo',
- 'data': { 'polarization': 'CpuS390Polarization' },
+ 'data': { 'polarization': 'S390CpuPolarization' },
'if': { 'all': [ 'TARGET_S390X', 'CONFIG_KVM' ] }
}
diff --git a/qapi/machine.json b/qapi/machine.json
index f9ea6b3..3cc055b 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -24,30 +24,31 @@
#
# @avr: since 5.1
#
+# @loongarch64: since 7.1
+#
# .. note:: The resulting QMP strings can be appended to the
-# "qemu-system-" prefix to produce the corresponding QEMU executable
-# name. This is true even for "qemu-system-x86_64".
+# "qemu-system-" prefix to produce the corresponding QEMU
+# executable name. This is true even for "qemu-system-x86_64".
#
# Since: 3.0
##
{ 'enum' : 'SysEmuTarget',
- 'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'cris', 'hppa', 'i386',
+ 'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'hppa', 'i386',
'loongarch64', 'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64',
'mips64el', 'mipsel', 'or1k', 'ppc',
'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4',
- 'sh4eb', 'sparc', 'sparc64', 'tricore',
+ 'sparc', 'sparc64', 'tricore',
'x86_64', 'xtensa', 'xtensaeb' ] }
##
-# @CpuS390State:
+# @S390CpuState:
#
# An enumeration of cpu states that can be assumed by a virtual S390
# CPU
#
# Since: 2.12
##
-{ 'enum': 'CpuS390State',
- 'prefix': 'S390_CPU_STATE',
+{ 'enum': 'S390CpuState',
'data': [ 'uninitialized', 'stopped', 'check-stop', 'operating', 'load' ] }
##
@@ -64,9 +65,9 @@
# Since: 2.12
##
{ 'struct': 'CpuInfoS390',
- 'data': { 'cpu-state': 'CpuS390State',
+ 'data': { 'cpu-state': 'S390CpuState',
'*dedicated': 'bool',
- '*entitlement': 'CpuS390Entitlement' } }
+ '*entitlement': 'S390CpuEntitlement' } }
##
# @CpuInfoFast:
@@ -369,8 +370,8 @@
#
# .. note:: A guest may or may not respond to this command. This
# command returning does not indicate that a guest has accepted the
-# request or that it has shut down. Many guests will respond to this
-# command by prompting the user in some way.
+# request or that it has shut down. Many guests will respond to
+# this command by prompting the user in some way.
#
# .. qmp-example::
#
@@ -435,7 +436,7 @@
# @inject-nmi:
#
# Injects a Non-Maskable Interrupt into the default CPU (x86/s390) or
-# all CPUs (ppc64). The command fails when the guest doesn't support
+# all CPUs (ppc64). The command fails when the guest doesn't support
# injecting.
#
# Since: 0.14
@@ -850,7 +851,11 @@
# <- { "return": {} }
##
{ 'command': 'memsave',
- 'data': {'val': 'int', 'size': 'int', 'filename': 'str', '*cpu-index': 'int'} }
+ 'data': {
+ 'val': 'uint64',
+ 'size': 'size',
+ 'filename': 'str',
+ '*cpu-index': 'int' } }
##
# @pmemsave:
@@ -876,7 +881,10 @@
# <- { "return": {} }
##
{ 'command': 'pmemsave',
- 'data': {'val': 'int', 'size': 'int', 'filename': 'str'} }
+ 'data': {
+ 'val': 'uint64',
+ 'size': 'size',
+ 'filename': 'str' } }
##
# @Memdev:
@@ -986,8 +994,8 @@
# @cluster-id: cluster number within the parent container the CPU
# belongs to (since 7.1)
#
-# @module-id: module number within the parent container the CPU belongs
-# to (since 9.1)
+# @module-id: module number within the parent container the CPU
+# belongs to (since 9.1)
#
# @core-id: core number within the parent container the CPU belongs to
#
@@ -1130,8 +1138,8 @@
# - If no balloon device is present, DeviceNotActive
#
# .. note:: This command just issues a request to the guest. When it
-# returns, the balloon size may not have changed. A guest can change
-# the balloon size independent of this command.
+# returns, the balloon size may not have changed. A guest can
+# change the balloon size independent of this command.
#
# Since: 0.14
#
@@ -1657,8 +1665,8 @@
# The members other than @cpus and @maxcpus define a topology of
# containers.
#
-# The ordering from highest/coarsest to lowest/finest is:
-# @drawers, @books, @sockets, @dies, @clusters, @cores, @threads.
+# The ordering from highest/coarsest to lowest/finest is: @drawers,
+# @books, @sockets, @dies, @clusters, @cores, @threads.
#
# Different architectures support different subsets of topology
# containers.
diff --git a/qapi/migration.json b/qapi/migration.json
index 073b67c..3af6aa1 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -142,8 +142,8 @@
#
# @postcopy-paused: during postcopy but paused. (since 3.0)
#
-# @postcopy-recover-setup: setup phase for a postcopy recovery process,
-# preparing for a recovery phase to start. (since 9.1)
+# @postcopy-recover-setup: setup phase for a postcopy recovery
+# process, preparing for a recovery phase to start. (since 9.1)
#
# @postcopy-recover: trying to recover from a paused postcopy. (since
# 3.0)
@@ -245,10 +245,10 @@
# blocked. Present and non-empty when migration is blocked.
# (since 6.0)
#
-# @dirty-limit-throttle-time-per-round: Maximum throttle time
-# (in microseconds) of virtual CPUs each dirty ring full round,
-# which shows how MigrationCapability dirty-limit affects the
-# guest during live migration. (Since 8.1)
+# @dirty-limit-throttle-time-per-round: Maximum throttle time (in
+# microseconds) of virtual CPUs each dirty ring full round, which
+# shows how MigrationCapability dirty-limit affects the guest
+# during live migration. (Since 8.1)
#
# @dirty-limit-ring-full-time: Estimated average dirty ring full time
# (in microseconds) for each dirty ring full round. The value
@@ -381,7 +381,7 @@
# Migration capabilities enumeration
#
# @xbzrle: Migration supports xbzrle (Xor Based Zero Run Length
-# Encoding). This feature allows us to minimize migration traffic
+# Encoding). This feature allows us to minimize migration traffic
# for certain work loads, by sending compressed difference of the
# pages
#
@@ -393,8 +393,8 @@
# efficiently. This essentially saves 1MB of zeroes per block on
# the wire. Enabling requires source and target VM to support
# this feature. To enable it is sufficient to enable the
-# capability on the source VM. The feature is disabled by default.
-# (since 1.6)
+# capability on the source VM. The feature is disabled by
+# default. (since 1.6)
#
# @events: generate events for each migration state change (since 2.4)
#
@@ -479,11 +479,14 @@
# Features:
#
# @unstable: Members @x-colo and @x-ignore-shared are experimental.
+# @deprecated: Member @zero-blocks is deprecated as being part of
+# block migration which was already removed.
#
# Since: 1.2
##
{ 'enum': 'MigrationCapability',
- 'data': ['xbzrle', 'rdma-pin-all', 'auto-converge', 'zero-blocks',
+ 'data': ['xbzrle', 'rdma-pin-all', 'auto-converge',
+ { 'name': 'zero-blocks', 'features': [ 'deprecated' ] },
'events', 'postcopy-ram',
{ 'name': 'x-colo', 'features': [ 'unstable' ] },
'release-ram',
@@ -561,18 +564,22 @@
#
# @zstd: use zstd compression method.
#
+# @qatzip: use qatzip compression method. (Since 9.2)
+#
# @qpl: use qpl compression method. Query Processing Library(qpl) is
-# based on the deflate compression algorithm and use the Intel
-# In-Memory Analytics Accelerator(IAA) accelerated compression
-# and decompression. (Since 9.1)
+# based on the deflate compression algorithm and use the Intel
+# In-Memory Analytics Accelerator(IAA) accelerated compression and
+# decompression. (Since 9.1)
#
# @uadk: use UADK library compression method. (Since 9.1)
#
# Since: 5.0
##
{ 'enum': 'MultiFDCompression',
+ 'prefix': 'MULTIFD_COMPRESSION',
'data': [ 'none', 'zlib',
{ 'name': 'zstd', 'if': 'CONFIG_ZSTD' },
+ { 'name': 'qatzip', 'if': 'CONFIG_QATZIP'},
{ 'name': 'qpl', 'if': 'CONFIG_QPL' },
{ 'name': 'uadk', 'if': 'CONFIG_UADK' } ] }
@@ -790,13 +797,18 @@
# migration, the compression level is an integer between 0 and 9,
# where 0 means no compression, 1 means the best compression
# speed, and 9 means best compression ratio which will consume
-# more CPU. Defaults to 1. (Since 5.0)
+# more CPU. Defaults to 1. (Since 5.0)
+#
+# @multifd-qatzip-level: Set the compression level to be used in live
+# migration. The level is an integer between 1 and 9, where 1 means
+# the best compression speed, and 9 means the best compression
+# ratio which will consume more CPU. Defaults to 1. (Since 9.2)
#
# @multifd-zstd-level: Set the compression level to be used in live
# migration, the compression level is an integer between 0 and 20,
# where 0 means no compression, 1 means the best compression
# speed, and 20 means best compression ratio which will consume
-# more CPU. Defaults to 1. (Since 5.0)
+# more CPU. Defaults to 1. (Since 5.0)
#
# @block-bitmap-mapping: Maps block nodes and bitmaps on them to
# aliases for the purpose of dirty bitmap migration. Such aliases
@@ -852,6 +864,7 @@
'xbzrle-cache-size', 'max-postcopy-bandwidth',
'max-cpu-throttle', 'multifd-compression',
'multifd-zlib-level', 'multifd-zstd-level',
+ 'multifd-qatzip-level',
'block-bitmap-mapping',
{ 'name': 'x-vcpu-dirty-limit-period', 'features': ['unstable'] },
'vcpu-dirty-limit',
@@ -965,13 +978,18 @@
# migration, the compression level is an integer between 0 and 9,
# where 0 means no compression, 1 means the best compression
# speed, and 9 means best compression ratio which will consume
-# more CPU. Defaults to 1. (Since 5.0)
+# more CPU. Defaults to 1. (Since 5.0)
+#
+# @multifd-qatzip-level: Set the compression level to be used in live
+# migration. The level is an integer between 1 and 9, where 1 means
+# the best compression speed, and 9 means the best compression
+# ratio which will consume more CPU. Defaults to 1. (Since 9.2)
#
# @multifd-zstd-level: Set the compression level to be used in live
# migration, the compression level is an integer between 0 and 20,
# where 0 means no compression, 1 means the best compression
# speed, and 20 means best compression ratio which will consume
-# more CPU. Defaults to 1. (Since 5.0)
+# more CPU. Defaults to 1. (Since 5.0)
#
# @block-bitmap-mapping: Maps block nodes and bitmaps on them to
# aliases for the purpose of dirty bitmap migration. Such aliases
@@ -1040,6 +1058,7 @@
'*max-cpu-throttle': 'uint8',
'*multifd-compression': 'MultiFDCompression',
'*multifd-zlib-level': 'uint8',
+ '*multifd-qatzip-level': 'uint8',
'*multifd-zstd-level': 'uint8',
'*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ],
'*x-vcpu-dirty-limit-period': { 'type': 'uint64',
@@ -1169,13 +1188,18 @@
# migration, the compression level is an integer between 0 and 9,
# where 0 means no compression, 1 means the best compression
# speed, and 9 means best compression ratio which will consume
-# more CPU. Defaults to 1. (Since 5.0)
+# more CPU. Defaults to 1. (Since 5.0)
+#
+# @multifd-qatzip-level: Set the compression level to be used in live
+# migration. The level is an integer between 1 and 9, where 1 means
+# the best compression speed, and 9 means the best compression
+# ratio which will consume more CPU. Defaults to 1. (Since 9.2)
#
# @multifd-zstd-level: Set the compression level to be used in live
# migration, the compression level is an integer between 0 and 20,
# where 0 means no compression, 1 means the best compression
# speed, and 20 means best compression ratio which will consume
-# more CPU. Defaults to 1. (Since 5.0)
+# more CPU. Defaults to 1. (Since 5.0)
#
# @block-bitmap-mapping: Maps block nodes and bitmaps on them to
# aliases for the purpose of dirty bitmap migration. Such aliases
@@ -1201,7 +1225,7 @@
# Defaults to 1. (Since 8.1)
#
# @mode: Migration mode. See description in @MigMode. Default is
-# 'normal'. (Since 8.2)
+# 'normal'. (Since 8.2)
#
# @zero-page-detection: Whether and how to detect zero pages.
# See description in @ZeroPageDetection. Default is 'multifd'.
@@ -1241,6 +1265,7 @@
'*max-cpu-throttle': 'uint8',
'*multifd-compression': 'MultiFDCompression',
'*multifd-zlib-level': 'uint8',
+ '*multifd-qatzip-level': 'uint8',
'*multifd-zstd-level': 'uint8',
'*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ],
'*x-vcpu-dirty-limit-period': { 'type': 'uint64',
@@ -1459,8 +1484,8 @@
#
# Cancel the current executing migration process.
#
-# .. note:: This command succeeds even if there is no migration process
-# running.
+# .. note:: This command succeeds even if there is no migration
+# process running.
#
# Since: 0.14
#
@@ -1604,7 +1629,7 @@
# should not be used.
#
# 4. The uri argument should have the Uniform Resource Identifier
-# of default destination VM. This connection will be bound to
+# of default destination VM. This connection will be bound to
# default network.
#
# 5. For now, number of migration streams is restricted to one,
@@ -1650,7 +1675,6 @@
# "filename": "/tmp/migfile",
# "offset": "0x1000" } } ] } }
# <- { "return": {} }
-#
##
{ 'command': 'migrate',
'data': {'*uri': 'str',
@@ -1671,7 +1695,8 @@
#
# @exit-on-error: Exit on incoming migration failure. Default true.
# When set to false, the failure triggers a MIGRATION event, and
-# error details could be retrieved with query-migrate. (since 9.1)
+# error details could be retrieved with query-migrate.
+# (since 9.1)
#
# Since: 2.3
#
@@ -1938,9 +1963,9 @@
# @UNPLUG_PRIMARY:
#
# Emitted from source side of a migration when migration state is
-# WAIT_UNPLUG. Device was unplugged by guest operating system. Device
-# resources in QEMU are kept on standby to be able to re-plug it in
-# case of migration failure.
+# WAIT_UNPLUG. Device was unplugged by guest operating system.
+# Device resources in QEMU are kept on standby to be able to re-plug
+# it in case of migration failure.
#
# @device-id: QEMU device id of the unplugged device
#
@@ -2084,16 +2109,16 @@
# This mode tracks page modification per each vCPU separately. It
# requires that KVM accelerator property "dirty-ring-size" is set.
#
-# @calc-time: time period for which dirty page rate is calculated.
-# By default it is specified in seconds, but the unit can be set
+# @calc-time: time period for which dirty page rate is calculated. By
+# default it is specified in seconds, but the unit can be set
# explicitly with @calc-time-unit. Note that larger @calc-time
# values will typically result in smaller dirty page rates because
-# page dirtying is a one-time event. Once some page is counted
-# as dirty during @calc-time period, further writes to this page
-# will not increase dirty page rate anymore.
+# page dirtying is a one-time event. Once some page is counted as
+# dirty during @calc-time period, further writes to this page will
+# not increase dirty page rate anymore.
#
-# @calc-time-unit: time unit in which @calc-time is specified.
-# By default it is seconds. (Since 8.2)
+# @calc-time-unit: time unit in which @calc-time is specified. By
+# default it is seconds. (Since 8.2)
#
# @sample-pages: number of sampled pages per each GiB of guest memory.
# Default value is 512. For 4KiB guest pages this corresponds to
diff --git a/qapi/misc.json b/qapi/misc.json
index 4a6f3ba..559b66f 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -26,7 +26,7 @@
# @skipauth: whether to skip authentication. Only applies to "vnc"
# and "spice" protocols
#
-# @tls: whether to perform TLS. Only applies to the "spice" protocol
+# @tls: whether to perform TLS. Only applies to the "spice" protocol
#
# Since: 0.14
#
@@ -104,8 +104,8 @@
# Returns a list of information about each iothread.
#
# .. note:: This list excludes the QEMU main loop thread, which is not
-# declared using the ``-object iothread`` command-line option. It is
-# always the main thread of the process.
+# declared using the ``-object iothread`` command-line option. It
+# is always the main thread of the process.
#
# Returns: a list of @IOThreadInfo for each iothread
#
@@ -141,8 +141,8 @@
# guest remains paused once migration finishes, as if the ``-S``
# option was passed on the command line.
#
-# In the "suspended" state, it will completely stop the VM and cause
-# a transition to the "paused" state. (Since 9.0)
+# In the "suspended" state, it will completely stop the VM and
+# cause a transition to the "paused" state. (Since 9.0)
#
# .. qmp-example::
#
@@ -158,15 +158,15 @@
#
# Since: 0.14
#
-# .. note:: This command will succeed if the guest is currently running.
-# It will also succeed if the guest is in the "inmigrate" state; in
-# this case, the effect of the command is to make sure the guest
-# starts once migration finishes, removing the effect of the ``-S``
-# command line option if it was passed.
+# .. note:: This command will succeed if the guest is currently
+# running. It will also succeed if the guest is in the "inmigrate"
+# state; in this case, the effect of the command is to make sure
+# the guest starts once migration finishes, removing the effect of
+# the ``-S`` command line option if it was passed.
#
# If the VM was previously suspended, and not been reset or woken,
-# this command will transition back to the "suspended" state. (Since
-# 9.0)
+# this command will transition back to the "suspended" state.
+# (Since 9.0)
#
# .. qmp-example::
#
@@ -227,8 +227,8 @@
#
# Known limitations:
#
-# * This command is stateless, this means that commands that
-# depend on state information (such as getfd) might not work.
+# * This command is stateless, this means that commands that depend
+# on state information (such as getfd) might not work.
#
# * Commands that prompt the user for data don't currently work.
#
@@ -341,7 +341,8 @@
#
# .. note:: The list of fd sets is shared by all monitor connections.
#
-# .. note:: If @fdset-id is not specified, a new fd set will be created.
+# .. note:: If @fdset-id is not specified, a new fd set will be
+# created.
#
# Since: 1.2
#
diff --git a/qapi/net.json b/qapi/net.json
index 31b3417..2739a2f 100644
--- a/qapi/net.json
+++ b/qapi/net.json
@@ -22,9 +22,9 @@
#
# Since: 0.14
#
-# .. note:: Not all network adapters support setting link status. This
-# command will succeed even if the network adapter does not support
-# link status notification.
+# .. note:: Not all network adapters support setting link status.
+# This command will succeed even if the network adapter does not
+# support link status notification.
#
# .. qmp-example::
#
@@ -403,7 +403,7 @@
# Connect a client to a netmap-enabled NIC or to a VALE switch port
#
# @ifname: Either the name of an existing network interface supported
-# by netmap, or the name of a VALE port (created on the fly). A
+# by netmap, or the name of a VALE port (created on the fly). A
# VALE port name is in the form 'valeXXX:YYY', where XXX and YYY
# are non-negative integers. XXX identifies a switch and YYY
# identifies a port of the switch. VALE ports having the same XXX
@@ -535,13 +535,13 @@
# interfaces that are in host mode and also with the host.
#
# @start-address: The starting IPv4 address to use for the interface.
-# Must be in the private IP range (RFC 1918). Must be specified
+# Must be in the private IP range (RFC 1918). Must be specified
# along with @end-address and @subnet-mask. This address is used
# as the gateway address. The subsequent address up to and
# including end-address are placed in the DHCP pool.
#
# @end-address: The DHCP IPv4 range end address to use for the
-# interface. Must be in the private IP range (RFC 1918). Must be
+# interface. Must be in the private IP range (RFC 1918). Must be
# specified along with @start-address and @subnet-mask.
#
# @subnet-mask: The IPv4 subnet mask to use on the interface. Must be
@@ -556,7 +556,7 @@
# network vmnet interface should be added to. If set, no DHCP
# service is provided for this interface and network communication
# is allowed only with other interfaces added to this network
-# identified by the UUID. Requires at least macOS Big Sur 11.0.
+# identified by the UUID. Requires at least macOS Big Sur 11.0.
#
# Since: 7.1
##
@@ -575,20 +575,20 @@
# vmnet (shared mode) network backend.
#
# Allows traffic originating from the vmnet interface to reach the
-# Internet through a network address translator (NAT). The vmnet
+# Internet through a network address translator (NAT). The vmnet
# interface can communicate with the host and with other shared mode
# interfaces on the same subnet. If no DHCP settings, subnet mask and
# IPv6 prefix specified, the interface can communicate with any of
# other interfaces in shared mode.
#
# @start-address: The starting IPv4 address to use for the interface.
-# Must be in the private IP range (RFC 1918). Must be specified
+# Must be in the private IP range (RFC 1918). Must be specified
# along with @end-address and @subnet-mask. This address is used
# as the gateway address. The subsequent address up to and
# including end-address are placed in the DHCP pool.
#
# @end-address: The DHCP IPv4 range end address to use for the
-# interface. Must be in the private IP range (RFC 1918). Must be
+# interface. Must be in the private IP range (RFC 1918). Must be
# specified along with @start-address and @subnet-mask.
#
# @subnet-mask: The IPv4 subnet mask to use on the interface. Must be
@@ -650,15 +650,26 @@
# attempt a reconnect after the given number of seconds. Setting
# this to zero disables this function. (default: 0) (since 8.0)
#
+# @reconnect-ms: For a client socket, if a socket is disconnected, then
+# attempt a reconnect after the given number of milliseconds. Setting
+# this to zero disables this function. This member is mutually
+# exclusive with @reconnect. (default: 0) (Since: 9.2)
+#
# Only SocketAddress types 'unix', 'inet' and 'fd' are supported.
#
+# Features:
+#
+# @deprecated: Member @reconnect is deprecated. Use @reconnect-ms
+# instead.
+#
# Since: 7.2
##
{ 'struct': 'NetdevStreamOptions',
'data': {
'addr': 'SocketAddress',
'*server': 'bool',
- '*reconnect': 'uint32' } }
+ '*reconnect': { 'type': 'int', 'features': [ 'deprecated' ] },
+ '*reconnect-ms': 'int' } }
##
# @NetdevDgramOptions:
@@ -703,12 +714,19 @@
# Available netdev drivers.
#
# @l2tpv3: since 2.1
+#
# @vhost-vdpa: since 5.1
+#
# @vmnet-host: since 7.1
+#
# @vmnet-shared: since 7.1
+#
# @vmnet-bridged: since 7.1
+#
# @stream: since 7.2
+#
# @dgram: since 7.2
+#
# @af-xdp: since 8.2
#
# Since: 2.7
diff --git a/qapi/pci.json b/qapi/pci.json
index ec28f1d..dc85a41 100644
--- a/qapi/pci.json
+++ b/qapi/pci.json
@@ -33,6 +33,8 @@
# - 'io' if the region is a PIO region
# - 'memory' if the region is a MMIO region
#
+# @address: memory address
+#
# @size: memory size
#
# @prefetch: if @type is 'memory', true if the memory is prefetchable
@@ -310,6 +312,5 @@
# }
#
# This example has been shortened as the real response is too long.
-#
##
{ 'command': 'query-pci', 'returns': ['PciInfo'] }
diff --git a/qapi/pragma.json b/qapi/pragma.json
index 59fbe74..023a2ef 100644
--- a/qapi/pragma.json
+++ b/qapi/pragma.json
@@ -46,34 +46,27 @@
'BlockdevSnapshotSyncWrapper',
'BlockdevSnapshotWrapper',
'BlockdevVmdkAdapterType',
- 'ChardevBackendKind',
- 'CpuS390Entitlement',
- 'CpuS390Polarization',
- 'CpuS390State',
- 'CxlCorErrorType',
'DisplayProtocol',
'DriveBackupWrapper',
'DummyBlockCoreForceArrays',
'DummyForceArrays',
'DummyVirtioForceArrays',
- 'GrabToggleKeys',
'HotKeyMod',
'ImageInfoSpecificKind',
'InputAxis',
'InputButton',
'IscsiHeaderDigest',
'IscsiTransport',
- 'JSONType',
'KeyValueKind',
'MemoryDeviceInfoKind',
'NetClientDriver',
'ObjectType',
- 'PciMemoryRegion',
- 'QCryptoAkCipherKeyType',
- 'QCryptodevBackendServiceType',
'QKeyCode',
'RbdAuthMode',
'RbdImageEncryptionFormat',
+ 'S390CpuEntitlement',
+ 'S390CpuPolarization',
+ 'S390CpuState',
'String',
'StringWrapper',
'SysEmuTarget',
@@ -83,9 +76,7 @@
'X86CPURegister32',
'XDbgBlockGraph',
'YankInstanceType',
- 'blockdev-reopen',
- 'query-rocker',
- 'query-rocker-ports' ],
+ 'blockdev-reopen' ],
# Externally visible types whose member names may use uppercase
'member-name-exceptions': [ # visible in:
'ACPISlotType', # query-acpi-ospm-status
diff --git a/qapi/qdev.json b/qapi/qdev.json
index e91ca03..53d147c 100644
--- a/qapi/qdev.json
+++ b/qapi/qdev.json
@@ -59,8 +59,8 @@
# the 'docs/qdev-device-use.txt' file.
#
# 3. It's possible to list device properties by running QEMU with
-# the ``-device DEVICE,help`` command-line argument, where DEVICE
-# is the device's name.
+# the ``-device DEVICE,help`` command-line argument, where
+# DEVICE is the device's name.
#
# .. qmp-example::
#
@@ -94,13 +94,13 @@
#
# .. note:: When this command completes, the device may not be removed
# from the guest. Hot removal is an operation that requires guest
-# cooperation. This command merely requests that the guest begin the
-# hot removal process. Completion of the device removal process is
-# signaled with a DEVICE_DELETED event. Guest reset will
-# automatically complete removal for all devices. If a guest-side
-# error in the hot removal process is detected, the device will not
-# be removed and a DEVICE_UNPLUG_GUEST_ERROR event is sent. Some
-# errors cannot be detected.
+# cooperation. This command merely requests that the guest begin
+# the hot removal process. Completion of the device removal
+# process is signaled with a DEVICE_DELETED event. Guest reset
+# will automatically complete removal for all devices. If a
+# guest-side error in the hot removal process is detected, the
+# device will not be removed and a DEVICE_UNPLUG_GUEST_ERROR event
+# is sent. Some errors cannot be detected.
#
# Since: 0.14
#
@@ -123,7 +123,7 @@
#
# Emitted whenever the device removal completion is acknowledged by
# the guest. At this point, it's safe to reuse the specified device
-# ID. Device removal can be initiated by the guest or by HMP/QMP
+# ID. Device removal can be initiated by the guest or by HMP/QMP
# commands.
#
# @device: the device's ID if it has one
diff --git a/qapi/qom.json b/qapi/qom.json
index 7e780e1..321ccd7 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -222,7 +222,8 @@
##
{ 'struct': 'CanHostSocketcanProperties',
'data': { 'if': 'str',
- 'canbus': 'str' } }
+ 'canbus': 'str' },
+ 'if': 'CONFIG_LINUX' }
##
# @ColoCompareProperties:
@@ -305,7 +306,8 @@
##
{ 'struct': 'CryptodevVhostUserProperties',
'base': 'CryptodevBackendProperties',
- 'data': { 'chardev': 'str' } }
+ 'data': { 'chardev': 'str' },
+ 'if': 'CONFIG_VHOST_CRYPTO' }
##
# @DBusVMStateProperties:
@@ -354,7 +356,7 @@
# filter list. "head" means the filter is inserted at the head of
# the filter list, before any existing filters. "tail" means the
# filter is inserted at the tail of the filter list, behind any
-# existing filters (default). "id=<id>" means the filter is
+# existing filters (default). "id=<id>" means the filter is
# inserted before or behind the filter specified by <id>,
# depending on the @insert property. (default: "tail")
#
@@ -514,7 +516,8 @@
'data': { 'evdev': 'str',
'*grab_all': 'bool',
'*repeat': 'bool',
- '*grab-toggle': 'GrabToggleKeys' } }
+ '*grab-toggle': 'GrabToggleKeys' },
+ 'if': 'CONFIG_LINUX' }
##
# @EventLoopBaseProperties:
@@ -617,8 +620,8 @@
# .. note:: prealloc=true and reserve=false cannot be set at the same
# time. With reserve=true, the behavior depends on the operating
# system: for example, Linux will not reserve swap space for shared
-# file mappings -- "not applicable". In contrast, reserve=false will
-# bail out if it cannot be configured accordingly.
+# file mappings -- "not applicable". In contrast, reserve=false
+# will bail out if it cannot be configured accordingly.
#
# Since: 2.1
##
@@ -643,9 +646,9 @@
# @align: the base address alignment when QEMU mmap(2)s @mem-path.
# Some backend stores specified by @mem-path require an alignment
# different than the default one used by QEMU, e.g. the device DAX
-# /dev/dax0.0 requires 2M alignment rather than 4K. In such cases,
-# users can specify the required alignment via this option. 0
-# selects a default alignment (currently the page size).
+# /dev/dax0.0 requires 2M alignment rather than 4K. In such
+# cases, users can specify the required alignment via this option.
+# 0 selects a default alignment (currently the page size).
# (default: 0)
#
# @offset: the offset into the target file that the region starts at.
@@ -706,7 +709,7 @@
#
# @hugetlbsize: the hugetlb page size on systems that support multiple
# hugetlb page sizes (it must be a power of 2 value supported by
-# the system). 0 selects a default page size. This option is
+# the system). 0 selects a default page size. This option is
# ignored if @hugetlb is false. (default: 0)
#
# @seal: if true, create a sealed-file, which will block further
@@ -718,7 +721,8 @@
'base': 'MemoryBackendProperties',
'data': { '*hugetlb': 'bool',
'*hugetlbsize': 'size',
- '*seal': 'bool' } }
+ '*seal': 'bool' },
+ 'if': 'CONFIG_LINUX' }
##
# @MemoryBackendShmProperties:
@@ -748,7 +752,8 @@
##
{ 'struct': 'MemoryBackendEpcProperties',
'base': 'MemoryBackendProperties',
- 'data': {} }
+ 'data': {},
+ 'if': 'CONFIG_LINUX' }
##
# @PrManagerHelperProperties:
@@ -761,7 +766,8 @@
# Since: 2.11
##
{ 'struct': 'PrManagerHelperProperties',
- 'data': { 'path': 'str' } }
+ 'data': { 'path': 'str' },
+ 'if': 'CONFIG_LINUX' }
##
# @QtestProperties:
@@ -884,7 +890,8 @@
##
{ 'struct': 'RngRandomProperties',
'base': 'RngProperties',
- 'data': { '*filename': 'str' } }
+ 'data': { '*filename': 'str' },
+ 'if': 'CONFIG_POSIX' }
##
# @SevCommonProperties:
@@ -923,17 +930,17 @@
#
# @handle: SEV firmware handle (default: 0)
#
-# @legacy-vm-type: Use legacy KVM_SEV_INIT KVM interface for creating the VM.
-# The newer KVM_SEV_INIT2 interface, from Linux >= 6.10, syncs
-# additional vCPU state when initializing the VMSA structures,
-# which will result in a different guest measurement. Set
-# this to 'on' to force compatibility with older QEMU or kernel
-# versions that rely on legacy KVM_SEV_INIT behavior. 'auto'
-# will behave identically to 'on', but will automatically
-# switch to using KVM_SEV_INIT2 if the user specifies any
-# additional options that require it. If set to 'off', QEMU
-# will require KVM_SEV_INIT2 unconditionally.
-# (default: off) (since 9.1)
+# @legacy-vm-type: Use legacy KVM_SEV_INIT KVM interface for creating
+# the VM. The newer KVM_SEV_INIT2 interface, from Linux >= 6.10,
+# syncs additional vCPU state when initializing the VMSA
+# structures, which will result in a different guest measurement.
+# Set this to 'on' to force compatibility with older QEMU or kernel
+# versions that rely on legacy KVM_SEV_INIT behavior. 'auto' will
+# behave identically to 'on', but will automatically switch to
+# using KVM_SEV_INIT2 if the user specifies any additional options
+# that require it. If set to 'off', QEMU will require
+# KVM_SEV_INIT2 unconditionally.
+# (default: off) (since 9.1)
#
# Since: 2.12
##
@@ -985,7 +992,7 @@
# @vcek-disabled: Guests are by default allowed to choose between VLEK
# (Versioned Loaded Endorsement Key) or VCEK (Versioned Chip
# Endorsement Key) when requesting attestation reports from
-# firmware. Set this to true to disable the use of VCEK.
+# firmware. Set this to true to disable the use of VCEK.
# (default: false) (since: 9.1)
#
# Since: 9.1
diff --git a/qapi/rocker.json b/qapi/rocker.json
index 2e63dcb..51aa5b4 100644
--- a/qapi/rocker.json
+++ b/qapi/rocker.json
@@ -26,6 +26,8 @@
#
# Return rocker switch information.
#
+# @name: switch name
+#
# Returns: @Rocker information
#
# Since: 2.4
@@ -42,7 +44,7 @@
##
# @RockerPortDuplex:
#
-# An eumeration of port duplex states.
+# An enumeration of port duplex states.
#
# @half: half duplex
#
@@ -55,7 +57,7 @@
##
# @RockerPortAutoneg:
#
-# An eumeration of port autoneg states.
+# An enumeration of port autoneg states.
#
# @off: autoneg is off
#
@@ -94,6 +96,8 @@
#
# Return rocker switch port information.
#
+# @name: port name
+#
# Returns: a list of @RockerPort information
#
# Since: 2.4
@@ -288,8 +292,8 @@
#
# @ttl-check: perform TTL check
#
-# .. note:: Optional members may or may not appear in the group depending
-# if they're relevant to the group type.
+# .. note:: Optional members may or may not appear in the group
+# depending if they're relevant to the group type.
#
# Since: 2.4
##
diff --git a/qapi/run-state.json b/qapi/run-state.json
index 287691c..ce95cfa 100644
--- a/qapi/run-state.json
+++ b/qapi/run-state.json
@@ -527,20 +527,20 @@
# Hyper-V specific guest panic information (HV crash MSRs)
#
# @arg1: for Windows, STOP code for the guest crash. For Linux,
-# an error code.
+# an error code.
#
# @arg2: for Windows, first argument of the STOP. For Linux, the
-# guest OS ID, which has the kernel version in bits 16-47
-# and 0x8100 in bits 48-63.
+# guest OS ID, which has the kernel version in bits 16-47 and
+# 0x8100 in bits 48-63.
#
# @arg3: for Windows, second argument of the STOP. For Linux, the
-# program counter of the guest.
+# program counter of the guest.
#
# @arg4: for Windows, third argument of the STOP. For Linux, the
-# RAX register (x86) or the stack pointer (aarch64) of the guest.
+# RAX register (x86) or the stack pointer (aarch64) of the guest.
#
# @arg5: for Windows, fourth argument of the STOP. For x86 Linux, the
-# stack pointer of the guest.
+# stack pointer of the guest.
#
# Since: 2.9
##
diff --git a/qapi/sockets.json b/qapi/sockets.json
index e76fdb9..6a95023 100644
--- a/qapi/sockets.json
+++ b/qapi/sockets.json
@@ -29,6 +29,7 @@
# @InetSocketAddressBase:
#
# @host: host part of the address
+#
# @port: port part of the address
##
{ 'struct': 'InetSocketAddressBase',
@@ -104,8 +105,8 @@
#
# @port: port
#
-# .. note:: String types are used to allow for possible future hostname
-# or service resolution support.
+# .. note:: String types are used to allow for possible future
+# hostname or service resolution support.
#
# Since: 2.8
##
diff --git a/qapi/stats.json b/qapi/stats.json
index efbbe26..8902ef9 100644
--- a/qapi/stats.json
+++ b/qapi/stats.json
@@ -117,10 +117,10 @@
# information for that target.
#
# @target: the kind of objects to query. Note that each possible
-# target may enable additional filtering options
+# target may enable additional filtering options
#
-# @providers: which providers to request statistics from, and optionally
-# which named values to return within each provider
+# @providers: which providers to request statistics from, and
+# optionally which named values to return within each provider
#
# Since: 7.1
##
diff --git a/qapi/transaction.json b/qapi/transaction.json
index b0ae343..021e383 100644
--- a/qapi/transaction.json
+++ b/qapi/transaction.json
@@ -238,8 +238,8 @@
# - Any errors from commands in the transaction
#
# .. note:: The transaction aborts on the first failure. Therefore,
-# there will be information on only one failed operation returned in
-# an error condition, and subsequent actions will not have been
+# there will be information on only one failed operation returned
+# in an error condition, and subsequent actions will not have been
# attempted.
#
# Since: 1.1
diff --git a/qapi/ui.json b/qapi/ui.json
index 5daca51..460a26b 100644
--- a/qapi/ui.json
+++ b/qapi/ui.json
@@ -48,8 +48,8 @@
# @password: the new password
#
# @connected: How to handle existing clients when changing the
-# password. If nothing is specified, defaults to 'keep'. For VNC,
-# only 'keep' is currently implemented.
+# password. If nothing is specified, defaults to 'keep'. For
+# VNC, only 'keep' is currently implemented.
#
# Since: 7.0
##
@@ -107,10 +107,11 @@
# - '+INT' where INT is the number of seconds from now (integer)
# - 'INT' where INT is the absolute time in seconds
#
-# .. note:: Time is relative to the server and currently there is no way
-# to coordinate server time with client time. It is not recommended
-# to use the absolute time version of the @time parameter unless
-# you're sure you are on the same machine as the QEMU instance.
+# .. note:: Time is relative to the server and currently there is no
+# way to coordinate server time with client time. It is not
+# recommended to use the absolute time version of the @time
+# parameter unless you're sure you are on the same machine as the
+# QEMU instance.
#
# Since: 7.0
##
@@ -624,7 +625,7 @@
# @id: vnc server name.
#
# @server: A list of @VncBasincInfo describing all listening sockets.
-# The list can be empty (in case the vnc server is disabled). It
+# The list can be empty (in case the vnc server is disabled). It
# also may have multiple entries: normal + websocket, possibly
# also ipv4 + ipv6 in the future.
#
@@ -719,8 +720,8 @@
#
# @client: client information
#
-# .. note:: This event is emitted before any authentication takes place,
-# thus the authentication ID is not provided.
+# .. note:: This event is emitted before any authentication takes
+# place, thus the authentication ID is not provided.
#
# Since: 0.13
#
@@ -948,6 +949,7 @@
# Since: 1.3
##
{ 'enum': 'QKeyCode',
+ 'prefix': 'Q_KEY_CODE',
'data': [ 'unmapped',
'shift', 'shift_r', 'alt', 'alt_r', 'ctrl',
'ctrl_r', 'menu', 'esc', '1', '2', '3', '4', '5', '6', '7', '8',
@@ -1266,7 +1268,7 @@
# Since: 2.6
#
# .. note:: The consoles are visible in the qom tree, under
-# ``/backend/console[$index]``. They have a device link and head
+# ``/backend/console[$index]``. They have a device link and head
# property, so it is possible to map which console belongs to which
# device and display.
#
@@ -1416,11 +1418,11 @@
#
# @left-command-key: Enable/disable forwarding of left command key to
# guest. Allows command-tab window switching on the host without
-# sending this key to the guest when "off". Defaults to "on"
+# sending this key to the guest when "off". Defaults to "on"
#
# @full-grab: Capture all key presses, including system combos. This
# requires accessibility permissions, since it performs a global
-# grab on key events. (default: off) See
+# grab on key events. (default: off) See
# https://support.apple.com/en-in/guide/mac-help/mh32356/mac
#
# @swap-opt-cmd: Swap the Option and Command keys so that their key
@@ -1432,7 +1434,7 @@
# "off". (Since 8.2)
#
# @zoom-interpolation: Apply interpolation to smooth output when
-# zoom-to-fit is enabled. Defaults to "off". (Since 9.0)
+# zoom-to-fit is enabled. Defaults to "off". (Since 9.0)
#
# Since: 7.0
##
diff --git a/qapi/vfio.json b/qapi/vfio.json
index 40cbcde..b53b7ca 100644
--- a/qapi/vfio.json
+++ b/qapi/vfio.json
@@ -7,7 +7,7 @@
##
##
-# @VfioMigrationState:
+# @QapiVfioMigrationState:
#
# An enumeration of the VFIO device migration states.
#
@@ -15,16 +15,16 @@
#
# @running: The device is running.
#
-# @stop-copy: The device is stopped and its internal state is available
-# for reading.
+# @stop-copy: The device is stopped and its internal state is
+# available for reading.
#
# @resuming: The device is stopped and its internal state is available
# for writing.
#
# @running-p2p: The device is running in the P2P quiescent state.
#
-# @pre-copy: The device is running, tracking its internal state and its
-# internal state is available for reading.
+# @pre-copy: The device is running, tracking its internal state and
+# its internal state is available for reading.
#
# @pre-copy-p2p: The device is running in the P2P quiescent state,
# tracking its internal state and its internal state is available
@@ -32,10 +32,9 @@
#
# Since: 9.1
##
-{ 'enum': 'VfioMigrationState',
+{ 'enum': 'QapiVfioMigrationState',
'data': [ 'stop', 'running', 'stop-copy', 'resuming', 'running-p2p',
- 'pre-copy', 'pre-copy-p2p' ],
- 'prefix': 'QAPI_VFIO_MIGRATION_STATE' }
+ 'pre-copy', 'pre-copy-p2p' ] }
##
# @VFIO_MIGRATION:
@@ -63,5 +62,5 @@
'data': {
'device-id': 'str',
'qom-path': 'str',
- 'device-state': 'VfioMigrationState'
+ 'device-state': 'QapiVfioMigrationState'
} }
diff --git a/qapi/virtio.json b/qapi/virtio.json
index 26df8b3..2529c2d 100644
--- a/qapi/virtio.json
+++ b/qapi/virtio.json
@@ -568,9 +568,9 @@
# .. note:: last_avail_idx will not be displayed in the case where the
# selected VirtIODevice has a running vhost device and the
# VirtIODevice VirtQueue index (queue) does not exist for the
-# corresponding vhost device vhost_virtqueue. Also, shadow_avail_idx
-# will not be displayed in the case where the selected VirtIODevice
-# has a running vhost device.
+# corresponding vhost device vhost_virtqueue. Also,
+# shadow_avail_idx will not be displayed in the case where the
+# selected VirtIODevice has a running vhost device.
#
# Since: 7.2
#
diff --git a/qemu-keymap.c b/qemu-keymap.c
index 701e433..6707067 100644
--- a/qemu-keymap.c
+++ b/qemu-keymap.c
@@ -154,9 +154,9 @@ static xkb_mod_mask_t get_mod(struct xkb_keymap *map, const char *name)
int main(int argc, char *argv[])
{
- static struct xkb_context *ctx;
- static struct xkb_keymap *map;
- static struct xkb_state *state;
+ struct xkb_context *ctx;
+ struct xkb_keymap *map;
+ struct xkb_state *state;
xkb_mod_index_t mod, mods;
int rc;
@@ -213,6 +213,7 @@ int main(int argc, char *argv[])
ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
map = xkb_keymap_new_from_names(ctx, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);
+ xkb_context_unref(ctx);
if (!map) {
/* libxkbcommon prints error */
exit(1);
@@ -234,6 +235,8 @@ int main(int argc, char *argv[])
state = xkb_state_new(map);
xkb_keymap_key_for_each(map, walk_map, state);
+ xkb_state_unref(state);
+ xkb_keymap_unref(map);
/* add quirks */
fprintf(outfile,
diff --git a/qemu-nbd.c b/qemu-nbd.c
index d7b3cca..a186d2e 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -390,7 +390,9 @@ static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc,
nb_fds++;
nbd_update_server_watch();
- nbd_client_new(cioc, tlscreds, tlsauthz, nbd_client_closed);
+ /* TODO - expose handshake timeout as command line option */
+ nbd_client_new(cioc, NBD_DEFAULT_HANDSHAKE_MAX_SECS,
+ tlscreds, tlsauthz, nbd_client_closed, NULL);
}
static void nbd_update_server_watch(void)
@@ -588,7 +590,8 @@ int main(int argc, char **argv)
pthread_t client_thread;
const char *fmt = NULL;
Error *local_err = NULL;
- BlockdevDetectZeroesOptions detect_zeroes = BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF;
+ BlockdevDetectZeroesOptions detect_zeroes =
+ BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF;
QDict *options = NULL;
const char *export_name = NULL; /* defaults to "" later for server mode */
const char *export_description = NULL;
diff --git a/qemu-options.hx b/qemu-options.hx
index 369ae81..dacc979 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -68,8 +68,8 @@ SRST
``vmport=on|off|auto``
Enables emulation of VMWare IO port, for vmmouse etc. auto says
- to select the value based on accel. For accel=xen the default is
- off otherwise the default is on.
+ to select the value based on accel and i8042. For accel=xen or
+ i8042=off the default is off otherwise the default is on.
``dump-guest-core=on|off``
Include guest memory in a core dump. The default is on.
@@ -1102,7 +1102,7 @@ SRST
external entity that provides the IPMI services.
A connection is made to an external BMC simulator. If you do this,
- it is strongly recommended that you use the "reconnect=" chardev
+ it is strongly recommended that you use the "reconnect-ms=" chardev
option to reconnect to the simulator if the connection is lost. Note
that if this is not used carefully, it can be a security issue, as
the interface has the ability to send resets, NMIs, and power off
@@ -1766,29 +1766,18 @@ DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
" [[,throttling.bps-total-max=bm]|[[,throttling.bps-read-max=rm][,throttling.bps-write-max=wm]]]\n"
" [[,throttling.iops-total-max=im]|[[,throttling.iops-read-max=irm][,throttling.iops-write-max=iwm]]]\n"
" [[,throttling.iops-size=is]]\n"
- "-fsdev proxy,id=id,socket=socket[,writeout=immediate][,readonly=on]\n"
- "-fsdev proxy,id=id,sock_fd=sock_fd[,writeout=immediate][,readonly=on]\n"
"-fsdev synth,id=id\n",
QEMU_ARCH_ALL)
SRST
``-fsdev local,id=id,path=path,security_model=security_model [,writeout=writeout][,readonly=on][,fmode=fmode][,dmode=dmode] [,throttling.option=value[,throttling.option=value[,...]]]``
\
-``-fsdev proxy,id=id,socket=socket[,writeout=writeout][,readonly=on]``
- \
-``-fsdev proxy,id=id,sock_fd=sock_fd[,writeout=writeout][,readonly=on]``
- \
``-fsdev synth,id=id[,readonly=on]``
Define a new file system device. Valid options are:
``local``
Accesses to the filesystem are done by QEMU.
- ``proxy``
- Accesses to the filesystem are done by virtfs-proxy-helper(1). This
- option is deprecated (since QEMU 8.1) and will be removed in a future
- version of QEMU. Use ``local`` instead.
-
``synth``
Synthetic filesystem, only used by QTests.
@@ -1813,8 +1802,6 @@ SRST
security model is same as passthrough except the sever won't
report failures if it fails to set file attributes like
ownership. Security model is mandatory only for local fsdriver.
- Other fsdrivers (like proxy) don't take security model as a
- parameter.
``writeout=writeout``
This is an optional argument. The only supported value is
@@ -1827,16 +1814,6 @@ SRST
Enables exporting 9p share as a readonly mount for guests. By
default read-write access is given.
- ``socket=socket``
- Enables proxy filesystem driver to use passed socket file for
- communicating with virtfs-proxy-helper(1).
-
- ``sock_fd=sock_fd``
- Enables proxy filesystem driver to use passed socket descriptor
- for communicating with virtfs-proxy-helper(1). Usually a helper
- like libvirt will create socketpair and pass one of the fds as
- sock\_fd.
-
``fmode=fmode``
Specifies the default mode for newly created files on the host.
Works only with security models "mapped-xattr" and
@@ -1889,18 +1866,12 @@ ERST
DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs,
"-virtfs local,path=path,mount_tag=tag,security_model=mapped-xattr|mapped-file|passthrough|none\n"
" [,id=id][,writeout=immediate][,readonly=on][,fmode=fmode][,dmode=dmode][,multidevs=remap|forbid|warn]\n"
- "-virtfs proxy,mount_tag=tag,socket=socket[,id=id][,writeout=immediate][,readonly=on]\n"
- "-virtfs proxy,mount_tag=tag,sock_fd=sock_fd[,id=id][,writeout=immediate][,readonly=on]\n"
"-virtfs synth,mount_tag=tag[,id=id][,readonly=on]\n",
QEMU_ARCH_ALL)
SRST
``-virtfs local,path=path,mount_tag=mount_tag ,security_model=security_model[,writeout=writeout][,readonly=on] [,fmode=fmode][,dmode=dmode][,multidevs=multidevs]``
\
-``-virtfs proxy,socket=socket,mount_tag=mount_tag [,writeout=writeout][,readonly=on]``
- \
-``-virtfs proxy,sock_fd=sock_fd,mount_tag=mount_tag [,writeout=writeout][,readonly=on]``
- \
``-virtfs synth,mount_tag=mount_tag``
Define a new virtual filesystem device and expose it to the guest using
a virtio-9p-device (a.k.a. 9pfs), which essentially means that a certain
@@ -1917,11 +1888,6 @@ SRST
``local``
Accesses to the filesystem are done by QEMU.
- ``proxy``
- Accesses to the filesystem are done by virtfs-proxy-helper(1).
- This option is deprecated (since QEMU 8.1) and will be removed in a
- future version of QEMU. Use ``local`` instead.
-
``synth``
Synthetic filesystem, only used by QTests.
@@ -1946,8 +1912,6 @@ SRST
security model is same as passthrough except the sever won't
report failures if it fails to set file attributes like
ownership. Security model is mandatory only for local fsdriver.
- Other fsdrivers (like proxy) don't take security model as a
- parameter.
``writeout=writeout``
This is an optional argument. The only supported value is
@@ -1960,16 +1924,6 @@ SRST
Enables exporting 9p share as a readonly mount for guests. By
default read-write access is given.
- ``socket=socket``
- Enables proxy filesystem driver to use passed socket file for
- communicating with virtfs-proxy-helper(1). Usually a helper like
- libvirt will create socketpair and pass one of the fds as
- sock\_fd.
-
- ``sock_fd``
- Enables proxy filesystem driver to use passed 'sock\_fd' as the
- socket descriptor for interfacing with virtfs-proxy-helper(1).
-
``fmode=fmode``
Specifies the default mode for newly created files on the host.
Works only with security models "mapped-xattr" and
@@ -2377,22 +2331,6 @@ SRST
pick the first available. (Since 2.9)
ERST
-DEF("portrait", 0, QEMU_OPTION_portrait,
- "-portrait rotate graphical output 90 deg left (only PXA LCD)\n",
- QEMU_ARCH_ALL)
-SRST
-``-portrait``
- Rotate graphical output 90 deg left (only PXA LCD).
-ERST
-
-DEF("rotate", HAS_ARG, QEMU_OPTION_rotate,
- "-rotate <deg> rotate graphical output some deg left (only PXA LCD)\n",
- QEMU_ARCH_ALL)
-SRST
-``-rotate deg``
- Rotate graphical output some deg left (only PXA LCD).
-ERST
-
DEF("vga", HAS_ARG, QEMU_OPTION_vga,
"-vga [std|cirrus|vmware|qxl|xenfb|tcx|cg3|virtio|none]\n"
" select video card type\n", QEMU_ARCH_ALL)
@@ -2704,7 +2642,7 @@ DEF("smbios", HAS_ARG, QEMU_OPTION_smbios,
" specify SMBIOS type 3 fields\n"
"-smbios type=4[,sock_pfx=str][,manufacturer=str][,version=str][,serial=str]\n"
" [,asset=str][,part=str][,max-speed=%d][,current-speed=%d]\n"
- " [,processor-family=%d,processor-id=%d]\n"
+ " [,processor-family=%d][,processor-id=%d]\n"
" specify SMBIOS type 4 fields\n"
"-smbios type=8[,external_reference=str][,internal_reference=str][,connector_type=%d][,port_type=%d]\n"
" specify SMBIOS type 8 fields\n"
@@ -2895,9 +2833,9 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
"-netdev socket,id=str[,fd=h][,udp=host:port][,localaddr=host:port]\n"
" configure a network backend to connect to another network\n"
" using an UDP tunnel\n"
- "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect=seconds]\n"
- "-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,abstract=on|off][,tight=on|off][,reconnect=seconds]\n"
- "-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor[,reconnect=seconds]\n"
+ "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]\n"
+ "-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,abstract=on|off][,tight=on|off][,reconnect-ms=milliseconds]\n"
+ "-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor[,reconnect-ms=milliseconds]\n"
" configure a network backend to connect to another network\n"
" using a socket connection in stream mode.\n"
"-netdev dgram,id=str,remote.type=inet,remote.host=maddr,remote.port=port[,local.type=inet,local.host=addr]\n"
@@ -3353,6 +3291,195 @@ SRST
-device e1000,netdev=n1,mac=52:54:00:12:34:56 \\
-netdev socket,id=n1,mcast=239.192.168.1:1102,localaddr=1.2.3.4
+``-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]``
+ Configure a network backend to connect to another QEMU virtual machine or a proxy using a TCP/IP socket.
+
+ ``server=on|off``
+ if ``on`` create a server socket
+
+ ``addr.host=host,addr.port=port``
+ socket address to listen on (server=on) or connect to (server=off)
+
+ ``to=maxport``
+ if present, this is range of possible addresses, with port between ``port`` and ``maxport``.
+
+ ``numeric=on|off``
+ if ``on`` ``host`` and ``port`` are guaranteed to be numeric, otherwise a name resolution should be attempted (default: ``off``)
+
+ ``keep-alive=on|off``
+ enable keep-alive when connecting to this socket. Not supported for passive sockets.
+
+ ``mptcp=on|off``
+ enable multipath TCP
+
+ ``ipv4=on|off``
+ whether to accept IPv4 addresses, default to try both IPv4 and IPv6
+
+ ``ipv6=on|off``
+ whether to accept IPv6 addresses, default to try both IPv4 and IPv6
+
+ ``reconnect-ms=milliseconds``
+ for a client socket, if a socket is disconnected, then attempt a reconnect after the given number of milliseconds.
+ Setting this to zero disables this function. (default: 0)
+
+ Example (two guests connected using a TCP/IP socket):
+
+ .. parsed-literal::
+
+ # first VM
+ |qemu_system| linux.img \\
+ -device virtio-net,netdev=net0,mac=52:54:00:12:34:56 \\
+ -netdev stream,id=net0,server=on,addr.type=inet,addr.host=localhost,addr.port=1234
+ # second VM
+ |qemu_system| linux.img \\
+ -device virtio-net,netdev=net0,mac=52:54:00:12:34:57 \\
+ -netdev stream,id=net0,server=off,addr.type=inet,addr.host=localhost,addr.port=1234,reconnect-ms=5000
+
+``-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,abstract=on|off][,tight=on|off][,reconnect-ms=milliseconds]``
+ Configure a network backend to connect to another QEMU virtual machine or a proxy using a stream oriented unix domain socket.
+
+ ``server=on|off``
+ if ``on`` create a server socket
+
+ ``addr.path=path``
+ filesystem path to use
+
+ ``abstract=on|off``
+ if ``on``, this is a Linux abstract socket address.
+
+ ``tight=on|off``
+ if false, pad an abstract socket address with enough null bytes to make it fill struct sockaddr_un member sun_path.
+
+ ``reconnect-ms=milliseconds``
+ for a client socket, if a socket is disconnected, then attempt a reconnect after the given number of milliseconds.
+ Setting this to zero disables this function. (default: 0)
+
+ Example (using passt as a replacement of -netdev user):
+
+ .. parsed-literal::
+
+ # start passt server as a non privileged user
+ passt
+ UNIX domain socket bound at /tmp/passt_1.socket
+ # start QEMU to connect to passt
+ |qemu_system| linux.img \\
+ -device virtio-net,netdev=net0 \\
+ -netdev stream,id=net0,server=off,addr.type=unix,addr.path=/tmp/passt_1.socket
+
+ Example (two guests connected using a stream oriented unix domain socket):
+
+ .. parsed-literal::
+
+ # first VM
+ |qemu_system| linux.img \\
+ -device virtio-net,netdev=net0,mac=52:54:00:12:34:56 \\
+ netdev stream,id=net0,server=on,addr.type=unix,addr.path=/tmp/qemu0
+ # second VM
+ |qemu_system| linux.img \\
+ -device virtio-net,netdev=net0,mac=52:54:00:12:34:57 \\
+ -netdev stream,id=net0,server=off,addr.type=unix,addr.path=/tmp/qemu0,reconnect-ms=5000
+
+``-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor[,reconnect-ms=milliseconds]``
+ Configure a network backend to connect to another QEMU virtual machine or a proxy using a stream oriented socket file descriptor.
+
+ ``server=on|off``
+ if ``on`` create a server socket
+
+ ``addr.str=file-descriptor``
+ file descriptor number to use as a socket
+
+ ``reconnect-ms=milliseconds``
+ for a client socket, if a socket is disconnected, then attempt a reconnect after the given number of milliseconds.
+ Setting this to zero disables this function. (default: 0)
+
+``-netdev dgram,id=str,remote.type=inet,remote.host=maddr,remote.port=port[,local.type=inet,local.host=addr]``
+ Configure a network backend to connect to a multicast address.
+
+ ``remote.host=maddr,remote.port=port``
+ multicast address
+
+ ``local.host=addr``
+ specify the host address to send packets from
+
+ Example:
+
+ .. parsed-literal::
+
+ # launch one QEMU instance
+ |qemu_system| linux.img \\
+ -device virtio-net,netdev=net0,mac=52:54:00:12:34:56 \\
+ -netdev dgram,id=net0,remote.type=inet,remote.host=224.0.0.1,remote.port=1234
+ # launch another QEMU instance on same "bus"
+ |qemu_system| linux.img \\
+ -device virtio-net,netdev=net0,mac=52:54:00:12:34:57 \\
+ -netdev dgram,id=net0,remote.type=inet,remote.host=224.0.0.1,remote.port=1234
+ # launch yet another QEMU instance on same "bus"
+ |qemu_system| linux.img \\
+ -device virtio-net,netdev=net0,mac=52:54:00:12:34:58 \\
+ -netdev dgram,id=net0,remote.type=inet,remote.host=224.0.0.1,remote.port=1234
+
+``-netdev dgram,id=str,remote.type=inet,remote.host=maddr,remote.port=port[,local.type=fd,local.str=file-descriptor]``
+ Configure a network backend to connect to a multicast address using a UDP socket file descriptor.
+
+ ``remote.host=maddr,remote.port=port``
+ multicast address
+
+ ``local.str=file-descriptor``
+ File descriptor to use to send packets
+
+``-netdev dgram,id=str,local.type=inet,local.host=addr,local.port=port[,remote.type=inet,remote.host=addr,remote.port=port]``
+ Configure a network backend to connect to another QEMU virtual
+ machine or a proxy using a datagram oriented unix domain socket.
+
+ ``local.host=addr,local.port=port``
+ IP address to use to send the packets from
+
+ ``remote.host=addr,remote.port=port``
+ Destination IP address
+
+ Example (two guests connected using an UDP/IP socket):
+
+ .. parsed-literal::
+
+ # first VM
+ |qemu_system| linux.img \\
+ -device virtio-net,netdev=net0,mac=52:54:00:12:34:56 \\
+ -netdev dgram,id=net0,local.type=inet,local.host=localhost,local.port=1234,remote.type=inet,remote.host=localhost,remote.port=1235
+ # second VM
+ |qemu_system| linux.img \\
+ -device virtio-net,netdev=net0,mac=52:54:00:12:34:56 \\
+ -netdev dgram,id=net0,local.type=inet,local.host=localhost,local.port=1235,remote.type=inet,remote.host=localhost,remote.port=1234
+
+``-netdev dgram,id=str,local.type=unix,local.path=path[,remote.type=unix,remote.path=path]``
+ Configure a network backend to connect to another QEMU virtual
+ machine or a proxy using a datagram oriented unix socket.
+
+ ``local.path=path``
+ filesystem path to use to bind the socket
+
+ ``remote.path=path``
+ filesystem path to use as a destination (see sendto(2))
+
+ Example (two guests connected using an UDP/UNIX socket):
+
+ .. parsed-literal::
+
+ # first VM
+ |qemu_system| linux.img \\
+ -device virtio-net,netdev=net0,mac=52:54:00:12:34:56 \\
+ -netdev dgram,id=net0,local.type=unix,local.path=/tmp/qemu0,remote.type=unix,remote.path=/tmp/qemu1
+ # second VM
+ |qemu_system| linux.img \\
+ -device virtio-net,netdev=net0,mac=52:54:00:12:34:57 \\
+ -netdev dgram,id=net0,local.type=unix,local.path=/tmp/qemu1,remote.type=unix,remote.path=/tmp/qemu0
+
+``-netdev dgram,id=str,local.type=fd,local.str=file-descriptor``
+ Configure a network backend to connect to another QEMU virtual
+ machine or a proxy using a datagram oriented socket file descriptor.
+
+ ``local.str=file-descriptor``
+ File descriptor to use to send packets
+
``-netdev l2tpv3,id=id,src=srcaddr,dst=dstaddr[,srcport=srcport][,dstport=dstport],txsession=txsession[,rxsession=rxsession][,ipv6=on|off][,udp=on|off][,cookie64=on|off][,counter=on|off][,pincounter=on|off][,txcookie=txcookie][,rxcookie=rxcookie][,offset=offset]``
Configure a L2TPv3 pseudowire host network backend. L2TPv3 (RFC3931)
is a popular protocol to transport Ethernet (and other Layer 2) data
@@ -3552,9 +3679,9 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
"-chardev help\n"
"-chardev null,id=id[,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
"-chardev socket,id=id[,host=host],port=port[,to=to][,ipv4=on|off][,ipv6=on|off][,nodelay=on|off]\n"
- " [,server=on|off][,wait=on|off][,telnet=on|off][,websocket=on|off][,reconnect=seconds][,mux=on|off]\n"
+ " [,server=on|off][,wait=on|off][,telnet=on|off][,websocket=on|off][,reconnect-ms=milliseconds][,mux=on|off]\n"
" [,logfile=PATH][,logappend=on|off][,tls-creds=ID][,tls-authz=ID] (tcp)\n"
- "-chardev socket,id=id,path=path[,server=on|off][,wait=on|off][,telnet=on|off][,websocket=on|off][,reconnect=seconds]\n"
+ "-chardev socket,id=id,path=path[,server=on|off][,wait=on|off][,telnet=on|off][,websocket=on|off][,reconnect-ms=milliseconds]\n"
" [,mux=on|off][,logfile=PATH][,logappend=on|off][,abstract=on|off][,tight=on|off] (unix)\n"
"-chardev udp,id=id[,host=host],port=port[,localaddr=localaddr]\n"
" [,localport=localport][,ipv4=on|off][,ipv6=on|off][,mux=on|off]\n"
@@ -3569,7 +3696,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
"-chardev console,id=id[,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
"-chardev serial,id=id,path=path[,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
#else
- "-chardev pty,id=id[,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
+ "-chardev pty,id=id[,path=path][,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
"-chardev stdio,id=id[,mux=on|off][,signal=on|off][,logfile=PATH][,logappend=on|off]\n"
#endif
#ifdef CONFIG_BRLAPI
@@ -3665,7 +3792,7 @@ The available backends are:
A void device. This device will not emit any data, and will drop any
data it receives. The null backend does not take any options.
-``-chardev socket,id=id[,TCP options or unix options][,server=on|off][,wait=on|off][,telnet=on|off][,websocket=on|off][,reconnect=seconds][,tls-creds=id][,tls-authz=id]``
+``-chardev socket,id=id[,TCP options or unix options][,server=on|off][,wait=on|off][,telnet=on|off][,websocket=on|off][,reconnect-ms=milliseconds][,tls-creds=id][,tls-authz=id]``
Create a two-way stream socket, which can be either a TCP or a unix
socket. A unix socket will be created if ``path`` is specified.
Behaviour is undefined if TCP options are specified for a unix
@@ -3682,9 +3809,9 @@ The available backends are:
``websocket=on|off`` specifies that the socket uses WebSocket protocol for
communication.
- ``reconnect`` sets the timeout for reconnecting on non-server
+ ``reconnect-ms`` sets the timeout for reconnecting on non-server
sockets when the remote end goes away. qemu will delay this many
- seconds and then attempt to reconnect. Zero disables reconnecting,
+ milliseconds and then attempt to reconnect. Zero disables reconnecting,
and is the default.
``tls-creds`` requests enablement of the TLS protocol for
@@ -3808,12 +3935,22 @@ The available backends are:
``path`` specifies the name of the serial device to open.
-``-chardev pty,id=id``
- Create a new pseudo-terminal on the host and connect to it. ``pty``
- does not take any options.
+``-chardev pty,id=id[,path=path]``
+ Create a new pseudo-terminal on the host and connect to it.
``pty`` is not available on Windows hosts.
+ If ``path`` is specified, QEMU will create a symbolic link at
+ that location which points to the new PTY device.
+
+ This avoids having to make QMP or HMP monitor queries to find out
+ what the new PTY device path is.
+
+ Note that while QEMU will remove the symlink when it exits
+ gracefully, it will not do so in case of crashes or on certain
+ startup errors. It is recommended that the user checks and removes
+ the symlink after QEMU terminates to account for this.
+
``-chardev stdio,id=id[,signal=on|off]``
Connect to standard input and standard output of the QEMU process.
@@ -4171,8 +4308,19 @@ SRST
vc:80Cx24C
- ``pty``
- [Linux only] Pseudo TTY (a new PTY is automatically allocated)
+ ``pty[:path]``
+ [Linux only] Pseudo TTY (a new PTY is automatically allocated).
+
+ If ``path`` is specified, QEMU will create a symbolic link at
+ that location which points to the new PTY device.
+
+ This avoids having to make QMP or HMP monitor queries to find
+ out what the new PTY device path is.
+
+ Note that while QEMU will remove the symlink when it exits
+ gracefully, it will not do so in case of crashes or on certain
+ startup errors. It is recommended that the user checks and
+ removes the symlink after QEMU terminates to account for this.
``none``
No device is allocated. Note that for machine types which
@@ -4242,14 +4390,14 @@ SRST
``telnet options:``
localhost 5555
- ``tcp:[host]:port[,server=on|off][,wait=on|off][,nodelay=on|off][,reconnect=seconds]``
+ ``tcp:[host]:port[,server=on|off][,wait=on|off][,nodelay=on|off][,reconnect-ms=milliseconds]``
The TCP Net Console has two modes of operation. It can send the
serial I/O to a location or wait for a connection from a
location. By default the TCP Net Console is sent to host at the
port. If you use the ``server=on`` option QEMU will wait for a client
socket application to connect to the port before continuing,
unless the ``wait=on|off`` option was specified. The ``nodelay=on|off``
- option disables the Nagle buffering algorithm. The ``reconnect=on``
+ option disables the Nagle buffering algorithm. The ``reconnect-ms``
option only applies if ``server=no`` is set, if the connection goes
down it will attempt to reconnect at the given interval. If host
is omitted, 0.0.0.0 is assumed. Only one TCP connection at a
@@ -4279,7 +4427,7 @@ SRST
The WebSocket protocol is used instead of raw tcp socket. The
port acts as a WebSocket server. Client mode is not supported.
- ``unix:path[,server=on|off][,wait=on|off][,reconnect=seconds]``
+ ``unix:path[,server=on|off][,wait=on|off][,reconnect-ms=milliseconds]``
A unix domain socket is used instead of a tcp socket. The option
works the same as if you had specified ``-serial tcp`` except
the unix domain socket path is used for connections.
diff --git a/qemu.nsi b/qemu.nsi
index 564d617..b186f22 100644
--- a/qemu.nsi
+++ b/qemu.nsi
@@ -7,7 +7,7 @@
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 2 of the License, or
-; (at your option) version 3 or any later version.
+; (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
@@ -16,6 +16,8 @@
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
+;
+; SPDX-License-Identifier: GPL-2.0-or-later
; NSIS_WIN32_MAKENSIS
diff --git a/qga/commands-bsd.c b/qga/commands-bsd.c
index 17bddda..94ff6fe 100644
--- a/qga/commands-bsd.c
+++ b/qga/commands-bsd.c
@@ -12,7 +12,6 @@
#include "qemu/osdep.h"
#include "qga-qapi-commands.h"
-#include "qapi/qmp/qerror.h"
#include "qapi/error.h"
#include "qemu/queue.h"
#include "commands-common.h"
@@ -149,30 +148,6 @@ int qmp_guest_fsfreeze_do_thaw(Error **errp)
}
return ret;
}
-
-GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-GuestCpuStatsList *qmp_guest_get_cpustats(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
#endif /* CONFIG_FSFREEZE */
#ifdef HAVE_GETIFADDRS
diff --git a/qga/commands-common.h b/qga/commands-common.h
index 8c1c56a..263e7c0 100644
--- a/qga/commands-common.h
+++ b/qga/commands-common.h
@@ -15,19 +15,10 @@
#if defined(__linux__)
#include <linux/fs.h>
-#ifdef FIFREEZE
-#define CONFIG_FSFREEZE
-#endif
-#ifdef FITRIM
-#define CONFIG_FSTRIM
-#endif
#endif /* __linux__ */
#ifdef __FreeBSD__
#include <ufs/ffs/fs.h>
-#ifdef UFSSUSPEND
-#define CONFIG_FSFREEZE
-#endif
#endif /* __FreeBSD__ */
#if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
diff --git a/qga/commands-linux.c b/qga/commands-linux.c
index 214e408..9b1746b 100644
--- a/qga/commands-linux.c
+++ b/qga/commands-linux.c
@@ -13,10 +13,25 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
+#include "qga-qapi-commands.h"
+#include "qapi/error.h"
#include "commands-common.h"
#include "cutils.h"
#include <mntent.h>
#include <sys/ioctl.h>
+#include <mntent.h>
+#include <linux/nvme_ioctl.h>
+#include "block/nvme.h"
+
+#ifdef CONFIG_LIBUDEV
+#include <libudev.h>
+#endif
+
+#ifdef HAVE_GETIFADDRS
+#include <net/if.h>
+#endif
+
+#include <sys/statvfs.h>
#if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
static int dev_major_minor(const char *devpath,
@@ -284,3 +299,1925 @@ int qmp_guest_fsfreeze_do_thaw(Error **errp)
return i;
}
#endif /* CONFIG_FSFREEZE */
+
+#if defined(CONFIG_FSFREEZE)
+
+static char *get_pci_driver(char const *syspath, int pathlen, Error **errp)
+{
+ char *path;
+ char *dpath;
+ char *driver = NULL;
+ char buf[PATH_MAX];
+ ssize_t len;
+
+ path = g_strndup(syspath, pathlen);
+ dpath = g_strdup_printf("%s/driver", path);
+ len = readlink(dpath, buf, sizeof(buf) - 1);
+ if (len != -1) {
+ buf[len] = 0;
+ driver = g_path_get_basename(buf);
+ }
+ g_free(dpath);
+ g_free(path);
+ return driver;
+}
+
+static int compare_uint(const void *_a, const void *_b)
+{
+ unsigned int a = *(unsigned int *)_a;
+ unsigned int b = *(unsigned int *)_b;
+
+ return a < b ? -1 : a > b ? 1 : 0;
+}
+
+/* Walk the specified sysfs and build a sorted list of host or ata numbers */
+static int build_hosts(char const *syspath, char const *host, bool ata,
+ unsigned int *hosts, int hosts_max, Error **errp)
+{
+ char *path;
+ DIR *dir;
+ struct dirent *entry;
+ int i = 0;
+
+ path = g_strndup(syspath, host - syspath);
+ dir = opendir(path);
+ if (!dir) {
+ error_setg_errno(errp, errno, "opendir(\"%s\")", path);
+ g_free(path);
+ return -1;
+ }
+
+ while (i < hosts_max) {
+ entry = readdir(dir);
+ if (!entry) {
+ break;
+ }
+ if (ata && sscanf(entry->d_name, "ata%d", hosts + i) == 1) {
+ ++i;
+ } else if (!ata && sscanf(entry->d_name, "host%d", hosts + i) == 1) {
+ ++i;
+ }
+ }
+
+ qsort(hosts, i, sizeof(hosts[0]), compare_uint);
+
+ g_free(path);
+ closedir(dir);
+ return i;
+}
+
+/*
+ * Store disk device info for devices on the PCI bus.
+ * Returns true if information has been stored, or false for failure.
+ */
+static bool build_guest_fsinfo_for_pci_dev(char const *syspath,
+ GuestDiskAddress *disk,
+ Error **errp)
+{
+ unsigned int pci[4], host, hosts[8], tgt[3];
+ int i, nhosts = 0, pcilen;
+ GuestPCIAddress *pciaddr = disk->pci_controller;
+ bool has_ata = false, has_host = false, has_tgt = false;
+ char *p, *q, *driver = NULL;
+ bool ret = false;
+
+ p = strstr(syspath, "/devices/pci");
+ if (!p || sscanf(p + 12, "%*x:%*x/%x:%x:%x.%x%n",
+ pci, pci + 1, pci + 2, pci + 3, &pcilen) < 4) {
+ g_debug("only pci device is supported: sysfs path '%s'", syspath);
+ return false;
+ }
+
+ p += 12 + pcilen;
+ while (true) {
+ driver = get_pci_driver(syspath, p - syspath, errp);
+ if (driver && (g_str_equal(driver, "ata_piix") ||
+ g_str_equal(driver, "sym53c8xx") ||
+ g_str_equal(driver, "virtio-pci") ||
+ g_str_equal(driver, "ahci") ||
+ g_str_equal(driver, "nvme") ||
+ g_str_equal(driver, "xhci_hcd") ||
+ g_str_equal(driver, "ehci-pci"))) {
+ break;
+ }
+
+ g_free(driver);
+ if (sscanf(p, "/%x:%x:%x.%x%n",
+ pci, pci + 1, pci + 2, pci + 3, &pcilen) == 4) {
+ p += pcilen;
+ continue;
+ }
+
+ g_debug("unsupported driver or sysfs path '%s'", syspath);
+ return false;
+ }
+
+ p = strstr(syspath, "/target");
+ if (p && sscanf(p + 7, "%*u:%*u:%*u/%*u:%u:%u:%u",
+ tgt, tgt + 1, tgt + 2) == 3) {
+ has_tgt = true;
+ }
+
+ p = strstr(syspath, "/ata");
+ if (p) {
+ q = p + 4;
+ has_ata = true;
+ } else {
+ p = strstr(syspath, "/host");
+ q = p + 5;
+ }
+ if (p && sscanf(q, "%u", &host) == 1) {
+ has_host = true;
+ nhosts = build_hosts(syspath, p, has_ata, hosts,
+ ARRAY_SIZE(hosts), errp);
+ if (nhosts < 0) {
+ goto cleanup;
+ }
+ }
+
+ pciaddr->domain = pci[0];
+ pciaddr->bus = pci[1];
+ pciaddr->slot = pci[2];
+ pciaddr->function = pci[3];
+
+ if (strcmp(driver, "ata_piix") == 0) {
+ /* a host per ide bus, target*:0:<unit>:0 */
+ if (!has_host || !has_tgt) {
+ g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
+ goto cleanup;
+ }
+ for (i = 0; i < nhosts; i++) {
+ if (host == hosts[i]) {
+ disk->bus_type = GUEST_DISK_BUS_TYPE_IDE;
+ disk->bus = i;
+ disk->unit = tgt[1];
+ break;
+ }
+ }
+ if (i >= nhosts) {
+ g_debug("no host for '%s' (driver '%s')", syspath, driver);
+ goto cleanup;
+ }
+ } else if (strcmp(driver, "sym53c8xx") == 0) {
+ /* scsi(LSI Logic): target*:0:<unit>:0 */
+ if (!has_tgt) {
+ g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
+ goto cleanup;
+ }
+ disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI;
+ disk->unit = tgt[1];
+ } else if (strcmp(driver, "virtio-pci") == 0) {
+ if (has_tgt) {
+ /* virtio-scsi: target*:0:0:<unit> */
+ disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI;
+ disk->unit = tgt[2];
+ } else {
+ /* virtio-blk: 1 disk per 1 device */
+ disk->bus_type = GUEST_DISK_BUS_TYPE_VIRTIO;
+ }
+ } else if (strcmp(driver, "ahci") == 0) {
+ /* ahci: 1 host per 1 unit */
+ if (!has_host || !has_tgt) {
+ g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
+ goto cleanup;
+ }
+ for (i = 0; i < nhosts; i++) {
+ if (host == hosts[i]) {
+ disk->unit = i;
+ disk->bus_type = GUEST_DISK_BUS_TYPE_SATA;
+ break;
+ }
+ }
+ if (i >= nhosts) {
+ g_debug("no host for '%s' (driver '%s')", syspath, driver);
+ goto cleanup;
+ }
+ } else if (strcmp(driver, "nvme") == 0) {
+ disk->bus_type = GUEST_DISK_BUS_TYPE_NVME;
+ } else if (strcmp(driver, "ehci-pci") == 0 || strcmp(driver, "xhci_hcd") == 0) {
+ disk->bus_type = GUEST_DISK_BUS_TYPE_USB;
+ } else {
+ g_debug("unknown driver '%s' (sysfs path '%s')", driver, syspath);
+ goto cleanup;
+ }
+
+ ret = true;
+
+cleanup:
+ g_free(driver);
+ return ret;
+}
+
+/*
+ * Store disk device info for non-PCI virtio devices (for example s390x
+ * channel I/O devices). Returns true if information has been stored, or
+ * false for failure.
+ */
+static bool build_guest_fsinfo_for_nonpci_virtio(char const *syspath,
+ GuestDiskAddress *disk,
+ Error **errp)
+{
+ unsigned int tgt[3];
+ char *p;
+
+ if (!strstr(syspath, "/virtio") || !strstr(syspath, "/block")) {
+ g_debug("Unsupported virtio device '%s'", syspath);
+ return false;
+ }
+
+ p = strstr(syspath, "/target");
+ if (p && sscanf(p + 7, "%*u:%*u:%*u/%*u:%u:%u:%u",
+ &tgt[0], &tgt[1], &tgt[2]) == 3) {
+ /* virtio-scsi: target*:0:<target>:<unit> */
+ disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI;
+ disk->bus = tgt[0];
+ disk->target = tgt[1];
+ disk->unit = tgt[2];
+ } else {
+ /* virtio-blk: 1 disk per 1 device */
+ disk->bus_type = GUEST_DISK_BUS_TYPE_VIRTIO;
+ }
+
+ return true;
+}
+
+/*
+ * Store disk device info for CCW devices (s390x channel I/O devices).
+ * Returns true if information has been stored, or false for failure.
+ */
+static bool build_guest_fsinfo_for_ccw_dev(char const *syspath,
+ GuestDiskAddress *disk,
+ Error **errp)
+{
+ unsigned int cssid, ssid, subchno, devno;
+ char *p;
+
+ p = strstr(syspath, "/devices/css");
+ if (!p || sscanf(p + 12, "%*x/%x.%x.%x/%*x.%*x.%x/",
+ &cssid, &ssid, &subchno, &devno) < 4) {
+ g_debug("could not parse ccw device sysfs path: %s", syspath);
+ return false;
+ }
+
+ disk->ccw_address = g_new0(GuestCCWAddress, 1);
+ disk->ccw_address->cssid = cssid;
+ disk->ccw_address->ssid = ssid;
+ disk->ccw_address->subchno = subchno;
+ disk->ccw_address->devno = devno;
+
+ if (strstr(p, "/virtio")) {
+ build_guest_fsinfo_for_nonpci_virtio(syspath, disk, errp);
+ }
+
+ return true;
+}
+
+/* Store disk device info specified by @sysfs into @fs */
+static void build_guest_fsinfo_for_real_device(char const *syspath,
+ GuestFilesystemInfo *fs,
+ Error **errp)
+{
+ GuestDiskAddress *disk;
+ GuestPCIAddress *pciaddr;
+ bool has_hwinf;
+#ifdef CONFIG_LIBUDEV
+ struct udev *udev = NULL;
+ struct udev_device *udevice = NULL;
+#endif
+
+ pciaddr = g_new0(GuestPCIAddress, 1);
+ pciaddr->domain = -1; /* -1 means field is invalid */
+ pciaddr->bus = -1;
+ pciaddr->slot = -1;
+ pciaddr->function = -1;
+
+ disk = g_new0(GuestDiskAddress, 1);
+ disk->pci_controller = pciaddr;
+ disk->bus_type = GUEST_DISK_BUS_TYPE_UNKNOWN;
+
+#ifdef CONFIG_LIBUDEV
+ udev = udev_new();
+ udevice = udev_device_new_from_syspath(udev, syspath);
+ if (udev == NULL || udevice == NULL) {
+ g_debug("failed to query udev");
+ } else {
+ const char *devnode, *serial;
+ devnode = udev_device_get_devnode(udevice);
+ if (devnode != NULL) {
+ disk->dev = g_strdup(devnode);
+ }
+ serial = udev_device_get_property_value(udevice, "ID_SERIAL");
+ if (serial != NULL && *serial != 0) {
+ disk->serial = g_strdup(serial);
+ }
+ }
+
+ udev_unref(udev);
+ udev_device_unref(udevice);
+#endif
+
+ if (strstr(syspath, "/devices/pci")) {
+ has_hwinf = build_guest_fsinfo_for_pci_dev(syspath, disk, errp);
+ } else if (strstr(syspath, "/devices/css")) {
+ has_hwinf = build_guest_fsinfo_for_ccw_dev(syspath, disk, errp);
+ } else if (strstr(syspath, "/virtio")) {
+ has_hwinf = build_guest_fsinfo_for_nonpci_virtio(syspath, disk, errp);
+ } else {
+ g_debug("Unsupported device type for '%s'", syspath);
+ has_hwinf = false;
+ }
+
+ if (has_hwinf || disk->dev || disk->serial) {
+ QAPI_LIST_PREPEND(fs->disk, disk);
+ } else {
+ qapi_free_GuestDiskAddress(disk);
+ }
+}
+
+static void build_guest_fsinfo_for_device(char const *devpath,
+ GuestFilesystemInfo *fs,
+ Error **errp);
+
+/* Store a list of slave devices of virtual volume specified by @syspath into
+ * @fs */
+static void build_guest_fsinfo_for_virtual_device(char const *syspath,
+ GuestFilesystemInfo *fs,
+ Error **errp)
+{
+ Error *err = NULL;
+ DIR *dir;
+ char *dirpath;
+ struct dirent *entry;
+
+ dirpath = g_strdup_printf("%s/slaves", syspath);
+ dir = opendir(dirpath);
+ if (!dir) {
+ if (errno != ENOENT) {
+ error_setg_errno(errp, errno, "opendir(\"%s\")", dirpath);
+ }
+ g_free(dirpath);
+ return;
+ }
+
+ for (;;) {
+ errno = 0;
+ entry = readdir(dir);
+ if (entry == NULL) {
+ if (errno) {
+ error_setg_errno(errp, errno, "readdir(\"%s\")", dirpath);
+ }
+ break;
+ }
+
+ if (entry->d_type == DT_LNK) {
+ char *path;
+
+ g_debug(" slave device '%s'", entry->d_name);
+ path = g_strdup_printf("%s/slaves/%s", syspath, entry->d_name);
+ build_guest_fsinfo_for_device(path, fs, &err);
+ g_free(path);
+
+ if (err) {
+ error_propagate(errp, err);
+ break;
+ }
+ }
+ }
+
+ g_free(dirpath);
+ closedir(dir);
+}
+
+static bool is_disk_virtual(const char *devpath, Error **errp)
+{
+ g_autofree char *syspath = realpath(devpath, NULL);
+
+ if (!syspath) {
+ error_setg_errno(errp, errno, "realpath(\"%s\")", devpath);
+ return false;
+ }
+ return strstr(syspath, "/devices/virtual/block/") != NULL;
+}
+
+/* Dispatch to functions for virtual/real device */
+static void build_guest_fsinfo_for_device(char const *devpath,
+ GuestFilesystemInfo *fs,
+ Error **errp)
+{
+ ERRP_GUARD();
+ g_autofree char *syspath = NULL;
+ bool is_virtual = false;
+
+ syspath = realpath(devpath, NULL);
+ if (!syspath) {
+ if (errno != ENOENT) {
+ error_setg_errno(errp, errno, "realpath(\"%s\")", devpath);
+ return;
+ }
+
+ /* ENOENT: This devpath may not exist because of container config */
+ if (!fs->name) {
+ fs->name = g_path_get_basename(devpath);
+ }
+ return;
+ }
+
+ if (!fs->name) {
+ fs->name = g_path_get_basename(syspath);
+ }
+
+ g_debug(" parse sysfs path '%s'", syspath);
+ is_virtual = is_disk_virtual(syspath, errp);
+ if (*errp != NULL) {
+ return;
+ }
+ if (is_virtual) {
+ build_guest_fsinfo_for_virtual_device(syspath, fs, errp);
+ } else {
+ build_guest_fsinfo_for_real_device(syspath, fs, errp);
+ }
+}
+
+#ifdef CONFIG_LIBUDEV
+
+/*
+ * Wrapper around build_guest_fsinfo_for_device() for getting just
+ * the disk address.
+ */
+static GuestDiskAddress *get_disk_address(const char *syspath, Error **errp)
+{
+ g_autoptr(GuestFilesystemInfo) fs = NULL;
+
+ fs = g_new0(GuestFilesystemInfo, 1);
+ build_guest_fsinfo_for_device(syspath, fs, errp);
+ if (fs->disk != NULL) {
+ return g_steal_pointer(&fs->disk->value);
+ }
+ return NULL;
+}
+
+static char *get_alias_for_syspath(const char *syspath)
+{
+ struct udev *udev = NULL;
+ struct udev_device *udevice = NULL;
+ char *ret = NULL;
+
+ udev = udev_new();
+ if (udev == NULL) {
+ g_debug("failed to query udev");
+ goto out;
+ }
+ udevice = udev_device_new_from_syspath(udev, syspath);
+ if (udevice == NULL) {
+ g_debug("failed to query udev for path: %s", syspath);
+ goto out;
+ } else {
+ const char *alias = udev_device_get_property_value(
+ udevice, "DM_NAME");
+ /*
+ * NULL means there was an error and empty string means there is no
+ * alias. In case of no alias we return NULL instead of empty string.
+ */
+ if (alias == NULL) {
+ g_debug("failed to query udev for device alias for: %s",
+ syspath);
+ } else if (*alias != 0) {
+ ret = g_strdup(alias);
+ }
+ }
+
+out:
+ udev_unref(udev);
+ udev_device_unref(udevice);
+ return ret;
+}
+
+static char *get_device_for_syspath(const char *syspath)
+{
+ struct udev *udev = NULL;
+ struct udev_device *udevice = NULL;
+ char *ret = NULL;
+
+ udev = udev_new();
+ if (udev == NULL) {
+ g_debug("failed to query udev");
+ goto out;
+ }
+ udevice = udev_device_new_from_syspath(udev, syspath);
+ if (udevice == NULL) {
+ g_debug("failed to query udev for path: %s", syspath);
+ goto out;
+ } else {
+ ret = g_strdup(udev_device_get_devnode(udevice));
+ }
+
+out:
+ udev_unref(udev);
+ udev_device_unref(udevice);
+ return ret;
+}
+
+static void get_disk_deps(const char *disk_dir, GuestDiskInfo *disk)
+{
+ g_autofree char *deps_dir = NULL;
+ const gchar *dep;
+ GDir *dp_deps = NULL;
+
+ /* List dependent disks */
+ deps_dir = g_strdup_printf("%s/slaves", disk_dir);
+ g_debug(" listing entries in: %s", deps_dir);
+ dp_deps = g_dir_open(deps_dir, 0, NULL);
+ if (dp_deps == NULL) {
+ g_debug("failed to list entries in %s", deps_dir);
+ return;
+ }
+ disk->has_dependencies = true;
+ while ((dep = g_dir_read_name(dp_deps)) != NULL) {
+ g_autofree char *dep_dir = NULL;
+ char *dev_name;
+
+ /* Add dependent disks */
+ dep_dir = g_strdup_printf("%s/%s", deps_dir, dep);
+ dev_name = get_device_for_syspath(dep_dir);
+ if (dev_name != NULL) {
+ g_debug(" adding dependent device: %s", dev_name);
+ QAPI_LIST_PREPEND(disk->dependencies, dev_name);
+ }
+ }
+ g_dir_close(dp_deps);
+}
+
+/*
+ * Detect partitions subdirectory, name is "<disk_name><number>" or
+ * "<disk_name>p<number>"
+ *
+ * @disk_name -- last component of /sys path (e.g. sda)
+ * @disk_dir -- sys path of the disk (e.g. /sys/block/sda)
+ * @disk_dev -- device node of the disk (e.g. /dev/sda)
+ */
+static GuestDiskInfoList *get_disk_partitions(
+ GuestDiskInfoList *list,
+ const char *disk_name, const char *disk_dir,
+ const char *disk_dev)
+{
+ GuestDiskInfoList *ret = list;
+ struct dirent *de_disk;
+ DIR *dp_disk = NULL;
+ size_t len = strlen(disk_name);
+
+ dp_disk = opendir(disk_dir);
+ while ((de_disk = readdir(dp_disk)) != NULL) {
+ g_autofree char *partition_dir = NULL;
+ char *dev_name;
+ GuestDiskInfo *partition;
+
+ if (!(de_disk->d_type & DT_DIR)) {
+ continue;
+ }
+
+ if (!(strncmp(disk_name, de_disk->d_name, len) == 0 &&
+ ((*(de_disk->d_name + len) == 'p' &&
+ isdigit(*(de_disk->d_name + len + 1))) ||
+ isdigit(*(de_disk->d_name + len))))) {
+ continue;
+ }
+
+ partition_dir = g_strdup_printf("%s/%s",
+ disk_dir, de_disk->d_name);
+ dev_name = get_device_for_syspath(partition_dir);
+ if (dev_name == NULL) {
+ g_debug("Failed to get device name for syspath: %s",
+ disk_dir);
+ continue;
+ }
+ partition = g_new0(GuestDiskInfo, 1);
+ partition->name = dev_name;
+ partition->partition = true;
+ partition->has_dependencies = true;
+ /* Add parent disk as dependent for easier tracking of hierarchy */
+ QAPI_LIST_PREPEND(partition->dependencies, g_strdup(disk_dev));
+
+ QAPI_LIST_PREPEND(ret, partition);
+ }
+ closedir(dp_disk);
+
+ return ret;
+}
+
+static void get_nvme_smart(GuestDiskInfo *disk)
+{
+ int fd;
+ GuestNVMeSmart *smart;
+ NvmeSmartLog log = {0};
+ struct nvme_admin_cmd cmd = {
+ .opcode = NVME_ADM_CMD_GET_LOG_PAGE,
+ .nsid = NVME_NSID_BROADCAST,
+ .addr = (uintptr_t)&log,
+ .data_len = sizeof(log),
+ .cdw10 = NVME_LOG_SMART_INFO | (1 << 15) /* RAE bit */
+ | (((sizeof(log) >> 2) - 1) << 16)
+ };
+
+ fd = qga_open_cloexec(disk->name, O_RDONLY, 0);
+ if (fd == -1) {
+ g_debug("Failed to open device: %s: %s", disk->name, g_strerror(errno));
+ return;
+ }
+
+ if (ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd)) {
+ g_debug("Failed to get smart: %s: %s", disk->name, g_strerror(errno));
+ close(fd);
+ return;
+ }
+
+ disk->smart = g_new0(GuestDiskSmart, 1);
+ disk->smart->type = GUEST_DISK_BUS_TYPE_NVME;
+
+ smart = &disk->smart->u.nvme;
+ smart->critical_warning = log.critical_warning;
+ smart->temperature = lduw_le_p(&log.temperature); /* unaligned field */
+ smart->available_spare = log.available_spare;
+ smart->available_spare_threshold = log.available_spare_threshold;
+ smart->percentage_used = log.percentage_used;
+ smart->data_units_read_lo = le64_to_cpu(log.data_units_read[0]);
+ smart->data_units_read_hi = le64_to_cpu(log.data_units_read[1]);
+ smart->data_units_written_lo = le64_to_cpu(log.data_units_written[0]);
+ smart->data_units_written_hi = le64_to_cpu(log.data_units_written[1]);
+ smart->host_read_commands_lo = le64_to_cpu(log.host_read_commands[0]);
+ smart->host_read_commands_hi = le64_to_cpu(log.host_read_commands[1]);
+ smart->host_write_commands_lo = le64_to_cpu(log.host_write_commands[0]);
+ smart->host_write_commands_hi = le64_to_cpu(log.host_write_commands[1]);
+ smart->controller_busy_time_lo = le64_to_cpu(log.controller_busy_time[0]);
+ smart->controller_busy_time_hi = le64_to_cpu(log.controller_busy_time[1]);
+ smart->power_cycles_lo = le64_to_cpu(log.power_cycles[0]);
+ smart->power_cycles_hi = le64_to_cpu(log.power_cycles[1]);
+ smart->power_on_hours_lo = le64_to_cpu(log.power_on_hours[0]);
+ smart->power_on_hours_hi = le64_to_cpu(log.power_on_hours[1]);
+ smart->unsafe_shutdowns_lo = le64_to_cpu(log.unsafe_shutdowns[0]);
+ smart->unsafe_shutdowns_hi = le64_to_cpu(log.unsafe_shutdowns[1]);
+ smart->media_errors_lo = le64_to_cpu(log.media_errors[0]);
+ smart->media_errors_hi = le64_to_cpu(log.media_errors[1]);
+ smart->number_of_error_log_entries_lo =
+ le64_to_cpu(log.number_of_error_log_entries[0]);
+ smart->number_of_error_log_entries_hi =
+ le64_to_cpu(log.number_of_error_log_entries[1]);
+
+ close(fd);
+}
+
+static void get_disk_smart(GuestDiskInfo *disk)
+{
+ if (disk->address
+ && (disk->address->bus_type == GUEST_DISK_BUS_TYPE_NVME)) {
+ get_nvme_smart(disk);
+ }
+}
+
+GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
+{
+ GuestDiskInfoList *ret = NULL;
+ GuestDiskInfo *disk;
+ DIR *dp = NULL;
+ struct dirent *de = NULL;
+
+ g_debug("listing /sys/block directory");
+ dp = opendir("/sys/block");
+ if (dp == NULL) {
+ error_setg_errno(errp, errno, "Can't open directory \"/sys/block\"");
+ return NULL;
+ }
+ while ((de = readdir(dp)) != NULL) {
+ g_autofree char *disk_dir = NULL, *line = NULL,
+ *size_path = NULL;
+ char *dev_name;
+ Error *local_err = NULL;
+ if (de->d_type != DT_LNK) {
+ g_debug(" skipping entry: %s", de->d_name);
+ continue;
+ }
+
+ /* Check size and skip zero-sized disks */
+ g_debug(" checking disk size");
+ size_path = g_strdup_printf("/sys/block/%s/size", de->d_name);
+ if (!g_file_get_contents(size_path, &line, NULL, NULL)) {
+ g_debug(" failed to read disk size");
+ continue;
+ }
+ if (g_strcmp0(line, "0\n") == 0) {
+ g_debug(" skipping zero-sized disk");
+ continue;
+ }
+
+ g_debug(" adding %s", de->d_name);
+ disk_dir = g_strdup_printf("/sys/block/%s", de->d_name);
+ dev_name = get_device_for_syspath(disk_dir);
+ if (dev_name == NULL) {
+ g_debug("Failed to get device name for syspath: %s",
+ disk_dir);
+ continue;
+ }
+ disk = g_new0(GuestDiskInfo, 1);
+ disk->name = dev_name;
+ disk->partition = false;
+ disk->alias = get_alias_for_syspath(disk_dir);
+ QAPI_LIST_PREPEND(ret, disk);
+
+ /* Get address for non-virtual devices */
+ bool is_virtual = is_disk_virtual(disk_dir, &local_err);
+ if (local_err != NULL) {
+ g_debug(" failed to check disk path, ignoring error: %s",
+ error_get_pretty(local_err));
+ error_free(local_err);
+ local_err = NULL;
+ /* Don't try to get the address */
+ is_virtual = true;
+ }
+ if (!is_virtual) {
+ disk->address = get_disk_address(disk_dir, &local_err);
+ if (local_err != NULL) {
+ g_debug(" failed to get device info, ignoring error: %s",
+ error_get_pretty(local_err));
+ error_free(local_err);
+ local_err = NULL;
+ }
+ }
+
+ get_disk_deps(disk_dir, disk);
+ get_disk_smart(disk);
+ ret = get_disk_partitions(ret, de->d_name, disk_dir, dev_name);
+ }
+
+ closedir(dp);
+
+ return ret;
+}
+
+#endif
+
+/* Return a list of the disk device(s)' info which @mount lies on */
+static GuestFilesystemInfo *build_guest_fsinfo(struct FsMount *mount,
+ Error **errp)
+{
+ GuestFilesystemInfo *fs = g_malloc0(sizeof(*fs));
+ struct statvfs buf;
+ unsigned long used, nonroot_total, fr_size;
+ char *devpath = g_strdup_printf("/sys/dev/block/%u:%u",
+ mount->devmajor, mount->devminor);
+
+ fs->mountpoint = g_strdup(mount->dirname);
+ fs->type = g_strdup(mount->devtype);
+ build_guest_fsinfo_for_device(devpath, fs, errp);
+
+ if (statvfs(fs->mountpoint, &buf) == 0) {
+ fr_size = buf.f_frsize;
+ used = buf.f_blocks - buf.f_bfree;
+ nonroot_total = used + buf.f_bavail;
+ fs->used_bytes = used * fr_size;
+ fs->total_bytes = nonroot_total * fr_size;
+ fs->total_bytes_privileged = buf.f_blocks * fr_size;
+
+ fs->has_total_bytes = true;
+ fs->has_total_bytes_privileged = true;
+ fs->has_used_bytes = true;
+ }
+
+ g_free(devpath);
+
+ return fs;
+}
+
+GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
+{
+ FsMountList mounts;
+ struct FsMount *mount;
+ GuestFilesystemInfoList *ret = NULL;
+ Error *local_err = NULL;
+
+ QTAILQ_INIT(&mounts);
+ if (!build_fs_mount_list(&mounts, &local_err)) {
+ error_propagate(errp, local_err);
+ return NULL;
+ }
+
+ QTAILQ_FOREACH(mount, &mounts, next) {
+ g_debug("Building guest fsinfo for '%s'", mount->dirname);
+
+ QAPI_LIST_PREPEND(ret, build_guest_fsinfo(mount, &local_err));
+ if (local_err) {
+ error_propagate(errp, local_err);
+ qapi_free_GuestFilesystemInfoList(ret);
+ ret = NULL;
+ break;
+ }
+ }
+
+ free_fs_mount_list(&mounts);
+ return ret;
+}
+#endif /* CONFIG_FSFREEZE */
+
+#if defined(CONFIG_FSTRIM)
+/*
+ * Walk list of mounted file systems in the guest, and trim them.
+ */
+GuestFilesystemTrimResponse *
+qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
+{
+ GuestFilesystemTrimResponse *response;
+ GuestFilesystemTrimResult *result;
+ int ret = 0;
+ FsMountList mounts;
+ struct FsMount *mount;
+ int fd;
+ struct fstrim_range r;
+
+ slog("guest-fstrim called");
+
+ QTAILQ_INIT(&mounts);
+ if (!build_fs_mount_list(&mounts, errp)) {
+ return NULL;
+ }
+
+ response = g_malloc0(sizeof(*response));
+
+ QTAILQ_FOREACH(mount, &mounts, next) {
+ result = g_malloc0(sizeof(*result));
+ result->path = g_strdup(mount->dirname);
+
+ QAPI_LIST_PREPEND(response->paths, result);
+
+ fd = qga_open_cloexec(mount->dirname, O_RDONLY, 0);
+ if (fd == -1) {
+ result->error = g_strdup_printf("failed to open: %s",
+ strerror(errno));
+ continue;
+ }
+
+ /* We try to cull filesystems we know won't work in advance, but other
+ * filesystems may not implement fstrim for less obvious reasons.
+ * These will report EOPNOTSUPP; while in some other cases ENOTTY
+ * will be reported (e.g. CD-ROMs).
+ * Any other error means an unexpected error.
+ */
+ r.start = 0;
+ r.len = -1;
+ r.minlen = has_minimum ? minimum : 0;
+ ret = ioctl(fd, FITRIM, &r);
+ if (ret == -1) {
+ if (errno == ENOTTY || errno == EOPNOTSUPP) {
+ result->error = g_strdup("trim not supported");
+ } else {
+ result->error = g_strdup_printf("failed to trim: %s",
+ strerror(errno));
+ }
+ close(fd);
+ continue;
+ }
+
+ result->has_minimum = true;
+ result->minimum = r.minlen;
+ result->has_trimmed = true;
+ result->trimmed = r.len;
+ close(fd);
+ }
+
+ free_fs_mount_list(&mounts);
+ return response;
+}
+#endif /* CONFIG_FSTRIM */
+
+#define LINUX_SYS_STATE_FILE "/sys/power/state"
+#define SUSPEND_SUPPORTED 0
+#define SUSPEND_NOT_SUPPORTED 1
+
+typedef enum {
+ SUSPEND_MODE_DISK = 0,
+ SUSPEND_MODE_RAM = 1,
+ SUSPEND_MODE_HYBRID = 2,
+} SuspendMode;
+
+/*
+ * Executes a command in a child process using g_spawn_sync,
+ * returning an int >= 0 representing the exit status of the
+ * process.
+ *
+ * If the program wasn't found in path, returns -1.
+ *
+ * If a problem happened when creating the child process,
+ * returns -1 and errp is set.
+ */
+static int run_process_child(const char *command[], Error **errp)
+{
+ int exit_status, spawn_flag;
+ GError *g_err = NULL;
+ bool success;
+
+ spawn_flag = G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL |
+ G_SPAWN_STDERR_TO_DEV_NULL;
+
+ success = g_spawn_sync(NULL, (char **)command, NULL, spawn_flag,
+ NULL, NULL, NULL, NULL,
+ &exit_status, &g_err);
+
+ if (success) {
+ return WEXITSTATUS(exit_status);
+ }
+
+ if (g_err && (g_err->code != G_SPAWN_ERROR_NOENT)) {
+ error_setg(errp, "failed to create child process, error '%s'",
+ g_err->message);
+ }
+
+ g_error_free(g_err);
+ return -1;
+}
+
+static bool systemd_supports_mode(SuspendMode mode, Error **errp)
+{
+ const char *systemctl_args[3] = {"systemd-hibernate", "systemd-suspend",
+ "systemd-hybrid-sleep"};
+ const char *cmd[4] = {"systemctl", "status", systemctl_args[mode], NULL};
+ int status;
+
+ status = run_process_child(cmd, errp);
+
+ /*
+ * systemctl status uses LSB return codes so we can expect
+ * status > 0 and be ok. To assert if the guest has support
+ * for the selected suspend mode, status should be < 4. 4 is
+ * the code for unknown service status, the return value when
+ * the service does not exist. A common value is status = 3
+ * (program is not running).
+ */
+ if (status > 0 && status < 4) {
+ return true;
+ }
+
+ return false;
+}
+
+static void systemd_suspend(SuspendMode mode, Error **errp)
+{
+ Error *local_err = NULL;
+ const char *systemctl_args[3] = {"hibernate", "suspend", "hybrid-sleep"};
+ const char *cmd[3] = {"systemctl", systemctl_args[mode], NULL};
+ int status;
+
+ status = run_process_child(cmd, &local_err);
+
+ if (status == 0) {
+ return;
+ }
+
+ if ((status == -1) && !local_err) {
+ error_setg(errp, "the helper program 'systemctl %s' was not found",
+ systemctl_args[mode]);
+ return;
+ }
+
+ if (local_err) {
+ error_propagate(errp, local_err);
+ } else {
+ error_setg(errp, "the helper program 'systemctl %s' returned an "
+ "unexpected exit status code (%d)",
+ systemctl_args[mode], status);
+ }
+}
+
+static bool pmutils_supports_mode(SuspendMode mode, Error **errp)
+{
+ Error *local_err = NULL;
+ const char *pmutils_args[3] = {"--hibernate", "--suspend",
+ "--suspend-hybrid"};
+ const char *cmd[3] = {"pm-is-supported", pmutils_args[mode], NULL};
+ int status;
+
+ status = run_process_child(cmd, &local_err);
+
+ if (status == SUSPEND_SUPPORTED) {
+ return true;
+ }
+
+ if ((status == -1) && !local_err) {
+ return false;
+ }
+
+ if (local_err) {
+ error_propagate(errp, local_err);
+ } else {
+ error_setg(errp,
+ "the helper program '%s' returned an unexpected exit"
+ " status code (%d)", "pm-is-supported", status);
+ }
+
+ return false;
+}
+
+static void pmutils_suspend(SuspendMode mode, Error **errp)
+{
+ Error *local_err = NULL;
+ const char *pmutils_binaries[3] = {"pm-hibernate", "pm-suspend",
+ "pm-suspend-hybrid"};
+ const char *cmd[2] = {pmutils_binaries[mode], NULL};
+ int status;
+
+ status = run_process_child(cmd, &local_err);
+
+ if (status == 0) {
+ return;
+ }
+
+ if ((status == -1) && !local_err) {
+ error_setg(errp, "the helper program '%s' was not found",
+ pmutils_binaries[mode]);
+ return;
+ }
+
+ if (local_err) {
+ error_propagate(errp, local_err);
+ } else {
+ error_setg(errp,
+ "the helper program '%s' returned an unexpected exit"
+ " status code (%d)", pmutils_binaries[mode], status);
+ }
+}
+
+static bool linux_sys_state_supports_mode(SuspendMode mode, Error **errp)
+{
+ const char *sysfile_strs[3] = {"disk", "mem", NULL};
+ const char *sysfile_str = sysfile_strs[mode];
+ char buf[32]; /* hopefully big enough */
+ int fd;
+ ssize_t ret;
+
+ if (!sysfile_str) {
+ error_setg(errp, "unknown guest suspend mode");
+ return false;
+ }
+
+ fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
+ if (fd < 0) {
+ return false;
+ }
+
+ ret = read(fd, buf, sizeof(buf) - 1);
+ close(fd);
+ if (ret <= 0) {
+ return false;
+ }
+ buf[ret] = '\0';
+
+ if (strstr(buf, sysfile_str)) {
+ return true;
+ }
+ return false;
+}
+
+static void linux_sys_state_suspend(SuspendMode mode, Error **errp)
+{
+ g_autoptr(GError) local_gerr = NULL;
+ const char *sysfile_strs[3] = {"disk", "mem", NULL};
+ const char *sysfile_str = sysfile_strs[mode];
+
+ if (!sysfile_str) {
+ error_setg(errp, "unknown guest suspend mode");
+ return;
+ }
+
+ if (!g_file_set_contents(LINUX_SYS_STATE_FILE, sysfile_str,
+ -1, &local_gerr)) {
+ error_setg(errp, "suspend: cannot write to '%s': %s",
+ LINUX_SYS_STATE_FILE, local_gerr->message);
+ return;
+ }
+}
+
+static void guest_suspend(SuspendMode mode, Error **errp)
+{
+ Error *local_err = NULL;
+ bool mode_supported = false;
+
+ if (systemd_supports_mode(mode, &local_err)) {
+ mode_supported = true;
+ systemd_suspend(mode, &local_err);
+
+ if (!local_err) {
+ return;
+ }
+ }
+
+ error_free(local_err);
+ local_err = NULL;
+
+ if (pmutils_supports_mode(mode, &local_err)) {
+ mode_supported = true;
+ pmutils_suspend(mode, &local_err);
+
+ if (!local_err) {
+ return;
+ }
+ }
+
+ error_free(local_err);
+ local_err = NULL;
+
+ if (linux_sys_state_supports_mode(mode, &local_err)) {
+ mode_supported = true;
+ linux_sys_state_suspend(mode, &local_err);
+ }
+
+ if (!mode_supported) {
+ error_free(local_err);
+ error_setg(errp,
+ "the requested suspend mode is not supported by the guest");
+ } else {
+ error_propagate(errp, local_err);
+ }
+}
+
+void qmp_guest_suspend_disk(Error **errp)
+{
+ guest_suspend(SUSPEND_MODE_DISK, errp);
+}
+
+void qmp_guest_suspend_ram(Error **errp)
+{
+ guest_suspend(SUSPEND_MODE_RAM, errp);
+}
+
+void qmp_guest_suspend_hybrid(Error **errp)
+{
+ guest_suspend(SUSPEND_MODE_HYBRID, errp);
+}
+
+/* Transfer online/offline status between @vcpu and the guest system.
+ *
+ * On input either @errp or *@errp must be NULL.
+ *
+ * In system-to-@vcpu direction, the following @vcpu fields are accessed:
+ * - R: vcpu->logical_id
+ * - W: vcpu->online
+ * - W: vcpu->can_offline
+ *
+ * In @vcpu-to-system direction, the following @vcpu fields are accessed:
+ * - R: vcpu->logical_id
+ * - R: vcpu->online
+ *
+ * Written members remain unmodified on error.
+ */
+static void transfer_vcpu(GuestLogicalProcessor *vcpu, bool sys2vcpu,
+ char *dirpath, Error **errp)
+{
+ int fd;
+ int res;
+ int dirfd;
+ static const char fn[] = "online";
+
+ dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
+ if (dirfd == -1) {
+ error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
+ return;
+ }
+
+ fd = openat(dirfd, fn, sys2vcpu ? O_RDONLY : O_RDWR);
+ if (fd == -1) {
+ if (errno != ENOENT) {
+ error_setg_errno(errp, errno, "open(\"%s/%s\")", dirpath, fn);
+ } else if (sys2vcpu) {
+ vcpu->online = true;
+ vcpu->can_offline = false;
+ } else if (!vcpu->online) {
+ error_setg(errp, "logical processor #%" PRId64 " can't be "
+ "offlined", vcpu->logical_id);
+ } /* otherwise pretend successful re-onlining */
+ } else {
+ unsigned char status;
+
+ res = pread(fd, &status, 1, 0);
+ if (res == -1) {
+ error_setg_errno(errp, errno, "pread(\"%s/%s\")", dirpath, fn);
+ } else if (res == 0) {
+ error_setg(errp, "pread(\"%s/%s\"): unexpected EOF", dirpath,
+ fn);
+ } else if (sys2vcpu) {
+ vcpu->online = (status != '0');
+ vcpu->can_offline = true;
+ } else if (vcpu->online != (status != '0')) {
+ status = '0' + vcpu->online;
+ if (pwrite(fd, &status, 1, 0) == -1) {
+ error_setg_errno(errp, errno, "pwrite(\"%s/%s\")", dirpath,
+ fn);
+ }
+ } /* otherwise pretend successful re-(on|off)-lining */
+
+ res = close(fd);
+ g_assert(res == 0);
+ }
+
+ res = close(dirfd);
+ g_assert(res == 0);
+}
+
+GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
+{
+ GuestLogicalProcessorList *head, **tail;
+ const char *cpu_dir = "/sys/devices/system/cpu";
+ const gchar *line;
+ g_autoptr(GDir) cpu_gdir = NULL;
+ Error *local_err = NULL;
+
+ head = NULL;
+ tail = &head;
+ cpu_gdir = g_dir_open(cpu_dir, 0, NULL);
+
+ if (cpu_gdir == NULL) {
+ error_setg_errno(errp, errno, "failed to list entries: %s", cpu_dir);
+ return NULL;
+ }
+
+ while (local_err == NULL && (line = g_dir_read_name(cpu_gdir)) != NULL) {
+ GuestLogicalProcessor *vcpu;
+ int64_t id;
+ if (sscanf(line, "cpu%" PRId64, &id)) {
+ g_autofree char *path = g_strdup_printf("/sys/devices/system/cpu/"
+ "cpu%" PRId64 "/", id);
+ vcpu = g_malloc0(sizeof *vcpu);
+ vcpu->logical_id = id;
+ vcpu->has_can_offline = true; /* lolspeak ftw */
+ transfer_vcpu(vcpu, true, path, &local_err);
+ QAPI_LIST_APPEND(tail, vcpu);
+ }
+ }
+
+ if (local_err == NULL) {
+ /* there's no guest with zero VCPUs */
+ g_assert(head != NULL);
+ return head;
+ }
+
+ qapi_free_GuestLogicalProcessorList(head);
+ error_propagate(errp, local_err);
+ return NULL;
+}
+
+int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
+{
+ int64_t processed;
+ Error *local_err = NULL;
+
+ processed = 0;
+ while (vcpus != NULL) {
+ char *path = g_strdup_printf("/sys/devices/system/cpu/cpu%" PRId64 "/",
+ vcpus->value->logical_id);
+
+ transfer_vcpu(vcpus->value, false, path, &local_err);
+ g_free(path);
+ if (local_err != NULL) {
+ break;
+ }
+ ++processed;
+ vcpus = vcpus->next;
+ }
+
+ if (local_err != NULL) {
+ if (processed == 0) {
+ error_propagate(errp, local_err);
+ } else {
+ error_free(local_err);
+ }
+ }
+
+ return processed;
+}
+
+
+static void ga_read_sysfs_file(int dirfd, const char *pathname, char *buf,
+ int size, Error **errp)
+{
+ int fd;
+ int res;
+
+ errno = 0;
+ fd = openat(dirfd, pathname, O_RDONLY);
+ if (fd == -1) {
+ error_setg_errno(errp, errno, "open sysfs file \"%s\"", pathname);
+ return;
+ }
+
+ res = pread(fd, buf, size, 0);
+ if (res == -1) {
+ error_setg_errno(errp, errno, "pread sysfs file \"%s\"", pathname);
+ } else if (res == 0) {
+ error_setg(errp, "pread sysfs file \"%s\": unexpected EOF", pathname);
+ }
+ close(fd);
+}
+
+static void ga_write_sysfs_file(int dirfd, const char *pathname,
+ const char *buf, int size, Error **errp)
+{
+ int fd;
+
+ errno = 0;
+ fd = openat(dirfd, pathname, O_WRONLY);
+ if (fd == -1) {
+ error_setg_errno(errp, errno, "open sysfs file \"%s\"", pathname);
+ return;
+ }
+
+ if (pwrite(fd, buf, size, 0) == -1) {
+ error_setg_errno(errp, errno, "pwrite sysfs file \"%s\"", pathname);
+ }
+
+ close(fd);
+}
+
+/* Transfer online/offline status between @mem_blk and the guest system.
+ *
+ * On input either @errp or *@errp must be NULL.
+ *
+ * In system-to-@mem_blk direction, the following @mem_blk fields are accessed:
+ * - R: mem_blk->phys_index
+ * - W: mem_blk->online
+ * - W: mem_blk->can_offline
+ *
+ * In @mem_blk-to-system direction, the following @mem_blk fields are accessed:
+ * - R: mem_blk->phys_index
+ * - R: mem_blk->online
+ *- R: mem_blk->can_offline
+ * Written members remain unmodified on error.
+ */
+static void transfer_memory_block(GuestMemoryBlock *mem_blk, bool sys2memblk,
+ GuestMemoryBlockResponse *result,
+ Error **errp)
+{
+ char *dirpath;
+ int dirfd;
+ char *status;
+ Error *local_err = NULL;
+
+ if (!sys2memblk) {
+ DIR *dp;
+
+ if (!result) {
+ error_setg(errp, "Internal error, 'result' should not be NULL");
+ return;
+ }
+ errno = 0;
+ dp = opendir("/sys/devices/system/memory/");
+ /* if there is no 'memory' directory in sysfs,
+ * we think this VM does not support online/offline memory block,
+ * any other solution?
+ */
+ if (!dp) {
+ if (errno == ENOENT) {
+ result->response =
+ GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_NOT_SUPPORTED;
+ }
+ goto out1;
+ }
+ closedir(dp);
+ }
+
+ dirpath = g_strdup_printf("/sys/devices/system/memory/memory%" PRId64 "/",
+ mem_blk->phys_index);
+ dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
+ if (dirfd == -1) {
+ if (sys2memblk) {
+ error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
+ } else {
+ if (errno == ENOENT) {
+ result->response = GUEST_MEMORY_BLOCK_RESPONSE_TYPE_NOT_FOUND;
+ } else {
+ result->response =
+ GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
+ }
+ }
+ g_free(dirpath);
+ goto out1;
+ }
+ g_free(dirpath);
+
+ status = g_malloc0(10);
+ ga_read_sysfs_file(dirfd, "state", status, 10, &local_err);
+ if (local_err) {
+ /* treat with sysfs file that not exist in old kernel */
+ if (errno == ENOENT) {
+ error_free(local_err);
+ if (sys2memblk) {
+ mem_blk->online = true;
+ mem_blk->can_offline = false;
+ } else if (!mem_blk->online) {
+ result->response =
+ GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_NOT_SUPPORTED;
+ }
+ } else {
+ if (sys2memblk) {
+ error_propagate(errp, local_err);
+ } else {
+ error_free(local_err);
+ result->response =
+ GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
+ }
+ }
+ goto out2;
+ }
+
+ if (sys2memblk) {
+ char removable = '0';
+
+ mem_blk->online = (strncmp(status, "online", 6) == 0);
+
+ ga_read_sysfs_file(dirfd, "removable", &removable, 1, &local_err);
+ if (local_err) {
+ /* if no 'removable' file, it doesn't support offline mem blk */
+ if (errno == ENOENT) {
+ error_free(local_err);
+ mem_blk->can_offline = false;
+ } else {
+ error_propagate(errp, local_err);
+ }
+ } else {
+ mem_blk->can_offline = (removable != '0');
+ }
+ } else {
+ if (mem_blk->online != (strncmp(status, "online", 6) == 0)) {
+ const char *new_state = mem_blk->online ? "online" : "offline";
+
+ ga_write_sysfs_file(dirfd, "state", new_state, strlen(new_state),
+ &local_err);
+ if (local_err) {
+ error_free(local_err);
+ result->response =
+ GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
+ goto out2;
+ }
+
+ result->response = GUEST_MEMORY_BLOCK_RESPONSE_TYPE_SUCCESS;
+ result->has_error_code = false;
+ } /* otherwise pretend successful re-(on|off)-lining */
+ }
+ g_free(status);
+ close(dirfd);
+ return;
+
+out2:
+ g_free(status);
+ close(dirfd);
+out1:
+ if (!sys2memblk) {
+ result->has_error_code = true;
+ result->error_code = errno;
+ }
+}
+
+GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
+{
+ GuestMemoryBlockList *head, **tail;
+ Error *local_err = NULL;
+ struct dirent *de;
+ DIR *dp;
+
+ head = NULL;
+ tail = &head;
+
+ dp = opendir("/sys/devices/system/memory/");
+ if (!dp) {
+ /* it's ok if this happens to be a system that doesn't expose
+ * memory blocks via sysfs, but otherwise we should report
+ * an error
+ */
+ if (errno != ENOENT) {
+ error_setg_errno(errp, errno, "Can't open directory"
+ "\"/sys/devices/system/memory/\"");
+ }
+ return NULL;
+ }
+
+ /* Note: the phys_index of memory block may be discontinuous,
+ * this is because a memblk is the unit of the Sparse Memory design, which
+ * allows discontinuous memory ranges (ex. NUMA), so here we should
+ * traverse the memory block directory.
+ */
+ while ((de = readdir(dp)) != NULL) {
+ GuestMemoryBlock *mem_blk;
+
+ if ((strncmp(de->d_name, "memory", 6) != 0) ||
+ !(de->d_type & DT_DIR)) {
+ continue;
+ }
+
+ mem_blk = g_malloc0(sizeof *mem_blk);
+ /* The d_name is "memoryXXX", phys_index is block id, same as XXX */
+ mem_blk->phys_index = strtoul(&de->d_name[6], NULL, 10);
+ mem_blk->has_can_offline = true; /* lolspeak ftw */
+ transfer_memory_block(mem_blk, true, NULL, &local_err);
+ if (local_err) {
+ break;
+ }
+
+ QAPI_LIST_APPEND(tail, mem_blk);
+ }
+
+ closedir(dp);
+ if (local_err == NULL) {
+ /* there's no guest with zero memory blocks */
+ if (head == NULL) {
+ error_setg(errp, "guest reported zero memory blocks!");
+ }
+ return head;
+ }
+
+ qapi_free_GuestMemoryBlockList(head);
+ error_propagate(errp, local_err);
+ return NULL;
+}
+
+GuestMemoryBlockResponseList *
+qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp)
+{
+ GuestMemoryBlockResponseList *head, **tail;
+ Error *local_err = NULL;
+
+ head = NULL;
+ tail = &head;
+
+ while (mem_blks != NULL) {
+ GuestMemoryBlockResponse *result;
+ GuestMemoryBlock *current_mem_blk = mem_blks->value;
+
+ result = g_malloc0(sizeof(*result));
+ result->phys_index = current_mem_blk->phys_index;
+ transfer_memory_block(current_mem_blk, false, result, &local_err);
+ if (local_err) { /* should never happen */
+ goto err;
+ }
+
+ QAPI_LIST_APPEND(tail, result);
+ mem_blks = mem_blks->next;
+ }
+
+ return head;
+err:
+ qapi_free_GuestMemoryBlockResponseList(head);
+ error_propagate(errp, local_err);
+ return NULL;
+}
+
+GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
+{
+ Error *local_err = NULL;
+ char *dirpath;
+ int dirfd;
+ char *buf;
+ GuestMemoryBlockInfo *info;
+
+ dirpath = g_strdup_printf("/sys/devices/system/memory/");
+ dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
+ if (dirfd == -1) {
+ error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
+ g_free(dirpath);
+ return NULL;
+ }
+ g_free(dirpath);
+
+ buf = g_malloc0(20);
+ ga_read_sysfs_file(dirfd, "block_size_bytes", buf, 20, &local_err);
+ close(dirfd);
+ if (local_err) {
+ g_free(buf);
+ error_propagate(errp, local_err);
+ return NULL;
+ }
+
+ info = g_new0(GuestMemoryBlockInfo, 1);
+ info->size = strtol(buf, NULL, 16); /* the unit is bytes */
+
+ g_free(buf);
+
+ return info;
+}
+
+#define MAX_NAME_LEN 128
+static GuestDiskStatsInfoList *guest_get_diskstats(Error **errp)
+{
+ GuestDiskStatsInfoList *head = NULL, **tail = &head;
+ const char *diskstats = "/proc/diskstats";
+ FILE *fp;
+ size_t n;
+ char *line = NULL;
+
+ fp = fopen(diskstats, "r");
+ if (fp == NULL) {
+ error_setg_errno(errp, errno, "open(\"%s\")", diskstats);
+ return NULL;
+ }
+
+ while (getline(&line, &n, fp) != -1) {
+ g_autofree GuestDiskStatsInfo *diskstatinfo = NULL;
+ g_autofree GuestDiskStats *diskstat = NULL;
+ char dev_name[MAX_NAME_LEN];
+ unsigned int ios_pgr, tot_ticks, rq_ticks, wr_ticks, dc_ticks, fl_ticks;
+ unsigned long rd_ios, rd_merges_or_rd_sec, rd_ticks_or_wr_sec, wr_ios;
+ unsigned long wr_merges, rd_sec_or_wr_ios, wr_sec;
+ unsigned long dc_ios, dc_merges, dc_sec, fl_ios;
+ unsigned int major, minor;
+ int i;
+
+ i = sscanf(line, "%u %u %s %lu %lu %lu"
+ "%lu %lu %lu %lu %u %u %u %u"
+ "%lu %lu %lu %u %lu %u",
+ &major, &minor, dev_name,
+ &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios,
+ &rd_ticks_or_wr_sec, &wr_ios, &wr_merges, &wr_sec,
+ &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks,
+ &dc_ios, &dc_merges, &dc_sec, &dc_ticks,
+ &fl_ios, &fl_ticks);
+
+ if (i < 7) {
+ continue;
+ }
+
+ diskstatinfo = g_new0(GuestDiskStatsInfo, 1);
+ diskstatinfo->name = g_strdup(dev_name);
+ diskstatinfo->major = major;
+ diskstatinfo->minor = minor;
+
+ diskstat = g_new0(GuestDiskStats, 1);
+ if (i == 7) {
+ diskstat->has_read_ios = true;
+ diskstat->read_ios = rd_ios;
+ diskstat->has_read_sectors = true;
+ diskstat->read_sectors = rd_merges_or_rd_sec;
+ diskstat->has_write_ios = true;
+ diskstat->write_ios = rd_sec_or_wr_ios;
+ diskstat->has_write_sectors = true;
+ diskstat->write_sectors = rd_ticks_or_wr_sec;
+ }
+ if (i >= 14) {
+ diskstat->has_read_ios = true;
+ diskstat->read_ios = rd_ios;
+ diskstat->has_read_sectors = true;
+ diskstat->read_sectors = rd_sec_or_wr_ios;
+ diskstat->has_read_merges = true;
+ diskstat->read_merges = rd_merges_or_rd_sec;
+ diskstat->has_read_ticks = true;
+ diskstat->read_ticks = rd_ticks_or_wr_sec;
+ diskstat->has_write_ios = true;
+ diskstat->write_ios = wr_ios;
+ diskstat->has_write_sectors = true;
+ diskstat->write_sectors = wr_sec;
+ diskstat->has_write_merges = true;
+ diskstat->write_merges = wr_merges;
+ diskstat->has_write_ticks = true;
+ diskstat->write_ticks = wr_ticks;
+ diskstat->has_ios_pgr = true;
+ diskstat->ios_pgr = ios_pgr;
+ diskstat->has_total_ticks = true;
+ diskstat->total_ticks = tot_ticks;
+ diskstat->has_weight_ticks = true;
+ diskstat->weight_ticks = rq_ticks;
+ }
+ if (i >= 18) {
+ diskstat->has_discard_ios = true;
+ diskstat->discard_ios = dc_ios;
+ diskstat->has_discard_merges = true;
+ diskstat->discard_merges = dc_merges;
+ diskstat->has_discard_sectors = true;
+ diskstat->discard_sectors = dc_sec;
+ diskstat->has_discard_ticks = true;
+ diskstat->discard_ticks = dc_ticks;
+ }
+ if (i >= 20) {
+ diskstat->has_flush_ios = true;
+ diskstat->flush_ios = fl_ios;
+ diskstat->has_flush_ticks = true;
+ diskstat->flush_ticks = fl_ticks;
+ }
+
+ diskstatinfo->stats = g_steal_pointer(&diskstat);
+ QAPI_LIST_APPEND(tail, diskstatinfo);
+ diskstatinfo = NULL;
+ }
+ free(line);
+ fclose(fp);
+ return head;
+}
+
+GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp)
+{
+ return guest_get_diskstats(errp);
+}
+
+GuestCpuStatsList *qmp_guest_get_cpustats(Error **errp)
+{
+ GuestCpuStatsList *head = NULL, **tail = &head;
+ const char *cpustats = "/proc/stat";
+ int clk_tck = sysconf(_SC_CLK_TCK);
+ FILE *fp;
+ size_t n;
+ char *line = NULL;
+
+ fp = fopen(cpustats, "r");
+ if (fp == NULL) {
+ error_setg_errno(errp, errno, "open(\"%s\")", cpustats);
+ return NULL;
+ }
+
+ while (getline(&line, &n, fp) != -1) {
+ GuestCpuStats *cpustat = NULL;
+ GuestLinuxCpuStats *linuxcpustat;
+ int i;
+ unsigned long user, system, idle, iowait, irq, softirq, steal, guest;
+ unsigned long nice, guest_nice;
+ char name[64];
+
+ i = sscanf(line, "%s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
+ name, &user, &nice, &system, &idle, &iowait, &irq, &softirq,
+ &steal, &guest, &guest_nice);
+
+ /* drop "cpu 1 2 3 ...", get "cpuX 1 2 3 ..." only */
+ if ((i == EOF) || strncmp(name, "cpu", 3) || (name[3] == '\0')) {
+ continue;
+ }
+
+ if (i < 5) {
+ slog("Parsing cpu stat from %s failed, see \"man proc\"", cpustats);
+ break;
+ }
+
+ cpustat = g_new0(GuestCpuStats, 1);
+ cpustat->type = GUEST_CPU_STATS_TYPE_LINUX;
+
+ linuxcpustat = &cpustat->u.q_linux;
+ linuxcpustat->cpu = atoi(&name[3]);
+ linuxcpustat->user = user * 1000 / clk_tck;
+ linuxcpustat->nice = nice * 1000 / clk_tck;
+ linuxcpustat->system = system * 1000 / clk_tck;
+ linuxcpustat->idle = idle * 1000 / clk_tck;
+
+ if (i > 5) {
+ linuxcpustat->has_iowait = true;
+ linuxcpustat->iowait = iowait * 1000 / clk_tck;
+ }
+
+ if (i > 6) {
+ linuxcpustat->has_irq = true;
+ linuxcpustat->irq = irq * 1000 / clk_tck;
+ linuxcpustat->has_softirq = true;
+ linuxcpustat->softirq = softirq * 1000 / clk_tck;
+ }
+
+ if (i > 8) {
+ linuxcpustat->has_steal = true;
+ linuxcpustat->steal = steal * 1000 / clk_tck;
+ }
+
+ if (i > 9) {
+ linuxcpustat->has_guest = true;
+ linuxcpustat->guest = guest * 1000 / clk_tck;
+ }
+
+ if (i > 10) {
+ linuxcpustat->has_guest = true;
+ linuxcpustat->guest = guest * 1000 / clk_tck;
+ linuxcpustat->has_guestnice = true;
+ linuxcpustat->guestnice = guest_nice * 1000 / clk_tck;
+ }
+
+ QAPI_LIST_APPEND(tail, cpustat);
+ }
+
+ free(line);
+ fclose(fp);
+ return head;
+}
+
+static char *hexToIPAddress(const void *hexValue, int is_ipv6)
+{
+ if (is_ipv6) {
+ char addr[INET6_ADDRSTRLEN];
+ struct in6_addr in6;
+ const char *hexStr = (const char *)hexValue;
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ sscanf(&hexStr[i * 2], "%02hhx", &in6.s6_addr[i]);
+ }
+ inet_ntop(AF_INET6, &in6, addr, INET6_ADDRSTRLEN);
+
+ return g_strdup(addr);
+ } else {
+ unsigned int hexInt = *(unsigned int *)hexValue;
+ unsigned int byte1 = (hexInt >> 24) & 0xFF;
+ unsigned int byte2 = (hexInt >> 16) & 0xFF;
+ unsigned int byte3 = (hexInt >> 8) & 0xFF;
+ unsigned int byte4 = hexInt & 0xFF;
+
+ return g_strdup_printf("%u.%u.%u.%u", byte4, byte3, byte2, byte1);
+ }
+}
+
+GuestNetworkRouteList *qmp_guest_network_get_route(Error **errp)
+{
+ GuestNetworkRouteList *head = NULL, **tail = &head;
+ const char *routeFiles[] = {"/proc/net/route", "/proc/net/ipv6_route"};
+ FILE *fp;
+ size_t n;
+ char *line = NULL;
+ int firstLine;
+ int is_ipv6;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ firstLine = 1;
+ is_ipv6 = (i == 1);
+ fp = fopen(routeFiles[i], "r");
+ if (fp == NULL) {
+ error_setg_errno(errp, errno, "open(\"%s\")", routeFiles[i]);
+ free(line);
+ continue;
+ }
+
+ while (getline(&line, &n, fp) != -1) {
+ if (firstLine && !is_ipv6) {
+ firstLine = 0;
+ continue;
+ }
+ GuestNetworkRoute *route = NULL;
+ GuestNetworkRoute *networkroute;
+ char Iface[IFNAMSIZ];
+ if (is_ipv6) {
+ char Destination[33], Source[33], NextHop[33];
+ int DesPrefixlen, SrcPrefixlen, Metric, RefCnt, Use, Flags;
+
+ /* Parse the line and extract the values */
+ if (sscanf(line, "%32s %x %32s %x %32s %x %x %x %x %s",
+ Destination, &DesPrefixlen, Source,
+ &SrcPrefixlen, NextHop, &Metric, &RefCnt,
+ &Use, &Flags, Iface) != 10) {
+ continue;
+ }
+
+ route = g_new0(GuestNetworkRoute, 1);
+ networkroute = route;
+ networkroute->iface = g_strdup(Iface);
+ networkroute->destination = hexToIPAddress(Destination, 1);
+ networkroute->metric = Metric;
+ networkroute->source = hexToIPAddress(Source, 1);
+ networkroute->desprefixlen = g_strdup_printf(
+ "%d", DesPrefixlen
+ );
+ networkroute->srcprefixlen = g_strdup_printf(
+ "%d", SrcPrefixlen
+ );
+ networkroute->nexthop = hexToIPAddress(NextHop, 1);
+ networkroute->has_flags = true;
+ networkroute->flags = Flags;
+ networkroute->has_refcnt = true;
+ networkroute->refcnt = RefCnt;
+ networkroute->has_use = true;
+ networkroute->use = Use;
+ networkroute->version = 6;
+ } else {
+ unsigned int Destination, Gateway, Mask, Flags;
+ int RefCnt, Use, Metric, MTU, Window, IRTT;
+
+ /* Parse the line and extract the values */
+ if (sscanf(line, "%s %X %X %x %d %d %d %X %d %d %d",
+ Iface, &Destination, &Gateway, &Flags, &RefCnt,
+ &Use, &Metric, &Mask, &MTU, &Window, &IRTT) != 11) {
+ continue;
+ }
+
+ route = g_new0(GuestNetworkRoute, 1);
+ networkroute = route;
+ networkroute->iface = g_strdup(Iface);
+ networkroute->destination = hexToIPAddress(&Destination, 0);
+ networkroute->gateway = hexToIPAddress(&Gateway, 0);
+ networkroute->mask = hexToIPAddress(&Mask, 0);
+ networkroute->metric = Metric;
+ networkroute->has_flags = true;
+ networkroute->flags = Flags;
+ networkroute->has_refcnt = true;
+ networkroute->refcnt = RefCnt;
+ networkroute->has_use = true;
+ networkroute->use = Use;
+ networkroute->has_mtu = true;
+ networkroute->mtu = MTU;
+ networkroute->has_window = true;
+ networkroute->window = Window;
+ networkroute->has_irtt = true;
+ networkroute->irtt = IRTT;
+ networkroute->version = 4;
+ }
+
+ QAPI_LIST_APPEND(tail, route);
+ }
+
+ free(line);
+ fclose(fp);
+ }
+
+ return head;
+}
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 7f05996..389c5ee 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -18,29 +18,17 @@
#include <dirent.h>
#include "qga-qapi-commands.h"
#include "qapi/error.h"
-#include "qapi/qmp/qerror.h"
#include "qemu/host-utils.h"
#include "qemu/sockets.h"
#include "qemu/base64.h"
#include "qemu/cutils.h"
#include "commands-common.h"
-#include "block/nvme.h"
#include "cutils.h"
#ifdef HAVE_UTMPX
#include <utmpx.h>
#endif
-#if defined(__linux__)
-#include <mntent.h>
-#include <sys/statvfs.h>
-#include <linux/nvme_ioctl.h>
-
-#ifdef CONFIG_LIBUDEV
-#include <libudev.h>
-#endif
-#endif
-
#ifdef HAVE_GETIFADDRS
#include <arpa/inet.h>
#include <sys/socket.h>
@@ -59,7 +47,7 @@
#endif
#endif
-static void ga_wait_child(pid_t pid, int *status, Error **errp)
+static bool ga_wait_child(pid_t pid, int *status, Error **errp)
{
pid_t rpid;
@@ -70,10 +58,11 @@ static void ga_wait_child(pid_t pid, int *status, Error **errp)
if (rpid == -1) {
error_setg_errno(errp, errno, "failed to wait for child (pid: %d)",
pid);
- return;
+ return false;
}
g_assert(rpid == pid);
+ return true;
}
static ssize_t ga_pipe_read_str(int fd[2], char **str)
@@ -178,8 +167,7 @@ static int ga_run_command(const char *argv[], const char *in_str,
goto out;
}
- ga_wait_child(pid, &status, errp);
- if (*errp) {
+ if (!ga_wait_child(pid, &status, errp)) {
goto out;
}
@@ -842,1308 +830,6 @@ static void guest_fsfreeze_cleanup(void)
}
#endif
-/* linux-specific implementations. avoid this if at all possible. */
-#if defined(__linux__)
-#if defined(CONFIG_FSFREEZE)
-
-static char *get_pci_driver(char const *syspath, int pathlen, Error **errp)
-{
- char *path;
- char *dpath;
- char *driver = NULL;
- char buf[PATH_MAX];
- ssize_t len;
-
- path = g_strndup(syspath, pathlen);
- dpath = g_strdup_printf("%s/driver", path);
- len = readlink(dpath, buf, sizeof(buf) - 1);
- if (len != -1) {
- buf[len] = 0;
- driver = g_path_get_basename(buf);
- }
- g_free(dpath);
- g_free(path);
- return driver;
-}
-
-static int compare_uint(const void *_a, const void *_b)
-{
- unsigned int a = *(unsigned int *)_a;
- unsigned int b = *(unsigned int *)_b;
-
- return a < b ? -1 : a > b ? 1 : 0;
-}
-
-/* Walk the specified sysfs and build a sorted list of host or ata numbers */
-static int build_hosts(char const *syspath, char const *host, bool ata,
- unsigned int *hosts, int hosts_max, Error **errp)
-{
- char *path;
- DIR *dir;
- struct dirent *entry;
- int i = 0;
-
- path = g_strndup(syspath, host - syspath);
- dir = opendir(path);
- if (!dir) {
- error_setg_errno(errp, errno, "opendir(\"%s\")", path);
- g_free(path);
- return -1;
- }
-
- while (i < hosts_max) {
- entry = readdir(dir);
- if (!entry) {
- break;
- }
- if (ata && sscanf(entry->d_name, "ata%d", hosts + i) == 1) {
- ++i;
- } else if (!ata && sscanf(entry->d_name, "host%d", hosts + i) == 1) {
- ++i;
- }
- }
-
- qsort(hosts, i, sizeof(hosts[0]), compare_uint);
-
- g_free(path);
- closedir(dir);
- return i;
-}
-
-/*
- * Store disk device info for devices on the PCI bus.
- * Returns true if information has been stored, or false for failure.
- */
-static bool build_guest_fsinfo_for_pci_dev(char const *syspath,
- GuestDiskAddress *disk,
- Error **errp)
-{
- unsigned int pci[4], host, hosts[8], tgt[3];
- int i, nhosts = 0, pcilen;
- GuestPCIAddress *pciaddr = disk->pci_controller;
- bool has_ata = false, has_host = false, has_tgt = false;
- char *p, *q, *driver = NULL;
- bool ret = false;
-
- p = strstr(syspath, "/devices/pci");
- if (!p || sscanf(p + 12, "%*x:%*x/%x:%x:%x.%x%n",
- pci, pci + 1, pci + 2, pci + 3, &pcilen) < 4) {
- g_debug("only pci device is supported: sysfs path '%s'", syspath);
- return false;
- }
-
- p += 12 + pcilen;
- while (true) {
- driver = get_pci_driver(syspath, p - syspath, errp);
- if (driver && (g_str_equal(driver, "ata_piix") ||
- g_str_equal(driver, "sym53c8xx") ||
- g_str_equal(driver, "virtio-pci") ||
- g_str_equal(driver, "ahci") ||
- g_str_equal(driver, "nvme") ||
- g_str_equal(driver, "xhci_hcd") ||
- g_str_equal(driver, "ehci-pci"))) {
- break;
- }
-
- g_free(driver);
- if (sscanf(p, "/%x:%x:%x.%x%n",
- pci, pci + 1, pci + 2, pci + 3, &pcilen) == 4) {
- p += pcilen;
- continue;
- }
-
- g_debug("unsupported driver or sysfs path '%s'", syspath);
- return false;
- }
-
- p = strstr(syspath, "/target");
- if (p && sscanf(p + 7, "%*u:%*u:%*u/%*u:%u:%u:%u",
- tgt, tgt + 1, tgt + 2) == 3) {
- has_tgt = true;
- }
-
- p = strstr(syspath, "/ata");
- if (p) {
- q = p + 4;
- has_ata = true;
- } else {
- p = strstr(syspath, "/host");
- q = p + 5;
- }
- if (p && sscanf(q, "%u", &host) == 1) {
- has_host = true;
- nhosts = build_hosts(syspath, p, has_ata, hosts,
- ARRAY_SIZE(hosts), errp);
- if (nhosts < 0) {
- goto cleanup;
- }
- }
-
- pciaddr->domain = pci[0];
- pciaddr->bus = pci[1];
- pciaddr->slot = pci[2];
- pciaddr->function = pci[3];
-
- if (strcmp(driver, "ata_piix") == 0) {
- /* a host per ide bus, target*:0:<unit>:0 */
- if (!has_host || !has_tgt) {
- g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
- goto cleanup;
- }
- for (i = 0; i < nhosts; i++) {
- if (host == hosts[i]) {
- disk->bus_type = GUEST_DISK_BUS_TYPE_IDE;
- disk->bus = i;
- disk->unit = tgt[1];
- break;
- }
- }
- if (i >= nhosts) {
- g_debug("no host for '%s' (driver '%s')", syspath, driver);
- goto cleanup;
- }
- } else if (strcmp(driver, "sym53c8xx") == 0) {
- /* scsi(LSI Logic): target*:0:<unit>:0 */
- if (!has_tgt) {
- g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
- goto cleanup;
- }
- disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI;
- disk->unit = tgt[1];
- } else if (strcmp(driver, "virtio-pci") == 0) {
- if (has_tgt) {
- /* virtio-scsi: target*:0:0:<unit> */
- disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI;
- disk->unit = tgt[2];
- } else {
- /* virtio-blk: 1 disk per 1 device */
- disk->bus_type = GUEST_DISK_BUS_TYPE_VIRTIO;
- }
- } else if (strcmp(driver, "ahci") == 0) {
- /* ahci: 1 host per 1 unit */
- if (!has_host || !has_tgt) {
- g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
- goto cleanup;
- }
- for (i = 0; i < nhosts; i++) {
- if (host == hosts[i]) {
- disk->unit = i;
- disk->bus_type = GUEST_DISK_BUS_TYPE_SATA;
- break;
- }
- }
- if (i >= nhosts) {
- g_debug("no host for '%s' (driver '%s')", syspath, driver);
- goto cleanup;
- }
- } else if (strcmp(driver, "nvme") == 0) {
- disk->bus_type = GUEST_DISK_BUS_TYPE_NVME;
- } else if (strcmp(driver, "ehci-pci") == 0 || strcmp(driver, "xhci_hcd") == 0) {
- disk->bus_type = GUEST_DISK_BUS_TYPE_USB;
- } else {
- g_debug("unknown driver '%s' (sysfs path '%s')", driver, syspath);
- goto cleanup;
- }
-
- ret = true;
-
-cleanup:
- g_free(driver);
- return ret;
-}
-
-/*
- * Store disk device info for non-PCI virtio devices (for example s390x
- * channel I/O devices). Returns true if information has been stored, or
- * false for failure.
- */
-static bool build_guest_fsinfo_for_nonpci_virtio(char const *syspath,
- GuestDiskAddress *disk,
- Error **errp)
-{
- unsigned int tgt[3];
- char *p;
-
- if (!strstr(syspath, "/virtio") || !strstr(syspath, "/block")) {
- g_debug("Unsupported virtio device '%s'", syspath);
- return false;
- }
-
- p = strstr(syspath, "/target");
- if (p && sscanf(p + 7, "%*u:%*u:%*u/%*u:%u:%u:%u",
- &tgt[0], &tgt[1], &tgt[2]) == 3) {
- /* virtio-scsi: target*:0:<target>:<unit> */
- disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI;
- disk->bus = tgt[0];
- disk->target = tgt[1];
- disk->unit = tgt[2];
- } else {
- /* virtio-blk: 1 disk per 1 device */
- disk->bus_type = GUEST_DISK_BUS_TYPE_VIRTIO;
- }
-
- return true;
-}
-
-/*
- * Store disk device info for CCW devices (s390x channel I/O devices).
- * Returns true if information has been stored, or false for failure.
- */
-static bool build_guest_fsinfo_for_ccw_dev(char const *syspath,
- GuestDiskAddress *disk,
- Error **errp)
-{
- unsigned int cssid, ssid, subchno, devno;
- char *p;
-
- p = strstr(syspath, "/devices/css");
- if (!p || sscanf(p + 12, "%*x/%x.%x.%x/%*x.%*x.%x/",
- &cssid, &ssid, &subchno, &devno) < 4) {
- g_debug("could not parse ccw device sysfs path: %s", syspath);
- return false;
- }
-
- disk->ccw_address = g_new0(GuestCCWAddress, 1);
- disk->ccw_address->cssid = cssid;
- disk->ccw_address->ssid = ssid;
- disk->ccw_address->subchno = subchno;
- disk->ccw_address->devno = devno;
-
- if (strstr(p, "/virtio")) {
- build_guest_fsinfo_for_nonpci_virtio(syspath, disk, errp);
- }
-
- return true;
-}
-
-/* Store disk device info specified by @sysfs into @fs */
-static void build_guest_fsinfo_for_real_device(char const *syspath,
- GuestFilesystemInfo *fs,
- Error **errp)
-{
- GuestDiskAddress *disk;
- GuestPCIAddress *pciaddr;
- bool has_hwinf;
-#ifdef CONFIG_LIBUDEV
- struct udev *udev = NULL;
- struct udev_device *udevice = NULL;
-#endif
-
- pciaddr = g_new0(GuestPCIAddress, 1);
- pciaddr->domain = -1; /* -1 means field is invalid */
- pciaddr->bus = -1;
- pciaddr->slot = -1;
- pciaddr->function = -1;
-
- disk = g_new0(GuestDiskAddress, 1);
- disk->pci_controller = pciaddr;
- disk->bus_type = GUEST_DISK_BUS_TYPE_UNKNOWN;
-
-#ifdef CONFIG_LIBUDEV
- udev = udev_new();
- udevice = udev_device_new_from_syspath(udev, syspath);
- if (udev == NULL || udevice == NULL) {
- g_debug("failed to query udev");
- } else {
- const char *devnode, *serial;
- devnode = udev_device_get_devnode(udevice);
- if (devnode != NULL) {
- disk->dev = g_strdup(devnode);
- }
- serial = udev_device_get_property_value(udevice, "ID_SERIAL");
- if (serial != NULL && *serial != 0) {
- disk->serial = g_strdup(serial);
- }
- }
-
- udev_unref(udev);
- udev_device_unref(udevice);
-#endif
-
- if (strstr(syspath, "/devices/pci")) {
- has_hwinf = build_guest_fsinfo_for_pci_dev(syspath, disk, errp);
- } else if (strstr(syspath, "/devices/css")) {
- has_hwinf = build_guest_fsinfo_for_ccw_dev(syspath, disk, errp);
- } else if (strstr(syspath, "/virtio")) {
- has_hwinf = build_guest_fsinfo_for_nonpci_virtio(syspath, disk, errp);
- } else {
- g_debug("Unsupported device type for '%s'", syspath);
- has_hwinf = false;
- }
-
- if (has_hwinf || disk->dev || disk->serial) {
- QAPI_LIST_PREPEND(fs->disk, disk);
- } else {
- qapi_free_GuestDiskAddress(disk);
- }
-}
-
-static void build_guest_fsinfo_for_device(char const *devpath,
- GuestFilesystemInfo *fs,
- Error **errp);
-
-/* Store a list of slave devices of virtual volume specified by @syspath into
- * @fs */
-static void build_guest_fsinfo_for_virtual_device(char const *syspath,
- GuestFilesystemInfo *fs,
- Error **errp)
-{
- Error *err = NULL;
- DIR *dir;
- char *dirpath;
- struct dirent *entry;
-
- dirpath = g_strdup_printf("%s/slaves", syspath);
- dir = opendir(dirpath);
- if (!dir) {
- if (errno != ENOENT) {
- error_setg_errno(errp, errno, "opendir(\"%s\")", dirpath);
- }
- g_free(dirpath);
- return;
- }
-
- for (;;) {
- errno = 0;
- entry = readdir(dir);
- if (entry == NULL) {
- if (errno) {
- error_setg_errno(errp, errno, "readdir(\"%s\")", dirpath);
- }
- break;
- }
-
- if (entry->d_type == DT_LNK) {
- char *path;
-
- g_debug(" slave device '%s'", entry->d_name);
- path = g_strdup_printf("%s/slaves/%s", syspath, entry->d_name);
- build_guest_fsinfo_for_device(path, fs, &err);
- g_free(path);
-
- if (err) {
- error_propagate(errp, err);
- break;
- }
- }
- }
-
- g_free(dirpath);
- closedir(dir);
-}
-
-static bool is_disk_virtual(const char *devpath, Error **errp)
-{
- g_autofree char *syspath = realpath(devpath, NULL);
-
- if (!syspath) {
- error_setg_errno(errp, errno, "realpath(\"%s\")", devpath);
- return false;
- }
- return strstr(syspath, "/devices/virtual/block/") != NULL;
-}
-
-/* Dispatch to functions for virtual/real device */
-static void build_guest_fsinfo_for_device(char const *devpath,
- GuestFilesystemInfo *fs,
- Error **errp)
-{
- ERRP_GUARD();
- g_autofree char *syspath = NULL;
- bool is_virtual = false;
-
- syspath = realpath(devpath, NULL);
- if (!syspath) {
- if (errno != ENOENT) {
- error_setg_errno(errp, errno, "realpath(\"%s\")", devpath);
- return;
- }
-
- /* ENOENT: This devpath may not exist because of container config */
- if (!fs->name) {
- fs->name = g_path_get_basename(devpath);
- }
- return;
- }
-
- if (!fs->name) {
- fs->name = g_path_get_basename(syspath);
- }
-
- g_debug(" parse sysfs path '%s'", syspath);
- is_virtual = is_disk_virtual(syspath, errp);
- if (*errp != NULL) {
- return;
- }
- if (is_virtual) {
- build_guest_fsinfo_for_virtual_device(syspath, fs, errp);
- } else {
- build_guest_fsinfo_for_real_device(syspath, fs, errp);
- }
-}
-
-#ifdef CONFIG_LIBUDEV
-
-/*
- * Wrapper around build_guest_fsinfo_for_device() for getting just
- * the disk address.
- */
-static GuestDiskAddress *get_disk_address(const char *syspath, Error **errp)
-{
- g_autoptr(GuestFilesystemInfo) fs = NULL;
-
- fs = g_new0(GuestFilesystemInfo, 1);
- build_guest_fsinfo_for_device(syspath, fs, errp);
- if (fs->disk != NULL) {
- return g_steal_pointer(&fs->disk->value);
- }
- return NULL;
-}
-
-static char *get_alias_for_syspath(const char *syspath)
-{
- struct udev *udev = NULL;
- struct udev_device *udevice = NULL;
- char *ret = NULL;
-
- udev = udev_new();
- if (udev == NULL) {
- g_debug("failed to query udev");
- goto out;
- }
- udevice = udev_device_new_from_syspath(udev, syspath);
- if (udevice == NULL) {
- g_debug("failed to query udev for path: %s", syspath);
- goto out;
- } else {
- const char *alias = udev_device_get_property_value(
- udevice, "DM_NAME");
- /*
- * NULL means there was an error and empty string means there is no
- * alias. In case of no alias we return NULL instead of empty string.
- */
- if (alias == NULL) {
- g_debug("failed to query udev for device alias for: %s",
- syspath);
- } else if (*alias != 0) {
- ret = g_strdup(alias);
- }
- }
-
-out:
- udev_unref(udev);
- udev_device_unref(udevice);
- return ret;
-}
-
-static char *get_device_for_syspath(const char *syspath)
-{
- struct udev *udev = NULL;
- struct udev_device *udevice = NULL;
- char *ret = NULL;
-
- udev = udev_new();
- if (udev == NULL) {
- g_debug("failed to query udev");
- goto out;
- }
- udevice = udev_device_new_from_syspath(udev, syspath);
- if (udevice == NULL) {
- g_debug("failed to query udev for path: %s", syspath);
- goto out;
- } else {
- ret = g_strdup(udev_device_get_devnode(udevice));
- }
-
-out:
- udev_unref(udev);
- udev_device_unref(udevice);
- return ret;
-}
-
-static void get_disk_deps(const char *disk_dir, GuestDiskInfo *disk)
-{
- g_autofree char *deps_dir = NULL;
- const gchar *dep;
- GDir *dp_deps = NULL;
-
- /* List dependent disks */
- deps_dir = g_strdup_printf("%s/slaves", disk_dir);
- g_debug(" listing entries in: %s", deps_dir);
- dp_deps = g_dir_open(deps_dir, 0, NULL);
- if (dp_deps == NULL) {
- g_debug("failed to list entries in %s", deps_dir);
- return;
- }
- disk->has_dependencies = true;
- while ((dep = g_dir_read_name(dp_deps)) != NULL) {
- g_autofree char *dep_dir = NULL;
- char *dev_name;
-
- /* Add dependent disks */
- dep_dir = g_strdup_printf("%s/%s", deps_dir, dep);
- dev_name = get_device_for_syspath(dep_dir);
- if (dev_name != NULL) {
- g_debug(" adding dependent device: %s", dev_name);
- QAPI_LIST_PREPEND(disk->dependencies, dev_name);
- }
- }
- g_dir_close(dp_deps);
-}
-
-/*
- * Detect partitions subdirectory, name is "<disk_name><number>" or
- * "<disk_name>p<number>"
- *
- * @disk_name -- last component of /sys path (e.g. sda)
- * @disk_dir -- sys path of the disk (e.g. /sys/block/sda)
- * @disk_dev -- device node of the disk (e.g. /dev/sda)
- */
-static GuestDiskInfoList *get_disk_partitions(
- GuestDiskInfoList *list,
- const char *disk_name, const char *disk_dir,
- const char *disk_dev)
-{
- GuestDiskInfoList *ret = list;
- struct dirent *de_disk;
- DIR *dp_disk = NULL;
- size_t len = strlen(disk_name);
-
- dp_disk = opendir(disk_dir);
- while ((de_disk = readdir(dp_disk)) != NULL) {
- g_autofree char *partition_dir = NULL;
- char *dev_name;
- GuestDiskInfo *partition;
-
- if (!(de_disk->d_type & DT_DIR)) {
- continue;
- }
-
- if (!(strncmp(disk_name, de_disk->d_name, len) == 0 &&
- ((*(de_disk->d_name + len) == 'p' &&
- isdigit(*(de_disk->d_name + len + 1))) ||
- isdigit(*(de_disk->d_name + len))))) {
- continue;
- }
-
- partition_dir = g_strdup_printf("%s/%s",
- disk_dir, de_disk->d_name);
- dev_name = get_device_for_syspath(partition_dir);
- if (dev_name == NULL) {
- g_debug("Failed to get device name for syspath: %s",
- disk_dir);
- continue;
- }
- partition = g_new0(GuestDiskInfo, 1);
- partition->name = dev_name;
- partition->partition = true;
- partition->has_dependencies = true;
- /* Add parent disk as dependent for easier tracking of hierarchy */
- QAPI_LIST_PREPEND(partition->dependencies, g_strdup(disk_dev));
-
- QAPI_LIST_PREPEND(ret, partition);
- }
- closedir(dp_disk);
-
- return ret;
-}
-
-static void get_nvme_smart(GuestDiskInfo *disk)
-{
- int fd;
- GuestNVMeSmart *smart;
- NvmeSmartLog log = {0};
- struct nvme_admin_cmd cmd = {
- .opcode = NVME_ADM_CMD_GET_LOG_PAGE,
- .nsid = NVME_NSID_BROADCAST,
- .addr = (uintptr_t)&log,
- .data_len = sizeof(log),
- .cdw10 = NVME_LOG_SMART_INFO | (1 << 15) /* RAE bit */
- | (((sizeof(log) >> 2) - 1) << 16)
- };
-
- fd = qga_open_cloexec(disk->name, O_RDONLY, 0);
- if (fd == -1) {
- g_debug("Failed to open device: %s: %s", disk->name, g_strerror(errno));
- return;
- }
-
- if (ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd)) {
- g_debug("Failed to get smart: %s: %s", disk->name, g_strerror(errno));
- close(fd);
- return;
- }
-
- disk->smart = g_new0(GuestDiskSmart, 1);
- disk->smart->type = GUEST_DISK_BUS_TYPE_NVME;
-
- smart = &disk->smart->u.nvme;
- smart->critical_warning = log.critical_warning;
- smart->temperature = lduw_le_p(&log.temperature); /* unaligned field */
- smart->available_spare = log.available_spare;
- smart->available_spare_threshold = log.available_spare_threshold;
- smart->percentage_used = log.percentage_used;
- smart->data_units_read_lo = le64_to_cpu(log.data_units_read[0]);
- smart->data_units_read_hi = le64_to_cpu(log.data_units_read[1]);
- smart->data_units_written_lo = le64_to_cpu(log.data_units_written[0]);
- smart->data_units_written_hi = le64_to_cpu(log.data_units_written[1]);
- smart->host_read_commands_lo = le64_to_cpu(log.host_read_commands[0]);
- smart->host_read_commands_hi = le64_to_cpu(log.host_read_commands[1]);
- smart->host_write_commands_lo = le64_to_cpu(log.host_write_commands[0]);
- smart->host_write_commands_hi = le64_to_cpu(log.host_write_commands[1]);
- smart->controller_busy_time_lo = le64_to_cpu(log.controller_busy_time[0]);
- smart->controller_busy_time_hi = le64_to_cpu(log.controller_busy_time[1]);
- smart->power_cycles_lo = le64_to_cpu(log.power_cycles[0]);
- smart->power_cycles_hi = le64_to_cpu(log.power_cycles[1]);
- smart->power_on_hours_lo = le64_to_cpu(log.power_on_hours[0]);
- smart->power_on_hours_hi = le64_to_cpu(log.power_on_hours[1]);
- smart->unsafe_shutdowns_lo = le64_to_cpu(log.unsafe_shutdowns[0]);
- smart->unsafe_shutdowns_hi = le64_to_cpu(log.unsafe_shutdowns[1]);
- smart->media_errors_lo = le64_to_cpu(log.media_errors[0]);
- smart->media_errors_hi = le64_to_cpu(log.media_errors[1]);
- smart->number_of_error_log_entries_lo =
- le64_to_cpu(log.number_of_error_log_entries[0]);
- smart->number_of_error_log_entries_hi =
- le64_to_cpu(log.number_of_error_log_entries[1]);
-
- close(fd);
-}
-
-static void get_disk_smart(GuestDiskInfo *disk)
-{
- if (disk->address
- && (disk->address->bus_type == GUEST_DISK_BUS_TYPE_NVME)) {
- get_nvme_smart(disk);
- }
-}
-
-GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
-{
- GuestDiskInfoList *ret = NULL;
- GuestDiskInfo *disk;
- DIR *dp = NULL;
- struct dirent *de = NULL;
-
- g_debug("listing /sys/block directory");
- dp = opendir("/sys/block");
- if (dp == NULL) {
- error_setg_errno(errp, errno, "Can't open directory \"/sys/block\"");
- return NULL;
- }
- while ((de = readdir(dp)) != NULL) {
- g_autofree char *disk_dir = NULL, *line = NULL,
- *size_path = NULL;
- char *dev_name;
- Error *local_err = NULL;
- if (de->d_type != DT_LNK) {
- g_debug(" skipping entry: %s", de->d_name);
- continue;
- }
-
- /* Check size and skip zero-sized disks */
- g_debug(" checking disk size");
- size_path = g_strdup_printf("/sys/block/%s/size", de->d_name);
- if (!g_file_get_contents(size_path, &line, NULL, NULL)) {
- g_debug(" failed to read disk size");
- continue;
- }
- if (g_strcmp0(line, "0\n") == 0) {
- g_debug(" skipping zero-sized disk");
- continue;
- }
-
- g_debug(" adding %s", de->d_name);
- disk_dir = g_strdup_printf("/sys/block/%s", de->d_name);
- dev_name = get_device_for_syspath(disk_dir);
- if (dev_name == NULL) {
- g_debug("Failed to get device name for syspath: %s",
- disk_dir);
- continue;
- }
- disk = g_new0(GuestDiskInfo, 1);
- disk->name = dev_name;
- disk->partition = false;
- disk->alias = get_alias_for_syspath(disk_dir);
- QAPI_LIST_PREPEND(ret, disk);
-
- /* Get address for non-virtual devices */
- bool is_virtual = is_disk_virtual(disk_dir, &local_err);
- if (local_err != NULL) {
- g_debug(" failed to check disk path, ignoring error: %s",
- error_get_pretty(local_err));
- error_free(local_err);
- local_err = NULL;
- /* Don't try to get the address */
- is_virtual = true;
- }
- if (!is_virtual) {
- disk->address = get_disk_address(disk_dir, &local_err);
- if (local_err != NULL) {
- g_debug(" failed to get device info, ignoring error: %s",
- error_get_pretty(local_err));
- error_free(local_err);
- local_err = NULL;
- }
- }
-
- get_disk_deps(disk_dir, disk);
- get_disk_smart(disk);
- ret = get_disk_partitions(ret, de->d_name, disk_dir, dev_name);
- }
-
- closedir(dp);
-
- return ret;
-}
-
-#else
-
-GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-#endif
-
-/* Return a list of the disk device(s)' info which @mount lies on */
-static GuestFilesystemInfo *build_guest_fsinfo(struct FsMount *mount,
- Error **errp)
-{
- GuestFilesystemInfo *fs = g_malloc0(sizeof(*fs));
- struct statvfs buf;
- unsigned long used, nonroot_total, fr_size;
- char *devpath = g_strdup_printf("/sys/dev/block/%u:%u",
- mount->devmajor, mount->devminor);
-
- fs->mountpoint = g_strdup(mount->dirname);
- fs->type = g_strdup(mount->devtype);
- build_guest_fsinfo_for_device(devpath, fs, errp);
-
- if (statvfs(fs->mountpoint, &buf) == 0) {
- fr_size = buf.f_frsize;
- used = buf.f_blocks - buf.f_bfree;
- nonroot_total = used + buf.f_bavail;
- fs->used_bytes = used * fr_size;
- fs->total_bytes = nonroot_total * fr_size;
- fs->total_bytes_privileged = buf.f_blocks * fr_size;
-
- fs->has_total_bytes = true;
- fs->has_total_bytes_privileged = true;
- fs->has_used_bytes = true;
- }
-
- g_free(devpath);
-
- return fs;
-}
-
-GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
-{
- FsMountList mounts;
- struct FsMount *mount;
- GuestFilesystemInfoList *ret = NULL;
- Error *local_err = NULL;
-
- QTAILQ_INIT(&mounts);
- if (!build_fs_mount_list(&mounts, &local_err)) {
- error_propagate(errp, local_err);
- return NULL;
- }
-
- QTAILQ_FOREACH(mount, &mounts, next) {
- g_debug("Building guest fsinfo for '%s'", mount->dirname);
-
- QAPI_LIST_PREPEND(ret, build_guest_fsinfo(mount, &local_err));
- if (local_err) {
- error_propagate(errp, local_err);
- qapi_free_GuestFilesystemInfoList(ret);
- ret = NULL;
- break;
- }
- }
-
- free_fs_mount_list(&mounts);
- return ret;
-}
-#endif /* CONFIG_FSFREEZE */
-
-#if defined(CONFIG_FSTRIM)
-/*
- * Walk list of mounted file systems in the guest, and trim them.
- */
-GuestFilesystemTrimResponse *
-qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
-{
- GuestFilesystemTrimResponse *response;
- GuestFilesystemTrimResult *result;
- int ret = 0;
- FsMountList mounts;
- struct FsMount *mount;
- int fd;
- struct fstrim_range r;
-
- slog("guest-fstrim called");
-
- QTAILQ_INIT(&mounts);
- if (!build_fs_mount_list(&mounts, errp)) {
- return NULL;
- }
-
- response = g_malloc0(sizeof(*response));
-
- QTAILQ_FOREACH(mount, &mounts, next) {
- result = g_malloc0(sizeof(*result));
- result->path = g_strdup(mount->dirname);
-
- QAPI_LIST_PREPEND(response->paths, result);
-
- fd = qga_open_cloexec(mount->dirname, O_RDONLY, 0);
- if (fd == -1) {
- result->error = g_strdup_printf("failed to open: %s",
- strerror(errno));
- continue;
- }
-
- /* We try to cull filesystems we know won't work in advance, but other
- * filesystems may not implement fstrim for less obvious reasons.
- * These will report EOPNOTSUPP; while in some other cases ENOTTY
- * will be reported (e.g. CD-ROMs).
- * Any other error means an unexpected error.
- */
- r.start = 0;
- r.len = -1;
- r.minlen = has_minimum ? minimum : 0;
- ret = ioctl(fd, FITRIM, &r);
- if (ret == -1) {
- if (errno == ENOTTY || errno == EOPNOTSUPP) {
- result->error = g_strdup("trim not supported");
- } else {
- result->error = g_strdup_printf("failed to trim: %s",
- strerror(errno));
- }
- close(fd);
- continue;
- }
-
- result->has_minimum = true;
- result->minimum = r.minlen;
- result->has_trimmed = true;
- result->trimmed = r.len;
- close(fd);
- }
-
- free_fs_mount_list(&mounts);
- return response;
-}
-#endif /* CONFIG_FSTRIM */
-
-
-#define LINUX_SYS_STATE_FILE "/sys/power/state"
-#define SUSPEND_SUPPORTED 0
-#define SUSPEND_NOT_SUPPORTED 1
-
-typedef enum {
- SUSPEND_MODE_DISK = 0,
- SUSPEND_MODE_RAM = 1,
- SUSPEND_MODE_HYBRID = 2,
-} SuspendMode;
-
-/*
- * Executes a command in a child process using g_spawn_sync,
- * returning an int >= 0 representing the exit status of the
- * process.
- *
- * If the program wasn't found in path, returns -1.
- *
- * If a problem happened when creating the child process,
- * returns -1 and errp is set.
- */
-static int run_process_child(const char *command[], Error **errp)
-{
- int exit_status, spawn_flag;
- GError *g_err = NULL;
- bool success;
-
- spawn_flag = G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL |
- G_SPAWN_STDERR_TO_DEV_NULL;
-
- success = g_spawn_sync(NULL, (char **)command, NULL, spawn_flag,
- NULL, NULL, NULL, NULL,
- &exit_status, &g_err);
-
- if (success) {
- return WEXITSTATUS(exit_status);
- }
-
- if (g_err && (g_err->code != G_SPAWN_ERROR_NOENT)) {
- error_setg(errp, "failed to create child process, error '%s'",
- g_err->message);
- }
-
- g_error_free(g_err);
- return -1;
-}
-
-static bool systemd_supports_mode(SuspendMode mode, Error **errp)
-{
- const char *systemctl_args[3] = {"systemd-hibernate", "systemd-suspend",
- "systemd-hybrid-sleep"};
- const char *cmd[4] = {"systemctl", "status", systemctl_args[mode], NULL};
- int status;
-
- status = run_process_child(cmd, errp);
-
- /*
- * systemctl status uses LSB return codes so we can expect
- * status > 0 and be ok. To assert if the guest has support
- * for the selected suspend mode, status should be < 4. 4 is
- * the code for unknown service status, the return value when
- * the service does not exist. A common value is status = 3
- * (program is not running).
- */
- if (status > 0 && status < 4) {
- return true;
- }
-
- return false;
-}
-
-static void systemd_suspend(SuspendMode mode, Error **errp)
-{
- Error *local_err = NULL;
- const char *systemctl_args[3] = {"hibernate", "suspend", "hybrid-sleep"};
- const char *cmd[3] = {"systemctl", systemctl_args[mode], NULL};
- int status;
-
- status = run_process_child(cmd, &local_err);
-
- if (status == 0) {
- return;
- }
-
- if ((status == -1) && !local_err) {
- error_setg(errp, "the helper program 'systemctl %s' was not found",
- systemctl_args[mode]);
- return;
- }
-
- if (local_err) {
- error_propagate(errp, local_err);
- } else {
- error_setg(errp, "the helper program 'systemctl %s' returned an "
- "unexpected exit status code (%d)",
- systemctl_args[mode], status);
- }
-}
-
-static bool pmutils_supports_mode(SuspendMode mode, Error **errp)
-{
- Error *local_err = NULL;
- const char *pmutils_args[3] = {"--hibernate", "--suspend",
- "--suspend-hybrid"};
- const char *cmd[3] = {"pm-is-supported", pmutils_args[mode], NULL};
- int status;
-
- status = run_process_child(cmd, &local_err);
-
- if (status == SUSPEND_SUPPORTED) {
- return true;
- }
-
- if ((status == -1) && !local_err) {
- return false;
- }
-
- if (local_err) {
- error_propagate(errp, local_err);
- } else {
- error_setg(errp,
- "the helper program '%s' returned an unexpected exit"
- " status code (%d)", "pm-is-supported", status);
- }
-
- return false;
-}
-
-static void pmutils_suspend(SuspendMode mode, Error **errp)
-{
- Error *local_err = NULL;
- const char *pmutils_binaries[3] = {"pm-hibernate", "pm-suspend",
- "pm-suspend-hybrid"};
- const char *cmd[2] = {pmutils_binaries[mode], NULL};
- int status;
-
- status = run_process_child(cmd, &local_err);
-
- if (status == 0) {
- return;
- }
-
- if ((status == -1) && !local_err) {
- error_setg(errp, "the helper program '%s' was not found",
- pmutils_binaries[mode]);
- return;
- }
-
- if (local_err) {
- error_propagate(errp, local_err);
- } else {
- error_setg(errp,
- "the helper program '%s' returned an unexpected exit"
- " status code (%d)", pmutils_binaries[mode], status);
- }
-}
-
-static bool linux_sys_state_supports_mode(SuspendMode mode, Error **errp)
-{
- const char *sysfile_strs[3] = {"disk", "mem", NULL};
- const char *sysfile_str = sysfile_strs[mode];
- char buf[32]; /* hopefully big enough */
- int fd;
- ssize_t ret;
-
- if (!sysfile_str) {
- error_setg(errp, "unknown guest suspend mode");
- return false;
- }
-
- fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
- if (fd < 0) {
- return false;
- }
-
- ret = read(fd, buf, sizeof(buf) - 1);
- close(fd);
- if (ret <= 0) {
- return false;
- }
- buf[ret] = '\0';
-
- if (strstr(buf, sysfile_str)) {
- return true;
- }
- return false;
-}
-
-static void linux_sys_state_suspend(SuspendMode mode, Error **errp)
-{
- g_autoptr(GError) local_gerr = NULL;
- const char *sysfile_strs[3] = {"disk", "mem", NULL};
- const char *sysfile_str = sysfile_strs[mode];
-
- if (!sysfile_str) {
- error_setg(errp, "unknown guest suspend mode");
- return;
- }
-
- if (!g_file_set_contents(LINUX_SYS_STATE_FILE, sysfile_str,
- -1, &local_gerr)) {
- error_setg(errp, "suspend: cannot write to '%s': %s",
- LINUX_SYS_STATE_FILE, local_gerr->message);
- return;
- }
-}
-
-static void guest_suspend(SuspendMode mode, Error **errp)
-{
- Error *local_err = NULL;
- bool mode_supported = false;
-
- if (systemd_supports_mode(mode, &local_err)) {
- mode_supported = true;
- systemd_suspend(mode, &local_err);
-
- if (!local_err) {
- return;
- }
- }
-
- error_free(local_err);
- local_err = NULL;
-
- if (pmutils_supports_mode(mode, &local_err)) {
- mode_supported = true;
- pmutils_suspend(mode, &local_err);
-
- if (!local_err) {
- return;
- }
- }
-
- error_free(local_err);
- local_err = NULL;
-
- if (linux_sys_state_supports_mode(mode, &local_err)) {
- mode_supported = true;
- linux_sys_state_suspend(mode, &local_err);
- }
-
- if (!mode_supported) {
- error_free(local_err);
- error_setg(errp,
- "the requested suspend mode is not supported by the guest");
- } else {
- error_propagate(errp, local_err);
- }
-}
-
-void qmp_guest_suspend_disk(Error **errp)
-{
- guest_suspend(SUSPEND_MODE_DISK, errp);
-}
-
-void qmp_guest_suspend_ram(Error **errp)
-{
- guest_suspend(SUSPEND_MODE_RAM, errp);
-}
-
-void qmp_guest_suspend_hybrid(Error **errp)
-{
- guest_suspend(SUSPEND_MODE_HYBRID, errp);
-}
-
-/* Transfer online/offline status between @vcpu and the guest system.
- *
- * On input either @errp or *@errp must be NULL.
- *
- * In system-to-@vcpu direction, the following @vcpu fields are accessed:
- * - R: vcpu->logical_id
- * - W: vcpu->online
- * - W: vcpu->can_offline
- *
- * In @vcpu-to-system direction, the following @vcpu fields are accessed:
- * - R: vcpu->logical_id
- * - R: vcpu->online
- *
- * Written members remain unmodified on error.
- */
-static void transfer_vcpu(GuestLogicalProcessor *vcpu, bool sys2vcpu,
- char *dirpath, Error **errp)
-{
- int fd;
- int res;
- int dirfd;
- static const char fn[] = "online";
-
- dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
- if (dirfd == -1) {
- error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
- return;
- }
-
- fd = openat(dirfd, fn, sys2vcpu ? O_RDONLY : O_RDWR);
- if (fd == -1) {
- if (errno != ENOENT) {
- error_setg_errno(errp, errno, "open(\"%s/%s\")", dirpath, fn);
- } else if (sys2vcpu) {
- vcpu->online = true;
- vcpu->can_offline = false;
- } else if (!vcpu->online) {
- error_setg(errp, "logical processor #%" PRId64 " can't be "
- "offlined", vcpu->logical_id);
- } /* otherwise pretend successful re-onlining */
- } else {
- unsigned char status;
-
- res = pread(fd, &status, 1, 0);
- if (res == -1) {
- error_setg_errno(errp, errno, "pread(\"%s/%s\")", dirpath, fn);
- } else if (res == 0) {
- error_setg(errp, "pread(\"%s/%s\"): unexpected EOF", dirpath,
- fn);
- } else if (sys2vcpu) {
- vcpu->online = (status != '0');
- vcpu->can_offline = true;
- } else if (vcpu->online != (status != '0')) {
- status = '0' + vcpu->online;
- if (pwrite(fd, &status, 1, 0) == -1) {
- error_setg_errno(errp, errno, "pwrite(\"%s/%s\")", dirpath,
- fn);
- }
- } /* otherwise pretend successful re-(on|off)-lining */
-
- res = close(fd);
- g_assert(res == 0);
- }
-
- res = close(dirfd);
- g_assert(res == 0);
-}
-
-GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
-{
- GuestLogicalProcessorList *head, **tail;
- const char *cpu_dir = "/sys/devices/system/cpu";
- const gchar *line;
- g_autoptr(GDir) cpu_gdir = NULL;
- Error *local_err = NULL;
-
- head = NULL;
- tail = &head;
- cpu_gdir = g_dir_open(cpu_dir, 0, NULL);
-
- if (cpu_gdir == NULL) {
- error_setg_errno(errp, errno, "failed to list entries: %s", cpu_dir);
- return NULL;
- }
-
- while (local_err == NULL && (line = g_dir_read_name(cpu_gdir)) != NULL) {
- GuestLogicalProcessor *vcpu;
- int64_t id;
- if (sscanf(line, "cpu%" PRId64, &id)) {
- g_autofree char *path = g_strdup_printf("/sys/devices/system/cpu/"
- "cpu%" PRId64 "/", id);
- vcpu = g_malloc0(sizeof *vcpu);
- vcpu->logical_id = id;
- vcpu->has_can_offline = true; /* lolspeak ftw */
- transfer_vcpu(vcpu, true, path, &local_err);
- QAPI_LIST_APPEND(tail, vcpu);
- }
- }
-
- if (local_err == NULL) {
- /* there's no guest with zero VCPUs */
- g_assert(head != NULL);
- return head;
- }
-
- qapi_free_GuestLogicalProcessorList(head);
- error_propagate(errp, local_err);
- return NULL;
-}
-
-int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
-{
- int64_t processed;
- Error *local_err = NULL;
-
- processed = 0;
- while (vcpus != NULL) {
- char *path = g_strdup_printf("/sys/devices/system/cpu/cpu%" PRId64 "/",
- vcpus->value->logical_id);
-
- transfer_vcpu(vcpus->value, false, path, &local_err);
- g_free(path);
- if (local_err != NULL) {
- break;
- }
- ++processed;
- vcpus = vcpus->next;
- }
-
- if (local_err != NULL) {
- if (processed == 0) {
- error_propagate(errp, local_err);
- } else {
- error_free(local_err);
- }
- }
-
- return processed;
-}
-#endif /* __linux__ */
-
#if defined(__linux__) || defined(__FreeBSD__)
void qmp_guest_set_user_password(const char *username,
const char *password,
@@ -2190,574 +876,8 @@ void qmp_guest_set_user_password(const char *username,
return;
}
}
-#else /* __linux__ || __FreeBSD__ */
-void qmp_guest_set_user_password(const char *username,
- const char *password,
- bool crypted,
- Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
-}
#endif /* __linux__ || __FreeBSD__ */
-#ifdef __linux__
-static void ga_read_sysfs_file(int dirfd, const char *pathname, char *buf,
- int size, Error **errp)
-{
- int fd;
- int res;
-
- errno = 0;
- fd = openat(dirfd, pathname, O_RDONLY);
- if (fd == -1) {
- error_setg_errno(errp, errno, "open sysfs file \"%s\"", pathname);
- return;
- }
-
- res = pread(fd, buf, size, 0);
- if (res == -1) {
- error_setg_errno(errp, errno, "pread sysfs file \"%s\"", pathname);
- } else if (res == 0) {
- error_setg(errp, "pread sysfs file \"%s\": unexpected EOF", pathname);
- }
- close(fd);
-}
-
-static void ga_write_sysfs_file(int dirfd, const char *pathname,
- const char *buf, int size, Error **errp)
-{
- int fd;
-
- errno = 0;
- fd = openat(dirfd, pathname, O_WRONLY);
- if (fd == -1) {
- error_setg_errno(errp, errno, "open sysfs file \"%s\"", pathname);
- return;
- }
-
- if (pwrite(fd, buf, size, 0) == -1) {
- error_setg_errno(errp, errno, "pwrite sysfs file \"%s\"", pathname);
- }
-
- close(fd);
-}
-
-/* Transfer online/offline status between @mem_blk and the guest system.
- *
- * On input either @errp or *@errp must be NULL.
- *
- * In system-to-@mem_blk direction, the following @mem_blk fields are accessed:
- * - R: mem_blk->phys_index
- * - W: mem_blk->online
- * - W: mem_blk->can_offline
- *
- * In @mem_blk-to-system direction, the following @mem_blk fields are accessed:
- * - R: mem_blk->phys_index
- * - R: mem_blk->online
- *- R: mem_blk->can_offline
- * Written members remain unmodified on error.
- */
-static void transfer_memory_block(GuestMemoryBlock *mem_blk, bool sys2memblk,
- GuestMemoryBlockResponse *result,
- Error **errp)
-{
- char *dirpath;
- int dirfd;
- char *status;
- Error *local_err = NULL;
-
- if (!sys2memblk) {
- DIR *dp;
-
- if (!result) {
- error_setg(errp, "Internal error, 'result' should not be NULL");
- return;
- }
- errno = 0;
- dp = opendir("/sys/devices/system/memory/");
- /* if there is no 'memory' directory in sysfs,
- * we think this VM does not support online/offline memory block,
- * any other solution?
- */
- if (!dp) {
- if (errno == ENOENT) {
- result->response =
- GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_NOT_SUPPORTED;
- }
- goto out1;
- }
- closedir(dp);
- }
-
- dirpath = g_strdup_printf("/sys/devices/system/memory/memory%" PRId64 "/",
- mem_blk->phys_index);
- dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
- if (dirfd == -1) {
- if (sys2memblk) {
- error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
- } else {
- if (errno == ENOENT) {
- result->response = GUEST_MEMORY_BLOCK_RESPONSE_TYPE_NOT_FOUND;
- } else {
- result->response =
- GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
- }
- }
- g_free(dirpath);
- goto out1;
- }
- g_free(dirpath);
-
- status = g_malloc0(10);
- ga_read_sysfs_file(dirfd, "state", status, 10, &local_err);
- if (local_err) {
- /* treat with sysfs file that not exist in old kernel */
- if (errno == ENOENT) {
- error_free(local_err);
- if (sys2memblk) {
- mem_blk->online = true;
- mem_blk->can_offline = false;
- } else if (!mem_blk->online) {
- result->response =
- GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_NOT_SUPPORTED;
- }
- } else {
- if (sys2memblk) {
- error_propagate(errp, local_err);
- } else {
- error_free(local_err);
- result->response =
- GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
- }
- }
- goto out2;
- }
-
- if (sys2memblk) {
- char removable = '0';
-
- mem_blk->online = (strncmp(status, "online", 6) == 0);
-
- ga_read_sysfs_file(dirfd, "removable", &removable, 1, &local_err);
- if (local_err) {
- /* if no 'removable' file, it doesn't support offline mem blk */
- if (errno == ENOENT) {
- error_free(local_err);
- mem_blk->can_offline = false;
- } else {
- error_propagate(errp, local_err);
- }
- } else {
- mem_blk->can_offline = (removable != '0');
- }
- } else {
- if (mem_blk->online != (strncmp(status, "online", 6) == 0)) {
- const char *new_state = mem_blk->online ? "online" : "offline";
-
- ga_write_sysfs_file(dirfd, "state", new_state, strlen(new_state),
- &local_err);
- if (local_err) {
- error_free(local_err);
- result->response =
- GUEST_MEMORY_BLOCK_RESPONSE_TYPE_OPERATION_FAILED;
- goto out2;
- }
-
- result->response = GUEST_MEMORY_BLOCK_RESPONSE_TYPE_SUCCESS;
- result->has_error_code = false;
- } /* otherwise pretend successful re-(on|off)-lining */
- }
- g_free(status);
- close(dirfd);
- return;
-
-out2:
- g_free(status);
- close(dirfd);
-out1:
- if (!sys2memblk) {
- result->has_error_code = true;
- result->error_code = errno;
- }
-}
-
-GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
-{
- GuestMemoryBlockList *head, **tail;
- Error *local_err = NULL;
- struct dirent *de;
- DIR *dp;
-
- head = NULL;
- tail = &head;
-
- dp = opendir("/sys/devices/system/memory/");
- if (!dp) {
- /* it's ok if this happens to be a system that doesn't expose
- * memory blocks via sysfs, but otherwise we should report
- * an error
- */
- if (errno != ENOENT) {
- error_setg_errno(errp, errno, "Can't open directory"
- "\"/sys/devices/system/memory/\"");
- }
- return NULL;
- }
-
- /* Note: the phys_index of memory block may be discontinuous,
- * this is because a memblk is the unit of the Sparse Memory design, which
- * allows discontinuous memory ranges (ex. NUMA), so here we should
- * traverse the memory block directory.
- */
- while ((de = readdir(dp)) != NULL) {
- GuestMemoryBlock *mem_blk;
-
- if ((strncmp(de->d_name, "memory", 6) != 0) ||
- !(de->d_type & DT_DIR)) {
- continue;
- }
-
- mem_blk = g_malloc0(sizeof *mem_blk);
- /* The d_name is "memoryXXX", phys_index is block id, same as XXX */
- mem_blk->phys_index = strtoul(&de->d_name[6], NULL, 10);
- mem_blk->has_can_offline = true; /* lolspeak ftw */
- transfer_memory_block(mem_blk, true, NULL, &local_err);
- if (local_err) {
- break;
- }
-
- QAPI_LIST_APPEND(tail, mem_blk);
- }
-
- closedir(dp);
- if (local_err == NULL) {
- /* there's no guest with zero memory blocks */
- if (head == NULL) {
- error_setg(errp, "guest reported zero memory blocks!");
- }
- return head;
- }
-
- qapi_free_GuestMemoryBlockList(head);
- error_propagate(errp, local_err);
- return NULL;
-}
-
-GuestMemoryBlockResponseList *
-qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp)
-{
- GuestMemoryBlockResponseList *head, **tail;
- Error *local_err = NULL;
-
- head = NULL;
- tail = &head;
-
- while (mem_blks != NULL) {
- GuestMemoryBlockResponse *result;
- GuestMemoryBlock *current_mem_blk = mem_blks->value;
-
- result = g_malloc0(sizeof(*result));
- result->phys_index = current_mem_blk->phys_index;
- transfer_memory_block(current_mem_blk, false, result, &local_err);
- if (local_err) { /* should never happen */
- goto err;
- }
-
- QAPI_LIST_APPEND(tail, result);
- mem_blks = mem_blks->next;
- }
-
- return head;
-err:
- qapi_free_GuestMemoryBlockResponseList(head);
- error_propagate(errp, local_err);
- return NULL;
-}
-
-GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
-{
- Error *local_err = NULL;
- char *dirpath;
- int dirfd;
- char *buf;
- GuestMemoryBlockInfo *info;
-
- dirpath = g_strdup_printf("/sys/devices/system/memory/");
- dirfd = open(dirpath, O_RDONLY | O_DIRECTORY);
- if (dirfd == -1) {
- error_setg_errno(errp, errno, "open(\"%s\")", dirpath);
- g_free(dirpath);
- return NULL;
- }
- g_free(dirpath);
-
- buf = g_malloc0(20);
- ga_read_sysfs_file(dirfd, "block_size_bytes", buf, 20, &local_err);
- close(dirfd);
- if (local_err) {
- g_free(buf);
- error_propagate(errp, local_err);
- return NULL;
- }
-
- info = g_new0(GuestMemoryBlockInfo, 1);
- info->size = strtol(buf, NULL, 16); /* the unit is bytes */
-
- g_free(buf);
-
- return info;
-}
-
-#define MAX_NAME_LEN 128
-static GuestDiskStatsInfoList *guest_get_diskstats(Error **errp)
-{
-#ifdef CONFIG_LINUX
- GuestDiskStatsInfoList *head = NULL, **tail = &head;
- const char *diskstats = "/proc/diskstats";
- FILE *fp;
- size_t n;
- char *line = NULL;
-
- fp = fopen(diskstats, "r");
- if (fp == NULL) {
- error_setg_errno(errp, errno, "open(\"%s\")", diskstats);
- return NULL;
- }
-
- while (getline(&line, &n, fp) != -1) {
- g_autofree GuestDiskStatsInfo *diskstatinfo = NULL;
- g_autofree GuestDiskStats *diskstat = NULL;
- char dev_name[MAX_NAME_LEN];
- unsigned int ios_pgr, tot_ticks, rq_ticks, wr_ticks, dc_ticks, fl_ticks;
- unsigned long rd_ios, rd_merges_or_rd_sec, rd_ticks_or_wr_sec, wr_ios;
- unsigned long wr_merges, rd_sec_or_wr_ios, wr_sec;
- unsigned long dc_ios, dc_merges, dc_sec, fl_ios;
- unsigned int major, minor;
- int i;
-
- i = sscanf(line, "%u %u %s %lu %lu %lu"
- "%lu %lu %lu %lu %u %u %u %u"
- "%lu %lu %lu %u %lu %u",
- &major, &minor, dev_name,
- &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios,
- &rd_ticks_or_wr_sec, &wr_ios, &wr_merges, &wr_sec,
- &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks,
- &dc_ios, &dc_merges, &dc_sec, &dc_ticks,
- &fl_ios, &fl_ticks);
-
- if (i < 7) {
- continue;
- }
-
- diskstatinfo = g_new0(GuestDiskStatsInfo, 1);
- diskstatinfo->name = g_strdup(dev_name);
- diskstatinfo->major = major;
- diskstatinfo->minor = minor;
-
- diskstat = g_new0(GuestDiskStats, 1);
- if (i == 7) {
- diskstat->has_read_ios = true;
- diskstat->read_ios = rd_ios;
- diskstat->has_read_sectors = true;
- diskstat->read_sectors = rd_merges_or_rd_sec;
- diskstat->has_write_ios = true;
- diskstat->write_ios = rd_sec_or_wr_ios;
- diskstat->has_write_sectors = true;
- diskstat->write_sectors = rd_ticks_or_wr_sec;
- }
- if (i >= 14) {
- diskstat->has_read_ios = true;
- diskstat->read_ios = rd_ios;
- diskstat->has_read_sectors = true;
- diskstat->read_sectors = rd_sec_or_wr_ios;
- diskstat->has_read_merges = true;
- diskstat->read_merges = rd_merges_or_rd_sec;
- diskstat->has_read_ticks = true;
- diskstat->read_ticks = rd_ticks_or_wr_sec;
- diskstat->has_write_ios = true;
- diskstat->write_ios = wr_ios;
- diskstat->has_write_sectors = true;
- diskstat->write_sectors = wr_sec;
- diskstat->has_write_merges = true;
- diskstat->write_merges = wr_merges;
- diskstat->has_write_ticks = true;
- diskstat->write_ticks = wr_ticks;
- diskstat->has_ios_pgr = true;
- diskstat->ios_pgr = ios_pgr;
- diskstat->has_total_ticks = true;
- diskstat->total_ticks = tot_ticks;
- diskstat->has_weight_ticks = true;
- diskstat->weight_ticks = rq_ticks;
- }
- if (i >= 18) {
- diskstat->has_discard_ios = true;
- diskstat->discard_ios = dc_ios;
- diskstat->has_discard_merges = true;
- diskstat->discard_merges = dc_merges;
- diskstat->has_discard_sectors = true;
- diskstat->discard_sectors = dc_sec;
- diskstat->has_discard_ticks = true;
- diskstat->discard_ticks = dc_ticks;
- }
- if (i >= 20) {
- diskstat->has_flush_ios = true;
- diskstat->flush_ios = fl_ios;
- diskstat->has_flush_ticks = true;
- diskstat->flush_ticks = fl_ticks;
- }
-
- diskstatinfo->stats = g_steal_pointer(&diskstat);
- QAPI_LIST_APPEND(tail, diskstatinfo);
- diskstatinfo = NULL;
- }
- free(line);
- fclose(fp);
- return head;
-#else
- g_debug("disk stats reporting available only for Linux");
- return NULL;
-#endif
-}
-
-GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp)
-{
- return guest_get_diskstats(errp);
-}
-
-GuestCpuStatsList *qmp_guest_get_cpustats(Error **errp)
-{
- GuestCpuStatsList *head = NULL, **tail = &head;
- const char *cpustats = "/proc/stat";
- int clk_tck = sysconf(_SC_CLK_TCK);
- FILE *fp;
- size_t n;
- char *line = NULL;
-
- fp = fopen(cpustats, "r");
- if (fp == NULL) {
- error_setg_errno(errp, errno, "open(\"%s\")", cpustats);
- return NULL;
- }
-
- while (getline(&line, &n, fp) != -1) {
- GuestCpuStats *cpustat = NULL;
- GuestLinuxCpuStats *linuxcpustat;
- int i;
- unsigned long user, system, idle, iowait, irq, softirq, steal, guest;
- unsigned long nice, guest_nice;
- char name[64];
-
- i = sscanf(line, "%s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
- name, &user, &nice, &system, &idle, &iowait, &irq, &softirq,
- &steal, &guest, &guest_nice);
-
- /* drop "cpu 1 2 3 ...", get "cpuX 1 2 3 ..." only */
- if ((i == EOF) || strncmp(name, "cpu", 3) || (name[3] == '\0')) {
- continue;
- }
-
- if (i < 5) {
- slog("Parsing cpu stat from %s failed, see \"man proc\"", cpustats);
- break;
- }
-
- cpustat = g_new0(GuestCpuStats, 1);
- cpustat->type = GUEST_CPU_STATS_TYPE_LINUX;
-
- linuxcpustat = &cpustat->u.q_linux;
- linuxcpustat->cpu = atoi(&name[3]);
- linuxcpustat->user = user * 1000 / clk_tck;
- linuxcpustat->nice = nice * 1000 / clk_tck;
- linuxcpustat->system = system * 1000 / clk_tck;
- linuxcpustat->idle = idle * 1000 / clk_tck;
-
- if (i > 5) {
- linuxcpustat->has_iowait = true;
- linuxcpustat->iowait = iowait * 1000 / clk_tck;
- }
-
- if (i > 6) {
- linuxcpustat->has_irq = true;
- linuxcpustat->irq = irq * 1000 / clk_tck;
- linuxcpustat->has_softirq = true;
- linuxcpustat->softirq = softirq * 1000 / clk_tck;
- }
-
- if (i > 8) {
- linuxcpustat->has_steal = true;
- linuxcpustat->steal = steal * 1000 / clk_tck;
- }
-
- if (i > 9) {
- linuxcpustat->has_guest = true;
- linuxcpustat->guest = guest * 1000 / clk_tck;
- }
-
- if (i > 10) {
- linuxcpustat->has_guest = true;
- linuxcpustat->guest = guest * 1000 / clk_tck;
- linuxcpustat->has_guestnice = true;
- linuxcpustat->guestnice = guest_nice * 1000 / clk_tck;
- }
-
- QAPI_LIST_APPEND(tail, cpustat);
- }
-
- free(line);
- fclose(fp);
- return head;
-}
-
-#else /* defined(__linux__) */
-
-void qmp_guest_suspend_disk(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
-}
-
-void qmp_guest_suspend_ram(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
-}
-
-void qmp_guest_suspend_hybrid(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
-}
-
-GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return -1;
-}
-
-GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-GuestMemoryBlockResponseList *
-qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-#endif
-
#ifdef HAVE_GETIFADDRS
static GuestNetworkInterface *
guest_find_interface(GuestNetworkInterfaceList *head,
@@ -3013,131 +1133,8 @@ error:
return NULL;
}
-#else
-
-GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
#endif /* HAVE_GETIFADDRS */
-#if !defined(CONFIG_FSFREEZE)
-
-GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
-
- return 0;
-}
-
-int64_t qmp_guest_fsfreeze_freeze(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
-
- return 0;
-}
-
-int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
- strList *mountpoints,
- Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
-
- return 0;
-}
-
-int64_t qmp_guest_fsfreeze_thaw(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
-
- return 0;
-}
-
-GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-GuestCpuStatsList *qmp_guest_get_cpustats(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-#endif /* CONFIG_FSFREEZE */
-
-#if !defined(CONFIG_FSTRIM)
-GuestFilesystemTrimResponse *
-qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-#endif
-
-/* add unsupported commands to the list of blocked RPCs */
-GList *ga_command_init_blockedrpcs(GList *blockedrpcs)
-{
-#if !defined(__linux__)
- {
- const char *list[] = {
- "guest-suspend-disk", "guest-suspend-ram",
- "guest-suspend-hybrid", "guest-get-vcpus", "guest-set-vcpus",
- "guest-get-memory-blocks", "guest-set-memory-blocks",
- "guest-get-memory-block-size", "guest-get-memory-block-info",
- NULL};
- char **p = (char **)list;
-
- while (*p) {
- blockedrpcs = g_list_append(blockedrpcs, g_strdup(*p++));
- }
- }
-#endif
-
-#if !defined(HAVE_GETIFADDRS)
- blockedrpcs = g_list_append(blockedrpcs,
- g_strdup("guest-network-get-interfaces"));
-#endif
-
-#if !defined(CONFIG_FSFREEZE)
- {
- const char *list[] = {
- "guest-get-fsinfo", "guest-fsfreeze-status",
- "guest-fsfreeze-freeze", "guest-fsfreeze-freeze-list",
- "guest-fsfreeze-thaw", "guest-get-fsinfo",
- "guest-get-disks", NULL};
- char **p = (char **)list;
-
- while (*p) {
- blockedrpcs = g_list_append(blockedrpcs, g_strdup(*p++));
- }
- }
-#endif
-
-#if !defined(CONFIG_FSTRIM)
- blockedrpcs = g_list_append(blockedrpcs, g_strdup("guest-fstrim"));
-#endif
-
- blockedrpcs = g_list_append(blockedrpcs, g_strdup("guest-get-devices"));
-
- return blockedrpcs;
-}
-
/* register init/cleanup routines for stateful command groups */
void ga_command_state_init(GAState *s, GACommandState *cs)
{
@@ -3200,15 +1197,7 @@ GuestUserList *qmp_guest_get_users(Error **errp)
return head;
}
-#else
-
-GuestUserList *qmp_guest_get_users(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-#endif
+#endif /* HAVE_UTMPX */
/* Replace escaped special characters with their real values. The replacement
* is done in place -- returned value is in the original string.
@@ -3345,13 +1334,6 @@ GuestOSInfo *qmp_guest_get_osinfo(Error **errp)
return info;
}
-GuestDeviceInfoList *qmp_guest_get_devices(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
-
- return NULL;
-}
-
#ifndef HOST_NAME_MAX
# ifdef _POSIX_HOST_NAME_MAX
# define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 0d1b836..038beb8 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -1203,7 +1203,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
{
if (!vss_initialized()) {
- error_setg(errp, QERR_UNSUPPORTED);
+ error_setg(errp, "fsfreeze not possible as VSS failed to initialize");
return 0;
}
@@ -1231,7 +1231,7 @@ int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
Error *local_err = NULL;
if (!vss_initialized()) {
- error_setg(errp, QERR_UNSUPPORTED);
+ error_setg(errp, "fsfreeze not possible as VSS failed to initialize");
return 0;
}
@@ -1266,7 +1266,7 @@ int64_t qmp_guest_fsfreeze_thaw(Error **errp)
int i;
if (!vss_initialized()) {
- error_setg(errp, QERR_UNSUPPORTED);
+ error_setg(errp, "fsfreeze not possible as VSS failed to initialize");
return 0;
}
@@ -1494,11 +1494,6 @@ out:
}
}
-void qmp_guest_suspend_hybrid(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
-}
-
static IP_ADAPTER_ADDRESSES *guest_get_adapters_addresses(Error **errp)
{
IP_ADAPTER_ADDRESSES *adptr_addrs = NULL;
@@ -1862,12 +1857,6 @@ GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
return NULL;
}
-int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return -1;
-}
-
static gchar *
get_net_error_message(gint error)
{
@@ -1925,7 +1914,7 @@ void qmp_guest_set_user_password(const char *username,
GError *gerr = NULL;
if (crypted) {
- error_setg(errp, QERR_UNSUPPORTED);
+ error_setg(errp, "'crypted' must be off on this host");
return;
}
@@ -1969,55 +1958,6 @@ done:
g_free(rawpasswddata);
}
-GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-GuestMemoryBlockResponseList *
-qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-/* add unsupported commands to the list of blocked RPCs */
-GList *ga_command_init_blockedrpcs(GList *blockedrpcs)
-{
- const char *list_unsupported[] = {
- "guest-suspend-hybrid",
- "guest-set-vcpus",
- "guest-get-memory-blocks", "guest-set-memory-blocks",
- "guest-get-memory-block-size", "guest-get-memory-block-info",
- NULL};
- char **p = (char **)list_unsupported;
-
- while (*p) {
- blockedrpcs = g_list_append(blockedrpcs, g_strdup(*p++));
- }
-
- if (!vss_init(true)) {
- g_debug("vss_init failed, vss commands are going to be disabled");
- const char *list[] = {
- "guest-get-fsinfo", "guest-fsfreeze-status",
- "guest-fsfreeze-freeze", "guest-fsfreeze-thaw", NULL};
- p = (char **)list;
-
- while (*p) {
- blockedrpcs = g_list_append(blockedrpcs, g_strdup(*p++));
- }
- }
-
- return blockedrpcs;
-}
-
/* register init/cleanup routines for stateful command groups */
void ga_command_state_init(GAState *s, GACommandState *cs)
{
@@ -2505,15 +2445,3 @@ char *qga_get_host_name(Error **errp)
return g_utf16_to_utf8(tmp, size, NULL, NULL, NULL);
}
-
-GuestDiskStatsInfoList *qmp_guest_get_diskstats(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
-
-GuestCpuStatsList *qmp_guest_get_cpustats(Error **errp)
-{
- error_setg(errp, QERR_UNSUPPORTED);
- return NULL;
-}
diff --git a/qga/main.c b/qga/main.c
index f4d5f15..5018676 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -70,6 +70,28 @@ typedef struct GAPersistentState {
typedef struct GAConfig GAConfig;
+struct GAConfig {
+ char *channel_path;
+ char *method;
+ char *log_filepath;
+ char *pid_filepath;
+#ifdef CONFIG_FSFREEZE
+ char *fsfreeze_hook;
+#endif
+ char *state_dir;
+#ifdef _WIN32
+ const char *service;
+#endif
+ gchar *bliststr; /* blockedrpcs may point to this string */
+ gchar *aliststr; /* allowedrpcs may point to this string */
+ GList *blockedrpcs;
+ GList *allowedrpcs;
+ int daemonize;
+ GLogLevelFlags log_level;
+ int dumpconf;
+ bool retry_path;
+};
+
struct GAState {
JSONMessageParser parser;
GMainLoop *main_loop;
@@ -226,12 +248,16 @@ static void usage(const char *cmd)
#ifdef CONFIG_FSFREEZE
g_autofree char *fsfreeze_hook = get_relocated_path(QGA_FSFREEZE_HOOK_DEFAULT);
#endif
+ g_autofree char *conf_path = get_relocated_path(QGA_CONF_DEFAULT);
printf(
"Usage: %s [-m <method> -p <path>] [<options>]\n"
"QEMU Guest Agent " QEMU_FULL_VERSION "\n"
QEMU_COPYRIGHT "\n"
"\n"
+" -c, --config=PATH configuration file path (default is\n"
+" %s/qemu-ga.conf\n"
+" unless overridden by the QGA_CONF environment variable)\n"
" -m, --method transport method: one of unix-listen, virtio-serial,\n"
" isa-serial, or vsock-listen (virtio-serial is the default)\n"
" -p, --path device/socket path (the default for virtio-serial is:\n"
@@ -272,8 +298,8 @@ QEMU_COPYRIGHT "\n"
" plug/unplug, etc.)\n"
" -h, --help display this help and exit\n"
"\n"
-QEMU_HELP_BOTTOM "\n"
- , cmd, QGA_VIRTIO_PATH_DEFAULT, QGA_SERIAL_PATH_DEFAULT,
+QEMU_HELP_BOTTOM "\n",
+ cmd, conf_path, QGA_VIRTIO_PATH_DEFAULT, QGA_SERIAL_PATH_DEFAULT,
dfl_pathnames.pidfile,
#ifdef CONFIG_FSFREEZE
fsfreeze_hook,
@@ -397,60 +423,79 @@ static gint ga_strcmp(gconstpointer str1, gconstpointer str2)
return strcmp(str1, str2);
}
-/* disable commands that aren't safe for fsfreeze */
-static void ga_disable_not_allowed_freeze(const QmpCommand *cmd, void *opaque)
+static bool ga_command_is_allowed(const QmpCommand *cmd, GAState *state)
{
- bool allowed = false;
int i = 0;
+ GAConfig *config = state->config;
const char *name = qmp_command_name(cmd);
+ /* Fallback policy is allow everything */
+ bool allowed = true;
+
+ if (config->allowedrpcs) {
+ /*
+ * If an allow-list is given, this changes the fallback
+ * policy to deny everything
+ */
+ allowed = false;
- while (ga_freeze_allowlist[i] != NULL) {
- if (strcmp(name, ga_freeze_allowlist[i]) == 0) {
+ if (g_list_find_custom(config->allowedrpcs, name, ga_strcmp) != NULL) {
allowed = true;
}
- i++;
}
- if (!allowed) {
- g_debug("disabling command: %s", name);
- qmp_disable_command(&ga_commands, name, "the agent is in frozen state");
- }
-}
-/* [re-]enable all commands, except those explicitly blocked by user */
-static void ga_enable_non_blocked(const QmpCommand *cmd, void *opaque)
-{
- GAState *s = opaque;
- GList *blockedrpcs = s->blockedrpcs;
- GList *allowedrpcs = s->allowedrpcs;
- const char *name = qmp_command_name(cmd);
-
- if (g_list_find_custom(blockedrpcs, name, ga_strcmp) == NULL) {
- if (qmp_command_is_enabled(cmd)) {
- return;
+ /*
+ * If both allowedrpcs and blockedrpcs are set, the blocked
+ * list will take priority
+ */
+ if (config->blockedrpcs) {
+ if (g_list_find_custom(config->blockedrpcs, name, ga_strcmp) != NULL) {
+ allowed = false;
}
+ }
- if (allowedrpcs &&
- g_list_find_custom(allowedrpcs, name, ga_strcmp) == NULL) {
- return;
- }
+ /*
+ * If frozen, this filtering must take priority over
+ * absolutely everything
+ */
+ if (state->frozen) {
+ allowed = false;
- g_debug("enabling command: %s", name);
- qmp_enable_command(&ga_commands, name);
+ while (ga_freeze_allowlist[i] != NULL) {
+ if (strcmp(name, ga_freeze_allowlist[i]) == 0) {
+ allowed = true;
+ }
+ i++;
+ }
}
+
+ return allowed;
}
-/* disable commands that aren't allowed */
-static void ga_disable_not_allowed(const QmpCommand *cmd, void *opaque)
+static void ga_apply_command_filters_iter(const QmpCommand *cmd, void *opaque)
{
- GList *allowedrpcs = opaque;
+ GAState *state = opaque;
+ bool want = ga_command_is_allowed(cmd, state);
+ bool have = qmp_command_is_enabled(cmd);
const char *name = qmp_command_name(cmd);
- if (g_list_find_custom(allowedrpcs, name, ga_strcmp) == NULL) {
+ if (want == have) {
+ return;
+ }
+
+ if (have) {
g_debug("disabling command: %s", name);
qmp_disable_command(&ga_commands, name, "the command is not allowed");
+ } else {
+ g_debug("enabling command: %s", name);
+ qmp_enable_command(&ga_commands, name);
}
}
+static void ga_apply_command_filters(GAState *state)
+{
+ qmp_for_each_command(&ga_commands, ga_apply_command_filters_iter, state);
+}
+
static bool ga_create_file(const char *path)
{
int fd = open(path, O_CREAT | O_WRONLY, S_IWUSR | S_IRUSR);
@@ -483,15 +528,14 @@ void ga_set_frozen(GAState *s)
if (ga_is_frozen(s)) {
return;
}
- /* disable all forbidden (for frozen state) commands */
- qmp_for_each_command(&ga_commands, ga_disable_not_allowed_freeze, NULL);
g_warning("disabling logging due to filesystem freeze");
- ga_disable_logging(s);
s->frozen = true;
if (!ga_create_file(s->state_filepath_isfrozen)) {
g_warning("unable to create %s, fsfreeze may not function properly",
s->state_filepath_isfrozen);
}
+ ga_apply_command_filters(s);
+ ga_disable_logging(s);
}
void ga_unset_frozen(GAState *s)
@@ -523,12 +567,12 @@ void ga_unset_frozen(GAState *s)
}
/* enable all disabled, non-blocked and allowed commands */
- qmp_for_each_command(&ga_commands, ga_enable_non_blocked, s);
s->frozen = false;
if (!ga_delete_file(s->state_filepath_isfrozen)) {
g_warning("unable to delete %s, fsfreeze may not function properly",
s->state_filepath_isfrozen);
}
+ ga_apply_command_filters(s);
}
#ifdef CONFIG_FSFREEZE
@@ -996,38 +1040,14 @@ static GList *split_list(const gchar *str, const gchar *delim)
return list;
}
-struct GAConfig {
- char *channel_path;
- char *method;
- char *log_filepath;
- char *pid_filepath;
-#ifdef CONFIG_FSFREEZE
- char *fsfreeze_hook;
-#endif
- char *state_dir;
-#ifdef _WIN32
- const char *service;
-#endif
- gchar *bliststr; /* blockedrpcs may point to this string */
- gchar *aliststr; /* allowedrpcs may point to this string */
- GList *blockedrpcs;
- GList *allowedrpcs;
- int daemonize;
- GLogLevelFlags log_level;
- int dumpconf;
- bool retry_path;
-};
-
-static void config_load(GAConfig *config)
+static void config_load(GAConfig *config, const char *confpath, bool required)
{
GError *gerr = NULL;
GKeyFile *keyfile;
- g_autofree char *conf = g_strdup(g_getenv("QGA_CONF")) ?: get_relocated_path(QGA_CONF_DEFAULT);
- const gchar *blockrpcs_key = "block-rpcs";
/* read system config */
keyfile = g_key_file_new();
- if (!g_key_file_load_from_file(keyfile, conf, 0, &gerr)) {
+ if (!g_key_file_load_from_file(keyfile, confpath, 0, &gerr)) {
goto end;
}
if (g_key_file_has_key(keyfile, "general", "daemon", NULL)) {
@@ -1071,9 +1091,9 @@ static void config_load(GAConfig *config)
g_key_file_get_boolean(keyfile, "general", "retry-path", &gerr);
}
- if (g_key_file_has_key(keyfile, "general", blockrpcs_key, NULL)) {
+ if (g_key_file_has_key(keyfile, "general", "block-rpcs", NULL)) {
config->bliststr =
- g_key_file_get_string(keyfile, "general", blockrpcs_key, &gerr);
+ g_key_file_get_string(keyfile, "general", "block-rpcs", &gerr);
config->blockedrpcs = g_list_concat(config->blockedrpcs,
split_list(config->bliststr, ","));
}
@@ -1084,19 +1104,12 @@ static void config_load(GAConfig *config)
split_list(config->aliststr, ","));
}
- if (g_key_file_has_key(keyfile, "general", blockrpcs_key, NULL) &&
- g_key_file_has_key(keyfile, "general", "allow-rpcs", NULL)) {
- g_critical("wrong config, using 'block-rpcs' and 'allow-rpcs' keys at"
- " the same time is not allowed");
- exit(EXIT_FAILURE);
- }
-
end:
g_key_file_free(keyfile);
- if (gerr &&
- !(gerr->domain == G_FILE_ERROR && gerr->code == G_FILE_ERROR_NOENT)) {
+ if (gerr && (required ||
+ !(gerr->domain == G_FILE_ERROR && gerr->code == G_FILE_ERROR_NOENT))) {
g_critical("error loading configuration from path: %s, %s",
- conf, gerr->message);
+ confpath, gerr->message);
exit(EXIT_FAILURE);
}
g_clear_error(&gerr);
@@ -1168,12 +1181,12 @@ static void config_dump(GAConfig *config)
static void config_parse(GAConfig *config, int argc, char **argv)
{
- const char *sopt = "hVvdm:p:l:f:F::b:a:s:t:Dr";
+ const char *sopt = "hVvdc:m:p:l:f:F::b:a:s:t:Dr";
int opt_ind = 0, ch;
- bool block_rpcs = false, allow_rpcs = false;
const struct option lopt[] = {
{ "help", 0, NULL, 'h' },
{ "version", 0, NULL, 'V' },
+ { "config", 1, NULL, 'c' },
{ "dump-conf", 0, NULL, 'D' },
{ "logfile", 1, NULL, 'l' },
{ "pidfile", 1, NULL, 'f' },
@@ -1193,6 +1206,26 @@ static void config_parse(GAConfig *config, int argc, char **argv)
{ "retry-path", 0, NULL, 'r' },
{ NULL, 0, NULL, 0 }
};
+ g_autofree char *confpath = g_strdup(g_getenv("QGA_CONF")) ?:
+ get_relocated_path(QGA_CONF_DEFAULT);
+ bool confrequired = false;
+
+ while ((ch = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
+ switch (ch) {
+ case 'c':
+ g_free(confpath);
+ confpath = g_strdup(optarg);
+ confrequired = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ config_load(config, confpath, confrequired);
+
+ /* Reset for second pass */
+ optind = 1;
while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
switch (ch) {
@@ -1245,7 +1278,6 @@ static void config_parse(GAConfig *config, int argc, char **argv)
}
config->blockedrpcs = g_list_concat(config->blockedrpcs,
split_list(optarg, ","));
- block_rpcs = true;
break;
}
case 'a': {
@@ -1255,7 +1287,6 @@ static void config_parse(GAConfig *config, int argc, char **argv)
}
config->allowedrpcs = g_list_concat(config->allowedrpcs,
split_list(optarg, ","));
- allow_rpcs = true;
break;
}
#ifdef _WIN32
@@ -1296,12 +1327,6 @@ static void config_parse(GAConfig *config, int argc, char **argv)
exit(EXIT_FAILURE);
}
}
-
- if (block_rpcs && allow_rpcs) {
- g_critical("wrong commandline, using --block-rpcs and --allow-rpcs at the"
- " same time is not allowed");
- exit(EXIT_FAILURE);
- }
}
static void config_free(GAConfig *config)
@@ -1395,6 +1420,10 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
" '%s': %s", config->state_dir, strerror(errno));
return NULL;
}
+
+ if (!vss_init(true)) {
+ g_debug("vss_init failed, vss commands will not function");
+ }
#endif
if (ga_is_frozen(s)) {
@@ -1408,7 +1437,6 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
s->deferred_options.log_filepath = config->log_filepath;
}
ga_disable_logging(s);
- qmp_for_each_command(&ga_commands, ga_disable_not_allowed_freeze, NULL);
} else {
if (config->daemonize) {
become_daemon(config->pid_filepath);
@@ -1432,25 +1460,6 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
return NULL;
}
- if (config->allowedrpcs) {
- qmp_for_each_command(&ga_commands, ga_disable_not_allowed, config->allowedrpcs);
- s->allowedrpcs = config->allowedrpcs;
- }
-
- /*
- * Some commands can be blocked due to system limitation.
- * Initialize blockedrpcs list even if allowedrpcs specified.
- */
- config->blockedrpcs = ga_command_init_blockedrpcs(config->blockedrpcs);
- if (config->blockedrpcs) {
- GList *l = config->blockedrpcs;
- s->blockedrpcs = config->blockedrpcs;
- do {
- g_debug("disabling command: %s", (char *)l->data);
- qmp_disable_command(&ga_commands, l->data, NULL);
- l = g_list_next(l);
- } while (l);
- }
s->command_state = ga_command_state_new();
ga_command_state_init(s, s->command_state);
ga_command_state_init_all(s->command_state);
@@ -1476,6 +1485,8 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
}
#endif
+ ga_apply_command_filters(s);
+
ga_state = s;
return s;
}
@@ -1579,7 +1590,6 @@ int main(int argc, char **argv)
qga_qmp_init_marshal(&ga_commands);
init_dfl_pathnames();
- config_load(config);
config_parse(config, argc, argv);
if (config->pid_filepath == NULL) {
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 1273d85..0537bb7 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -2,15 +2,6 @@
# vim: filetype=python
##
-# = General note concerning the use of guest agent interfaces
-#
-# "unsupported" is a higher-level error than the errors that
-# individual commands might document. The caller should always be
-# prepared to receive QERR_UNSUPPORTED, even if the given command
-# doesn't specify it, or doesn't document any failure mode at all.
-##
-
-##
# = QEMU guest agent protocol commands and structs
##
@@ -412,7 +403,8 @@
# Since: 0.15.0
##
{ 'enum': 'GuestFsfreezeStatus',
- 'data': [ 'thawed', 'frozen' ] }
+ 'data': [ 'thawed', 'frozen' ],
+ 'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSFREEZE'] } }
##
# @guest-fsfreeze-status:
@@ -429,7 +421,8 @@
# Since: 0.15.0
##
{ 'command': 'guest-fsfreeze-status',
- 'returns': 'GuestFsfreezeStatus' }
+ 'returns': 'GuestFsfreezeStatus',
+ 'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSFREEZE'] } }
##
# @guest-fsfreeze-freeze:
@@ -451,7 +444,8 @@
# Since: 0.15.0
##
{ 'command': 'guest-fsfreeze-freeze',
- 'returns': 'int' }
+ 'returns': 'int',
+ 'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSFREEZE'] } }
##
# @guest-fsfreeze-freeze-list:
@@ -471,7 +465,8 @@
##
{ 'command': 'guest-fsfreeze-freeze-list',
'data': { '*mountpoints': ['str'] },
- 'returns': 'int' }
+ 'returns': 'int',
+ 'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSFREEZE'] } }
##
# @guest-fsfreeze-thaw:
@@ -488,7 +483,8 @@
# Since: 0.15.0
##
{ 'command': 'guest-fsfreeze-thaw',
- 'returns': 'int' }
+ 'returns': 'int',
+ 'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSFREEZE'] } }
##
# @GuestFilesystemTrimResult:
@@ -505,7 +501,8 @@
##
{ 'struct': 'GuestFilesystemTrimResult',
'data': {'path': 'str',
- '*trimmed': 'int', '*minimum': 'int', '*error': 'str'} }
+ '*trimmed': 'int', '*minimum': 'int', '*error': 'str'},
+ 'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSTRIM'] } }
##
# @GuestFilesystemTrimResponse:
@@ -515,7 +512,8 @@
# Since: 2.4
##
{ 'struct': 'GuestFilesystemTrimResponse',
- 'data': {'paths': ['GuestFilesystemTrimResult']} }
+ 'data': {'paths': ['GuestFilesystemTrimResult']},
+ 'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSTRIM'] } }
##
# @guest-fstrim:
@@ -537,7 +535,8 @@
##
{ 'command': 'guest-fstrim',
'data': { '*minimum': 'int' },
- 'returns': 'GuestFilesystemTrimResponse' }
+ 'returns': 'GuestFilesystemTrimResponse',
+ 'if': { 'any': ['CONFIG_WIN32', 'CONFIG_FSTRIM'] } }
##
# @guest-suspend-disk:
@@ -566,7 +565,8 @@
#
# Since: 1.1
##
-{ 'command': 'guest-suspend-disk', 'success-response': false }
+{ 'command': 'guest-suspend-disk', 'success-response': false,
+ 'if': { 'any': ['CONFIG_LINUX', 'CONFIG_WIN32'] } }
##
# @guest-suspend-ram:
@@ -602,7 +602,8 @@
#
# Since: 1.1
##
-{ 'command': 'guest-suspend-ram', 'success-response': false }
+{ 'command': 'guest-suspend-ram', 'success-response': false,
+ 'if': { 'any': ['CONFIG_LINUX', 'CONFIG_WIN32'] } }
##
# @guest-suspend-hybrid:
@@ -637,7 +638,8 @@
#
# Since: 1.1
##
-{ 'command': 'guest-suspend-hybrid', 'success-response': false }
+{ 'command': 'guest-suspend-hybrid', 'success-response': false,
+ 'if': 'CONFIG_LINUX' }
##
# @GuestIpAddressType:
@@ -651,7 +653,8 @@
# Since: 1.1
##
{ 'enum': 'GuestIpAddressType',
- 'data': [ 'ipv4', 'ipv6' ] }
+ 'data': [ 'ipv4', 'ipv6' ],
+ 'if': { 'any': ['CONFIG_WIN32', 'HAVE_GETIFADDRS'] } }
##
# @GuestIpAddress:
@@ -667,7 +670,8 @@
{ 'struct': 'GuestIpAddress',
'data': {'ip-address': 'str',
'ip-address-type': 'GuestIpAddressType',
- 'prefix': 'int'} }
+ 'prefix': 'int'},
+ 'if': { 'any': ['CONFIG_WIN32', 'HAVE_GETIFADDRS'] } }
##
# @GuestNetworkInterfaceStat:
@@ -699,7 +703,8 @@
'tx-packets': 'uint64',
'tx-errs': 'uint64',
'tx-dropped': 'uint64'
- } }
+ },
+ 'if': { 'any': ['CONFIG_WIN32', 'HAVE_GETIFADDRS'] } }
##
# @GuestNetworkInterface:
@@ -719,7 +724,8 @@
'data': {'name': 'str',
'*hardware-address': 'str',
'*ip-addresses': ['GuestIpAddress'],
- '*statistics': 'GuestNetworkInterfaceStat' } }
+ '*statistics': 'GuestNetworkInterfaceStat' },
+ 'if': { 'any': ['CONFIG_WIN32', 'HAVE_GETIFADDRS'] } }
##
# @guest-network-get-interfaces:
@@ -731,7 +737,8 @@
# Since: 1.1
##
{ 'command': 'guest-network-get-interfaces',
- 'returns': ['GuestNetworkInterface'] }
+ 'returns': ['GuestNetworkInterface'],
+ 'if': { 'any': ['CONFIG_WIN32', 'HAVE_GETIFADDRS'] } }
##
# @GuestLogicalProcessor:
@@ -750,7 +757,8 @@
{ 'struct': 'GuestLogicalProcessor',
'data': {'logical-id': 'int',
'online': 'bool',
- '*can-offline': 'bool'} }
+ '*can-offline': 'bool'},
+ 'if': { 'any': ['CONFIG_LINUX', 'CONFIG_WIN32'] } }
##
# @guest-get-vcpus:
@@ -765,7 +773,8 @@
# Since: 1.5
##
{ 'command': 'guest-get-vcpus',
- 'returns': ['GuestLogicalProcessor'] }
+ 'returns': ['GuestLogicalProcessor'],
+ 'if': { 'any': ['CONFIG_LINUX', 'CONFIG_WIN32'] } }
##
# @guest-set-vcpus:
@@ -807,7 +816,8 @@
##
{ 'command': 'guest-set-vcpus',
'data': {'vcpus': ['GuestLogicalProcessor'] },
- 'returns': 'int' }
+ 'returns': 'int',
+ 'if': 'CONFIG_LINUX' }
##
# @GuestDiskBusType:
@@ -859,7 +869,8 @@
{ 'enum': 'GuestDiskBusType',
'data': [ 'ide', 'fdc', 'scsi', 'virtio', 'xen', 'usb', 'uml', 'sata',
'sd', 'unknown', 'ieee1394', 'ssa', 'fibre', 'raid', 'iscsi',
- 'sas', 'mmc', 'virtual', 'file-backed-virtual', 'nvme' ] }
+ 'sas', 'mmc', 'virtual', 'file-backed-virtual', 'nvme' ],
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
##
@@ -877,7 +888,8 @@
##
{ 'struct': 'GuestPCIAddress',
'data': {'domain': 'int', 'bus': 'int',
- 'slot': 'int', 'function': 'int'} }
+ 'slot': 'int', 'function': 'int'},
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
##
# @GuestCCWAddress:
@@ -896,7 +908,8 @@
'data': {'cssid': 'int',
'ssid': 'int',
'subchno': 'int',
- 'devno': 'int'} }
+ 'devno': 'int'},
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
##
# @GuestDiskAddress:
@@ -925,7 +938,8 @@
'bus-type': 'GuestDiskBusType',
'bus': 'int', 'target': 'int', 'unit': 'int',
'*serial': 'str', '*dev': 'str',
- '*ccw-address': 'GuestCCWAddress'} }
+ '*ccw-address': 'GuestCCWAddress'},
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
##
# @GuestNVMeSmart:
@@ -962,7 +976,8 @@
'media-errors-lo': 'uint64',
'media-errors-hi': 'uint64',
'number-of-error-log-entries-lo': 'uint64',
- 'number-of-error-log-entries-hi': 'uint64' } }
+ 'number-of-error-log-entries-hi': 'uint64' },
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LIBUDEV' ] } }
##
# @GuestDiskSmart:
@@ -976,7 +991,8 @@
{ 'union': 'GuestDiskSmart',
'base': { 'type': 'GuestDiskBusType' },
'discriminator': 'type',
- 'data': { 'nvme': 'GuestNVMeSmart' } }
+ 'data': { 'nvme': 'GuestNVMeSmart' },
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LIBUDEV' ] } }
##
# @GuestDiskInfo:
@@ -1001,7 +1017,8 @@
{ 'struct': 'GuestDiskInfo',
'data': {'name': 'str', 'partition': 'bool', '*dependencies': ['str'],
'*address': 'GuestDiskAddress', '*alias': 'str',
- '*smart': 'GuestDiskSmart'} }
+ '*smart': 'GuestDiskSmart'},
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LIBUDEV' ] } }
##
# @guest-get-disks:
@@ -1014,7 +1031,8 @@
# Since: 5.2
##
{ 'command': 'guest-get-disks',
- 'returns': ['GuestDiskInfo'] }
+ 'returns': ['GuestDiskInfo'],
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LIBUDEV' ] } }
##
# @GuestFilesystemInfo:
@@ -1040,7 +1058,8 @@
{ 'struct': 'GuestFilesystemInfo',
'data': {'name': 'str', 'mountpoint': 'str', 'type': 'str',
'*used-bytes': 'uint64', '*total-bytes': 'uint64',
- '*total-bytes-privileged': 'uint64', 'disk': ['GuestDiskAddress']} }
+ '*total-bytes-privileged': 'uint64', 'disk': ['GuestDiskAddress']},
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
##
# @guest-get-fsinfo:
@@ -1053,7 +1072,8 @@
# Since: 2.2
##
{ 'command': 'guest-get-fsinfo',
- 'returns': ['GuestFilesystemInfo'] }
+ 'returns': ['GuestFilesystemInfo'],
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX' ] } }
##
# @guest-set-user-password:
@@ -1080,7 +1100,8 @@
# Since: 2.3
##
{ 'command': 'guest-set-user-password',
- 'data': { 'username': 'str', 'password': 'str', 'crypted': 'bool' } }
+ 'data': { 'username': 'str', 'password': 'str', 'crypted': 'bool' },
+ 'if': { 'any': [ 'CONFIG_WIN32', 'CONFIG_LINUX', 'CONFIG_FREEBSD'] } }
##
# @GuestMemoryBlock:
@@ -1100,7 +1121,8 @@
{ 'struct': 'GuestMemoryBlock',
'data': {'phys-index': 'uint64',
'online': 'bool',
- '*can-offline': 'bool'} }
+ '*can-offline': 'bool'},
+ 'if': 'CONFIG_LINUX' }
##
# @guest-get-memory-blocks:
@@ -1116,7 +1138,8 @@
# Since: 2.3
##
{ 'command': 'guest-get-memory-blocks',
- 'returns': ['GuestMemoryBlock'] }
+ 'returns': ['GuestMemoryBlock'],
+ 'if': 'CONFIG_LINUX' }
##
# @GuestMemoryBlockResponseType:
@@ -1139,7 +1162,8 @@
##
{ 'enum': 'GuestMemoryBlockResponseType',
'data': ['success', 'not-found', 'operation-not-supported',
- 'operation-failed'] }
+ 'operation-failed'],
+ 'if': 'CONFIG_LINUX' }
##
# @GuestMemoryBlockResponse:
@@ -1157,7 +1181,8 @@
{ 'struct': 'GuestMemoryBlockResponse',
'data': { 'phys-index': 'uint64',
'response': 'GuestMemoryBlockResponseType',
- '*error-code': 'int' }}
+ '*error-code': 'int' },
+ 'if': 'CONFIG_LINUX'}
##
# @guest-set-memory-blocks:
@@ -1188,7 +1213,8 @@
##
{ 'command': 'guest-set-memory-blocks',
'data': {'mem-blks': ['GuestMemoryBlock'] },
- 'returns': ['GuestMemoryBlockResponse'] }
+ 'returns': ['GuestMemoryBlockResponse'],
+ 'if': 'CONFIG_LINUX' }
##
# @GuestMemoryBlockInfo:
@@ -1200,7 +1226,8 @@
# Since: 2.3
##
{ 'struct': 'GuestMemoryBlockInfo',
- 'data': {'size': 'uint64'} }
+ 'data': {'size': 'uint64'},
+ 'if': 'CONFIG_LINUX' }
##
# @guest-get-memory-block-info:
@@ -1212,7 +1239,8 @@
# Since: 2.3
##
{ 'command': 'guest-get-memory-block-info',
- 'returns': 'GuestMemoryBlockInfo' }
+ 'returns': 'GuestMemoryBlockInfo',
+ 'if': 'CONFIG_LINUX' }
##
# @GuestExecStatus:
@@ -1378,7 +1406,8 @@
# Since: 2.10
##
{ 'struct': 'GuestUser',
- 'data': { 'user': 'str', 'login-time': 'number', '*domain': 'str' } }
+ 'data': { 'user': 'str', 'login-time': 'number', '*domain': 'str' },
+ 'if': { 'any': ['CONFIG_WIN32', 'HAVE_UTMPX' ] } }
##
# @guest-get-users:
@@ -1390,7 +1419,8 @@
# Since: 2.10
##
{ 'command': 'guest-get-users',
- 'returns': ['GuestUser'] }
+ 'returns': ['GuestUser'],
+ 'if': { 'any': ['CONFIG_WIN32', 'HAVE_UTMPX' ] } }
##
# @GuestTimezone:
@@ -1499,7 +1529,8 @@
# @pci: PCI device
##
{ 'enum': 'GuestDeviceType',
- 'data': [ 'pci' ] }
+ 'data': [ 'pci' ],
+ 'if': 'CONFIG_WIN32' }
##
# @GuestDeviceIdPCI:
@@ -1511,7 +1542,8 @@
# Since: 5.2
##
{ 'struct': 'GuestDeviceIdPCI',
- 'data': { 'vendor-id': 'uint16', 'device-id': 'uint16' } }
+ 'data': { 'vendor-id': 'uint16', 'device-id': 'uint16' },
+ 'if': 'CONFIG_WIN32' }
##
# @GuestDeviceId:
@@ -1525,7 +1557,8 @@
{ 'union': 'GuestDeviceId',
'base': { 'type': 'GuestDeviceType' },
'discriminator': 'type',
- 'data': { 'pci': 'GuestDeviceIdPCI' } }
+ 'data': { 'pci': 'GuestDeviceIdPCI' },
+ 'if': 'CONFIG_WIN32' }
##
# @GuestDeviceInfo:
@@ -1546,7 +1579,8 @@
'*driver-date': 'int',
'*driver-version': 'str',
'*id': 'GuestDeviceId'
- } }
+ },
+ 'if': 'CONFIG_WIN32' }
##
# @guest-get-devices:
@@ -1558,7 +1592,8 @@
# Since: 5.2
##
{ 'command': 'guest-get-devices',
- 'returns': ['GuestDeviceInfo'] }
+ 'returns': ['GuestDeviceInfo'],
+ 'if': 'CONFIG_WIN32' }
##
# @GuestAuthorizedKeys:
@@ -1685,7 +1720,8 @@
'*ios-pgr': 'uint64',
'*total-ticks': 'uint64',
'*weight-ticks': 'uint64'
- } }
+ },
+ 'if': 'CONFIG_LINUX' }
##
# @GuestDiskStatsInfo:
@@ -1702,7 +1738,8 @@
'data': {'name': 'str',
'major': 'uint64',
'minor': 'uint64',
- 'stats': 'GuestDiskStats' } }
+ 'stats': 'GuestDiskStats' },
+ 'if': 'CONFIG_LINUX' }
##
# @guest-get-diskstats:
@@ -1714,7 +1751,8 @@
# Since: 7.1
##
{ 'command': 'guest-get-diskstats',
- 'returns': ['GuestDiskStatsInfo']
+ 'returns': ['GuestDiskStatsInfo'],
+ 'if': 'CONFIG_LINUX'
}
##
@@ -1727,7 +1765,8 @@
# Since: 7.1
##
{ 'enum': 'GuestCpuStatsType',
- 'data': [ 'linux' ] }
+ 'data': [ 'linux' ],
+ 'if': 'CONFIG_LINUX' }
##
@@ -1772,7 +1811,8 @@
'*steal': 'uint64',
'*guest': 'uint64',
'*guestnice': 'uint64'
- } }
+ },
+ 'if': 'CONFIG_LINUX' }
##
# @GuestCpuStats:
@@ -1786,7 +1826,8 @@
{ 'union': 'GuestCpuStats',
'base': { 'type': 'GuestCpuStatsType' },
'discriminator': 'type',
- 'data': { 'linux': 'GuestLinuxCpuStats' } }
+ 'data': { 'linux': 'GuestLinuxCpuStats' },
+ 'if': 'CONFIG_LINUX' }
##
# @guest-get-cpustats:
@@ -1798,5 +1839,79 @@
# Since: 7.1
##
{ 'command': 'guest-get-cpustats',
- 'returns': ['GuestCpuStats']
+ 'returns': ['GuestCpuStats'],
+ 'if': 'CONFIG_LINUX'
+}
+
+##
+# @GuestNetworkRoute:
+#
+# Route information, currently, only linux supported.
+#
+# @iface: The destination network or host's egress network interface in the routing table
+#
+# @destination: The IP address of the target network or host, The final destination of the packet
+#
+# @metric: Route metric
+#
+# @gateway: The IP address of the next hop router
+#
+# @mask: Subnet Mask (IPv4 only)
+#
+# @irtt: Initial round-trip delay (not for windows, IPv4 only)
+#
+# @flags: Route flags (not for windows)
+#
+# @refcnt: The route's reference count (not for windows)
+#
+# @use: Route usage count (not for windows)
+#
+# @window: TCP window size, used for flow control (not for windows, IPv4 only)
+#
+# @mtu: Data link layer maximum packet size (not for windows)
+#
+# @desprefixlen: Destination prefix length (for IPv6)
+#
+# @source: Source IP address (for IPv6)
+#
+# @srcprefixlen: Source prefix length (for IPv6)
+#
+# @nexthop: Next hop IP address (for IPv6)
+#
+# @version: IP version (4 or 6)
+#
+# Since: 9.1
+
+##
+{ 'struct': 'GuestNetworkRoute',
+ 'data': {'iface': 'str',
+ 'destination': 'str',
+ 'metric': 'int',
+ '*gateway': 'str',
+ '*mask': 'str',
+ '*irtt': 'int',
+ '*flags': 'uint64',
+ '*refcnt': 'int',
+ '*use': 'int',
+ '*window': 'int',
+ '*mtu': 'int',
+ '*desprefixlen': 'str',
+ '*source': 'str',
+ '*srcprefixlen': 'str',
+ '*nexthop': 'str',
+ 'version': 'int'
+ },
+ 'if': 'CONFIG_LINUX' }
+
+##
+# @guest-network-get-route:
+#
+# Retrieve information about route of network.
+# Returns: List of route info of guest.
+#
+# Since: 9.1
+##
+{ 'command': 'guest-network-get-route',
+ 'returns': ['GuestNetworkRoute'],
+ 'if': 'CONFIG_LINUX'
}
diff --git a/qobject/qlit.c b/qobject/qlit.c
index be83321..a62865b 100644
--- a/qobject/qlit.c
+++ b/qobject/qlit.c
@@ -118,7 +118,7 @@ QObject *qobject_from_qlit(const QLitObject *qlit)
case QTYPE_QBOOL:
return QOBJECT(qbool_from_bool(qlit->value.qbool));
default:
- assert(0);
+ g_assert_not_reached();
}
return NULL;
diff --git a/qobject/qnum.c b/qobject/qnum.c
index 2bbeaed..dd8ea49 100644
--- a/qobject/qnum.c
+++ b/qobject/qnum.c
@@ -85,8 +85,7 @@ bool qnum_get_try_int(const QNum *qn, int64_t *val)
return false;
}
- assert(0);
- return false;
+ g_assert_not_reached();
}
/**
@@ -123,8 +122,7 @@ bool qnum_get_try_uint(const QNum *qn, uint64_t *val)
return false;
}
- assert(0);
- return false;
+ g_assert_not_reached();
}
/**
@@ -156,8 +154,7 @@ double qnum_get_double(QNum *qn)
return qn->u.dbl;
}
- assert(0);
- return 0.0;
+ g_assert_not_reached();
}
char *qnum_to_string(QNum *qn)
@@ -172,8 +169,7 @@ char *qnum_to_string(QNum *qn)
return g_strdup_printf("%.17g", qn->u.dbl);
}
- assert(0);
- return NULL;
+ g_assert_not_reached();
}
/**
diff --git a/qom/object.c b/qom/object.c
index 157a45c..11424cf 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -2079,7 +2079,6 @@ const char *object_get_canonical_path_component(const Object *obj)
/* obj had a parent but was not a child, should never happen */
g_assert_not_reached();
- return NULL;
}
char *object_get_canonical_path(const Object *obj)
@@ -2185,7 +2184,7 @@ static Object *object_resolve_partial_path(Object *parent,
}
Object *object_resolve_path_type(const char *path, const char *typename,
- bool *ambiguousp)
+ bool *ambiguous)
{
Object *obj;
char **parts;
@@ -2194,14 +2193,17 @@ Object *object_resolve_path_type(const char *path, const char *typename,
assert(parts);
if (parts[0] == NULL || strcmp(parts[0], "") != 0) {
- bool ambiguous = false;
+ bool ambig = false;
obj = object_resolve_partial_path(object_get_root(), parts,
- typename, &ambiguous);
- if (ambiguousp) {
- *ambiguousp = ambiguous;
+ typename, &ambig);
+ if (ambiguous) {
+ *ambiguous = ambig;
}
} else {
obj = object_resolve_abs_path(object_get_root(), parts + 1, typename);
+ if (ambiguous) {
+ *ambiguous = false;
+ }
}
g_strfreev(parts);
@@ -2227,7 +2229,7 @@ Object *object_resolve_path_at(Object *parent, const char *path)
Object *object_resolve_type_unambiguous(const char *typename, Error **errp)
{
- bool ambig;
+ bool ambig = false;
Object *o = object_resolve_path_type("", typename, &ambig);
if (ambig) {
diff --git a/replay/replay-events.c b/replay/replay-events.c
index af0721c..2e46eda 100644
--- a/replay/replay-events.c
+++ b/replay/replay-events.c
@@ -92,15 +92,6 @@ void replay_flush_events(void)
}
}
-void replay_disable_events(void)
-{
- if (replay_mode != REPLAY_MODE_NONE) {
- events_enabled = false;
- /* Flush events queue before waiting of completion */
- replay_flush_events();
- }
-}
-
/*! Adds specified async event to the queue */
void replay_add_event(ReplayAsyncEventKind event_kind,
void *opaque,
diff --git a/replay/replay.c b/replay/replay.c
index a2c576c..895fa6b 100644
--- a/replay/replay.c
+++ b/replay/replay.c
@@ -385,6 +385,8 @@ static void replay_enable(const char *fname, int mode)
replay_fetch_data_kind();
}
+ runstate_replay_enable();
+
replay_init_events();
}
@@ -449,27 +451,6 @@ void replay_start(void)
replay_enable_events();
}
-/*
- * For none/record the answer is yes.
- */
-bool replay_can_wait(void)
-{
- if (replay_mode == REPLAY_MODE_PLAY) {
- /*
- * For playback we shouldn't ever be at a point we wait. If
- * the instruction count has reached zero and we have an
- * unconsumed event we should go around again and consume it.
- */
- if (replay_state.instruction_count == 0 && replay_state.has_unread_data) {
- return false;
- } else {
- replay_sync_error("Playback shouldn't have to iowait");
- }
- }
- return true;
-}
-
-
void replay_finish(void)
{
if (replay_mode == REPLAY_MODE_NONE) {
diff --git a/roms/edk2 b/roms/edk2
-Subproject edc6681206c1a8791981a2f911d2fb8b3d2f576
+Subproject b158dad150bf02879668f72ce30644525083820
diff --git a/roms/edk2-build.config b/roms/edk2-build.config
index cc9b211..9e45361 100644
--- a/roms/edk2-build.config
+++ b/roms/edk2-build.config
@@ -131,3 +131,16 @@ cpy1 = FV/RISCV_VIRT_CODE.fd edk2-riscv-code.fd
cpy2 = FV/RISCV_VIRT_VARS.fd edk2-riscv-vars.fd
pad1 = edk2-riscv-code.fd 32m
pad2 = edk2-riscv-vars.fd 32m
+
+####################################################################################
+# LoongArch64
+
+[build.loongarch64.qemu]
+conf = OvmfPkg/LoongArchVirt/LoongArchVirtQemu.dsc
+arch = LOONGARCH64
+plat = LoongArchVirtQemu
+dest = ../pc-bios
+cpy1 = FV/QEMU_EFI.fd edk2-loongarch64-code.fd
+pad1 = edk2-loongarch64-code.fd 16m
+cpy2 = FV/QEMU_VARS.fd edk2-loongarch64-vars.fd
+pad2 = edk2-loongarch64-vars.fd 16m
diff --git a/roms/edk2-version b/roms/edk2-version
index 1594ed8..069f19f 100644
--- a/roms/edk2-version
+++ b/roms/edk2-version
@@ -1,2 +1,2 @@
-EDK2_STABLE = edk2-stable202402
-EDK2_DATE = 02/14/2024
+EDK2_STABLE = edk2-stable202408
+EDK2_DATE = 08/13/2024
diff --git a/roms/openbios b/roms/openbios
-Subproject af97fd7af5e7c18f591a7b987291d3db4ffb28b
+Subproject c3a19c1e54977a53027d6232050e1e3e39a98a1
diff --git a/roms/opensbi b/roms/opensbi
-Subproject a2b255b88918715173942f2c5e1f97ac9e90c87
+Subproject 43cace6c3671e5172d0df0a8963e552bb04b7b2
diff --git a/rust/.gitignore b/rust/.gitignore
new file mode 100644
index 0000000..1bf71b1
--- /dev/null
+++ b/rust/.gitignore
@@ -0,0 +1,3 @@
+# Ignore any cargo development build artifacts; for qemu-wide builds, all build
+# artifacts will go to the meson build directory.
+target
diff --git a/rust/Kconfig b/rust/Kconfig
new file mode 100644
index 0000000..f9f5c39
--- /dev/null
+++ b/rust/Kconfig
@@ -0,0 +1 @@
+source hw/Kconfig
diff --git a/rust/hw/Kconfig b/rust/hw/Kconfig
new file mode 100644
index 0000000..4d934f3
--- /dev/null
+++ b/rust/hw/Kconfig
@@ -0,0 +1,2 @@
+# devices Kconfig
+source char/Kconfig
diff --git a/rust/hw/char/Kconfig b/rust/hw/char/Kconfig
new file mode 100644
index 0000000..a1732a9
--- /dev/null
+++ b/rust/hw/char/Kconfig
@@ -0,0 +1,3 @@
+config X_PL011_RUST
+ bool
+ default y if HAVE_RUST
diff --git a/rust/hw/char/meson.build b/rust/hw/char/meson.build
new file mode 100644
index 0000000..5716dc4
--- /dev/null
+++ b/rust/hw/char/meson.build
@@ -0,0 +1 @@
+subdir('pl011')
diff --git a/rust/hw/char/pl011/.gitignore b/rust/hw/char/pl011/.gitignore
new file mode 100644
index 0000000..71eaff2
--- /dev/null
+++ b/rust/hw/char/pl011/.gitignore
@@ -0,0 +1,2 @@
+# Ignore generated bindings file overrides.
+src/bindings.rs.inc
diff --git a/rust/hw/char/pl011/Cargo.lock b/rust/hw/char/pl011/Cargo.lock
new file mode 100644
index 0000000..b58cebb
--- /dev/null
+++ b/rust/hw/char/pl011/Cargo.lock
@@ -0,0 +1,134 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "arbitrary-int"
+version = "1.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c84fc003e338a6f69fbd4f7fe9f92b535ff13e9af8997f3b14b6ddff8b1df46d"
+
+[[package]]
+name = "bilge"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc707ed8ebf81de5cd6c7f48f54b4c8621760926cdf35a57000747c512e67b57"
+dependencies = [
+ "arbitrary-int",
+ "bilge-impl",
+]
+
+[[package]]
+name = "bilge-impl"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "feb11e002038ad243af39c2068c8a72bcf147acf05025dcdb916fcc000adb2d8"
+dependencies = [
+ "itertools",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "either"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
+
+[[package]]
+name = "itertools"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "pl011"
+version = "0.1.0"
+dependencies = [
+ "bilge",
+ "bilge-impl",
+ "qemu_api",
+ "qemu_api_macros",
+]
+
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.84"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "qemu_api"
+version = "0.1.0"
+
+[[package]]
+name = "qemu_api_macros"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.66"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
diff --git a/rust/hw/char/pl011/Cargo.toml b/rust/hw/char/pl011/Cargo.toml
new file mode 100644
index 0000000..b089e3d
--- /dev/null
+++ b/rust/hw/char/pl011/Cargo.toml
@@ -0,0 +1,26 @@
+[package]
+name = "pl011"
+version = "0.1.0"
+edition = "2021"
+authors = ["Manos Pitsidianakis <manos.pitsidianakis@linaro.org>"]
+license = "GPL-2.0-or-later"
+readme = "README.md"
+homepage = "https://www.qemu.org"
+description = "pl011 device model for QEMU"
+repository = "https://gitlab.com/epilys/rust-for-qemu"
+resolver = "2"
+publish = false
+keywords = []
+categories = []
+
+[lib]
+crate-type = ["staticlib"]
+
+[dependencies]
+bilge = { version = "0.2.0" }
+bilge-impl = { version = "0.2.0" }
+qemu_api = { path = "../../../qemu-api" }
+qemu_api_macros = { path = "../../../qemu-api-macros" }
+
+# Do not include in any global workspace
+[workspace]
diff --git a/rust/hw/char/pl011/README.md b/rust/hw/char/pl011/README.md
new file mode 100644
index 0000000..cd7dea3
--- /dev/null
+++ b/rust/hw/char/pl011/README.md
@@ -0,0 +1,31 @@
+# PL011 QEMU Device Model
+
+This library implements a device model for the PrimeCellĀ® UART (PL011)
+device in QEMU.
+
+## Build static lib
+
+Host build target must be explicitly specified:
+
+```sh
+cargo build --target x86_64-unknown-linux-gnu
+```
+
+Replace host target triplet if necessary.
+
+## Generate Rust documentation
+
+To generate docs for this crate, including private items:
+
+```sh
+cargo doc --no-deps --document-private-items --target x86_64-unknown-linux-gnu
+```
+
+To include direct dependencies like `bilge` (bitmaps for register types):
+
+```sh
+cargo tree --depth 1 -e normal --prefix none \
+ | cut -d' ' -f1 \
+ | xargs printf -- '-p %s\n' \
+ | xargs cargo doc --no-deps --document-private-items --target x86_64-unknown-linux-gnu
+```
diff --git a/rust/hw/char/pl011/meson.build b/rust/hw/char/pl011/meson.build
new file mode 100644
index 0000000..547cca5
--- /dev/null
+++ b/rust/hw/char/pl011/meson.build
@@ -0,0 +1,26 @@
+subproject('bilge-0.2-rs', required: true)
+subproject('bilge-impl-0.2-rs', required: true)
+
+bilge_dep = dependency('bilge-0.2-rs')
+bilge_impl_dep = dependency('bilge-impl-0.2-rs')
+
+_libpl011_rs = static_library(
+ 'pl011',
+ files('src/lib.rs'),
+ override_options: ['rust_std=2021', 'build.rust_std=2021'],
+ rust_abi: 'rust',
+ dependencies: [
+ bilge_dep,
+ bilge_impl_dep,
+ qemu_api,
+ qemu_api_macros,
+ ],
+)
+
+rust_devices_ss.add(when: 'CONFIG_X_PL011_RUST', if_true: [declare_dependency(
+ link_whole: [_libpl011_rs],
+ # Putting proc macro crates in `dependencies` is necessary for Meson to find
+ # them when compiling the root per-target static rust lib.
+ dependencies: [bilge_impl_dep, qemu_api_macros],
+ variables: {'crate': 'pl011'},
+)])
diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs
new file mode 100644
index 0000000..c7193b4
--- /dev/null
+++ b/rust/hw/char/pl011/src/device.rs
@@ -0,0 +1,599 @@
+// Copyright 2024, Linaro Limited
+// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+use core::{
+ ffi::{c_int, c_uchar, c_uint, c_void, CStr},
+ ptr::{addr_of, addr_of_mut, NonNull},
+};
+
+use qemu_api::{
+ bindings::{self, *},
+ definitions::ObjectImpl,
+};
+
+use crate::{
+ memory_ops::PL011_OPS,
+ registers::{self, Interrupt},
+ RegisterOffset,
+};
+
+static PL011_ID_ARM: [c_uchar; 8] = [0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1];
+
+const DATA_BREAK: u32 = 1 << 10;
+
+/// QEMU sourced constant.
+pub const PL011_FIFO_DEPTH: usize = 16_usize;
+
+#[repr(C)]
+#[derive(Debug, qemu_api_macros::Object)]
+/// PL011 Device Model in QEMU
+pub struct PL011State {
+ pub parent_obj: SysBusDevice,
+ pub iomem: MemoryRegion,
+ #[doc(alias = "fr")]
+ pub flags: registers::Flags,
+ #[doc(alias = "lcr")]
+ pub line_control: registers::LineControl,
+ #[doc(alias = "rsr")]
+ pub receive_status_error_clear: registers::ReceiveStatusErrorClear,
+ #[doc(alias = "cr")]
+ pub control: registers::Control,
+ pub dmacr: u32,
+ pub int_enabled: u32,
+ pub int_level: u32,
+ pub read_fifo: [u32; PL011_FIFO_DEPTH],
+ pub ilpr: u32,
+ pub ibrd: u32,
+ pub fbrd: u32,
+ pub ifl: u32,
+ pub read_pos: usize,
+ pub read_count: usize,
+ pub read_trigger: usize,
+ #[doc(alias = "chr")]
+ pub char_backend: CharBackend,
+ /// QEMU interrupts
+ ///
+ /// ```text
+ /// * sysbus MMIO region 0: device registers
+ /// * sysbus IRQ 0: `UARTINTR` (combined interrupt line)
+ /// * sysbus IRQ 1: `UARTRXINTR` (receive FIFO interrupt line)
+ /// * sysbus IRQ 2: `UARTTXINTR` (transmit FIFO interrupt line)
+ /// * sysbus IRQ 3: `UARTRTINTR` (receive timeout interrupt line)
+ /// * sysbus IRQ 4: `UARTMSINTR` (momem status interrupt line)
+ /// * sysbus IRQ 5: `UARTEINTR` (error interrupt line)
+ /// ```
+ #[doc(alias = "irq")]
+ pub interrupts: [qemu_irq; 6usize],
+ #[doc(alias = "clk")]
+ pub clock: NonNull<Clock>,
+ #[doc(alias = "migrate_clk")]
+ pub migrate_clock: bool,
+}
+
+impl ObjectImpl for PL011State {
+ type Class = PL011Class;
+ const TYPE_INFO: qemu_api::bindings::TypeInfo = qemu_api::type_info! { Self };
+ const TYPE_NAME: &'static CStr = crate::TYPE_PL011;
+ const PARENT_TYPE_NAME: Option<&'static CStr> = Some(TYPE_SYS_BUS_DEVICE);
+ const ABSTRACT: bool = false;
+ const INSTANCE_INIT: Option<unsafe extern "C" fn(obj: *mut Object)> = Some(pl011_init);
+ const INSTANCE_POST_INIT: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
+ const INSTANCE_FINALIZE: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
+}
+
+#[repr(C)]
+pub struct PL011Class {
+ _inner: [u8; 0],
+}
+
+impl qemu_api::definitions::Class for PL011Class {
+ const CLASS_INIT: Option<
+ unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut core::ffi::c_void),
+ > = Some(crate::device_class::pl011_class_init);
+ const CLASS_BASE_INIT: Option<
+ unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut core::ffi::c_void),
+ > = None;
+}
+
+#[used]
+pub static CLK_NAME: &CStr = c"clk";
+
+impl PL011State {
+ /// Initializes a pre-allocated, unitialized instance of `PL011State`.
+ ///
+ /// # Safety
+ ///
+ /// `self` must point to a correctly sized and aligned location for the
+ /// `PL011State` type. It must not be called more than once on the same
+ /// location/instance. All its fields are expected to hold unitialized
+ /// values with the sole exception of `parent_obj`.
+ pub unsafe fn init(&mut self) {
+ let dev = addr_of_mut!(*self).cast::<DeviceState>();
+ // SAFETY:
+ //
+ // self and self.iomem are guaranteed to be valid at this point since callers
+ // must make sure the `self` reference is valid.
+ unsafe {
+ memory_region_init_io(
+ addr_of_mut!(self.iomem),
+ addr_of_mut!(*self).cast::<Object>(),
+ &PL011_OPS,
+ addr_of_mut!(*self).cast::<c_void>(),
+ Self::TYPE_INFO.name,
+ 0x1000,
+ );
+ let sbd = addr_of_mut!(*self).cast::<SysBusDevice>();
+ sysbus_init_mmio(sbd, addr_of_mut!(self.iomem));
+ for irq in self.interrupts.iter_mut() {
+ sysbus_init_irq(sbd, irq);
+ }
+ }
+ // SAFETY:
+ //
+ // self.clock is not initialized at this point; but since `NonNull<_>` is Copy,
+ // we can overwrite the undefined value without side effects. This is
+ // safe since all PL011State instances are created by QOM code which
+ // calls this function to initialize the fields; therefore no code is
+ // able to access an invalid self.clock value.
+ unsafe {
+ self.clock = NonNull::new(qdev_init_clock_in(
+ dev,
+ CLK_NAME.as_ptr(),
+ None, /* pl011_clock_update */
+ addr_of_mut!(*self).cast::<c_void>(),
+ ClockEvent::ClockUpdate.0,
+ ))
+ .unwrap();
+ }
+ }
+
+ pub fn read(
+ &mut self,
+ offset: hwaddr,
+ _size: core::ffi::c_uint,
+ ) -> std::ops::ControlFlow<u64, u64> {
+ use RegisterOffset::*;
+
+ std::ops::ControlFlow::Break(match RegisterOffset::try_from(offset) {
+ Err(v) if (0x3f8..0x400).contains(&v) => {
+ u64::from(PL011_ID_ARM[((offset - 0xfe0) >> 2) as usize])
+ }
+ Err(_) => {
+ // qemu_log_mask(LOG_GUEST_ERROR, "pl011_read: Bad offset 0x%x\n", (int)offset);
+ 0
+ }
+ Ok(DR) => {
+ // s->flags &= ~PL011_FLAG_RXFF;
+ self.flags.set_receive_fifo_full(false);
+ let c = self.read_fifo[self.read_pos];
+ if self.read_count > 0 {
+ self.read_count -= 1;
+ self.read_pos = (self.read_pos + 1) & (self.fifo_depth() - 1);
+ }
+ if self.read_count == 0 {
+ // self.flags |= PL011_FLAG_RXFE;
+ self.flags.set_receive_fifo_empty(true);
+ }
+ if self.read_count + 1 == self.read_trigger {
+ //self.int_level &= ~ INT_RX;
+ self.int_level &= !registers::INT_RX;
+ }
+ // Update error bits.
+ self.receive_status_error_clear = c.to_be_bytes()[3].into();
+ self.update();
+ // Must call qemu_chr_fe_accept_input, so return Continue:
+ return std::ops::ControlFlow::Continue(c.into());
+ }
+ Ok(RSR) => u8::from(self.receive_status_error_clear).into(),
+ Ok(FR) => u16::from(self.flags).into(),
+ Ok(FBRD) => self.fbrd.into(),
+ Ok(ILPR) => self.ilpr.into(),
+ Ok(IBRD) => self.ibrd.into(),
+ Ok(LCR_H) => u16::from(self.line_control).into(),
+ Ok(CR) => {
+ // We exercise our self-control.
+ u16::from(self.control).into()
+ }
+ Ok(FLS) => self.ifl.into(),
+ Ok(IMSC) => self.int_enabled.into(),
+ Ok(RIS) => self.int_level.into(),
+ Ok(MIS) => u64::from(self.int_level & self.int_enabled),
+ Ok(ICR) => {
+ // "The UARTICR Register is the interrupt clear register and is write-only"
+ // Source: ARM DDI 0183G 3.3.13 Interrupt Clear Register, UARTICR
+ 0
+ }
+ Ok(DMACR) => self.dmacr.into(),
+ })
+ }
+
+ pub fn write(&mut self, offset: hwaddr, value: u64) {
+ // eprintln!("write offset {offset} value {value}");
+ use RegisterOffset::*;
+ let value: u32 = value as u32;
+ match RegisterOffset::try_from(offset) {
+ Err(_bad_offset) => {
+ eprintln!("write bad offset {offset} value {value}");
+ }
+ Ok(DR) => {
+ // ??? Check if transmitter is enabled.
+ let ch: u8 = value as u8;
+ // XXX this blocks entire thread. Rewrite to use
+ // qemu_chr_fe_write and background I/O callbacks
+
+ // SAFETY: self.char_backend is a valid CharBackend instance after it's been
+ // initialized in realize().
+ unsafe {
+ qemu_chr_fe_write_all(addr_of_mut!(self.char_backend), &ch, 1);
+ }
+ self.loopback_tx(value);
+ self.int_level |= registers::INT_TX;
+ self.update();
+ }
+ Ok(RSR) => {
+ self.receive_status_error_clear = 0.into();
+ }
+ Ok(FR) => {
+ // flag writes are ignored
+ }
+ Ok(ILPR) => {
+ self.ilpr = value;
+ }
+ Ok(IBRD) => {
+ self.ibrd = value;
+ }
+ Ok(FBRD) => {
+ self.fbrd = value;
+ }
+ Ok(LCR_H) => {
+ let value = value as u16;
+ let new_val: registers::LineControl = value.into();
+ // Reset the FIFO state on FIFO enable or disable
+ if bool::from(self.line_control.fifos_enabled())
+ ^ bool::from(new_val.fifos_enabled())
+ {
+ self.reset_fifo();
+ }
+ if self.line_control.send_break() ^ new_val.send_break() {
+ let mut break_enable: c_int = new_val.send_break().into();
+ // SAFETY: self.char_backend is a valid CharBackend instance after it's been
+ // initialized in realize().
+ unsafe {
+ qemu_chr_fe_ioctl(
+ addr_of_mut!(self.char_backend),
+ CHR_IOCTL_SERIAL_SET_BREAK as i32,
+ addr_of_mut!(break_enable).cast::<c_void>(),
+ );
+ }
+ self.loopback_break(break_enable > 0);
+ }
+ self.line_control = new_val;
+ self.set_read_trigger();
+ }
+ Ok(CR) => {
+ // ??? Need to implement the enable bit.
+ let value = value as u16;
+ self.control = value.into();
+ self.loopback_mdmctrl();
+ }
+ Ok(FLS) => {
+ self.ifl = value;
+ self.set_read_trigger();
+ }
+ Ok(IMSC) => {
+ self.int_enabled = value;
+ self.update();
+ }
+ Ok(RIS) => {}
+ Ok(MIS) => {}
+ Ok(ICR) => {
+ self.int_level &= !value;
+ self.update();
+ }
+ Ok(DMACR) => {
+ self.dmacr = value;
+ if value & 3 > 0 {
+ // qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
+ eprintln!("pl011: DMA not implemented");
+ }
+ }
+ }
+ }
+
+ #[inline]
+ fn loopback_tx(&mut self, value: u32) {
+ if !self.loopback_enabled() {
+ return;
+ }
+
+ // Caveat:
+ //
+ // In real hardware, TX loopback happens at the serial-bit level
+ // and then reassembled by the RX logics back into bytes and placed
+ // into the RX fifo. That is, loopback happens after TX fifo.
+ //
+ // Because the real hardware TX fifo is time-drained at the frame
+ // rate governed by the configured serial format, some loopback
+ // bytes in TX fifo may still be able to get into the RX fifo
+ // that could be full at times while being drained at software
+ // pace.
+ //
+ // In such scenario, the RX draining pace is the major factor
+ // deciding which loopback bytes get into the RX fifo, unless
+ // hardware flow-control is enabled.
+ //
+ // For simplicity, the above described is not emulated.
+ self.put_fifo(value);
+ }
+
+ fn loopback_mdmctrl(&mut self) {
+ if !self.loopback_enabled() {
+ return;
+ }
+
+ /*
+ * Loopback software-driven modem control outputs to modem status inputs:
+ * FR.RI <= CR.Out2
+ * FR.DCD <= CR.Out1
+ * FR.CTS <= CR.RTS
+ * FR.DSR <= CR.DTR
+ *
+ * The loopback happens immediately even if this call is triggered
+ * by setting only CR.LBE.
+ *
+ * CTS/RTS updates due to enabled hardware flow controls are not
+ * dealt with here.
+ */
+
+ //fr = s->flags & ~(PL011_FLAG_RI | PL011_FLAG_DCD |
+ // PL011_FLAG_DSR | PL011_FLAG_CTS);
+ //fr |= (cr & CR_OUT2) ? PL011_FLAG_RI : 0;
+ //fr |= (cr & CR_OUT1) ? PL011_FLAG_DCD : 0;
+ //fr |= (cr & CR_RTS) ? PL011_FLAG_CTS : 0;
+ //fr |= (cr & CR_DTR) ? PL011_FLAG_DSR : 0;
+ //
+ self.flags.set_ring_indicator(self.control.out_2());
+ self.flags.set_data_carrier_detect(self.control.out_1());
+ self.flags.set_clear_to_send(self.control.request_to_send());
+ self.flags
+ .set_data_set_ready(self.control.data_transmit_ready());
+
+ // Change interrupts based on updated FR
+ let mut il = self.int_level;
+
+ il &= !Interrupt::MS;
+ //il |= (fr & PL011_FLAG_DSR) ? INT_DSR : 0;
+ //il |= (fr & PL011_FLAG_DCD) ? INT_DCD : 0;
+ //il |= (fr & PL011_FLAG_CTS) ? INT_CTS : 0;
+ //il |= (fr & PL011_FLAG_RI) ? INT_RI : 0;
+
+ if self.flags.data_set_ready() {
+ il |= Interrupt::DSR as u32;
+ }
+ if self.flags.data_carrier_detect() {
+ il |= Interrupt::DCD as u32;
+ }
+ if self.flags.clear_to_send() {
+ il |= Interrupt::CTS as u32;
+ }
+ if self.flags.ring_indicator() {
+ il |= Interrupt::RI as u32;
+ }
+ self.int_level = il;
+ self.update();
+ }
+
+ fn loopback_break(&mut self, enable: bool) {
+ if enable {
+ self.loopback_tx(DATA_BREAK);
+ }
+ }
+
+ fn set_read_trigger(&mut self) {
+ self.read_trigger = 1;
+ }
+
+ pub fn realize(&mut self) {
+ // SAFETY: self.char_backend has the correct size and alignment for a
+ // CharBackend object, and its callbacks are of the correct types.
+ unsafe {
+ qemu_chr_fe_set_handlers(
+ addr_of_mut!(self.char_backend),
+ Some(pl011_can_receive),
+ Some(pl011_receive),
+ Some(pl011_event),
+ None,
+ addr_of_mut!(*self).cast::<c_void>(),
+ core::ptr::null_mut(),
+ true,
+ );
+ }
+ }
+
+ pub fn reset(&mut self) {
+ self.line_control.reset();
+ self.receive_status_error_clear.reset();
+ self.dmacr = 0;
+ self.int_enabled = 0;
+ self.int_level = 0;
+ self.ilpr = 0;
+ self.ibrd = 0;
+ self.fbrd = 0;
+ self.read_trigger = 1;
+ self.ifl = 0x12;
+ self.control.reset();
+ self.flags = 0.into();
+ self.reset_fifo();
+ }
+
+ pub fn reset_fifo(&mut self) {
+ self.read_count = 0;
+ self.read_pos = 0;
+
+ /* Reset FIFO flags */
+ self.flags.reset();
+ }
+
+ pub fn can_receive(&self) -> bool {
+ // trace_pl011_can_receive(s->lcr, s->read_count, r);
+ self.read_count < self.fifo_depth()
+ }
+
+ pub fn event(&mut self, event: QEMUChrEvent) {
+ if event == bindings::QEMUChrEvent::CHR_EVENT_BREAK && !self.fifo_enabled() {
+ self.put_fifo(DATA_BREAK);
+ self.receive_status_error_clear.set_break_error(true);
+ }
+ }
+
+ #[inline]
+ pub fn fifo_enabled(&self) -> bool {
+ matches!(self.line_control.fifos_enabled(), registers::Mode::FIFO)
+ }
+
+ #[inline]
+ pub fn loopback_enabled(&self) -> bool {
+ self.control.enable_loopback()
+ }
+
+ #[inline]
+ pub fn fifo_depth(&self) -> usize {
+ // Note: FIFO depth is expected to be power-of-2
+ if self.fifo_enabled() {
+ return PL011_FIFO_DEPTH;
+ }
+ 1
+ }
+
+ pub fn put_fifo(&mut self, value: c_uint) {
+ let depth = self.fifo_depth();
+ assert!(depth > 0);
+ let slot = (self.read_pos + self.read_count) & (depth - 1);
+ self.read_fifo[slot] = value;
+ self.read_count += 1;
+ // s->flags &= ~PL011_FLAG_RXFE;
+ self.flags.set_receive_fifo_empty(false);
+ if self.read_count == depth {
+ //s->flags |= PL011_FLAG_RXFF;
+ self.flags.set_receive_fifo_full(true);
+ }
+
+ if self.read_count == self.read_trigger {
+ self.int_level |= registers::INT_RX;
+ self.update();
+ }
+ }
+
+ pub fn update(&self) {
+ let flags = self.int_level & self.int_enabled;
+ for (irq, i) in self.interrupts.iter().zip(IRQMASK) {
+ // SAFETY: self.interrupts have been initialized in init().
+ unsafe { qemu_set_irq(*irq, i32::from(flags & i != 0)) };
+ }
+ }
+}
+
+/// Which bits in the interrupt status matter for each outbound IRQ line ?
+pub const IRQMASK: [u32; 6] = [
+ /* combined IRQ */
+ Interrupt::E
+ | Interrupt::MS
+ | Interrupt::RT as u32
+ | Interrupt::TX as u32
+ | Interrupt::RX as u32,
+ Interrupt::RX as u32,
+ Interrupt::TX as u32,
+ Interrupt::RT as u32,
+ Interrupt::MS,
+ Interrupt::E,
+];
+
+/// # Safety
+///
+/// We expect the FFI user of this function to pass a valid pointer, that has
+/// the same size as [`PL011State`]. We also expect the device is
+/// readable/writeable from one thread at any time.
+#[no_mangle]
+pub unsafe extern "C" fn pl011_can_receive(opaque: *mut c_void) -> c_int {
+ unsafe {
+ debug_assert!(!opaque.is_null());
+ let state = NonNull::new_unchecked(opaque.cast::<PL011State>());
+ state.as_ref().can_receive().into()
+ }
+}
+
+/// # Safety
+///
+/// We expect the FFI user of this function to pass a valid pointer, that has
+/// the same size as [`PL011State`]. We also expect the device is
+/// readable/writeable from one thread at any time.
+///
+/// The buffer and size arguments must also be valid.
+#[no_mangle]
+pub unsafe extern "C" fn pl011_receive(
+ opaque: *mut core::ffi::c_void,
+ buf: *const u8,
+ size: core::ffi::c_int,
+) {
+ unsafe {
+ debug_assert!(!opaque.is_null());
+ let mut state = NonNull::new_unchecked(opaque.cast::<PL011State>());
+ if state.as_ref().loopback_enabled() {
+ return;
+ }
+ if size > 0 {
+ debug_assert!(!buf.is_null());
+ state.as_mut().put_fifo(c_uint::from(buf.read_volatile()))
+ }
+ }
+}
+
+/// # Safety
+///
+/// We expect the FFI user of this function to pass a valid pointer, that has
+/// the same size as [`PL011State`]. We also expect the device is
+/// readable/writeable from one thread at any time.
+#[no_mangle]
+pub unsafe extern "C" fn pl011_event(opaque: *mut core::ffi::c_void, event: QEMUChrEvent) {
+ unsafe {
+ debug_assert!(!opaque.is_null());
+ let mut state = NonNull::new_unchecked(opaque.cast::<PL011State>());
+ state.as_mut().event(event)
+ }
+}
+
+/// # Safety
+///
+/// We expect the FFI user of this function to pass a valid pointer for `chr`.
+#[no_mangle]
+pub unsafe extern "C" fn pl011_create(
+ addr: u64,
+ irq: qemu_irq,
+ chr: *mut Chardev,
+) -> *mut DeviceState {
+ unsafe {
+ let dev: *mut DeviceState = qdev_new(PL011State::TYPE_INFO.name);
+ let sysbus: *mut SysBusDevice = dev.cast::<SysBusDevice>();
+
+ qdev_prop_set_chr(dev, bindings::TYPE_CHARDEV.as_ptr(), chr);
+ sysbus_realize_and_unref(sysbus, addr_of!(error_fatal) as *mut *mut Error);
+ sysbus_mmio_map(sysbus, 0, addr);
+ sysbus_connect_irq(sysbus, 0, irq);
+ dev
+ }
+}
+
+/// # Safety
+///
+/// We expect the FFI user of this function to pass a valid pointer, that has
+/// the same size as [`PL011State`]. We also expect the device is
+/// readable/writeable from one thread at any time.
+#[no_mangle]
+pub unsafe extern "C" fn pl011_init(obj: *mut Object) {
+ unsafe {
+ debug_assert!(!obj.is_null());
+ let mut state = NonNull::new_unchecked(obj.cast::<PL011State>());
+ state.as_mut().init();
+ }
+}
diff --git a/rust/hw/char/pl011/src/device_class.rs b/rust/hw/char/pl011/src/device_class.rs
new file mode 100644
index 0000000..b7ab31a
--- /dev/null
+++ b/rust/hw/char/pl011/src/device_class.rs
@@ -0,0 +1,70 @@
+// Copyright 2024, Linaro Limited
+// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+use core::ptr::NonNull;
+
+use qemu_api::{bindings::*, definitions::ObjectImpl};
+
+use crate::device::PL011State;
+
+#[used]
+pub static VMSTATE_PL011: VMStateDescription = VMStateDescription {
+ name: PL011State::TYPE_INFO.name,
+ unmigratable: true,
+ ..unsafe { ::core::mem::MaybeUninit::<VMStateDescription>::zeroed().assume_init() }
+};
+
+qemu_api::declare_properties! {
+ PL011_PROPERTIES,
+ qemu_api::define_property!(
+ c"chardev",
+ PL011State,
+ char_backend,
+ unsafe { &qdev_prop_chr },
+ CharBackend
+ ),
+ qemu_api::define_property!(
+ c"migrate-clk",
+ PL011State,
+ migrate_clock,
+ unsafe { &qdev_prop_bool },
+ bool
+ ),
+}
+
+qemu_api::device_class_init! {
+ pl011_class_init,
+ props => PL011_PROPERTIES,
+ realize_fn => Some(pl011_realize),
+ legacy_reset_fn => Some(pl011_reset),
+ vmsd => VMSTATE_PL011,
+}
+
+/// # Safety
+///
+/// We expect the FFI user of this function to pass a valid pointer, that has
+/// the same size as [`PL011State`]. We also expect the device is
+/// readable/writeable from one thread at any time.
+#[no_mangle]
+pub unsafe extern "C" fn pl011_realize(dev: *mut DeviceState, _errp: *mut *mut Error) {
+ unsafe {
+ assert!(!dev.is_null());
+ let mut state = NonNull::new_unchecked(dev.cast::<PL011State>());
+ state.as_mut().realize();
+ }
+}
+
+/// # Safety
+///
+/// We expect the FFI user of this function to pass a valid pointer, that has
+/// the same size as [`PL011State`]. We also expect the device is
+/// readable/writeable from one thread at any time.
+#[no_mangle]
+pub unsafe extern "C" fn pl011_reset(dev: *mut DeviceState) {
+ unsafe {
+ assert!(!dev.is_null());
+ let mut state = NonNull::new_unchecked(dev.cast::<PL011State>());
+ state.as_mut().reset();
+ }
+}
diff --git a/rust/hw/char/pl011/src/lib.rs b/rust/hw/char/pl011/src/lib.rs
new file mode 100644
index 0000000..2939ee5
--- /dev/null
+++ b/rust/hw/char/pl011/src/lib.rs
@@ -0,0 +1,586 @@
+// Copyright 2024, Linaro Limited
+// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// PL011 QEMU Device Model
+//
+// This library implements a device model for the PrimeCellĀ® UART (PL011)
+// device in QEMU.
+//
+#![doc = include_str!("../README.md")]
+//! # Library crate
+//!
+//! See [`PL011State`](crate::device::PL011State) for the device model type and
+//! the [`registers`] module for register types.
+
+#![deny(
+ rustdoc::broken_intra_doc_links,
+ rustdoc::redundant_explicit_links,
+ clippy::correctness,
+ clippy::suspicious,
+ clippy::complexity,
+ clippy::perf,
+ clippy::cargo,
+ clippy::nursery,
+ clippy::style,
+ // restriction group
+ clippy::dbg_macro,
+ clippy::as_underscore,
+ clippy::assertions_on_result_states,
+ // pedantic group
+ clippy::doc_markdown,
+ clippy::borrow_as_ptr,
+ clippy::cast_lossless,
+ clippy::option_if_let_else,
+ clippy::missing_const_for_fn,
+ clippy::cognitive_complexity,
+ clippy::missing_safety_doc,
+ )]
+
+extern crate bilge;
+extern crate bilge_impl;
+extern crate qemu_api;
+
+pub mod device;
+pub mod device_class;
+pub mod memory_ops;
+
+pub const TYPE_PL011: &::core::ffi::CStr = c"pl011";
+
+/// Offset of each register from the base memory address of the device.
+///
+/// # Source
+/// ARM DDI 0183G, Table 3-1 p.3-3
+#[doc(alias = "offset")]
+#[allow(non_camel_case_types)]
+#[repr(u64)]
+#[derive(Debug)]
+pub enum RegisterOffset {
+ /// Data Register
+ ///
+ /// A write to this register initiates the actual data transmission
+ #[doc(alias = "UARTDR")]
+ DR = 0x000,
+ /// Receive Status Register or Error Clear Register
+ #[doc(alias = "UARTRSR")]
+ #[doc(alias = "UARTECR")]
+ RSR = 0x004,
+ /// Flag Register
+ ///
+ /// A read of this register shows if transmission is complete
+ #[doc(alias = "UARTFR")]
+ FR = 0x018,
+ /// Fractional Baud Rate Register
+ ///
+ /// responsible for baud rate speed
+ #[doc(alias = "UARTFBRD")]
+ FBRD = 0x028,
+ /// `IrDA` Low-Power Counter Register
+ #[doc(alias = "UARTILPR")]
+ ILPR = 0x020,
+ /// Integer Baud Rate Register
+ ///
+ /// Responsible for baud rate speed
+ #[doc(alias = "UARTIBRD")]
+ IBRD = 0x024,
+ /// line control register (data frame format)
+ #[doc(alias = "UARTLCR_H")]
+ LCR_H = 0x02C,
+ /// Toggle UART, transmission or reception
+ #[doc(alias = "UARTCR")]
+ CR = 0x030,
+ /// Interrupt FIFO Level Select Register
+ #[doc(alias = "UARTIFLS")]
+ FLS = 0x034,
+ /// Interrupt Mask Set/Clear Register
+ #[doc(alias = "UARTIMSC")]
+ IMSC = 0x038,
+ /// Raw Interrupt Status Register
+ #[doc(alias = "UARTRIS")]
+ RIS = 0x03C,
+ /// Masked Interrupt Status Register
+ #[doc(alias = "UARTMIS")]
+ MIS = 0x040,
+ /// Interrupt Clear Register
+ #[doc(alias = "UARTICR")]
+ ICR = 0x044,
+ /// DMA control Register
+ #[doc(alias = "UARTDMACR")]
+ DMACR = 0x048,
+ ///// Reserved, offsets `0x04C` to `0x07C`.
+ //Reserved = 0x04C,
+}
+
+impl core::convert::TryFrom<u64> for RegisterOffset {
+ type Error = u64;
+
+ fn try_from(value: u64) -> Result<Self, Self::Error> {
+ macro_rules! case {
+ ($($discriminant:ident),*$(,)*) => {
+ /* check that matching on all macro arguments compiles, which means we are not
+ * missing any enum value; if the type definition ever changes this will stop
+ * compiling.
+ */
+ const fn _assert_exhaustive(val: RegisterOffset) {
+ match val {
+ $(RegisterOffset::$discriminant => (),)*
+ }
+ }
+
+ match value {
+ $(x if x == Self::$discriminant as u64 => Ok(Self::$discriminant),)*
+ _ => Err(value),
+ }
+ }
+ }
+ case! { DR, RSR, FR, FBRD, ILPR, IBRD, LCR_H, CR, FLS, IMSC, RIS, MIS, ICR, DMACR }
+ }
+}
+
+pub mod registers {
+ //! Device registers exposed as typed structs which are backed by arbitrary
+ //! integer bitmaps. [`Data`], [`Control`], [`LineControl`], etc.
+ //!
+ //! All PL011 registers are essentially 32-bit wide, but are typed here as
+ //! bitmaps with only the necessary width. That is, if a struct bitmap
+ //! in this module is for example 16 bits long, it should be conceived
+ //! as a 32-bit register where the unmentioned higher bits are always
+ //! unused thus treated as zero when read or written.
+ use bilge::prelude::*;
+
+ // TODO: FIFO Mode has different semantics
+ /// Data Register, `UARTDR`
+ ///
+ /// The `UARTDR` register is the data register.
+ ///
+ /// For words to be transmitted:
+ ///
+ /// - if the FIFOs are enabled, data written to this location is pushed onto
+ /// the transmit
+ /// FIFO
+ /// - if the FIFOs are not enabled, data is stored in the transmitter
+ /// holding register (the
+ /// bottom word of the transmit FIFO).
+ ///
+ /// The write operation initiates transmission from the UART. The data is
+ /// prefixed with a start bit, appended with the appropriate parity bit
+ /// (if parity is enabled), and a stop bit. The resultant word is then
+ /// transmitted.
+ ///
+ /// For received words:
+ ///
+ /// - if the FIFOs are enabled, the data byte and the 4-bit status (break,
+ /// frame, parity,
+ /// and overrun) is pushed onto the 12-bit wide receive FIFO
+ /// - if the FIFOs are not enabled, the data byte and status are stored in
+ /// the receiving
+ /// holding register (the bottom word of the receive FIFO).
+ ///
+ /// The received data byte is read by performing reads from the `UARTDR`
+ /// register along with the corresponding status information. The status
+ /// information can also be read by a read of the `UARTRSR/UARTECR`
+ /// register.
+ ///
+ /// # Note
+ ///
+ /// You must disable the UART before any of the control registers are
+ /// reprogrammed. When the UART is disabled in the middle of
+ /// transmission or reception, it completes the current character before
+ /// stopping.
+ ///
+ /// # Source
+ /// ARM DDI 0183G 3.3.1 Data Register, UARTDR
+ #[bitsize(16)]
+ #[derive(Clone, Copy, DebugBits, FromBits)]
+ #[doc(alias = "UARTDR")]
+ pub struct Data {
+ _reserved: u4,
+ pub data: u8,
+ pub framing_error: bool,
+ pub parity_error: bool,
+ pub break_error: bool,
+ pub overrun_error: bool,
+ }
+
+ // TODO: FIFO Mode has different semantics
+ /// Receive Status Register / Error Clear Register, `UARTRSR/UARTECR`
+ ///
+ /// The UARTRSR/UARTECR register is the receive status register/error clear
+ /// register. Receive status can also be read from the `UARTRSR`
+ /// register. If the status is read from this register, then the status
+ /// information for break, framing and parity corresponds to the
+ /// data character read from the [Data register](Data), `UARTDR` prior to
+ /// reading the UARTRSR register. The status information for overrun is
+ /// set immediately when an overrun condition occurs.
+ ///
+ ///
+ /// # Note
+ /// The received data character must be read first from the [Data
+ /// Register](Data), `UARTDR` before reading the error status associated
+ /// with that data character from the `UARTRSR` register. This read
+ /// sequence cannot be reversed, because the `UARTRSR` register is
+ /// updated only when a read occurs from the `UARTDR` register. However,
+ /// the status information can also be obtained by reading the `UARTDR`
+ /// register
+ ///
+ /// # Source
+ /// ARM DDI 0183G 3.3.2 Receive Status Register/Error Clear Register,
+ /// UARTRSR/UARTECR
+ #[bitsize(8)]
+ #[derive(Clone, Copy, DebugBits, FromBits)]
+ pub struct ReceiveStatusErrorClear {
+ pub framing_error: bool,
+ pub parity_error: bool,
+ pub break_error: bool,
+ pub overrun_error: bool,
+ _reserved_unpredictable: u4,
+ }
+
+ impl ReceiveStatusErrorClear {
+ pub fn reset(&mut self) {
+ // All the bits are cleared to 0 on reset.
+ *self = 0.into();
+ }
+ }
+
+ impl Default for ReceiveStatusErrorClear {
+ fn default() -> Self {
+ 0.into()
+ }
+ }
+
+ #[bitsize(16)]
+ #[derive(Clone, Copy, DebugBits, FromBits)]
+ /// Flag Register, `UARTFR`
+ #[doc(alias = "UARTFR")]
+ pub struct Flags {
+ /// CTS Clear to send. This bit is the complement of the UART clear to
+ /// send, `nUARTCTS`, modem status input. That is, the bit is 1
+ /// when `nUARTCTS` is LOW.
+ pub clear_to_send: bool,
+ /// DSR Data set ready. This bit is the complement of the UART data set
+ /// ready, `nUARTDSR`, modem status input. That is, the bit is 1 when
+ /// `nUARTDSR` is LOW.
+ pub data_set_ready: bool,
+ /// DCD Data carrier detect. This bit is the complement of the UART data
+ /// carrier detect, `nUARTDCD`, modem status input. That is, the bit is
+ /// 1 when `nUARTDCD` is LOW.
+ pub data_carrier_detect: bool,
+ /// BUSY UART busy. If this bit is set to 1, the UART is busy
+ /// transmitting data. This bit remains set until the complete
+ /// byte, including all the stop bits, has been sent from the
+ /// shift register. This bit is set as soon as the transmit FIFO
+ /// becomes non-empty, regardless of whether the UART is enabled
+ /// or not.
+ pub busy: bool,
+ /// RXFE Receive FIFO empty. The meaning of this bit depends on the
+ /// state of the FEN bit in the UARTLCR_H register. If the FIFO
+ /// is disabled, this bit is set when the receive holding
+ /// register is empty. If the FIFO is enabled, the RXFE bit is
+ /// set when the receive FIFO is empty.
+ pub receive_fifo_empty: bool,
+ /// TXFF Transmit FIFO full. The meaning of this bit depends on the
+ /// state of the FEN bit in the UARTLCR_H register. If the FIFO
+ /// is disabled, this bit is set when the transmit holding
+ /// register is full. If the FIFO is enabled, the TXFF bit is
+ /// set when the transmit FIFO is full.
+ pub transmit_fifo_full: bool,
+ /// RXFF Receive FIFO full. The meaning of this bit depends on the state
+ /// of the FEN bit in the UARTLCR_H register. If the FIFO is
+ /// disabled, this bit is set when the receive holding register
+ /// is full. If the FIFO is enabled, the RXFF bit is set when
+ /// the receive FIFO is full.
+ pub receive_fifo_full: bool,
+ /// Transmit FIFO empty. The meaning of this bit depends on the state of
+ /// the FEN bit in the [Line Control register](LineControl),
+ /// `UARTLCR_H`. If the FIFO is disabled, this bit is set when the
+ /// transmit holding register is empty. If the FIFO is enabled,
+ /// the TXFE bit is set when the transmit FIFO is empty. This
+ /// bit does not indicate if there is data in the transmit shift
+ /// register.
+ pub transmit_fifo_empty: bool,
+ /// `RI`, is `true` when `nUARTRI` is `LOW`.
+ pub ring_indicator: bool,
+ _reserved_zero_no_modify: u7,
+ }
+
+ impl Flags {
+ pub fn reset(&mut self) {
+ // After reset TXFF, RXFF, and BUSY are 0, and TXFE and RXFE are 1
+ self.set_receive_fifo_full(false);
+ self.set_transmit_fifo_full(false);
+ self.set_busy(false);
+ self.set_receive_fifo_empty(true);
+ self.set_transmit_fifo_empty(true);
+ }
+ }
+
+ impl Default for Flags {
+ fn default() -> Self {
+ let mut ret: Self = 0.into();
+ ret.reset();
+ ret
+ }
+ }
+
+ #[bitsize(16)]
+ #[derive(Clone, Copy, DebugBits, FromBits)]
+ /// Line Control Register, `UARTLCR_H`
+ #[doc(alias = "UARTLCR_H")]
+ pub struct LineControl {
+ /// 15:8 - Reserved, do not modify, read as zero.
+ _reserved_zero_no_modify: u8,
+ /// 7 SPS Stick parity select.
+ /// 0 = stick parity is disabled
+ /// 1 = either:
+ /// ā€¢ if the EPS bit is 0 then the parity bit is transmitted and checked
+ /// as a 1 ā€¢ if the EPS bit is 1 then the parity bit is
+ /// transmitted and checked as a 0. This bit has no effect when
+ /// the PEN bit disables parity checking and generation. See Table 3-11
+ /// on page 3-14 for the parity truth table.
+ pub sticky_parity: bool,
+ /// WLEN Word length. These bits indicate the number of data bits
+ /// transmitted or received in a frame as follows: b11 = 8 bits
+ /// b10 = 7 bits
+ /// b01 = 6 bits
+ /// b00 = 5 bits.
+ pub word_length: WordLength,
+ /// FEN Enable FIFOs:
+ /// 0 = FIFOs are disabled (character mode) that is, the FIFOs become
+ /// 1-byte-deep holding registers 1 = transmit and receive FIFO
+ /// buffers are enabled (FIFO mode).
+ pub fifos_enabled: Mode,
+ /// 3 STP2 Two stop bits select. If this bit is set to 1, two stop bits
+ /// are transmitted at the end of the frame. The receive
+ /// logic does not check for two stop bits being received.
+ pub two_stops_bits: bool,
+ /// EPS Even parity select. Controls the type of parity the UART uses
+ /// during transmission and reception:
+ /// - 0 = odd parity. The UART generates or checks for an odd number of
+ /// 1s in the data and parity bits.
+ /// - 1 = even parity. The UART generates or checks for an even number
+ /// of 1s in the data and parity bits.
+ /// This bit has no effect when the `PEN` bit disables parity checking
+ /// and generation. See Table 3-11 on page 3-14 for the parity
+ /// truth table.
+ pub parity: Parity,
+ /// 1 PEN Parity enable:
+ ///
+ /// - 0 = parity is disabled and no parity bit added to the data frame
+ /// - 1 = parity checking and generation is enabled.
+ ///
+ /// See Table 3-11 on page 3-14 for the parity truth table.
+ pub parity_enabled: bool,
+ /// BRK Send break.
+ ///
+ /// If this bit is set to `1`, a low-level is continually output on the
+ /// `UARTTXD` output, after completing transmission of the
+ /// current character. For the proper execution of the break command,
+ /// the software must set this bit for at least two complete
+ /// frames. For normal use, this bit must be cleared to `0`.
+ pub send_break: bool,
+ }
+
+ impl LineControl {
+ pub fn reset(&mut self) {
+ // All the bits are cleared to 0 when reset.
+ *self = 0.into();
+ }
+ }
+
+ impl Default for LineControl {
+ fn default() -> Self {
+ 0.into()
+ }
+ }
+
+ #[bitsize(1)]
+ #[derive(Clone, Copy, Debug, Eq, FromBits, PartialEq)]
+ /// `EPS` "Even parity select", field of [Line Control
+ /// register](LineControl).
+ pub enum Parity {
+ /// - 0 = odd parity. The UART generates or checks for an odd number of
+ /// 1s in the data and parity bits.
+ Odd = 0,
+ /// - 1 = even parity. The UART generates or checks for an even number
+ /// of 1s in the data and parity bits.
+ Even = 1,
+ }
+
+ #[bitsize(1)]
+ #[derive(Clone, Copy, Debug, Eq, FromBits, PartialEq)]
+ /// `FEN` "Enable FIFOs" or Device mode, field of [Line Control
+ /// register](LineControl).
+ pub enum Mode {
+ /// 0 = FIFOs are disabled (character mode) that is, the FIFOs become
+ /// 1-byte-deep holding registers
+ Character = 0,
+ /// 1 = transmit and receive FIFO buffers are enabled (FIFO mode).
+ FIFO = 1,
+ }
+
+ impl From<Mode> for bool {
+ fn from(val: Mode) -> Self {
+ matches!(val, Mode::FIFO)
+ }
+ }
+
+ #[bitsize(2)]
+ #[derive(Clone, Copy, Debug, Eq, FromBits, PartialEq)]
+ /// `WLEN` Word length, field of [Line Control register](LineControl).
+ ///
+ /// These bits indicate the number of data bits transmitted or received in a
+ /// frame as follows:
+ pub enum WordLength {
+ /// b11 = 8 bits
+ _8Bits = 0b11,
+ /// b10 = 7 bits
+ _7Bits = 0b10,
+ /// b01 = 6 bits
+ _6Bits = 0b01,
+ /// b00 = 5 bits.
+ _5Bits = 0b00,
+ }
+
+ /// Control Register, `UARTCR`
+ ///
+ /// The `UARTCR` register is the control register. All the bits are cleared
+ /// to `0` on reset except for bits `9` and `8` that are set to `1`.
+ ///
+ /// # Source
+ /// ARM DDI 0183G, 3.3.8 Control Register, `UARTCR`, Table 3-12
+ #[bitsize(16)]
+ #[doc(alias = "UARTCR")]
+ #[derive(Clone, Copy, DebugBits, FromBits)]
+ pub struct Control {
+ /// `UARTEN` UART enable: 0 = UART is disabled. If the UART is disabled
+ /// in the middle of transmission or reception, it completes the current
+ /// character before stopping. 1 = the UART is enabled. Data
+ /// transmission and reception occurs for either UART signals or SIR
+ /// signals depending on the setting of the SIREN bit.
+ pub enable_uart: bool,
+ /// `SIREN` `SIR` enable: 0 = IrDA SIR ENDEC is disabled. `nSIROUT`
+ /// remains LOW (no light pulse generated), and signal transitions on
+ /// SIRIN have no effect. 1 = IrDA SIR ENDEC is enabled. Data is
+ /// transmitted and received on nSIROUT and SIRIN. UARTTXD remains HIGH,
+ /// in the marking state. Signal transitions on UARTRXD or modem status
+ /// inputs have no effect. This bit has no effect if the UARTEN bit
+ /// disables the UART.
+ pub enable_sir: bool,
+ /// `SIRLP` SIR low-power IrDA mode. This bit selects the IrDA encoding
+ /// mode. If this bit is cleared to 0, low-level bits are transmitted as
+ /// an active high pulse with a width of 3/ 16th of the bit period. If
+ /// this bit is set to 1, low-level bits are transmitted with a pulse
+ /// width that is 3 times the period of the IrLPBaud16 input signal,
+ /// regardless of the selected bit rate. Setting this bit uses less
+ /// power, but might reduce transmission distances.
+ pub sir_lowpower_irda_mode: u1,
+ /// Reserved, do not modify, read as zero.
+ _reserved_zero_no_modify: u4,
+ /// `LBE` Loopback enable. If this bit is set to 1 and the SIREN bit is
+ /// set to 1 and the SIRTEST bit in the Test Control register, UARTTCR
+ /// on page 4-5 is set to 1, then the nSIROUT path is inverted, and fed
+ /// through to the SIRIN path. The SIRTEST bit in the test register must
+ /// be set to 1 to override the normal half-duplex SIR operation. This
+ /// must be the requirement for accessing the test registers during
+ /// normal operation, and SIRTEST must be cleared to 0 when loopback
+ /// testing is finished. This feature reduces the amount of external
+ /// coupling required during system test. If this bit is set to 1, and
+ /// the SIRTEST bit is set to 0, the UARTTXD path is fed through to the
+ /// UARTRXD path. In either SIR mode or UART mode, when this bit is set,
+ /// the modem outputs are also fed through to the modem inputs. This bit
+ /// is cleared to 0 on reset, to disable loopback.
+ pub enable_loopback: bool,
+ /// `TXE` Transmit enable. If this bit is set to 1, the transmit section
+ /// of the UART is enabled. Data transmission occurs for either UART
+ /// signals, or SIR signals depending on the setting of the SIREN bit.
+ /// When the UART is disabled in the middle of transmission, it
+ /// completes the current character before stopping.
+ pub enable_transmit: bool,
+ /// `RXE` Receive enable. If this bit is set to 1, the receive section
+ /// of the UART is enabled. Data reception occurs for either UART
+ /// signals or SIR signals depending on the setting of the SIREN bit.
+ /// When the UART is disabled in the middle of reception, it completes
+ /// the current character before stopping.
+ pub enable_receive: bool,
+ /// `DTR` Data transmit ready. This bit is the complement of the UART
+ /// data transmit ready, `nUARTDTR`, modem status output. That is, when
+ /// the bit is programmed to a 1 then `nUARTDTR` is LOW.
+ pub data_transmit_ready: bool,
+ /// `RTS` Request to send. This bit is the complement of the UART
+ /// request to send, `nUARTRTS`, modem status output. That is, when the
+ /// bit is programmed to a 1 then `nUARTRTS` is LOW.
+ pub request_to_send: bool,
+ /// `Out1` This bit is the complement of the UART Out1 (`nUARTOut1`)
+ /// modem status output. That is, when the bit is programmed to a 1 the
+ /// output is 0. For DTE this can be used as Data Carrier Detect (DCD).
+ pub out_1: bool,
+ /// `Out2` This bit is the complement of the UART Out2 (`nUARTOut2`)
+ /// modem status output. That is, when the bit is programmed to a 1, the
+ /// output is 0. For DTE this can be used as Ring Indicator (RI).
+ pub out_2: bool,
+ /// `RTSEn` RTS hardware flow control enable. If this bit is set to 1,
+ /// RTS hardware flow control is enabled. Data is only requested when
+ /// there is space in the receive FIFO for it to be received.
+ pub rts_hardware_flow_control_enable: bool,
+ /// `CTSEn` CTS hardware flow control enable. If this bit is set to 1,
+ /// CTS hardware flow control is enabled. Data is only transmitted when
+ /// the `nUARTCTS` signal is asserted.
+ pub cts_hardware_flow_control_enable: bool,
+ }
+
+ impl Control {
+ pub fn reset(&mut self) {
+ *self = 0.into();
+ self.set_enable_receive(true);
+ self.set_enable_transmit(true);
+ }
+ }
+
+ impl Default for Control {
+ fn default() -> Self {
+ let mut ret: Self = 0.into();
+ ret.reset();
+ ret
+ }
+ }
+
+ /// Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC
+ pub const INT_OE: u32 = 1 << 10;
+ pub const INT_BE: u32 = 1 << 9;
+ pub const INT_PE: u32 = 1 << 8;
+ pub const INT_FE: u32 = 1 << 7;
+ pub const INT_RT: u32 = 1 << 6;
+ pub const INT_TX: u32 = 1 << 5;
+ pub const INT_RX: u32 = 1 << 4;
+ pub const INT_DSR: u32 = 1 << 3;
+ pub const INT_DCD: u32 = 1 << 2;
+ pub const INT_CTS: u32 = 1 << 1;
+ pub const INT_RI: u32 = 1 << 0;
+ pub const INT_E: u32 = INT_OE | INT_BE | INT_PE | INT_FE;
+ pub const INT_MS: u32 = INT_RI | INT_DSR | INT_DCD | INT_CTS;
+
+ #[repr(u32)]
+ pub enum Interrupt {
+ OE = 1 << 10,
+ BE = 1 << 9,
+ PE = 1 << 8,
+ FE = 1 << 7,
+ RT = 1 << 6,
+ TX = 1 << 5,
+ RX = 1 << 4,
+ DSR = 1 << 3,
+ DCD = 1 << 2,
+ CTS = 1 << 1,
+ RI = 1 << 0,
+ }
+
+ impl Interrupt {
+ pub const E: u32 = INT_OE | INT_BE | INT_PE | INT_FE;
+ pub const MS: u32 = INT_RI | INT_DSR | INT_DCD | INT_CTS;
+ }
+}
+
+// TODO: You must disable the UART before any of the control registers are
+// reprogrammed. When the UART is disabled in the middle of transmission or
+// reception, it completes the current character before stopping
diff --git a/rust/hw/char/pl011/src/memory_ops.rs b/rust/hw/char/pl011/src/memory_ops.rs
new file mode 100644
index 0000000..8d066eb
--- /dev/null
+++ b/rust/hw/char/pl011/src/memory_ops.rs
@@ -0,0 +1,59 @@
+// Copyright 2024, Linaro Limited
+// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+use core::{mem::MaybeUninit, ptr::NonNull};
+
+use qemu_api::bindings::*;
+
+use crate::device::PL011State;
+
+pub static PL011_OPS: MemoryRegionOps = MemoryRegionOps {
+ read: Some(pl011_read),
+ write: Some(pl011_write),
+ read_with_attrs: None,
+ write_with_attrs: None,
+ endianness: device_endian::DEVICE_NATIVE_ENDIAN,
+ valid: unsafe { MaybeUninit::<MemoryRegionOps__bindgen_ty_1>::zeroed().assume_init() },
+ impl_: MemoryRegionOps__bindgen_ty_2 {
+ min_access_size: 4,
+ max_access_size: 4,
+ ..unsafe { MaybeUninit::<MemoryRegionOps__bindgen_ty_2>::zeroed().assume_init() }
+ },
+};
+
+#[no_mangle]
+unsafe extern "C" fn pl011_read(
+ opaque: *mut core::ffi::c_void,
+ addr: hwaddr,
+ size: core::ffi::c_uint,
+) -> u64 {
+ assert!(!opaque.is_null());
+ let mut state = unsafe { NonNull::new_unchecked(opaque.cast::<PL011State>()) };
+ let val = unsafe { state.as_mut().read(addr, size) };
+ match val {
+ std::ops::ControlFlow::Break(val) => val,
+ std::ops::ControlFlow::Continue(val) => {
+ // SAFETY: self.char_backend is a valid CharBackend instance after it's been
+ // initialized in realize().
+ let cb_ptr = unsafe { core::ptr::addr_of_mut!(state.as_mut().char_backend) };
+ unsafe { qemu_chr_fe_accept_input(cb_ptr) };
+
+ val
+ }
+ }
+}
+
+#[no_mangle]
+unsafe extern "C" fn pl011_write(
+ opaque: *mut core::ffi::c_void,
+ addr: hwaddr,
+ data: u64,
+ _size: core::ffi::c_uint,
+) {
+ unsafe {
+ assert!(!opaque.is_null());
+ let mut state = NonNull::new_unchecked(opaque.cast::<PL011State>());
+ state.as_mut().write(addr, data)
+ }
+}
diff --git a/rust/hw/meson.build b/rust/hw/meson.build
new file mode 100644
index 0000000..8601966
--- /dev/null
+++ b/rust/hw/meson.build
@@ -0,0 +1 @@
+subdir('char')
diff --git a/rust/meson.build b/rust/meson.build
new file mode 100644
index 0000000..def7738
--- /dev/null
+++ b/rust/meson.build
@@ -0,0 +1,4 @@
+subdir('qemu-api-macros')
+subdir('qemu-api')
+
+subdir('hw')
diff --git a/rust/qemu-api-macros/Cargo.lock b/rust/qemu-api-macros/Cargo.lock
new file mode 100644
index 0000000..fdc0fce
--- /dev/null
+++ b/rust/qemu-api-macros/Cargo.lock
@@ -0,0 +1,47 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "qemu_api_macros"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.72"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
diff --git a/rust/qemu-api-macros/Cargo.toml b/rust/qemu-api-macros/Cargo.toml
new file mode 100644
index 0000000..144cc36
--- /dev/null
+++ b/rust/qemu-api-macros/Cargo.toml
@@ -0,0 +1,25 @@
+[package]
+name = "qemu_api_macros"
+version = "0.1.0"
+edition = "2021"
+authors = ["Manos Pitsidianakis <manos.pitsidianakis@linaro.org>"]
+license = "GPL-2.0-or-later"
+readme = "README.md"
+homepage = "https://www.qemu.org"
+description = "Rust bindings for QEMU - Utility macros"
+repository = "https://gitlab.com/qemu-project/qemu/"
+resolver = "2"
+publish = false
+keywords = []
+categories = []
+
+[lib]
+proc-macro = true
+
+[dependencies]
+proc-macro2 = "1"
+quote = "1"
+syn = "2"
+
+# Do not include in any global workspace
+[workspace]
diff --git a/rust/qemu-api-macros/README.md b/rust/qemu-api-macros/README.md
new file mode 100644
index 0000000..f60f54a
--- /dev/null
+++ b/rust/qemu-api-macros/README.md
@@ -0,0 +1 @@
+# `qemu-api-macros` - Utility macros for defining QEMU devices
diff --git a/rust/qemu-api-macros/meson.build b/rust/qemu-api-macros/meson.build
new file mode 100644
index 0000000..517b9a4
--- /dev/null
+++ b/rust/qemu-api-macros/meson.build
@@ -0,0 +1,23 @@
+quote_dep = dependency('quote-1-rs', native: true)
+syn_dep = dependency('syn-2-rs', native: true)
+proc_macro2_dep = dependency('proc-macro2-1-rs', native: true)
+
+_qemu_api_macros_rs = import('rust').proc_macro(
+ 'qemu_api_macros',
+ files('src/lib.rs'),
+ override_options: ['rust_std=2021', 'build.rust_std=2021'],
+ rust_args: [
+ '--cfg', 'use_fallback',
+ '--cfg', 'feature="syn-error"',
+ '--cfg', 'feature="proc-macro"',
+ ],
+ dependencies: [
+ proc_macro2_dep,
+ quote_dep,
+ syn_dep,
+ ],
+)
+
+qemu_api_macros = declare_dependency(
+ link_with: _qemu_api_macros_rs,
+)
diff --git a/rust/qemu-api-macros/src/lib.rs b/rust/qemu-api-macros/src/lib.rs
new file mode 100644
index 0000000..59aba59
--- /dev/null
+++ b/rust/qemu-api-macros/src/lib.rs
@@ -0,0 +1,43 @@
+// Copyright 2024, Linaro Limited
+// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+use proc_macro::TokenStream;
+use quote::{format_ident, quote};
+use syn::{parse_macro_input, DeriveInput};
+
+#[proc_macro_derive(Object)]
+pub fn derive_object(input: TokenStream) -> TokenStream {
+ let input = parse_macro_input!(input as DeriveInput);
+
+ let name = input.ident;
+ let module_static = format_ident!("__{}_LOAD_MODULE", name);
+
+ let expanded = quote! {
+ #[allow(non_upper_case_globals)]
+ #[used]
+ #[cfg_attr(target_os = "linux", link_section = ".ctors")]
+ #[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
+ #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
+ pub static #module_static: extern "C" fn() = {
+ extern "C" fn __register() {
+ unsafe {
+ ::qemu_api::bindings::type_register_static(&<#name as ::qemu_api::definitions::ObjectImpl>::TYPE_INFO);
+ }
+ }
+
+ extern "C" fn __load() {
+ unsafe {
+ ::qemu_api::bindings::register_module_init(
+ Some(__register),
+ ::qemu_api::bindings::module_init_type::MODULE_INIT_QOM
+ );
+ }
+ }
+
+ __load
+ };
+ };
+
+ TokenStream::from(expanded)
+}
diff --git a/rust/qemu-api/.gitignore b/rust/qemu-api/.gitignore
new file mode 100644
index 0000000..b9e7e00
--- /dev/null
+++ b/rust/qemu-api/.gitignore
@@ -0,0 +1,2 @@
+# Ignore generated bindings file overrides.
+src/bindings.rs
diff --git a/rust/qemu-api/Cargo.lock b/rust/qemu-api/Cargo.lock
new file mode 100644
index 0000000..e9c51a2
--- /dev/null
+++ b/rust/qemu-api/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "qemu_api"
+version = "0.1.0"
diff --git a/rust/qemu-api/Cargo.toml b/rust/qemu-api/Cargo.toml
new file mode 100644
index 0000000..3677def
--- /dev/null
+++ b/rust/qemu-api/Cargo.toml
@@ -0,0 +1,26 @@
+[package]
+name = "qemu_api"
+version = "0.1.0"
+edition = "2021"
+authors = ["Manos Pitsidianakis <manos.pitsidianakis@linaro.org>"]
+license = "GPL-2.0-or-later"
+readme = "README.md"
+homepage = "https://www.qemu.org"
+description = "Rust bindings for QEMU"
+repository = "https://gitlab.com/qemu-project/qemu/"
+resolver = "2"
+publish = false
+keywords = []
+categories = []
+
+[dependencies]
+
+[features]
+default = []
+allocator = []
+
+# Do not include in any global workspace
+[workspace]
+
+[lints.rust]
+unexpected_cfgs = { level = "warn", check-cfg = ['cfg(MESON)', 'cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)'] }
diff --git a/rust/qemu-api/README.md b/rust/qemu-api/README.md
new file mode 100644
index 0000000..7588fa2
--- /dev/null
+++ b/rust/qemu-api/README.md
@@ -0,0 +1,17 @@
+# QEMU bindings and API wrappers
+
+This library exports helper Rust types, Rust macros and C FFI bindings for internal QEMU APIs.
+
+The C bindings can be generated with `bindgen`, using this build target:
+
+```console
+$ ninja bindings.rs
+```
+
+## Generate Rust documentation
+
+To generate docs for this crate, including private items:
+
+```sh
+cargo doc --no-deps --document-private-items
+```
diff --git a/rust/qemu-api/build.rs b/rust/qemu-api/build.rs
new file mode 100644
index 0000000..419b154
--- /dev/null
+++ b/rust/qemu-api/build.rs
@@ -0,0 +1,14 @@
+// Copyright 2024, Linaro Limited
+// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+use std::path::Path;
+
+fn main() {
+ if !Path::new("src/bindings.rs").exists() {
+ panic!(
+ "No generated C bindings found! Either build them manually with bindgen or with meson \
+ (`ninja bindings.rs`) and copy them to src/bindings.rs, or build through meson."
+ );
+ }
+}
diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build
new file mode 100644
index 0000000..c72d34b
--- /dev/null
+++ b/rust/qemu-api/meson.build
@@ -0,0 +1,24 @@
+_qemu_api_rs = static_library(
+ 'qemu_api',
+ structured_sources(
+ [
+ 'src/lib.rs',
+ 'src/definitions.rs',
+ 'src/device_class.rs',
+ ],
+ {'.' : bindings_rs},
+ ),
+ override_options: ['rust_std=2021', 'build.rust_std=2021'],
+ rust_abi: 'rust',
+ rust_args: rustc_args + [
+ '--cfg', 'MESON',
+ # '--cfg', 'feature="allocator"',
+ ],
+ dependencies: [
+ qemu_api_macros,
+ ],
+)
+
+qemu_api = declare_dependency(
+ link_with: _qemu_api_rs,
+)
diff --git a/rust/qemu-api/src/definitions.rs b/rust/qemu-api/src/definitions.rs
new file mode 100644
index 0000000..60bd3f8
--- /dev/null
+++ b/rust/qemu-api/src/definitions.rs
@@ -0,0 +1,97 @@
+// Copyright 2024, Linaro Limited
+// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+//! Definitions required by QEMU when registering a device.
+
+use ::core::ffi::{c_void, CStr};
+
+use crate::bindings::{Object, ObjectClass, TypeInfo};
+
+/// Trait a type must implement to be registered with QEMU.
+pub trait ObjectImpl {
+ type Class;
+ const TYPE_INFO: TypeInfo;
+ const TYPE_NAME: &'static CStr;
+ const PARENT_TYPE_NAME: Option<&'static CStr>;
+ const ABSTRACT: bool;
+ const INSTANCE_INIT: Option<unsafe extern "C" fn(obj: *mut Object)>;
+ const INSTANCE_POST_INIT: Option<unsafe extern "C" fn(obj: *mut Object)>;
+ const INSTANCE_FINALIZE: Option<unsafe extern "C" fn(obj: *mut Object)>;
+}
+
+pub trait Class {
+ const CLASS_INIT: Option<unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void)>;
+ const CLASS_BASE_INIT: Option<
+ unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void),
+ >;
+}
+
+#[macro_export]
+macro_rules! module_init {
+ ($func:expr, $type:expr) => {
+ #[used]
+ #[cfg_attr(target_os = "linux", link_section = ".ctors")]
+ #[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
+ #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
+ pub static LOAD_MODULE: extern "C" fn() = {
+ extern "C" fn __load() {
+ unsafe {
+ $crate::bindings::register_module_init(Some($func), $type);
+ }
+ }
+
+ __load
+ };
+ };
+ (qom: $func:ident => $body:block) => {
+ // NOTE: To have custom identifiers for the ctor func we need to either supply
+ // them directly as a macro argument or create them with a proc macro.
+ #[used]
+ #[cfg_attr(target_os = "linux", link_section = ".ctors")]
+ #[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
+ #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
+ pub static LOAD_MODULE: extern "C" fn() = {
+ extern "C" fn __load() {
+ #[no_mangle]
+ unsafe extern "C" fn $func() {
+ $body
+ }
+
+ unsafe {
+ $crate::bindings::register_module_init(
+ Some($func),
+ $crate::bindings::module_init_type::MODULE_INIT_QOM,
+ );
+ }
+ }
+
+ __load
+ };
+ };
+}
+
+#[macro_export]
+macro_rules! type_info {
+ ($t:ty) => {
+ $crate::bindings::TypeInfo {
+ name: <$t as $crate::definitions::ObjectImpl>::TYPE_NAME.as_ptr(),
+ parent: if let Some(pname) = <$t as $crate::definitions::ObjectImpl>::PARENT_TYPE_NAME {
+ pname.as_ptr()
+ } else {
+ ::core::ptr::null_mut()
+ },
+ instance_size: ::core::mem::size_of::<$t>() as $crate::bindings::size_t,
+ instance_align: ::core::mem::align_of::<$t>() as $crate::bindings::size_t,
+ instance_init: <$t as $crate::definitions::ObjectImpl>::INSTANCE_INIT,
+ instance_post_init: <$t as $crate::definitions::ObjectImpl>::INSTANCE_POST_INIT,
+ instance_finalize: <$t as $crate::definitions::ObjectImpl>::INSTANCE_FINALIZE,
+ abstract_: <$t as $crate::definitions::ObjectImpl>::ABSTRACT,
+ class_size: ::core::mem::size_of::<<$t as $crate::definitions::ObjectImpl>::Class>() as $crate::bindings::size_t,
+ class_init: <<$t as $crate::definitions::ObjectImpl>::Class as $crate::definitions::Class>::CLASS_INIT,
+ class_base_init: <<$t as $crate::definitions::ObjectImpl>::Class as $crate::definitions::Class>::CLASS_BASE_INIT,
+ class_data: ::core::ptr::null_mut(),
+ interfaces: ::core::ptr::null_mut(),
+ };
+ }
+}
diff --git a/rust/qemu-api/src/device_class.rs b/rust/qemu-api/src/device_class.rs
new file mode 100644
index 0000000..1ea95be
--- /dev/null
+++ b/rust/qemu-api/src/device_class.rs
@@ -0,0 +1,128 @@
+// Copyright 2024, Linaro Limited
+// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+use std::sync::OnceLock;
+
+use crate::bindings::Property;
+
+#[macro_export]
+macro_rules! device_class_init {
+ ($func:ident, props => $props:ident, realize_fn => $realize_fn:expr, legacy_reset_fn => $legacy_reset_fn:expr, vmsd => $vmsd:ident$(,)*) => {
+ #[no_mangle]
+ pub unsafe extern "C" fn $func(
+ klass: *mut $crate::bindings::ObjectClass,
+ _: *mut ::core::ffi::c_void,
+ ) {
+ let mut dc =
+ ::core::ptr::NonNull::new(klass.cast::<$crate::bindings::DeviceClass>()).unwrap();
+ dc.as_mut().realize = $realize_fn;
+ dc.as_mut().vmsd = &$vmsd;
+ $crate::bindings::device_class_set_legacy_reset(dc.as_mut(), $legacy_reset_fn);
+ $crate::bindings::device_class_set_props(dc.as_mut(), $props.as_mut_ptr());
+ }
+ };
+}
+
+#[macro_export]
+macro_rules! define_property {
+ ($name:expr, $state:ty, $field:expr, $prop:expr, $type:expr, default = $defval:expr$(,)*) => {
+ $crate::bindings::Property {
+ name: {
+ #[used]
+ static _TEMP: &::core::ffi::CStr = $name;
+ _TEMP.as_ptr()
+ },
+ info: $prop,
+ offset: ::core::mem::offset_of!($state, $field)
+ .try_into()
+ .expect("Could not fit offset value to type"),
+ bitnr: 0,
+ bitmask: 0,
+ set_default: true,
+ defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval.into() },
+ arrayoffset: 0,
+ arrayinfo: ::core::ptr::null(),
+ arrayfieldsize: 0,
+ link_type: ::core::ptr::null(),
+ }
+ };
+ ($name:expr, $state:ty, $field:expr, $prop:expr, $type:expr$(,)*) => {
+ $crate::bindings::Property {
+ name: {
+ #[used]
+ static _TEMP: &::core::ffi::CStr = $name;
+ _TEMP.as_ptr()
+ },
+ info: $prop,
+ offset: ::core::mem::offset_of!($state, $field)
+ .try_into()
+ .expect("Could not fit offset value to type"),
+ bitnr: 0,
+ bitmask: 0,
+ set_default: false,
+ defval: $crate::bindings::Property__bindgen_ty_1 { i: 0 },
+ arrayoffset: 0,
+ arrayinfo: ::core::ptr::null(),
+ arrayfieldsize: 0,
+ link_type: ::core::ptr::null(),
+ }
+ };
+}
+
+#[repr(C)]
+pub struct Properties<const N: usize>(pub OnceLock<[Property; N]>, pub fn() -> [Property; N]);
+
+impl<const N: usize> Properties<N> {
+ pub fn as_mut_ptr(&mut self) -> *mut Property {
+ _ = self.0.get_or_init(self.1);
+ self.0.get_mut().unwrap().as_mut_ptr()
+ }
+}
+
+#[macro_export]
+macro_rules! declare_properties {
+ ($ident:ident, $($prop:expr),*$(,)*) => {
+
+ const fn _calc_prop_len() -> usize {
+ let mut len = 1;
+ $({
+ _ = stringify!($prop);
+ len += 1;
+ })*
+ len
+ }
+ const PROP_LEN: usize = _calc_prop_len();
+
+ fn _make_properties() -> [$crate::bindings::Property; PROP_LEN] {
+ [
+ $($prop),*,
+ unsafe { ::core::mem::MaybeUninit::<$crate::bindings::Property>::zeroed().assume_init() },
+ ]
+ }
+
+ #[no_mangle]
+ pub static mut $ident: $crate::device_class::Properties<PROP_LEN> = $crate::device_class::Properties(::std::sync::OnceLock::new(), _make_properties);
+ };
+}
+
+#[macro_export]
+macro_rules! vm_state_description {
+ ($(#[$outer:meta])*
+ $name:ident,
+ $(name: $vname:expr,)*
+ $(unmigratable: $um_val:expr,)*
+ ) => {
+ #[used]
+ $(#[$outer])*
+ pub static $name: $crate::bindings::VMStateDescription = $crate::bindings::VMStateDescription {
+ $(name: {
+ #[used]
+ static VMSTATE_NAME: &::core::ffi::CStr = $vname;
+ $vname.as_ptr()
+ },)*
+ unmigratable: true,
+ ..unsafe { ::core::mem::MaybeUninit::<$crate::bindings::VMStateDescription>::zeroed().assume_init() }
+ };
+ }
+}
diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs
new file mode 100644
index 0000000..e72fb4b
--- /dev/null
+++ b/rust/qemu-api/src/lib.rs
@@ -0,0 +1,166 @@
+// Copyright 2024, Linaro Limited
+// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#![cfg_attr(not(MESON), doc = include_str!("../README.md"))]
+
+#[allow(
+ dead_code,
+ improper_ctypes_definitions,
+ improper_ctypes,
+ non_camel_case_types,
+ non_snake_case,
+ non_upper_case_globals,
+ unsafe_op_in_unsafe_fn,
+ clippy::missing_const_for_fn,
+ clippy::too_many_arguments,
+ clippy::approx_constant,
+ clippy::use_self,
+ clippy::useless_transmute,
+ clippy::missing_safety_doc,
+)]
+#[rustfmt::skip]
+pub mod bindings;
+
+unsafe impl Send for bindings::Property {}
+unsafe impl Sync for bindings::Property {}
+unsafe impl Sync for bindings::TypeInfo {}
+unsafe impl Sync for bindings::VMStateDescription {}
+
+pub mod definitions;
+pub mod device_class;
+
+#[cfg(test)]
+mod tests;
+
+use std::alloc::{GlobalAlloc, Layout};
+
+#[cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)]
+extern "C" {
+ fn g_aligned_alloc0(
+ n_blocks: bindings::gsize,
+ n_block_bytes: bindings::gsize,
+ alignment: bindings::gsize,
+ ) -> bindings::gpointer;
+ fn g_aligned_free(mem: bindings::gpointer);
+}
+
+#[cfg(not(HAVE_GLIB_WITH_ALIGNED_ALLOC))]
+extern "C" {
+ fn qemu_memalign(alignment: usize, size: usize) -> *mut ::core::ffi::c_void;
+ fn qemu_vfree(ptr: *mut ::core::ffi::c_void);
+}
+
+extern "C" {
+ fn g_malloc0(n_bytes: bindings::gsize) -> bindings::gpointer;
+ fn g_free(mem: bindings::gpointer);
+}
+
+/// An allocator that uses the same allocator as QEMU in C.
+///
+/// It is enabled by default with the `allocator` feature.
+///
+/// To set it up manually as a global allocator in your crate:
+///
+/// ```ignore
+/// use qemu_api::QemuAllocator;
+///
+/// #[global_allocator]
+/// static GLOBAL: QemuAllocator = QemuAllocator::new();
+/// ```
+#[derive(Clone, Copy, Debug)]
+#[repr(C)]
+pub struct QemuAllocator {
+ _unused: [u8; 0],
+}
+
+#[cfg_attr(all(feature = "allocator", not(test)), global_allocator)]
+pub static GLOBAL: QemuAllocator = QemuAllocator::new();
+
+impl QemuAllocator {
+ // From the glibc documentation, on GNU systems, malloc guarantees 16-byte
+ // alignment on 64-bit systems and 8-byte alignment on 32-bit systems. See
+ // https://www.gnu.org/software/libc/manual/html_node/Malloc-Examples.html.
+ // This alignment guarantee also applies to Windows and Android. On Darwin
+ // and OpenBSD, the alignment is 16 bytes on both 64-bit and 32-bit systems.
+ #[cfg(all(
+ target_pointer_width = "32",
+ not(any(target_os = "macos", target_os = "openbsd"))
+ ))]
+ pub const DEFAULT_ALIGNMENT_BYTES: Option<usize> = Some(8);
+ #[cfg(all(
+ target_pointer_width = "64",
+ not(any(target_os = "macos", target_os = "openbsd"))
+ ))]
+ pub const DEFAULT_ALIGNMENT_BYTES: Option<usize> = Some(16);
+ #[cfg(all(
+ any(target_pointer_width = "32", target_pointer_width = "64"),
+ any(target_os = "macos", target_os = "openbsd")
+ ))]
+ pub const DEFAULT_ALIGNMENT_BYTES: Option<usize> = Some(16);
+ #[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))]
+ pub const DEFAULT_ALIGNMENT_BYTES: Option<usize> = None;
+
+ pub const fn new() -> Self {
+ Self { _unused: [] }
+ }
+}
+
+impl Default for QemuAllocator {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+// Sanity check.
+const _: [(); 8] = [(); ::core::mem::size_of::<*mut ::core::ffi::c_void>()];
+
+unsafe impl GlobalAlloc for QemuAllocator {
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ if matches!(Self::DEFAULT_ALIGNMENT_BYTES, Some(default) if default.checked_rem(layout.align()) == Some(0))
+ {
+ // SAFETY: g_malloc0() is safe to call.
+ unsafe { g_malloc0(layout.size().try_into().unwrap()).cast::<u8>() }
+ } else {
+ #[cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)]
+ {
+ // SAFETY: g_aligned_alloc0() is safe to call.
+ unsafe {
+ g_aligned_alloc0(
+ layout.size().try_into().unwrap(),
+ 1,
+ layout.align().try_into().unwrap(),
+ )
+ .cast::<u8>()
+ }
+ }
+ #[cfg(not(HAVE_GLIB_WITH_ALIGNED_ALLOC))]
+ {
+ // SAFETY: qemu_memalign() is safe to call.
+ unsafe { qemu_memalign(layout.align(), layout.size()).cast::<u8>() }
+ }
+ }
+ }
+
+ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+ if matches!(Self::DEFAULT_ALIGNMENT_BYTES, Some(default) if default.checked_rem(layout.align()) == Some(0))
+ {
+ // SAFETY: `ptr` must have been allocated by Self::alloc thus a valid
+ // glib-allocated pointer, so `g_free`ing is safe.
+ unsafe { g_free(ptr.cast::<_>()) }
+ } else {
+ #[cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)]
+ {
+ // SAFETY: `ptr` must have been allocated by Self::alloc thus a valid aligned
+ // glib-allocated pointer, so `g_aligned_free`ing is safe.
+ unsafe { g_aligned_free(ptr.cast::<_>()) }
+ }
+ #[cfg(not(HAVE_GLIB_WITH_ALIGNED_ALLOC))]
+ {
+ // SAFETY: `ptr` must have been allocated by Self::alloc thus a valid aligned
+ // glib-allocated pointer, so `qemu_vfree`ing is safe.
+ unsafe { qemu_vfree(ptr.cast::<_>()) }
+ }
+ }
+ }
+}
diff --git a/rust/qemu-api/src/tests.rs b/rust/qemu-api/src/tests.rs
new file mode 100644
index 0000000..df54edb
--- /dev/null
+++ b/rust/qemu-api/src/tests.rs
@@ -0,0 +1,49 @@
+// Copyright 2024, Linaro Limited
+// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+use crate::{
+ bindings::*, declare_properties, define_property, device_class_init, vm_state_description,
+};
+
+#[test]
+fn test_device_decl_macros() {
+ // Test that macros can compile.
+ vm_state_description! {
+ VMSTATE,
+ name: c"name",
+ unmigratable: true,
+ }
+
+ #[repr(C)]
+ pub struct DummyState {
+ pub char_backend: CharBackend,
+ pub migrate_clock: bool,
+ }
+
+ declare_properties! {
+ DUMMY_PROPERTIES,
+ define_property!(
+ c"chardev",
+ DummyState,
+ char_backend,
+ unsafe { &qdev_prop_chr },
+ CharBackend
+ ),
+ define_property!(
+ c"migrate-clk",
+ DummyState,
+ migrate_clock,
+ unsafe { &qdev_prop_bool },
+ bool
+ ),
+ }
+
+ device_class_init! {
+ dummy_class_init,
+ props => DUMMY_PROPERTIES,
+ realize_fn => None,
+ reset_fn => None,
+ vmsd => VMSTATE,
+ }
+}
diff --git a/rust/rustfmt.toml b/rust/rustfmt.toml
new file mode 100644
index 0000000..ebecb99
--- /dev/null
+++ b/rust/rustfmt.toml
@@ -0,0 +1,7 @@
+edition = "2021"
+format_generated_files = false
+format_code_in_doc_comments = true
+format_strings = true
+imports_granularity = "Crate"
+group_imports = "StdExternalCrate"
+wrap_comments = true
diff --git a/include/hw/cris/etraxfs.h b/rust/wrapper.h
index 012c4e9..77e4021 100644
--- a/include/hw/cris/etraxfs.h
+++ b/rust/wrapper.h
@@ -1,7 +1,9 @@
/*
- * QEMU ETRAX System Emulator
+ * QEMU System Emulator
*
- * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
+ * Copyright (c) 2024 Linaro Ltd.
+ *
+ * Authors: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -22,33 +24,24 @@
* THE SOFTWARE.
*/
-#ifndef HW_ETRAXFS_H
-#define HW_ETRAXFS_H
-#include "net/net.h"
-#include "hw/cris/etraxfs_dma.h"
-#include "hw/qdev-properties.h"
+/*
+ * This header file is meant to be used as input to the `bindgen` application
+ * in order to generate C FFI compatible Rust bindings.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/module.h"
+#include "qemu-io.h"
+#include "sysemu/sysemu.h"
#include "hw/sysbus.h"
+#include "exec/memory.h"
+#include "chardev/char-fe.h"
+#include "hw/clock.h"
+#include "hw/qdev-clock.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
+#include "hw/irq.h"
#include "qapi/error.h"
-
-DeviceState *etraxfs_eth_init(hwaddr base, int phyaddr,
- struct etraxfs_dma_client *dma_out,
- struct etraxfs_dma_client *dma_in);
-
-static inline DeviceState *etraxfs_ser_create(hwaddr addr,
- qemu_irq irq,
- Chardev *chr)
-{
- DeviceState *dev;
- SysBusDevice *s;
-
- dev = qdev_new("etraxfs-serial");
- 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
+#include "migration/vmstate.h"
+#include "chardev/char-serial.h"
diff --git a/scripts/archive-source.sh b/scripts/archive-source.sh
index 65af806..30677c3 100755
--- a/scripts/archive-source.sh
+++ b/scripts/archive-source.sh
@@ -26,7 +26,11 @@ sub_file="${sub_tdir}/submodule.tar"
# independent of what the developer currently has initialized
# in their checkout, because the build environment is completely
# different to the host OS.
-subprojects="keycodemapdb libvfio-user berkeley-softfloat-3 berkeley-testfloat-3"
+subprojects="keycodemapdb libvfio-user berkeley-softfloat-3
+ berkeley-testfloat-3 arbitrary-int-1-rs bilge-0.2-rs
+ bilge-impl-0.2-rs either-1-rs itertools-0.11-rs proc-macro2-1-rs
+ proc-macro-error-1-rs proc-macro-error-attr-1-rs quote-1-rs
+ syn-2-rs unicode-ident-1-rs"
sub_deinit=""
function cleanup() {
@@ -48,13 +52,34 @@ function tree_ish() {
echo "$retval"
}
+function subproject_dir() {
+ if test ! -f "subprojects/$1.wrap"; then
+ error "scripts/archive-source.sh should only process wrap subprojects"
+ fi
+
+ # Print the directory key of the wrap file, defaulting to the
+ # subproject name. The wrap file is in ini format and should
+ # have a single section only. There should be only one section
+ # named "[wrap-*]", which helps keeping the script simple.
+ local dir
+ dir=$(sed -n \
+ -e '/^\[wrap-[a-z][a-z]*\]$/,/^\[/{' \
+ -e '/^directory *= */!b' \
+ -e 's///p' \
+ -e 'q' \
+ -e '}' \
+ "subprojects/$1.wrap")
+
+ echo "${dir:-$1}"
+}
+
git archive --format tar "$(tree_ish)" > "$tar_file"
test $? -ne 0 && error "failed to archive qemu"
for sp in $subprojects; do
meson subprojects download $sp
test $? -ne 0 && error "failed to download subproject $sp"
- tar --append --file "$tar_file" --exclude=.git subprojects/$sp
+ tar --append --file "$tar_file" --exclude=.git subprojects/"$(subproject_dir $sp)"
test $? -ne 0 && error "failed to append subproject $sp to $tar_file"
done
exit 0
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index ff373a7..1b21249 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -1374,6 +1374,9 @@ sub process {
my $in_header_lines = $file ? 0 : 1;
my $in_commit_log = 0; #Scanning lines before patch
my $reported_maintainer_file = 0;
+ my $reported_mixing_imported_file = 0;
+ my $in_imported_file = 0;
+ my $in_no_imported_file = 0;
my $non_utf8_charset = 0;
our @report = ();
@@ -1673,6 +1676,27 @@ sub process {
# ignore non-hunk lines and lines being removed
next if (!$hunk_line || $line =~ /^-/);
+# Check that updating imported files from Linux are not mixed with other changes
+ if ($realfile =~ /^(linux-headers|include\/standard-headers)\//) {
+ if (!$in_imported_file) {
+ WARN("added, moved or deleted file(s) " .
+ "imported from Linux, are you using " .
+ "scripts/update-linux-headers.sh?\n" .
+ $herecurr);
+ }
+ $in_imported_file = 1;
+ } else {
+ $in_no_imported_file = 1;
+ }
+
+ if (!$reported_mixing_imported_file &&
+ $in_imported_file && $in_no_imported_file) {
+ ERROR("headers imported from Linux should be self-" .
+ "contained in a patch with no other changes\n" .
+ $herecurr);
+ $reported_mixing_imported_file = 1;
+ }
+
# ignore files that are being periodically imported from Linux
next if ($realfile =~ /^(linux-headers|include\/standard-headers)\//);
@@ -3078,6 +3102,10 @@ sub process {
if ($line =~ /\b(g_)?assert\(0\)/) {
ERROR("use g_assert_not_reached() instead of assert(0)\n" . $herecurr);
}
+ if ($line =~ /\b(g_)?assert\(false\)/) {
+ ERROR("use g_assert_not_reached() instead of assert(false)\n" .
+ $herecurr);
+ }
if ($line =~ /\bstrerrorname_np\(/) {
ERROR("use strerror() instead of strerrorname_np()\n" . $herecurr);
}
diff --git a/scripts/ci/gitlab-ci-section b/scripts/ci/gitlab-ci-section
new file mode 100644
index 0000000..9bbe804
--- /dev/null
+++ b/scripts/ci/gitlab-ci-section
@@ -0,0 +1,29 @@
+# Copyright (c) 2024 Linaro Ltd
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# gitlab-ci-section: This is a shell script fragment which defines
+# functions section_start and section_end which will emit marker lines
+# that GitLab will interpret as the beginning or end of a "collapsible
+# section" in a CI job log. See
+# https://docs.gitlab.com/ee/ci/yaml/script.html#expand-and-collapse-job-log-sections
+#
+# This is intended to be sourced in the before_script section of
+# a CI config; the section_start and section_end functions will
+# then be available for use in the before_script and script sections.
+
+# Section names are [-_.A-Za-z0-9] and the section_start pairs with
+# a section_end with the same section name.
+# The description can be any printable text without newlines; this is
+# what will appear in the log.
+
+# Usage:
+# section_start section_name "Description of the section"
+section_start () {
+ printf "section_start:%s:%s\r\e[0K%s\n" "$(date +%s)" "$1" "$2"
+}
+
+# Usage:
+# section_end section_name
+section_end () {
+ printf "section_end:%s:%s\r\e[0K\n" "$(date +%s)" "$1"
+}
diff --git a/scripts/ci/setup/gitlab-runner.yml b/scripts/ci/setup/gitlab-runner.yml
index 7bdafab..57e7fae 100644
--- a/scripts/ci/setup/gitlab-runner.yml
+++ b/scripts/ci/setup/gitlab-runner.yml
@@ -49,30 +49,51 @@
- debug:
msg: gitlab-runner arch is {{ gitlab_runner_arch }}
- - name: Download the matching gitlab-runner (DEB)
+ # Debian/Ubuntu setup
+ - name: Get gitlab-runner repo setup script (DEB)
get_url:
dest: "/root/"
- url: "https://gitlab-runner-downloads.s3.amazonaws.com/latest/deb/gitlab-runner_{{ gitlab_runner_arch }}.deb"
+ url: "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh"
+ mode: 0755
when:
- ansible_facts['distribution'] == 'Ubuntu'
- - name: Download the matching gitlab-runner (RPM)
+ - name: Run gitlab-runner repo setup script (DEB)
+ shell: "/root/script.deb.sh"
+ when:
+ - ansible_facts['distribution'] == 'Ubuntu'
+
+ - name: Install gitlab-runner (DEB)
+ ansible.builtin.apt:
+ name: gitlab-runner
+ update_cache: yes
+ state: present
+ when:
+ - ansible_facts['distribution'] == 'Ubuntu'
+
+ # RPM setup
+ - name: Get gitlab-runner repo setup script (RPM)
get_url:
dest: "/root/"
- url: "https://gitlab-runner-downloads.s3.amazonaws.com/latest/rpm/gitlab-runner_{{ gitlab_runner_arch }}.rpm"
+ url: "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh"
+ mode: 0755
when:
- ansible_facts['distribution'] == 'CentOS'
- - name: Install gitlab-runner via package manager (DEB)
- apt: deb="/root/gitlab-runner_{{ gitlab_runner_arch }}.deb"
+ - name: Run gitlab-runner repo setup script (RPM)
+ shell: "/root/script.rpm.sh"
when:
- - ansible_facts['distribution'] == 'Ubuntu'
+ - ansible_facts['distribution'] == 'CentOS'
- - name: Install gitlab-runner via package manager (RPM)
- yum: name="/root/gitlab-runner_{{ gitlab_runner_arch }}.rpm"
+ - name: Install gitlab-runner (RPM)
+ yum:
+ name: gitlab-runner
+ update_cache: yes
+ state: present
when:
- ansible_facts['distribution'] == 'CentOS'
+ # Register Runners
- name: Register the gitlab-runner
command: "/usr/bin/gitlab-runner register --non-interactive --url {{ gitlab_runner_server_url }} --registration-token {{ gitlab_runner_registration_token }} --executor shell --tag-list {{ ansible_facts[\"architecture\"] }},{{ ansible_facts[\"distribution\"]|lower }}_{{ ansible_facts[\"distribution_version\"] }} --description '{{ ansible_facts[\"distribution\"] }} {{ ansible_facts[\"distribution_version\"] }} {{ ansible_facts[\"architecture\"] }} ({{ ansible_facts[\"os_family\"] }})'"
diff --git a/scripts/ci/setup/ubuntu/build-environment.yml b/scripts/ci/setup/ubuntu/build-environment.yml
index edf1900..56b5160 100644
--- a/scripts/ci/setup/ubuntu/build-environment.yml
+++ b/scripts/ci/setup/ubuntu/build-environment.yml
@@ -39,7 +39,6 @@
when:
- ansible_facts['distribution'] == 'Ubuntu'
- ansible_facts['distribution_version'] == '22.04'
- - ansible_facts['architecture'] == 'aarch64' or ansible_facts['architecture'] == 'x86_64'
- name: Install packages for QEMU on Ubuntu 22.04
package:
@@ -47,7 +46,6 @@
when:
- ansible_facts['distribution'] == 'Ubuntu'
- ansible_facts['distribution_version'] == '22.04'
- - ansible_facts['architecture'] == 'aarch64' or ansible_facts['architecture'] == 'x86_64'
- name: Install armhf cross-compile packages to build QEMU on AArch64 Ubuntu 22.04
package:
diff --git a/scripts/ci/setup/ubuntu/ubuntu-2204-aarch64.yaml b/scripts/ci/setup/ubuntu/ubuntu-2204-aarch64.yaml
index fd5489c..71a0f0c 100644
--- a/scripts/ci/setup/ubuntu/ubuntu-2204-aarch64.yaml
+++ b/scripts/ci/setup/ubuntu/ubuntu-2204-aarch64.yaml
@@ -49,6 +49,7 @@ packages:
- libglusterfs-dev
- libgnutls28-dev
- libgtk-3-dev
+ - libgtk-vnc-2.0-dev
- libibverbs-dev
- libiscsi-dev
- libjemalloc-dev
diff --git a/scripts/ci/setup/ubuntu/ubuntu-2204-s390x.yaml b/scripts/ci/setup/ubuntu/ubuntu-2204-s390x.yaml
index afa0450..d8de967 100644
--- a/scripts/ci/setup/ubuntu/ubuntu-2204-s390x.yaml
+++ b/scripts/ci/setup/ubuntu/ubuntu-2204-s390x.yaml
@@ -49,6 +49,7 @@ packages:
- libglusterfs-dev
- libgnutls28-dev
- libgtk-3-dev
+ - libgtk-vnc-2.0-dev
- libibverbs-dev
- libiscsi-dev
- libjemalloc-dev
diff --git a/scripts/coccinelle/device-reset.cocci b/scripts/coccinelle/device-reset.cocci
new file mode 100644
index 0000000..510042a
--- /dev/null
+++ b/scripts/coccinelle/device-reset.cocci
@@ -0,0 +1,30 @@
+// Convert opencoded DeviceClass::reset assignments to calls to
+// device_class_set_legacy_reset()
+//
+// Copyright Linaro Ltd 2024
+// This work is licensed under the terms of the GNU GPLv2 or later.
+//
+// spatch --macro-file scripts/cocci-macro-file.h \
+// --sp-file scripts/coccinelle/device-reset.cocci \
+// --keep-comments --smpl-spacing --in-place --include-headers --dir hw
+//
+// For simplicity we assume some things about the code we're modifying
+// that happen to be true for all our targets:
+// * all cpu_class_set_parent_reset() callsites have a 'DeviceClass *dc' local
+// * the parent reset field in the target CPU class is 'parent_reset'
+// * no reset function already has a 'dev' local
+
+@@
+identifier dc, resetfn;
+@@
+ DeviceClass *dc;
+ ...
+- dc->reset = resetfn;
++ device_class_set_legacy_reset(dc, resetfn);
+@@
+identifier dc, resetfn;
+@@
+ DeviceClass *dc;
+ ...
+- dc->reset = &resetfn;
++ device_class_set_legacy_reset(dc, resetfn);
diff --git a/scripts/coverity-scan/COMPONENTS.md b/scripts/coverity-scan/COMPONENTS.md
index 858190b..a58e741 100644
--- a/scripts/coverity-scan/COMPONENTS.md
+++ b/scripts/coverity-scan/COMPONENTS.md
@@ -9,9 +9,6 @@ arm
avr
~ .*/qemu((/include)?/hw/avr/.*|/target/avr/.*)
-cris
- ~ .*/qemu((/include)?/hw/cris/.*|/target/cris/.*)
-
hexagon-gen (component should be ignored in analysis)
~ .*/qemu(/target/hexagon/.*generated.*)
diff --git a/scripts/gensyscalls.sh b/scripts/gensyscalls.sh
deleted file mode 100755
index 8495728..0000000
--- a/scripts/gensyscalls.sh
+++ /dev/null
@@ -1,103 +0,0 @@
-#!/bin/sh
-#
-# Update syscall_nr.h files from linux headers asm-generic/unistd.h
-#
-# This code is licensed under the GPL version 2 or later. See
-# the COPYING file in the top-level directory.
-#
-
-linux="$1"
-output="$2"
-
-TMP=$(mktemp -d)
-
-if [ "$linux" = "" ] ; then
- echo "Needs path to linux source tree" 1>&2
- exit 1
-fi
-
-if [ "$output" = "" ] ; then
- output="$PWD"
-fi
-
-upper()
-{
- echo "$1" | tr "[:lower:]" "[:upper:]" | tr "[:punct:]" "_"
-}
-
-qemu_arch()
-{
- case "$1" in
- arm64)
- echo "aarch64"
- ;;
- *)
- echo "$1"
- ;;
- esac
-}
-
-read_includes()
-{
- arch=$1
- bits=$2
-
- cpp -P -nostdinc -fdirectives-only \
- -D_UAPI_ASM_$(upper ${arch})_BITSPERLONG_H \
- -D__ASM_$(upper ${arch})_BITSPERLONG_H \
- -D__BITS_PER_LONG=${bits} \
- -I${linux}/arch/${arch}/include/uapi/ \
- -I${linux}/include/uapi \
- -I${TMP} \
- "${linux}/arch/${arch}/include/uapi/asm/unistd.h"
-}
-
-filter_defines()
-{
- grep -e "#define __NR_" -e "#define __NR3264"
-}
-
-rename_defines()
-{
- sed "s/ __NR_/ TARGET_NR_/g;s/(__NR_/(TARGET_NR_/g"
-}
-
-evaluate_values()
-{
- sed "s/#define TARGET_NR_/QEMU TARGET_NR_/" | \
- cpp -P -nostdinc | \
- sed "s/^QEMU /#define /"
-}
-
-generate_syscall_nr()
-{
- arch=$1
- bits=$2
- file="$3"
- guard="$(upper LINUX_USER_$(qemu_arch $arch)_$(basename "$file"))"
-
- (echo "/*"
- echo " * This file contains the system call numbers."
- echo " * Do not modify."
- echo " * This file is generated by scripts/gensyscalls.sh"
- echo " */"
- echo "#ifndef ${guard}"
- echo "#define ${guard}"
- echo
- read_includes $arch $bits | filter_defines | rename_defines | \
- evaluate_values | sort -n -k 3
- echo
- echo "#endif /* ${guard} */") > "$file"
-}
-
-mkdir "$TMP/asm"
-> "$TMP/asm/bitsperlong.h"
-
-generate_syscall_nr arm64 64 "$output/linux-user/aarch64/syscall_nr.h"
-generate_syscall_nr openrisc 32 "$output/linux-user/openrisc/syscall_nr.h"
-
-generate_syscall_nr riscv 32 "$output/linux-user/riscv/syscall32_nr.h"
-generate_syscall_nr riscv 64 "$output/linux-user/riscv/syscall64_nr.h"
-generate_syscall_nr hexagon 32 "$output/linux-user/hexagon/syscall_nr.h"
-generate_syscall_nr loongarch 64 "$output/linux-user/loongarch64/syscall_nr.h"
-rm -fr "$TMP"
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 240923d..fec83f5 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -1,5 +1,5 @@
#!/usr/bin/env perl
-# SPDX-License-Identifier: GPL-2.0
+# SPDX-License-Identifier: GPL-2.0-only
use warnings;
use strict;
diff --git a/scripts/make-release b/scripts/make-release
index 6e0433d..8dc9391 100755
--- a/scripts/make-release
+++ b/scripts/make-release
@@ -17,7 +17,11 @@ if [ $# -ne 2 ]; then
fi
# Only include wraps that are invoked with subproject()
-SUBPROJECTS="libvfio-user keycodemapdb berkeley-softfloat-3 berkeley-testfloat-3"
+SUBPROJECTS="libvfio-user keycodemapdb berkeley-softfloat-3
+ berkeley-testfloat-3 arbitrary-int-1-rs bilge-0.2-rs
+ bilge-impl-0.2-rs either-1-rs itertools-0.11-rs proc-macro2-1-rs
+ proc-macro-error-1-rs proc-macro-error-attr-1-rs quote-1-rs
+ syn-2-rs unicode-ident-1-rs"
src="$1"
version="$2"
diff --git a/scripts/meson-buildoptions. b/scripts/meson-buildoptions.
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/scripts/meson-buildoptions.
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index c97079a..6d08605 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -21,6 +21,7 @@ meson_options_help() {
printf "%s\n" ' --disable-relocatable toggle relocatable install'
printf "%s\n" ' --docdir=VALUE Base directory for documentation installation'
printf "%s\n" ' (can be empty) [share/doc]'
+ printf "%s\n" ' --enable-asan enable address sanitizer'
printf "%s\n" ' --enable-block-drv-whitelist-in-tools'
printf "%s\n" ' use block whitelist also in tools instead of only'
printf "%s\n" ' QEMU'
@@ -46,13 +47,13 @@ meson_options_help() {
printf "%s\n" ' getrandom()'
printf "%s\n" ' --enable-safe-stack SafeStack Stack Smash Protection (requires'
printf "%s\n" ' clang/llvm and coroutine backend ucontext)'
- printf "%s\n" ' --enable-sanitizers enable default sanitizers'
printf "%s\n" ' --enable-strip Strip targets on install'
printf "%s\n" ' --enable-tcg-interpreter TCG with bytecode interpreter (slow)'
printf "%s\n" ' --enable-trace-backends=CHOICES'
printf "%s\n" ' Set available tracing backends [log] (choices:'
printf "%s\n" ' dtrace/ftrace/log/nop/simple/syslog/ust)'
printf "%s\n" ' --enable-tsan enable thread sanitizer'
+ printf "%s\n" ' --enable-ubsan enable undefined behaviour sanitizer'
printf "%s\n" ' --firmwarepath=VALUES search PATH for firmware files [share/qemu-'
printf "%s\n" ' firmware]'
printf "%s\n" ' --iasl=VALUE Path to ACPI disassembler'
@@ -163,6 +164,7 @@ meson_options_help() {
printf "%s\n" ' pixman pixman support'
printf "%s\n" ' plugins TCG plugins via shared library loading'
printf "%s\n" ' png PNG support with libpng'
+ printf "%s\n" ' qatzip QATzip compression support'
printf "%s\n" ' qcow1 qcow1 image format support'
printf "%s\n" ' qed qed image format support'
printf "%s\n" ' qga-vss build QGA VSS support (broken with MinGW)'
@@ -170,6 +172,7 @@ meson_options_help() {
printf "%s\n" ' rbd Ceph block device driver'
printf "%s\n" ' rdma Enable RDMA-based migration'
printf "%s\n" ' replication replication support'
+ printf "%s\n" ' rust Rust support'
printf "%s\n" ' rutabaga-gfx rutabaga_gfx support'
printf "%s\n" ' sdl SDL user interface'
printf "%s\n" ' sdl-image SDL Image support for icons'
@@ -206,8 +209,6 @@ meson_options_help() {
printf "%s\n" ' vhost-vdpa vhost-vdpa kernel backend support'
printf "%s\n" ' virglrenderer virgl rendering support'
printf "%s\n" ' virtfs virtio-9p support'
- printf "%s\n" ' virtfs-proxy-helper'
- printf "%s\n" ' virtio-9p proxy helper support'
printf "%s\n" ' vmdk vmdk image format support'
printf "%s\n" ' vmnet vmnet.framework network backend support'
printf "%s\n" ' vnc VNC server'
@@ -230,6 +231,8 @@ _meson_option_parse() {
--disable-af-xdp) printf "%s" -Daf_xdp=disabled ;;
--enable-alsa) printf "%s" -Dalsa=enabled ;;
--disable-alsa) printf "%s" -Dalsa=disabled ;;
+ --enable-asan) printf "%s" -Dasan=true ;;
+ --disable-asan) printf "%s" -Dasan=false ;;
--enable-attr) printf "%s" -Dattr=enabled ;;
--disable-attr) printf "%s" -Dattr=disabled ;;
--audio-drv-list=*) quote_sh "-Daudio_drv_list=$2" ;;
@@ -427,6 +430,8 @@ _meson_option_parse() {
--enable-png) printf "%s" -Dpng=enabled ;;
--disable-png) printf "%s" -Dpng=disabled ;;
--prefix=*) quote_sh "-Dprefix=$2" ;;
+ --enable-qatzip) printf "%s" -Dqatzip=enabled ;;
+ --disable-qatzip) printf "%s" -Dqatzip=disabled ;;
--enable-qcow1) printf "%s" -Dqcow1=enabled ;;
--disable-qcow1) printf "%s" -Dqcow1=disabled ;;
--enable-qed) printf "%s" -Dqed=enabled ;;
@@ -452,12 +457,12 @@ _meson_option_parse() {
--disable-replication) printf "%s" -Dreplication=disabled ;;
--enable-rng-none) printf "%s" -Drng_none=true ;;
--disable-rng-none) printf "%s" -Drng_none=false ;;
+ --enable-rust) printf "%s" -Drust=enabled ;;
+ --disable-rust) printf "%s" -Drust=disabled ;;
--enable-rutabaga-gfx) printf "%s" -Drutabaga_gfx=enabled ;;
--disable-rutabaga-gfx) printf "%s" -Drutabaga_gfx=disabled ;;
--enable-safe-stack) printf "%s" -Dsafe_stack=true ;;
--disable-safe-stack) printf "%s" -Dsafe_stack=false ;;
- --enable-sanitizers) printf "%s" -Dsanitizers=true ;;
- --disable-sanitizers) printf "%s" -Dsanitizers=false ;;
--enable-sdl) printf "%s" -Dsdl=enabled ;;
--disable-sdl) printf "%s" -Dsdl=disabled ;;
--enable-sdl-image) printf "%s" -Dsdl_image=enabled ;;
@@ -505,6 +510,8 @@ _meson_option_parse() {
--disable-u2f) printf "%s" -Du2f=disabled ;;
--enable-uadk) printf "%s" -Duadk=enabled ;;
--disable-uadk) printf "%s" -Duadk=disabled ;;
+ --enable-ubsan) printf "%s" -Dubsan=true ;;
+ --disable-ubsan) printf "%s" -Dubsan=false ;;
--enable-usb-redir) printf "%s" -Dusb_redir=enabled ;;
--disable-usb-redir) printf "%s" -Dusb_redir=disabled ;;
--enable-vde) printf "%s" -Dvde=enabled ;;
@@ -533,8 +540,6 @@ _meson_option_parse() {
--disable-virglrenderer) printf "%s" -Dvirglrenderer=disabled ;;
--enable-virtfs) printf "%s" -Dvirtfs=enabled ;;
--disable-virtfs) printf "%s" -Dvirtfs=disabled ;;
- --enable-virtfs-proxy-helper) printf "%s" -Dvirtfs_proxy_helper=enabled ;;
- --disable-virtfs-proxy-helper) printf "%s" -Dvirtfs_proxy_helper=disabled ;;
--enable-vmdk) printf "%s" -Dvmdk=enabled ;;
--disable-vmdk) printf "%s" -Dvmdk=disabled ;;
--enable-vmnet) printf "%s" -Dvmnet=enabled ;;
diff --git a/scripts/minikconf.py b/scripts/minikconf.py
index bcd9101..6f7f43b 100644
--- a/scripts/minikconf.py
+++ b/scripts/minikconf.py
@@ -112,7 +112,7 @@ class KconfigData:
def set_value(self, val, clause):
self.clauses_for_var.append(clause)
if self.has_value() and self.value != val:
- print("The following clauses were found for " + self.name)
+ print("The following clauses were found for " + self.name, file=sys.stderr)
for i in self.clauses_for_var:
print(" " + str(i), file=sys.stderr)
raise KconfigDataError('contradiction between clauses when setting %s' % self)
diff --git a/scripts/probe-gdb-support.py b/scripts/probe-gdb-support.py
index 46d6c00..6bcadce 100644
--- a/scripts/probe-gdb-support.py
+++ b/scripts/probe-gdb-support.py
@@ -19,59 +19,61 @@
import argparse
import re
-from subprocess import check_output, STDOUT
+from subprocess import check_output, STDOUT, CalledProcessError
+import sys
-# mappings from gdb arch to QEMU target
-mappings = {
- "alpha" : "alpha",
+# Mappings from gdb arch to QEMU target
+MAP = {
+ "alpha" : ["alpha"],
"aarch64" : ["aarch64", "aarch64_be"],
- "armv7": "arm",
+ "armv7": ["arm"],
"armv8-a" : ["aarch64", "aarch64_be"],
- "avr" : "avr",
- "cris" : "cris",
+ "avr" : ["avr"],
# no hexagon in upstream gdb
- "hppa1.0" : "hppa",
- "i386" : "i386",
- "i386:x86-64" : "x86_64",
- "Loongarch64" : "loongarch64",
- "m68k" : "m68k",
- "MicroBlaze" : "microblaze",
+ "hppa1.0" : ["hppa"],
+ "i386" : ["i386"],
+ "i386:x86-64" : ["x86_64"],
+ "Loongarch64" : ["loongarch64"],
+ "m68k" : ["m68k"],
+ "MicroBlaze" : ["microblaze"],
"mips:isa64" : ["mips64", "mips64el"],
- "or1k" : "or1k",
- "powerpc:common" : "ppc",
+ "or1k" : ["or1k"],
+ "powerpc:common" : ["ppc"],
"powerpc:common64" : ["ppc64", "ppc64le"],
- "riscv:rv32" : "riscv32",
- "riscv:rv64" : "riscv64",
- "s390:64-bit" : "s390x",
+ "riscv:rv32" : ["riscv32"],
+ "riscv:rv64" : ["riscv64"],
+ "s390:64-bit" : ["s390x"],
"sh4" : ["sh4", "sh4eb"],
- "sparc": "sparc",
- "sparc:v8plus": "sparc32plus",
- "sparc:v9a" : "sparc64",
+ "sparc": ["sparc"],
+ "sparc:v8plus": ["sparc32plus"],
+ "sparc:v9a" : ["sparc64"],
# no tricore in upstream gdb
"xtensa" : ["xtensa", "xtensaeb"]
}
+
def do_probe(gdb):
- gdb_out = check_output([gdb,
- "-ex", "set architecture",
- "-ex", "quit"], stderr=STDOUT)
+ try:
+ gdb_out = check_output([gdb,
+ "-ex", "set architecture",
+ "-ex", "quit"], stderr=STDOUT, encoding="utf-8")
+ except (OSError) as e:
+ sys.exit(e)
+ except CalledProcessError as e:
+ sys.exit(f'{e}. Output:\n\n{e.output}')
+
+ found_gdb_archs = re.search(r'Valid arguments are (.*)', gdb_out)
- m = re.search(r"Valid arguments are (.*)",
- gdb_out.decode("utf-8"))
+ targets = set()
+ if found_gdb_archs:
+ gdb_archs = found_gdb_archs.group(1).split(", ")
+ mapped_gdb_archs = [arch for arch in gdb_archs if arch in MAP]
- valid_arches = set()
+ targets = {target for arch in mapped_gdb_archs for target in MAP[arch]}
- if m.group(1):
- for arch in m.group(1).split(", "):
- if arch in mappings:
- mapping = mappings[arch]
- if isinstance(mapping, str):
- valid_arches.add(mapping)
- else:
- for entry in mapping:
- valid_arches.add(entry)
+ # QEMU targets
+ return targets
- return valid_arches
def main() -> None:
parser = argparse.ArgumentParser(description='Probe GDB Architectures')
diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
index 737b059..d7c8aa3 100644
--- a/scripts/qapi/common.py
+++ b/scripts/qapi/common.py
@@ -40,22 +40,28 @@ def camel_to_upper(value: str) -> str:
ENUM_Name2 -> ENUM_NAME2
ENUM24_Name -> ENUM24_NAME
"""
- c_fun_str = c_name(value, False)
- if value.isupper():
- return c_fun_str
-
- new_name = ''
- length = len(c_fun_str)
- for i in range(length):
- char = c_fun_str[i]
- # When char is upper case and no '_' appears before, do more checks
- if char.isupper() and (i > 0) and c_fun_str[i - 1] != '_':
- if i < length - 1 and c_fun_str[i + 1].islower():
- new_name += '_'
- elif c_fun_str[i - 1].isdigit():
- new_name += '_'
- new_name += char
- return new_name.lstrip('_').upper()
+ ret = value[0]
+ upc = value[0].isupper()
+
+ # Copy remainder of ``value`` to ``ret`` with '_' inserted
+ for ch in value[1:]:
+ if ch.isupper() == upc:
+ pass
+ elif upc:
+ # ``ret`` ends in upper case, next char isn't: insert '_'
+ # before the last upper case char unless there is one
+ # already, or it's at the beginning
+ if len(ret) > 2 and ret[-2].isalnum():
+ ret = ret[:-1] + '_' + ret[-1]
+ else:
+ # ``ret`` doesn't end in upper case, next char is: insert
+ # '_' before it
+ if ret[-1].isalnum():
+ ret += '_'
+ ret += ch
+ upc = ch.isupper()
+
+ return c_name(ret.upper()).lstrip('_')
def c_enum_const(type_name: str,
@@ -68,9 +74,9 @@ def c_enum_const(type_name: str,
:param const_name: The name of this constant.
:param prefix: Optional, prefix that overrides the type_name.
"""
- if prefix is not None:
- type_name = prefix
- return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
+ if prefix is None:
+ prefix = camel_to_upper(type_name)
+ return prefix + '_' + c_name(const_name, False).upper()
def c_name(name: str, protect: bool = True) -> str:
diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
index d65c35f..e97c978 100644
--- a/scripts/qapi/schema.py
+++ b/scripts/qapi/schema.py
@@ -1249,7 +1249,7 @@ class QAPISchema:
[{'name': n} for n in qtypes], None)
self._def_definition(QAPISchemaEnumType(
- 'QType', None, None, None, None, qtype_values, 'QTYPE'))
+ 'QType', None, None, None, None, qtype_values, None))
def _make_features(
self,
diff --git a/scripts/replay-dump.py b/scripts/replay-dump.py
index d668193..4ce7ff5 100755
--- a/scripts/replay-dump.py
+++ b/scripts/replay-dump.py
@@ -20,6 +20,8 @@
import argparse
import struct
+import os
+import sys
from collections import namedtuple
from os import path
@@ -99,7 +101,7 @@ def call_decode(table, index, dumpfile):
print("Could not decode index: %d" % (index))
print("Entry is: %s" % (decoder))
print("Decode Table is:\n%s" % (table))
- return False
+ raise(Exception("unknown event"))
else:
return decoder.fn(decoder.eid, decoder.name, dumpfile)
@@ -120,7 +122,7 @@ def print_event(eid, name, string=None, event_count=None):
def decode_unimp(eid, name, _unused_dumpfile):
"Unimplemented decoder, will trigger exit"
print("%s not handled - will now stop" % (name))
- return False
+ raise(Exception("unhandled event"))
def decode_plain(eid, name, _unused_dumpfile):
"Plain events without additional data"
@@ -134,6 +136,30 @@ def swallow_async_qword(eid, name, dumpfile):
print(" %s(%d) @ %d" % (name, eid, step_id))
return True
+def swallow_bytes(eid, name, dumpfile, nr):
+ """Swallow nr bytes of data without looking at it"""
+ dumpfile.seek(nr, os.SEEK_CUR)
+
+total_insns = 0
+
+def decode_instruction(eid, name, dumpfile):
+ global total_insns
+ ins_diff = read_dword(dumpfile)
+ total_insns += ins_diff
+ print_event(eid, name, "+ %d -> %d" % (ins_diff, total_insns))
+ return True
+
+def decode_interrupt(eid, name, dumpfile):
+ print_event(eid, name)
+ return True
+
+def decode_exception(eid, name, dumpfile):
+ print_event(eid, name)
+ return True
+
+# v12 does away with the additional event byte and encodes it in the main type
+# Between v8 and v9, REPLAY_ASYNC_BH_ONESHOT was added, but we don't decode
+# those versions so leave it out.
async_decode_table = [ Decoder(0, "REPLAY_ASYNC_EVENT_BH", swallow_async_qword),
Decoder(1, "REPLAY_ASYNC_INPUT", decode_unimp),
Decoder(2, "REPLAY_ASYNC_INPUT_SYNC", decode_unimp),
@@ -142,8 +168,8 @@ async_decode_table = [ Decoder(0, "REPLAY_ASYNC_EVENT_BH", swallow_async_qword),
Decoder(5, "REPLAY_ASYNC_EVENT_NET", decode_unimp),
]
# See replay_read_events/replay_read_event
-def decode_async(eid, name, dumpfile):
- """Decode an ASYNC event"""
+def decode_async_old(eid, name, dumpfile):
+ """Decode an ASYNC event (pre-v8)"""
print_event(eid, name)
@@ -157,13 +183,37 @@ def decode_async(eid, name, dumpfile):
return call_decode(async_decode_table, async_event_kind, dumpfile)
-total_insns = 0
+def decode_async_bh(eid, name, dumpfile):
+ op_id = read_qword(dumpfile)
+ print_event(eid, name)
+ return True
-def decode_instruction(eid, name, dumpfile):
- global total_insns
- ins_diff = read_dword(dumpfile)
- total_insns += ins_diff
- print_event(eid, name, "+ %d -> %d" % (ins_diff, total_insns))
+def decode_async_bh_oneshot(eid, name, dumpfile):
+ op_id = read_qword(dumpfile)
+ print_event(eid, name)
+ return True
+
+def decode_async_char_read(eid, name, dumpfile):
+ char_id = read_byte(dumpfile)
+ size = read_dword(dumpfile)
+ print_event(eid, name, "device:%x chars:%s" % (char_id, dumpfile.read(size)))
+ return True
+
+def decode_async_block(eid, name, dumpfile):
+ op_id = read_qword(dumpfile)
+ print_event(eid, name)
+ return True
+
+def decode_async_net(eid, name, dumpfile):
+ net_id = read_byte(dumpfile)
+ flags = read_dword(dumpfile)
+ size = read_dword(dumpfile)
+ swallow_bytes(eid, name, dumpfile, size)
+ print_event(eid, name, "net:%x flags:%x bytes:%d" % (net_id, flags, size))
+ return True
+
+def decode_shutdown(eid, name, dumpfile):
+ print_event(eid, name)
return True
def decode_char_write(eid, name, dumpfile):
@@ -177,7 +227,22 @@ def decode_audio_out(eid, name, dumpfile):
print_event(eid, name, "%d" % (audio_data))
return True
-def decode_checkpoint(eid, name, dumpfile):
+def decode_random(eid, name, dumpfile):
+ ret = read_dword(dumpfile)
+ size = read_dword(dumpfile)
+ swallow_bytes(eid, name, dumpfile, size)
+ if (ret):
+ print_event(eid, name, "%d bytes (getrandom failed)" % (size))
+ else:
+ print_event(eid, name, "%d bytes" % (size))
+ return True
+
+def decode_clock(eid, name, dumpfile):
+ clock_data = read_qword(dumpfile)
+ print_event(eid, name, "0x%x" % (clock_data))
+ return True
+
+def __decode_checkpoint(eid, name, dumpfile, old):
"""Decode a checkpoint.
Checkpoints contain a series of async events with their own specific data.
@@ -189,38 +254,33 @@ def decode_checkpoint(eid, name, dumpfile):
# if the next event is EVENT_ASYNC there are a bunch of
# async events to read, otherwise we are done
- if next_event != 3:
- print_event(eid, name, "no additional data", event_number)
- else:
+ if (old and next_event == 3) or (not old and next_event >= 3 and next_event <= 9):
print_event(eid, name, "more data follows", event_number)
+ else:
+ print_event(eid, name, "no additional data", event_number)
replay_state.reuse_event(next_event)
return True
+def decode_checkpoint_old(eid, name, dumpfile):
+ return __decode_checkpoint(eid, name, dumpfile, False)
+
+def decode_checkpoint(eid, name, dumpfile):
+ return __decode_checkpoint(eid, name, dumpfile, True)
+
def decode_checkpoint_init(eid, name, dumpfile):
print_event(eid, name)
return True
-def decode_interrupt(eid, name, dumpfile):
+def decode_end(eid, name, dumpfile):
print_event(eid, name)
- return True
-
-def decode_clock(eid, name, dumpfile):
- clock_data = read_qword(dumpfile)
- print_event(eid, name, "0x%x" % (clock_data))
- return True
-
-def decode_random(eid, name, dumpfile):
- ret = read_dword(dumpfile)
- data = read_array(dumpfile)
- print_event(eid, "%d bytes of random data" % len(data))
- return True
+ return False
# pre-MTTCG merge
v5_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
Decoder(2, "EVENT_EXCEPTION", decode_plain),
- Decoder(3, "EVENT_ASYNC", decode_async),
+ Decoder(3, "EVENT_ASYNC", decode_async_old),
Decoder(4, "EVENT_SHUTDOWN", decode_unimp),
Decoder(5, "EVENT_CHAR_WRITE", decode_char_write),
Decoder(6, "EVENT_CHAR_READ_ALL", decode_unimp),
@@ -242,7 +302,7 @@ v5_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
v6_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
Decoder(2, "EVENT_EXCEPTION", decode_plain),
- Decoder(3, "EVENT_ASYNC", decode_async),
+ Decoder(3, "EVENT_ASYNC", decode_async_old),
Decoder(4, "EVENT_SHUTDOWN", decode_unimp),
Decoder(5, "EVENT_CHAR_WRITE", decode_char_write),
Decoder(6, "EVENT_CHAR_READ_ALL", decode_unimp),
@@ -266,7 +326,7 @@ v6_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
v7_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
Decoder(2, "EVENT_EXCEPTION", decode_unimp),
- Decoder(3, "EVENT_ASYNC", decode_async),
+ Decoder(3, "EVENT_ASYNC", decode_async_old),
Decoder(4, "EVENT_SHUTDOWN", decode_unimp),
Decoder(5, "EVENT_SHUTDOWN_HOST_ERR", decode_unimp),
Decoder(6, "EVENT_SHUTDOWN_HOST_QMP", decode_unimp),
@@ -296,32 +356,31 @@ v7_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
v12_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
Decoder(1, "EVENT_INTERRUPT", decode_interrupt),
- Decoder(2, "EVENT_EXCEPTION", decode_plain),
- Decoder(3, "EVENT_ASYNC", decode_async),
- Decoder(4, "EVENT_ASYNC", decode_async),
- Decoder(5, "EVENT_ASYNC", decode_async),
- Decoder(6, "EVENT_ASYNC", decode_async),
- Decoder(6, "EVENT_ASYNC", decode_async),
- Decoder(8, "EVENT_ASYNC", decode_async),
- Decoder(9, "EVENT_ASYNC", decode_async),
- Decoder(10, "EVENT_ASYNC", decode_async),
- Decoder(11, "EVENT_SHUTDOWN", decode_unimp),
- Decoder(12, "EVENT_SHUTDOWN_HOST_ERR", decode_unimp),
- Decoder(13, "EVENT_SHUTDOWN_HOST_QMP_QUIT", decode_unimp),
- Decoder(14, "EVENT_SHUTDOWN_HOST_QMP_RESET", decode_unimp),
- Decoder(14, "EVENT_SHUTDOWN_HOST_SIGNAL", decode_unimp),
- Decoder(15, "EVENT_SHUTDOWN_HOST_UI", decode_unimp),
- Decoder(16, "EVENT_SHUTDOWN_GUEST_SHUTDOWN", decode_unimp),
- Decoder(17, "EVENT_SHUTDOWN_GUEST_RESET", decode_unimp),
- Decoder(18, "EVENT_SHUTDOWN_GUEST_PANIC", decode_unimp),
- Decoder(19, "EVENT_SHUTDOWN_GUEST_SUBSYSTEM_RESET", decode_unimp),
- Decoder(20, "EVENT_SHUTDOWN_GUEST_SNAPSHOT_LOAD", decode_unimp),
- Decoder(21, "EVENT_SHUTDOWN___MAX", decode_unimp),
+ Decoder(2, "EVENT_EXCEPTION", decode_exception),
+ Decoder(3, "EVENT_ASYNC_BH", decode_async_bh),
+ Decoder(4, "EVENT_ASYNC_BH_ONESHOT", decode_async_bh_oneshot),
+ Decoder(5, "EVENT_ASYNC_INPUT", decode_unimp),
+ Decoder(6, "EVENT_ASYNC_INPUT_SYNC", decode_unimp),
+ Decoder(7, "EVENT_ASYNC_CHAR_READ", decode_async_char_read),
+ Decoder(8, "EVENT_ASYNC_BLOCK", decode_async_block),
+ Decoder(9, "EVENT_ASYNC_NET", decode_async_net),
+ Decoder(10, "EVENT_SHUTDOWN", decode_shutdown),
+ Decoder(11, "EVENT_SHUTDOWN_HOST_ERR", decode_shutdown),
+ Decoder(12, "EVENT_SHUTDOWN_HOST_QMP_QUIT", decode_shutdown),
+ Decoder(13, "EVENT_SHUTDOWN_HOST_QMP_RESET", decode_shutdown),
+ Decoder(14, "EVENT_SHUTDOWN_HOST_SIGNAL", decode_shutdown),
+ Decoder(15, "EVENT_SHUTDOWN_HOST_UI", decode_shutdown),
+ Decoder(16, "EVENT_SHUTDOWN_GUEST_SHUTDOWN", decode_shutdown),
+ Decoder(17, "EVENT_SHUTDOWN_GUEST_RESET", decode_shutdown),
+ Decoder(18, "EVENT_SHUTDOWN_GUEST_PANIC", decode_shutdown),
+ Decoder(19, "EVENT_SHUTDOWN_SUBSYS_RESET", decode_shutdown),
+ Decoder(20, "EVENT_SHUTDOWN_SNAPSHOT_LOAD", decode_shutdown),
+ Decoder(21, "EVENT_SHUTDOWN___MAX", decode_shutdown),
Decoder(22, "EVENT_CHAR_WRITE", decode_char_write),
Decoder(23, "EVENT_CHAR_READ_ALL", decode_unimp),
Decoder(24, "EVENT_CHAR_READ_ALL_ERROR", decode_unimp),
- Decoder(25, "EVENT_AUDIO_IN", decode_unimp),
- Decoder(26, "EVENT_AUDIO_OUT", decode_audio_out),
+ Decoder(25, "EVENT_AUDIO_OUT", decode_audio_out),
+ Decoder(26, "EVENT_AUDIO_IN", decode_unimp),
Decoder(27, "EVENT_RANDOM", decode_random),
Decoder(28, "EVENT_CLOCK_HOST", decode_clock),
Decoder(29, "EVENT_CLOCK_VIRTUAL_RT", decode_clock),
@@ -334,6 +393,7 @@ v12_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
Decoder(36, "EVENT_CP_CLOCK_VIRTUAL_RT", decode_checkpoint),
Decoder(37, "EVENT_CP_INIT", decode_checkpoint_init),
Decoder(38, "EVENT_CP_RESET", decode_checkpoint),
+ Decoder(39, "EVENT_END", decode_end),
]
def parse_arguments():
@@ -375,6 +435,7 @@ def decode_file(filename):
dumpfile)
except Exception as inst:
print(f"error {inst}")
+ sys.exit(1)
finally:
print(f"Reached {dumpfile.tell()} of {dumpsize} bytes")
diff --git a/scripts/rust/rust_root_crate.sh b/scripts/rust/rust_root_crate.sh
new file mode 100755
index 0000000..975bddf
--- /dev/null
+++ b/scripts/rust/rust_root_crate.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+set -eu
+
+cat <<EOF
+// @generated
+// This file is autogenerated by scripts/rust_root_crate.sh
+
+EOF
+
+for crate in $*; do
+ echo "extern crate $crate;"
+done
diff --git a/scripts/rust/rustc_args.py b/scripts/rust/rustc_args.py
new file mode 100644
index 0000000..e4cc972
--- /dev/null
+++ b/scripts/rust/rustc_args.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python3
+
+"""Generate rustc arguments for meson rust builds.
+
+This program generates --cfg compile flags for the configuration headers passed
+as arguments.
+
+Copyright (c) 2024 Linaro Ltd.
+
+Authors:
+ Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+
+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/>.
+"""
+
+import argparse
+import logging
+
+from typing import List
+
+
+def generate_cfg_flags(header: str) -> List[str]:
+ """Converts defines from config[..].h headers to rustc --cfg flags."""
+
+ def cfg_name(name: str) -> str:
+ """Filter function for C #defines"""
+ if (
+ name.startswith("CONFIG_")
+ or name.startswith("TARGET_")
+ or name.startswith("HAVE_")
+ ):
+ return name
+ return ""
+
+ with open(header, encoding="utf-8") as cfg:
+ config = [l.split()[1:] for l in cfg if l.startswith("#define")]
+
+ cfg_list = []
+ for cfg in config:
+ name = cfg_name(cfg[0])
+ if not name:
+ continue
+ if len(cfg) >= 2 and cfg[1] != "1":
+ continue
+ cfg_list.append("--cfg")
+ cfg_list.append(name)
+ return cfg_list
+
+
+def main() -> None:
+ # pylint: disable=missing-function-docstring
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-v", "--verbose", action="store_true")
+ parser.add_argument(
+ "--config-headers",
+ metavar="CONFIG_HEADER",
+ action="append",
+ dest="config_headers",
+ help="paths to any configuration C headers (*.h files), if any",
+ required=False,
+ default=[],
+ )
+ args = parser.parse_args()
+ if args.verbose:
+ logging.basicConfig(level=logging.DEBUG)
+ logging.debug("args: %s", args)
+ for header in args.config_headers:
+ for tok in generate_cfg_flags(header):
+ print(tok)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/update-syscalltbl.sh b/scripts/update-syscalltbl.sh
index 2d23e56..f0927c5 100755
--- a/scripts/update-syscalltbl.sh
+++ b/scripts/update-syscalltbl.sh
@@ -1,13 +1,18 @@
TBL_LIST="\
arch/alpha/kernel/syscalls/syscall.tbl,linux-user/alpha/syscall.tbl \
arch/arm/tools/syscall.tbl,linux-user/arm/syscall.tbl \
+scripts/syscall.tbl,linux-user/aarch64/syscall_64.tbl \
+scripts/syscall.tbl,linux-user/hexagon/syscall.tbl \
+scripts/syscall.tbl,linux-user/loongarch64/syscall.tbl \
arch/m68k/kernel/syscalls/syscall.tbl,linux-user/m68k/syscall.tbl \
arch/microblaze/kernel/syscalls/syscall.tbl,linux-user/microblaze/syscall.tbl \
arch/mips/kernel/syscalls/syscall_n32.tbl,linux-user/mips64/syscall_n32.tbl \
arch/mips/kernel/syscalls/syscall_n64.tbl,linux-user/mips64/syscall_n64.tbl \
arch/mips/kernel/syscalls/syscall_o32.tbl,linux-user/mips/syscall_o32.tbl \
+scripts/syscall.tbl,linux-user/openrisc/syscall.tbl \
arch/parisc/kernel/syscalls/syscall.tbl,linux-user/hppa/syscall.tbl \
arch/powerpc/kernel/syscalls/syscall.tbl,linux-user/ppc/syscall.tbl \
+scripts/syscall.tbl,linux-user/riscv/syscall.tbl \
arch/s390/kernel/syscalls/syscall.tbl,linux-user/s390x/syscall.tbl \
arch/sh/kernel/syscalls/syscall.tbl,linux-user/sh4/syscall.tbl \
arch/sparc/kernel/syscalls/syscall.tbl,linux-user/sparc64/syscall.tbl \
diff --git a/semihosting/Kconfig b/semihosting/Kconfig
index eaf3a20..fbe6ac8 100644
--- a/semihosting/Kconfig
+++ b/semihosting/Kconfig
@@ -1,6 +1,7 @@
config SEMIHOSTING
bool
+ depends on TCG
config ARM_COMPATIBLE_SEMIHOSTING
bool
diff --git a/subprojects/.gitignore b/subprojects/.gitignore
index adca026..50f173f 100644
--- a/subprojects/.gitignore
+++ b/subprojects/.gitignore
@@ -6,3 +6,14 @@
/keycodemapdb
/libvfio-user
/slirp
+/arbitrary-int-1.2.7
+/bilge-0.2.0
+/bilge-impl-0.2.0
+/either-1.12.0
+/itertools-0.11.0
+/proc-macro-error-1.0.4
+/proc-macro-error-attr-1.0.4
+/proc-macro2-1.0.84
+/quote-1.0.36
+/syn-2.0.66
+/unicode-ident-1.0.12
diff --git a/subprojects/arbitrary-int-1-rs.wrap b/subprojects/arbitrary-int-1-rs.wrap
new file mode 100644
index 0000000..e580538
--- /dev/null
+++ b/subprojects/arbitrary-int-1-rs.wrap
@@ -0,0 +1,7 @@
+[wrap-file]
+directory = arbitrary-int-1.2.7
+source_url = https://crates.io/api/v1/crates/arbitrary-int/1.2.7/download
+source_filename = arbitrary-int-1.2.7.tar.gz
+source_hash = c84fc003e338a6f69fbd4f7fe9f92b535ff13e9af8997f3b14b6ddff8b1df46d
+#method = cargo
+patch_directory = arbitrary-int-1-rs
diff --git a/subprojects/bilge-0.2-rs.wrap b/subprojects/bilge-0.2-rs.wrap
new file mode 100644
index 0000000..7a4339d
--- /dev/null
+++ b/subprojects/bilge-0.2-rs.wrap
@@ -0,0 +1,7 @@
+[wrap-file]
+directory = bilge-0.2.0
+source_url = https://crates.io/api/v1/crates/bilge/0.2.0/download
+source_filename = bilge-0.2.0.tar.gz
+source_hash = dc707ed8ebf81de5cd6c7f48f54b4c8621760926cdf35a57000747c512e67b57
+#method = cargo
+patch_directory = bilge-0.2-rs
diff --git a/subprojects/bilge-impl-0.2-rs.wrap b/subprojects/bilge-impl-0.2-rs.wrap
new file mode 100644
index 0000000..eefb10c
--- /dev/null
+++ b/subprojects/bilge-impl-0.2-rs.wrap
@@ -0,0 +1,7 @@
+[wrap-file]
+directory = bilge-impl-0.2.0
+source_url = https://crates.io/api/v1/crates/bilge-impl/0.2.0/download
+source_filename = bilge-impl-0.2.0.tar.gz
+source_hash = feb11e002038ad243af39c2068c8a72bcf147acf05025dcdb916fcc000adb2d8
+#method = cargo
+patch_directory = bilge-impl-0.2-rs
diff --git a/subprojects/either-1-rs.wrap b/subprojects/either-1-rs.wrap
new file mode 100644
index 0000000..6046712
--- /dev/null
+++ b/subprojects/either-1-rs.wrap
@@ -0,0 +1,7 @@
+[wrap-file]
+directory = either-1.12.0
+source_url = https://crates.io/api/v1/crates/either/1.12.0/download
+source_filename = either-1.12.0.tar.gz
+source_hash = 3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b
+#method = cargo
+patch_directory = either-1-rs
diff --git a/subprojects/itertools-0.11-rs.wrap b/subprojects/itertools-0.11-rs.wrap
new file mode 100644
index 0000000..66b0525
--- /dev/null
+++ b/subprojects/itertools-0.11-rs.wrap
@@ -0,0 +1,7 @@
+[wrap-file]
+directory = itertools-0.11.0
+source_url = https://crates.io/api/v1/crates/itertools/0.11.0/download
+source_filename = itertools-0.11.0.tar.gz
+source_hash = b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57
+#method = cargo
+patch_directory = itertools-0.11-rs
diff --git a/subprojects/packagefiles/arbitrary-int-1-rs/meson.build b/subprojects/packagefiles/arbitrary-int-1-rs/meson.build
new file mode 100644
index 0000000..34a189c
--- /dev/null
+++ b/subprojects/packagefiles/arbitrary-int-1-rs/meson.build
@@ -0,0 +1,19 @@
+project('arbitrary-int-1-rs', 'rust',
+ version: '1.2.7',
+ license: 'MIT',
+ default_options: [])
+
+_arbitrary_int_rs = static_library(
+ 'arbitrary_int',
+ files('src/lib.rs'),
+ gnu_symbol_visibility: 'hidden',
+ override_options: ['rust_std=2021', 'build.rust_std=2021'],
+ rust_abi: 'rust',
+ dependencies: [],
+)
+
+arbitrary_int_dep = declare_dependency(
+ link_with: _arbitrary_int_rs,
+)
+
+meson.override_dependency('arbitrary-int-1-rs', arbitrary_int_dep)
diff --git a/subprojects/packagefiles/bilge-0.2-rs/meson.build b/subprojects/packagefiles/bilge-0.2-rs/meson.build
new file mode 100644
index 0000000..a6ed4a8
--- /dev/null
+++ b/subprojects/packagefiles/bilge-0.2-rs/meson.build
@@ -0,0 +1,29 @@
+project(
+ 'bilge-0.2-rs',
+ 'rust',
+ version : '0.2.0',
+ license : 'MIT or Apache-2.0',
+)
+
+subproject('arbitrary-int-1-rs', required: true)
+subproject('bilge-impl-0.2-rs', required: true)
+
+arbitrary_int_dep = dependency('arbitrary-int-1-rs')
+bilge_impl_dep = dependency('bilge-impl-0.2-rs')
+
+lib = static_library(
+ 'bilge',
+ 'src/lib.rs',
+ override_options : ['rust_std=2021', 'build.rust_std=2021'],
+ rust_abi : 'rust',
+ dependencies: [
+ arbitrary_int_dep,
+ bilge_impl_dep,
+ ],
+)
+
+bilge_dep = declare_dependency(
+ link_with : [lib],
+)
+
+meson.override_dependency('bilge-0.2-rs', bilge_dep)
diff --git a/subprojects/packagefiles/bilge-impl-0.2-rs/meson.build b/subprojects/packagefiles/bilge-impl-0.2-rs/meson.build
new file mode 100644
index 0000000..80243c7
--- /dev/null
+++ b/subprojects/packagefiles/bilge-impl-0.2-rs/meson.build
@@ -0,0 +1,45 @@
+project('bilge-impl-0.2-rs', 'rust',
+ version: '0.2.0',
+ license: 'MIT OR Apache-2.0',
+ default_options: [])
+
+subproject('itertools-0.11-rs', required: true)
+subproject('proc-macro-error-attr-1-rs', required: true)
+subproject('proc-macro-error-1-rs', required: true)
+subproject('quote-1-rs', required: true)
+subproject('syn-2-rs', required: true)
+subproject('proc-macro2-1-rs', required: true)
+
+itertools_dep = dependency('itertools-0.11-rs', native: true)
+proc_macro_error_attr_dep = dependency('proc-macro-error-attr-1-rs', native: true)
+proc_macro_error_dep = dependency('proc-macro-error-1-rs', native: true)
+quote_dep = dependency('quote-1-rs', native: true)
+syn_dep = dependency('syn-2-rs', native: true)
+proc_macro2_dep = dependency('proc-macro2-1-rs', native: true)
+
+rust = import('rust')
+
+_bilge_impl_rs = rust.proc_macro(
+ 'bilge_impl',
+ files('src/lib.rs'),
+ override_options: ['rust_std=2021', 'build.rust_std=2021'],
+ rust_args: [
+ '--cfg', 'use_fallback',
+ '--cfg', 'feature="syn-error"',
+ '--cfg', 'feature="proc-macro"',
+ ],
+ dependencies: [
+ itertools_dep,
+ proc_macro_error_attr_dep,
+ proc_macro_error_dep,
+ quote_dep,
+ syn_dep,
+ proc_macro2_dep,
+ ],
+)
+
+bilge_impl_dep = declare_dependency(
+ link_with: _bilge_impl_rs,
+)
+
+meson.override_dependency('bilge-impl-0.2-rs', bilge_impl_dep)
diff --git a/subprojects/packagefiles/either-1-rs/meson.build b/subprojects/packagefiles/either-1-rs/meson.build
new file mode 100644
index 0000000..a5842eb
--- /dev/null
+++ b/subprojects/packagefiles/either-1-rs/meson.build
@@ -0,0 +1,24 @@
+project('either-1-rs', 'rust',
+ version: '1.12.0',
+ license: 'MIT OR Apache-2.0',
+ default_options: [])
+
+_either_rs = static_library(
+ 'either',
+ files('src/lib.rs'),
+ gnu_symbol_visibility: 'hidden',
+ override_options: ['rust_std=2018', 'build.rust_std=2018'],
+ rust_abi: 'rust',
+ rust_args: [
+ '--cfg', 'feature="use_std"',
+ '--cfg', 'feature="use_alloc"',
+ ],
+ dependencies: [],
+ native: true,
+)
+
+either_dep = declare_dependency(
+ link_with: _either_rs,
+)
+
+meson.override_dependency('either-1-rs', either_dep, native: true)
diff --git a/subprojects/packagefiles/itertools-0.11-rs/meson.build b/subprojects/packagefiles/itertools-0.11-rs/meson.build
new file mode 100644
index 0000000..13d2d27
--- /dev/null
+++ b/subprojects/packagefiles/itertools-0.11-rs/meson.build
@@ -0,0 +1,30 @@
+project('itertools-0.11-rs', 'rust',
+ version: '0.11.0',
+ license: 'MIT OR Apache-2.0',
+ default_options: [])
+
+subproject('either-1-rs', required: true)
+
+either_dep = dependency('either-1-rs', native: true)
+
+_itertools_rs = static_library(
+ 'itertools',
+ files('src/lib.rs'),
+ gnu_symbol_visibility: 'hidden',
+ override_options: ['rust_std=2018', 'build.rust_std=2018'],
+ rust_abi: 'rust',
+ rust_args: [
+ '--cfg', 'feature="use_std"',
+ '--cfg', 'feature="use_alloc"',
+ ],
+ dependencies: [
+ either_dep,
+ ],
+ native: true,
+)
+
+itertools_dep = declare_dependency(
+ link_with: _itertools_rs,
+)
+
+meson.override_dependency('itertools-0.11-rs', itertools_dep, native: true)
diff --git a/subprojects/packagefiles/proc-macro-error-1-rs/meson.build b/subprojects/packagefiles/proc-macro-error-1-rs/meson.build
new file mode 100644
index 0000000..38ea7b8
--- /dev/null
+++ b/subprojects/packagefiles/proc-macro-error-1-rs/meson.build
@@ -0,0 +1,40 @@
+project('proc-macro-error-1-rs', 'rust',
+ version: '1.0.4',
+ license: 'MIT OR Apache-2.0',
+ default_options: [])
+
+subproject('proc-macro-error-attr-1-rs', required: true)
+subproject('quote-1-rs', required: true)
+subproject('syn-2-rs', required: true)
+subproject('proc-macro2-1-rs', required: true)
+
+proc_macro_error_attr_dep = dependency('proc-macro-error-attr-1-rs', native: true)
+proc_macro2_dep = dependency('proc-macro2-1-rs', native: true)
+quote_dep = dependency('quote-1-rs', native: true)
+syn_dep = dependency('syn-2-rs', native: true)
+
+_proc_macro_error_rs = static_library(
+ 'proc_macro_error',
+ files('src/lib.rs'),
+ override_options: ['rust_std=2018', 'build.rust_std=2018'],
+ rust_abi: 'rust',
+ rust_args: [
+ '--cfg', 'use_fallback',
+ '--cfg', 'feature="syn-error"',
+ '--cfg', 'feature="proc-macro"',
+ '-A', 'non_fmt_panics'
+ ],
+ dependencies: [
+ proc_macro_error_attr_dep,
+ proc_macro2_dep,
+ quote_dep,
+ syn_dep,
+ ],
+ native: true,
+)
+
+proc_macro_error_dep = declare_dependency(
+ link_with: _proc_macro_error_rs,
+)
+
+meson.override_dependency('proc-macro-error-1-rs', proc_macro_error_dep, native: true)
diff --git a/subprojects/packagefiles/proc-macro-error-attr-1-rs/meson.build b/subprojects/packagefiles/proc-macro-error-attr-1-rs/meson.build
new file mode 100644
index 0000000..d900c54
--- /dev/null
+++ b/subprojects/packagefiles/proc-macro-error-attr-1-rs/meson.build
@@ -0,0 +1,32 @@
+project('proc-macro-error-attr-1-rs', 'rust',
+ version: '1.12.0',
+ license: 'MIT OR Apache-2.0',
+ default_options: [])
+
+subproject('proc-macro2-1-rs', required: true)
+subproject('quote-1-rs', required: true)
+
+proc_macro2_dep = dependency('proc-macro2-1-rs', native: true)
+quote_dep = dependency('quote-1-rs', native: true)
+
+rust = import('rust')
+_proc_macro_error_attr_rs = rust.proc_macro(
+ 'proc_macro_error_attr',
+ files('src/lib.rs'),
+ override_options: ['rust_std=2018', 'build.rust_std=2018'],
+ rust_args: [
+ '--cfg', 'use_fallback',
+ '--cfg', 'feature="syn-error"',
+ '--cfg', 'feature="proc-macro"'
+ ],
+ dependencies: [
+ proc_macro2_dep,
+ quote_dep,
+ ],
+)
+
+proc_macro_error_attr_dep = declare_dependency(
+ link_with: _proc_macro_error_attr_rs,
+)
+
+meson.override_dependency('proc-macro-error-attr-1-rs', proc_macro_error_attr_dep, native: true)
diff --git a/subprojects/packagefiles/proc-macro2-1-rs/meson.build b/subprojects/packagefiles/proc-macro2-1-rs/meson.build
new file mode 100644
index 0000000..818ec59
--- /dev/null
+++ b/subprojects/packagefiles/proc-macro2-1-rs/meson.build
@@ -0,0 +1,31 @@
+project('proc-macro2-1-rs', 'rust',
+ version: '1.0.84',
+ license: 'MIT OR Apache-2.0',
+ default_options: [])
+
+subproject('unicode-ident-1-rs', required: true)
+
+unicode_ident_dep = dependency('unicode-ident-1-rs', native: true)
+
+_proc_macro2_rs = static_library(
+ 'proc_macro2',
+ files('src/lib.rs'),
+ gnu_symbol_visibility: 'hidden',
+ override_options: ['rust_std=2021', 'build.rust_std=2021'],
+ rust_abi: 'rust',
+ rust_args: [
+ '--cfg', 'feature="proc-macro"',
+ '--cfg', 'span_locations',
+ '--cfg', 'wrap_proc_macro',
+ ],
+ dependencies: [
+ unicode_ident_dep,
+ ],
+ native: true,
+)
+
+proc_macro2_dep = declare_dependency(
+ link_with: _proc_macro2_rs,
+)
+
+meson.override_dependency('proc-macro2-1-rs', proc_macro2_dep, native: true)
diff --git a/subprojects/packagefiles/quote-1-rs/meson.build b/subprojects/packagefiles/quote-1-rs/meson.build
new file mode 100644
index 0000000..d36609b
--- /dev/null
+++ b/subprojects/packagefiles/quote-1-rs/meson.build
@@ -0,0 +1,29 @@
+project('quote-1-rs', 'rust',
+ version: '1.12.0',
+ license: 'MIT OR Apache-2.0',
+ default_options: [])
+
+subproject('proc-macro2-1-rs', required: true)
+
+proc_macro2_dep = dependency('proc-macro2-1-rs', native: true)
+
+_quote_rs = static_library(
+ 'quote',
+ files('src/lib.rs'),
+ gnu_symbol_visibility: 'hidden',
+ override_options: ['rust_std=2021', 'build.rust_std=2021'],
+ rust_abi: 'rust',
+ rust_args: [
+ '--cfg', 'feature="proc-macro"',
+ ],
+ dependencies: [
+ proc_macro2_dep,
+ ],
+ native: true,
+)
+
+quote_dep = declare_dependency(
+ link_with: _quote_rs,
+)
+
+meson.override_dependency('quote-1-rs', quote_dep, native: true)
diff --git a/subprojects/packagefiles/syn-2-rs/meson.build b/subprojects/packagefiles/syn-2-rs/meson.build
new file mode 100644
index 0000000..a53335f
--- /dev/null
+++ b/subprojects/packagefiles/syn-2-rs/meson.build
@@ -0,0 +1,40 @@
+project('syn-2-rs', 'rust',
+ version: '2.0.66',
+ license: 'MIT OR Apache-2.0',
+ default_options: [])
+
+subproject('proc-macro2-1-rs', required: true)
+subproject('quote-1-rs', required: true)
+subproject('unicode-ident-1-rs', required: true)
+
+proc_macro2_dep = dependency('proc-macro2-1-rs', native: true)
+quote_dep = dependency('quote-1-rs', native: true)
+unicode_ident_dep = dependency('unicode-ident-1-rs', native: true)
+
+_syn_rs = static_library(
+ 'syn',
+ files('src/lib.rs'),
+ gnu_symbol_visibility: 'hidden',
+ override_options: ['rust_std=2021', 'build.rust_std=2021'],
+ rust_abi: 'rust',
+ rust_args: [
+ '--cfg', 'feature="full"',
+ '--cfg', 'feature="derive"',
+ '--cfg', 'feature="parsing"',
+ '--cfg', 'feature="printing"',
+ '--cfg', 'feature="clone-impls"',
+ '--cfg', 'feature="proc-macro"',
+ ],
+ dependencies: [
+ quote_dep,
+ proc_macro2_dep,
+ unicode_ident_dep,
+ ],
+ native: true,
+)
+
+syn_dep = declare_dependency(
+ link_with: _syn_rs,
+)
+
+meson.override_dependency('syn-2-rs', syn_dep, native: true)
diff --git a/subprojects/packagefiles/unicode-ident-1-rs/meson.build b/subprojects/packagefiles/unicode-ident-1-rs/meson.build
new file mode 100644
index 0000000..54f2376
--- /dev/null
+++ b/subprojects/packagefiles/unicode-ident-1-rs/meson.build
@@ -0,0 +1,20 @@
+project('unicode-ident-1-rs', 'rust',
+ version: '1.0.12',
+ license: '(MIT OR Apache-2.0) AND Unicode-DFS-2016',
+ default_options: [])
+
+_unicode_ident_rs = static_library(
+ 'unicode_ident',
+ files('src/lib.rs'),
+ gnu_symbol_visibility: 'hidden',
+ override_options: ['rust_std=2021', 'build.rust_std=2021'],
+ rust_abi: 'rust',
+ dependencies: [],
+ native: true,
+)
+
+unicode_ident_dep = declare_dependency(
+ link_with: _unicode_ident_rs,
+)
+
+meson.override_dependency('unicode-ident-1-rs', unicode_ident_dep, native: true)
diff --git a/subprojects/proc-macro-error-1-rs.wrap b/subprojects/proc-macro-error-1-rs.wrap
new file mode 100644
index 0000000..b7db03b
--- /dev/null
+++ b/subprojects/proc-macro-error-1-rs.wrap
@@ -0,0 +1,7 @@
+[wrap-file]
+directory = proc-macro-error-1.0.4
+source_url = https://crates.io/api/v1/crates/proc-macro-error/1.0.4/download
+source_filename = proc-macro-error-1.0.4.tar.gz
+source_hash = da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c
+#method = cargo
+patch_directory = proc-macro-error-1-rs
diff --git a/subprojects/proc-macro-error-attr-1-rs.wrap b/subprojects/proc-macro-error-attr-1-rs.wrap
new file mode 100644
index 0000000..d13d8a2
--- /dev/null
+++ b/subprojects/proc-macro-error-attr-1-rs.wrap
@@ -0,0 +1,7 @@
+[wrap-file]
+directory = proc-macro-error-attr-1.0.4
+source_url = https://crates.io/api/v1/crates/proc-macro-error-attr/1.0.4/download
+source_filename = proc-macro-error-attr-1.0.4.tar.gz
+source_hash = a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869
+#method = cargo
+patch_directory = proc-macro-error-attr-1-rs
diff --git a/subprojects/proc-macro2-1-rs.wrap b/subprojects/proc-macro2-1-rs.wrap
new file mode 100644
index 0000000..7053e2c
--- /dev/null
+++ b/subprojects/proc-macro2-1-rs.wrap
@@ -0,0 +1,7 @@
+[wrap-file]
+directory = proc-macro2-1.0.84
+source_url = https://crates.io/api/v1/crates/proc-macro2/1.0.84/download
+source_filename = proc-macro2-1.0.84.0.tar.gz
+source_hash = ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6
+#method = cargo
+patch_directory = proc-macro2-1-rs
diff --git a/subprojects/quote-1-rs.wrap b/subprojects/quote-1-rs.wrap
new file mode 100644
index 0000000..6e7ea69
--- /dev/null
+++ b/subprojects/quote-1-rs.wrap
@@ -0,0 +1,7 @@
+[wrap-file]
+directory = quote-1.0.36
+source_url = https://crates.io/api/v1/crates/quote/1.0.36/download
+source_filename = quote-1.0.36.0.tar.gz
+source_hash = 0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7
+#method = cargo
+patch_directory = quote-1-rs
diff --git a/subprojects/syn-2-rs.wrap b/subprojects/syn-2-rs.wrap
new file mode 100644
index 0000000..13ffdac
--- /dev/null
+++ b/subprojects/syn-2-rs.wrap
@@ -0,0 +1,7 @@
+[wrap-file]
+directory = syn-2.0.66
+source_url = https://crates.io/api/v1/crates/syn/2.0.66/download
+source_filename = syn-2.0.66.0.tar.gz
+source_hash = c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5
+#method = cargo
+patch_directory = syn-2-rs
diff --git a/subprojects/unicode-ident-1-rs.wrap b/subprojects/unicode-ident-1-rs.wrap
new file mode 100644
index 0000000..4609f96
--- /dev/null
+++ b/subprojects/unicode-ident-1-rs.wrap
@@ -0,0 +1,7 @@
+[wrap-file]
+directory = unicode-ident-1.0.12
+source_url = https://crates.io/api/v1/crates/unicode-ident/1.0.12/download
+source_filename = unicode-ident-1.0.12.tar.gz
+source_hash = 3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b
+#method = cargo
+patch_directory = unicode-ident-1-rs
diff --git a/subprojects/unicode-ident-1-rs/meson.build b/subprojects/unicode-ident-1-rs/meson.build
new file mode 100644
index 0000000..54f2376
--- /dev/null
+++ b/subprojects/unicode-ident-1-rs/meson.build
@@ -0,0 +1,20 @@
+project('unicode-ident-1-rs', 'rust',
+ version: '1.0.12',
+ license: '(MIT OR Apache-2.0) AND Unicode-DFS-2016',
+ default_options: [])
+
+_unicode_ident_rs = static_library(
+ 'unicode_ident',
+ files('src/lib.rs'),
+ gnu_symbol_visibility: 'hidden',
+ override_options: ['rust_std=2021', 'build.rust_std=2021'],
+ rust_abi: 'rust',
+ dependencies: [],
+ native: true,
+)
+
+unicode_ident_dep = declare_dependency(
+ link_with: _unicode_ident_rs,
+)
+
+meson.override_dependency('unicode-ident-1-rs', unicode_ident_dep, native: true)
diff --git a/system/async-teardown.c b/system/async-teardown.c
index 396963c..9148ee8 100644
--- a/system/async-teardown.c
+++ b/system/async-teardown.c
@@ -26,40 +26,6 @@
static pid_t the_ppid;
-/*
- * Close all open file descriptors.
- */
-static void close_all_open_fd(void)
-{
- struct dirent *de;
- int fd, dfd;
- DIR *dir;
-
-#ifdef CONFIG_CLOSE_RANGE
- int r = close_range(0, ~0U, 0);
- if (!r) {
- /* Success, no need to try other ways. */
- return;
- }
-#endif
-
- dir = opendir("/proc/self/fd");
- if (!dir) {
- /* If /proc is not mounted, there is nothing that can be done. */
- return;
- }
- /* Avoid closing the directory. */
- dfd = dirfd(dir);
-
- for (de = readdir(dir); de; de = readdir(dir)) {
- fd = atoi(de->d_name);
- if (fd != dfd) {
- close(fd);
- }
- }
- closedir(dir);
-}
-
static void hup_handler(int signal)
{
/* Check every second if this process has been reparented. */
@@ -85,9 +51,8 @@ static int async_teardown_fn(void *arg)
/*
* Close all file descriptors that might have been inherited from the
* main qemu process when doing clone, needed to make libvirt happy.
- * Not using close_range for increased compatibility with older kernels.
*/
- close_all_open_fd();
+ qemu_close_all_open_fd(NULL, 0);
/* Set up a handler for SIGHUP and unblock SIGHUP. */
sigaction(SIGHUP, &sa, NULL);
diff --git a/system/cpu-throttle.c b/system/cpu-throttle.c
index c951a6c..7632dc6 100644
--- a/system/cpu-throttle.c
+++ b/system/cpu-throttle.c
@@ -28,6 +28,7 @@
#include "qemu/main-loop.h"
#include "sysemu/cpus.h"
#include "sysemu/cpu-throttle.h"
+#include "trace.h"
/* vcpu throttling controls */
static QEMUTimer *throttle_timer;
@@ -95,6 +96,8 @@ void cpu_throttle_set(int new_throttle_pct)
*/
bool throttle_active = cpu_throttle_active();
+ trace_cpu_throttle_set(new_throttle_pct);
+
/* Ensure throttle percentage is within valid range */
new_throttle_pct = MIN(new_throttle_pct, CPU_THROTTLE_PCT_MAX);
new_throttle_pct = MAX(new_throttle_pct, CPU_THROTTLE_PCT_MIN);
diff --git a/system/cpus.c b/system/cpus.c
index 5e3a988..1c818ff 100644
--- a/system/cpus.c
+++ b/system/cpus.c
@@ -792,14 +792,14 @@ int vm_stop_force_state(RunState state)
}
}
-void qmp_memsave(int64_t addr, int64_t size, const char *filename,
+void qmp_memsave(uint64_t addr, uint64_t size, const char *filename,
bool has_cpu, int64_t cpu_index, Error **errp)
{
FILE *f;
- uint32_t l;
+ uint64_t l;
CPUState *cpu;
uint8_t buf[1024];
- int64_t orig_addr = addr, orig_size = size;
+ uint64_t orig_addr = addr, orig_size = size;
if (!has_cpu) {
cpu_index = 0;
@@ -823,7 +823,7 @@ void qmp_memsave(int64_t addr, int64_t size, const char *filename,
if (l > size)
l = size;
if (cpu_memory_rw_debug(cpu, addr, buf, l, 0) != 0) {
- error_setg(errp, "Invalid addr 0x%016" PRIx64 "/size %" PRId64
+ error_setg(errp, "Invalid addr 0x%016" PRIx64 "/size %" PRIu64
" specified", orig_addr, orig_size);
goto exit;
}
@@ -840,11 +840,11 @@ exit:
fclose(f);
}
-void qmp_pmemsave(int64_t addr, int64_t size, const char *filename,
+void qmp_pmemsave(uint64_t addr, uint64_t size, const char *filename,
Error **errp)
{
FILE *f;
- uint32_t l;
+ uint64_t l;
uint8_t buf[1024];
f = fopen(filename, "wb");
diff --git a/system/globals.c b/system/globals.c
index d602a04..84ce943 100644
--- a/system/globals.c
+++ b/system/globals.c
@@ -40,7 +40,6 @@ int autostart = 1;
int vga_interface_type = VGA_NONE;
bool vga_interface_created;
Chardev *parallel_hds[MAX_PARALLEL_PORTS];
-int graphic_rotate;
QEMUOptionRom option_rom[MAX_OPTION_ROMS];
int nb_option_roms;
int old_param;
diff --git a/system/memory.c b/system/memory.c
index 5e6eb45..85f6834 100644
--- a/system/memory.c
+++ b/system/memory.c
@@ -941,6 +941,38 @@ static void flat_range_coalesced_io_add(FlatRange *fr, AddressSpace *as)
}
}
+static void
+flat_range_coalesced_io_notify_listener_add_del(FlatRange *fr,
+ MemoryRegionSection *mrs,
+ MemoryListener *listener,
+ AddressSpace *as, bool add)
+{
+ CoalescedMemoryRange *cmr;
+ MemoryRegion *mr = fr->mr;
+ AddrRange tmp;
+
+ QTAILQ_FOREACH(cmr, &mr->coalesced, link) {
+ tmp = addrrange_shift(cmr->addr,
+ int128_sub(fr->addr.start,
+ int128_make64(fr->offset_in_region)));
+
+ if (!addrrange_intersects(tmp, fr->addr)) {
+ return;
+ }
+ tmp = addrrange_intersection(tmp, fr->addr);
+
+ if (add && listener->coalesced_io_add) {
+ listener->coalesced_io_add(listener, mrs,
+ int128_get64(tmp.start),
+ int128_get64(tmp.size));
+ } else if (!add && listener->coalesced_io_del) {
+ listener->coalesced_io_del(listener, mrs,
+ int128_get64(tmp.start),
+ int128_get64(tmp.size));
+ }
+ }
+}
+
static void address_space_update_topology_pass(AddressSpace *as,
const FlatView *old_view,
const FlatView *new_view,
@@ -3015,8 +3047,10 @@ void memory_global_dirty_log_stop(unsigned int flags)
static void listener_add_address_space(MemoryListener *listener,
AddressSpace *as)
{
+ unsigned i;
FlatView *view;
FlatRange *fr;
+ MemoryRegionIoeventfd *fd;
if (listener->begin) {
listener->begin(listener);
@@ -3041,10 +3075,34 @@ static void listener_add_address_space(MemoryListener *listener,
if (listener->region_add) {
listener->region_add(listener, &section);
}
+
+ /* send coalesced io add notifications */
+ flat_range_coalesced_io_notify_listener_add_del(fr, &section,
+ listener, as, true);
+
if (fr->dirty_log_mask && listener->log_start) {
listener->log_start(listener, &section, 0, fr->dirty_log_mask);
}
}
+
+ /*
+ * register all eventfds for this address space for the newly registered
+ * listener.
+ */
+ for (i = 0; i < as->ioeventfd_nb; i++) {
+ fd = &as->ioeventfds[i];
+ MemoryRegionSection section = (MemoryRegionSection) {
+ .fv = view,
+ .offset_within_address_space = int128_get64(fd->addr.start),
+ .size = fd->addr.size,
+ };
+
+ if (listener->eventfd_add) {
+ listener->eventfd_add(listener, &section,
+ fd->match_data, fd->data, fd->e);
+ }
+ }
+
if (listener->commit) {
listener->commit(listener);
}
@@ -3054,8 +3112,10 @@ static void listener_add_address_space(MemoryListener *listener,
static void listener_del_address_space(MemoryListener *listener,
AddressSpace *as)
{
+ unsigned i;
FlatView *view;
FlatRange *fr;
+ MemoryRegionIoeventfd *fd;
if (listener->begin) {
listener->begin(listener);
@@ -3067,10 +3127,33 @@ static void listener_del_address_space(MemoryListener *listener,
if (fr->dirty_log_mask && listener->log_stop) {
listener->log_stop(listener, &section, fr->dirty_log_mask, 0);
}
+
+ /* send coalesced io del notifications */
+ flat_range_coalesced_io_notify_listener_add_del(fr, &section,
+ listener, as, false);
if (listener->region_del) {
listener->region_del(listener, &section);
}
}
+
+ /*
+ * de-register all eventfds for this address space for the current
+ * listener.
+ */
+ for (i = 0; i < as->ioeventfd_nb; i++) {
+ fd = &as->ioeventfds[i];
+ MemoryRegionSection section = (MemoryRegionSection) {
+ .fv = view,
+ .offset_within_address_space = int128_get64(fd->addr.start),
+ .size = fd->addr.size,
+ };
+
+ if (listener->eventfd_del) {
+ listener->eventfd_del(listener, &section,
+ fd->match_data, fd->data, fd->e);
+ }
+ }
+
if (listener->commit) {
listener->commit(listener);
}
@@ -3148,7 +3231,8 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name)
as->ioeventfds = NULL;
QTAILQ_INIT(&as->listeners);
QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link);
- as->bounce.in_use = false;
+ as->max_bounce_buffer_size = DEFAULT_MAX_BOUNCE_BUFFER_SIZE;
+ as->bounce_buffer_size = 0;
qemu_mutex_init(&as->map_client_list_lock);
QLIST_INIT(&as->map_client_list);
as->name = g_strdup(name ? name : "anonymous");
@@ -3158,7 +3242,7 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name)
static void do_address_space_destroy(AddressSpace *as)
{
- assert(!qatomic_read(&as->bounce.in_use));
+ assert(qatomic_read(&as->bounce_buffer_size) == 0);
assert(QLIST_EMPTY(&as->map_client_list));
qemu_mutex_destroy(&as->map_client_list_lock);
diff --git a/system/memory_mapping.c b/system/memory_mapping.c
index 6f884c5..ca2390e 100644
--- a/system/memory_mapping.c
+++ b/system/memory_mapping.c
@@ -12,6 +12,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/range.h"
#include "qapi/error.h"
#include "sysemu/memory_mapping.h"
@@ -353,8 +354,7 @@ void memory_mapping_filter(MemoryMappingList *list, int64_t begin,
MemoryMapping *cur, *next;
QTAILQ_FOREACH_SAFE(cur, &list->head, next, next) {
- if (cur->phys_addr >= begin + length ||
- cur->phys_addr + cur->length <= begin) {
+ if (!ranges_overlap(cur->phys_addr, cur->length, begin, length)) {
QTAILQ_REMOVE(&list->head, cur, next);
g_free(cur);
list->num--;
diff --git a/system/physmem.c b/system/physmem.c
index 9a3b3a7..dc1db3a 100644
--- a/system/physmem.c
+++ b/system/physmem.c
@@ -763,6 +763,7 @@ void cpu_address_space_init(CPUState *cpu, int asidx,
if (!cpu->cpu_ases) {
cpu->cpu_ases = g_new0(CPUAddressSpace, cpu->num_ases);
+ cpu->cpu_ases_count = cpu->num_ases;
}
newas = &cpu->cpu_ases[asidx];
@@ -776,6 +777,34 @@ void cpu_address_space_init(CPUState *cpu, int asidx,
}
}
+void cpu_address_space_destroy(CPUState *cpu, int asidx)
+{
+ CPUAddressSpace *cpuas;
+
+ assert(cpu->cpu_ases);
+ assert(asidx >= 0 && asidx < cpu->num_ases);
+ /* KVM cannot currently support multiple address spaces. */
+ assert(asidx == 0 || !kvm_enabled());
+
+ cpuas = &cpu->cpu_ases[asidx];
+ if (tcg_enabled()) {
+ memory_listener_unregister(&cpuas->tcg_as_listener);
+ }
+
+ address_space_destroy(cpuas->as);
+ g_free_rcu(cpuas->as, rcu);
+
+ if (asidx == 0) {
+ /* reset the convenience alias for address space 0 */
+ cpu->as = NULL;
+ }
+
+ if (--cpu->cpu_ases_count == 0) {
+ g_free(cpu->cpu_ases);
+ cpu->cpu_ases = NULL;
+ }
+}
+
AddressSpace *cpu_get_address_space(CPUState *cpu, int asidx)
{
/* Return the AddressSpace corresponding to the specified index */
@@ -894,13 +923,19 @@ DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty
(MemoryRegion *mr, hwaddr offset, hwaddr length, unsigned client)
{
DirtyMemoryBlocks *blocks;
- ram_addr_t start = memory_region_get_ram_addr(mr) + offset;
+ ram_addr_t start, first, last;
unsigned long align = 1UL << (TARGET_PAGE_BITS + BITS_PER_LEVEL);
- ram_addr_t first = QEMU_ALIGN_DOWN(start, align);
- ram_addr_t last = QEMU_ALIGN_UP(start + length, align);
DirtyBitmapSnapshot *snap;
unsigned long page, end, dest;
+ start = memory_region_get_ram_addr(mr);
+ /* We know we're only called for RAM MemoryRegions */
+ assert(start != RAM_ADDR_INVALID);
+ start += offset;
+
+ first = QEMU_ALIGN_DOWN(start, align);
+ last = QEMU_ALIGN_UP(start + length, align);
+
snap = g_malloc0(sizeof(*snap) +
((last - first) >> (TARGET_PAGE_BITS + 3)));
snap->start = first;
@@ -1499,18 +1534,6 @@ static ram_addr_t find_ram_offset(ram_addr_t size)
return offset;
}
-static unsigned long last_ram_page(void)
-{
- RAMBlock *block;
- ram_addr_t last = 0;
-
- RCU_READ_LOCK_GUARD();
- RAMBLOCK_FOREACH(block) {
- last = MAX(last, block->offset + block->max_length);
- }
- return last >> TARGET_PAGE_BITS;
-}
-
static void qemu_ram_setup_dump(void *addr, ram_addr_t size)
{
int ret;
@@ -1764,13 +1787,11 @@ void qemu_ram_msync(RAMBlock *block, ram_addr_t start, ram_addr_t length)
}
/* Called with ram_list.mutex held */
-static void dirty_memory_extend(ram_addr_t old_ram_size,
- ram_addr_t new_ram_size)
+static void dirty_memory_extend(ram_addr_t new_ram_size)
{
- ram_addr_t old_num_blocks = DIV_ROUND_UP(old_ram_size,
- DIRTY_MEMORY_BLOCK_SIZE);
- ram_addr_t new_num_blocks = DIV_ROUND_UP(new_ram_size,
- DIRTY_MEMORY_BLOCK_SIZE);
+ unsigned int old_num_blocks = ram_list.num_dirty_blocks;
+ unsigned int new_num_blocks = DIV_ROUND_UP(new_ram_size,
+ DIRTY_MEMORY_BLOCK_SIZE);
int i;
/* Only need to extend if block count increased */
@@ -1802,6 +1823,8 @@ static void dirty_memory_extend(ram_addr_t old_ram_size,
g_free_rcu(old_blocks, rcu);
}
}
+
+ ram_list.num_dirty_blocks = new_num_blocks;
}
static void ram_block_add(RAMBlock *new_block, Error **errp)
@@ -1811,11 +1834,9 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
RAMBlock *block;
RAMBlock *last_block = NULL;
bool free_on_error = false;
- ram_addr_t old_ram_size, new_ram_size;
+ ram_addr_t ram_size;
Error *err = NULL;
- old_ram_size = last_ram_page();
-
qemu_mutex_lock_ramlist();
new_block->offset = find_ram_offset(new_block->max_length);
@@ -1866,11 +1887,8 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
}
}
- new_ram_size = MAX(old_ram_size,
- (new_block->offset + new_block->max_length) >> TARGET_PAGE_BITS);
- if (new_ram_size > old_ram_size) {
- dirty_memory_extend(old_ram_size, new_ram_size);
- }
+ ram_size = (new_block->offset + new_block->max_length) >> TARGET_PAGE_BITS;
+ dirty_memory_extend(ram_size);
/* Keep the list sorted from biggest to smallest block. Unlike QTAILQ,
* QLIST (which has an RCU-friendly variant) does not have insertion at
* tail, so save the last element in last_block.
@@ -2630,7 +2648,11 @@ static void invalidate_and_set_dirty(MemoryRegion *mr, hwaddr addr,
hwaddr length)
{
uint8_t dirty_log_mask = memory_region_get_dirty_log_mask(mr);
- addr += memory_region_get_ram_addr(mr);
+ ram_addr_t ramaddr = memory_region_get_ram_addr(mr);
+
+ /* We know we're only called for RAM MemoryRegions */
+ assert(ramaddr != RAM_ADDR_INVALID);
+ addr += ramaddr;
/* No early return if dirty_log_mask is or becomes 0, because
* cpu_physical_memory_set_dirty_range will still call
@@ -3056,6 +3078,20 @@ void cpu_flush_icache_range(hwaddr start, hwaddr len)
NULL, len, FLUSH_CACHE);
}
+/*
+ * A magic value stored in the first 8 bytes of the bounce buffer struct. Used
+ * to detect illegal pointers passed to address_space_unmap.
+ */
+#define BOUNCE_BUFFER_MAGIC 0xb4017ceb4ffe12ed
+
+typedef struct {
+ uint64_t magic;
+ MemoryRegion *mr;
+ hwaddr addr;
+ size_t len;
+ uint8_t buffer[];
+} BounceBuffer;
+
static void
address_space_unregister_map_client_do(AddressSpaceMapClient *client)
{
@@ -3081,9 +3117,9 @@ void address_space_register_map_client(AddressSpace *as, QEMUBH *bh)
QEMU_LOCK_GUARD(&as->map_client_list_lock);
client->bh = bh;
QLIST_INSERT_HEAD(&as->map_client_list, client, link);
- /* Write map_client_list before reading in_use. */
+ /* Write map_client_list before reading bounce_buffer_size. */
smp_mb();
- if (!qatomic_read(&as->bounce.in_use)) {
+ if (qatomic_read(&as->bounce_buffer_size) < as->max_bounce_buffer_size) {
address_space_notify_map_clients_locked(as);
}
}
@@ -3212,28 +3248,40 @@ void *address_space_map(AddressSpace *as,
mr = flatview_translate(fv, addr, &xlat, &l, is_write, attrs);
if (!memory_access_is_direct(mr, is_write)) {
- if (qatomic_xchg(&as->bounce.in_use, true)) {
+ size_t used = qatomic_read(&as->bounce_buffer_size);
+ for (;;) {
+ hwaddr alloc = MIN(as->max_bounce_buffer_size - used, l);
+ size_t new_size = used + alloc;
+ size_t actual =
+ qatomic_cmpxchg(&as->bounce_buffer_size, used, new_size);
+ if (actual == used) {
+ l = alloc;
+ break;
+ }
+ used = actual;
+ }
+
+ if (l == 0) {
*plen = 0;
return NULL;
}
- /* Avoid unbounded allocations */
- l = MIN(l, TARGET_PAGE_SIZE);
- as->bounce.buffer = qemu_memalign(TARGET_PAGE_SIZE, l);
- as->bounce.addr = addr;
- as->bounce.len = l;
+ BounceBuffer *bounce = g_malloc0(l + sizeof(BounceBuffer));
+ bounce->magic = BOUNCE_BUFFER_MAGIC;
memory_region_ref(mr);
- as->bounce.mr = mr;
+ bounce->mr = mr;
+ bounce->addr = addr;
+ bounce->len = l;
+
if (!is_write) {
- flatview_read(fv, addr, MEMTXATTRS_UNSPECIFIED,
- as->bounce.buffer, l);
+ flatview_read(fv, addr, attrs,
+ bounce->buffer, l);
}
*plen = l;
- return as->bounce.buffer;
+ return bounce->buffer;
}
-
memory_region_ref(mr);
*plen = flatview_extend_translation(fv, addr, len, mr, xlat,
l, is_write, attrs);
@@ -3248,12 +3296,11 @@ void *address_space_map(AddressSpace *as,
void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len,
bool is_write, hwaddr access_len)
{
- if (buffer != as->bounce.buffer) {
- MemoryRegion *mr;
- ram_addr_t addr1;
+ MemoryRegion *mr;
+ ram_addr_t addr1;
- mr = memory_region_from_host(buffer, &addr1);
- assert(mr != NULL);
+ mr = memory_region_from_host(buffer, &addr1);
+ if (mr != NULL) {
if (is_write) {
invalidate_and_set_dirty(mr, addr1, access_len);
}
@@ -3263,15 +3310,22 @@ void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len,
memory_region_unref(mr);
return;
}
+
+
+ BounceBuffer *bounce = container_of(buffer, BounceBuffer, buffer);
+ assert(bounce->magic == BOUNCE_BUFFER_MAGIC);
+
if (is_write) {
- address_space_write(as, as->bounce.addr, MEMTXATTRS_UNSPECIFIED,
- as->bounce.buffer, access_len);
- }
- qemu_vfree(as->bounce.buffer);
- as->bounce.buffer = NULL;
- memory_region_unref(as->bounce.mr);
- /* Clear in_use before reading map_client_list. */
- qatomic_set_mb(&as->bounce.in_use, false);
+ address_space_write(as, bounce->addr, MEMTXATTRS_UNSPECIFIED,
+ bounce->buffer, access_len);
+ }
+
+ qatomic_sub(&as->bounce_buffer_size, bounce->len);
+ bounce->magic = ~BOUNCE_BUFFER_MAGIC;
+ memory_region_unref(bounce->mr);
+ g_free(bounce);
+ /* Write bounce_buffer_size before reading map_client_list. */
+ smp_mb();
address_space_notify_map_clients(as);
}
diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c
index 6af6ef7..44994ea 100644
--- a/system/qdev-monitor.c
+++ b/system/qdev-monitor.c
@@ -55,12 +55,18 @@ typedef struct QDevAlias
} QDevAlias;
/* default virtio transport per architecture */
-#define QEMU_ARCH_VIRTIO_PCI (QEMU_ARCH_ALPHA | QEMU_ARCH_ARM | \
- QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \
- QEMU_ARCH_MIPS | QEMU_ARCH_PPC | \
- QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \
- QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \
- QEMU_ARCH_LOONGARCH)
+#define QEMU_ARCH_VIRTIO_PCI (QEMU_ARCH_ALPHA | \
+ QEMU_ARCH_ARM | \
+ QEMU_ARCH_HPPA | \
+ QEMU_ARCH_I386 | \
+ QEMU_ARCH_LOONGARCH | \
+ QEMU_ARCH_MIPS | \
+ QEMU_ARCH_OPENRISC | \
+ QEMU_ARCH_PPC | \
+ QEMU_ARCH_RISCV | \
+ QEMU_ARCH_SH4 | \
+ QEMU_ARCH_SPARC | \
+ QEMU_ARCH_XTENSA)
#define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X)
#define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K)
diff --git a/system/qemu-seccomp.c b/system/qemu-seccomp.c
index 98ffce0..71ac444 100644
--- a/system/qemu-seccomp.c
+++ b/system/qemu-seccomp.c
@@ -47,10 +47,10 @@ const struct scmp_arg_cmp sched_setscheduler_arg[] = {
};
/*
- * See 'NOTES' in 'man 2 clone' - s390 & cross have 'flags' in
+ * See 'NOTES' in 'man 2 clone' - s390 has 'flags' in
* different position to other architectures
*/
-#if defined(HOST_S390X) || defined(HOST_S390) || defined(HOST_CRIS)
+#if defined(HOST_S390X) || defined(HOST_S390)
#define CLONE_FLAGS_ARG 1
#else
#define CLONE_FLAGS_ARG 0
diff --git a/system/rtc.c b/system/rtc.c
index dc44576..216d2ae 100644
--- a/system/rtc.c
+++ b/system/rtc.c
@@ -62,7 +62,7 @@ static time_t qemu_ref_timedate(QEMUClockType clock)
}
break;
default:
- assert(0);
+ g_assert_not_reached();
}
return value;
}
diff --git a/system/runstate.c b/system/runstate.c
index c833316..c2c9afa 100644
--- a/system/runstate.c
+++ b/system/runstate.c
@@ -32,6 +32,7 @@
#include "exec/cpu-common.h"
#include "gdbstub/syscalls.h"
#include "hw/boards.h"
+#include "hw/resettable.h"
#include "migration/misc.h"
#include "migration/postcopy-ram.h"
#include "monitor/monitor.h"
@@ -181,6 +182,12 @@ static const RunStateTransition runstate_transitions_def[] = {
{ RUN_STATE__MAX, RUN_STATE__MAX },
};
+static const RunStateTransition replay_play_runstate_transitions_def[] = {
+ { RUN_STATE_SHUTDOWN, RUN_STATE_RUNNING},
+
+ { RUN_STATE__MAX, RUN_STATE__MAX },
+};
+
static bool runstate_valid_transitions[RUN_STATE__MAX][RUN_STATE__MAX];
bool runstate_check(RunState state)
@@ -188,14 +195,33 @@ bool runstate_check(RunState state)
return current_run_state == state;
}
-static void runstate_init(void)
+static void transitions_set_valid(const RunStateTransition *rst)
{
const RunStateTransition *p;
- memset(&runstate_valid_transitions, 0, sizeof(runstate_valid_transitions));
- for (p = &runstate_transitions_def[0]; p->from != RUN_STATE__MAX; p++) {
+ for (p = rst; p->from != RUN_STATE__MAX; p++) {
runstate_valid_transitions[p->from][p->to] = true;
}
+}
+
+void runstate_replay_enable(void)
+{
+ assert(replay_mode != REPLAY_MODE_NONE);
+
+ if (replay_mode == REPLAY_MODE_PLAY) {
+ /*
+ * When reverse-debugging, it is possible to move state from
+ * shutdown to running.
+ */
+ transitions_set_valid(&replay_play_runstate_transitions_def[0]);
+ }
+}
+
+static void runstate_init(void)
+{
+ memset(&runstate_valid_transitions, 0, sizeof(runstate_valid_transitions));
+
+ transitions_set_valid(&runstate_transitions_def[0]);
qemu_mutex_init(&vmstop_lock);
}
@@ -482,15 +508,23 @@ static int qemu_debug_requested(void)
void qemu_system_reset(ShutdownCause reason)
{
MachineClass *mc;
+ ResetType type;
mc = current_machine ? MACHINE_GET_CLASS(current_machine) : NULL;
cpu_synchronize_all_states();
+ switch (reason) {
+ case SHUTDOWN_CAUSE_SNAPSHOT_LOAD:
+ type = RESET_TYPE_SNAPSHOT_LOAD;
+ break;
+ default:
+ type = RESET_TYPE_COLD;
+ }
if (mc && mc->reset) {
- mc->reset(current_machine, reason);
+ mc->reset(current_machine, type);
} else {
- qemu_devices_reset(reason);
+ qemu_devices_reset(type);
}
switch (reason) {
case SHUTDOWN_CAUSE_NONE:
diff --git a/system/trace-events b/system/trace-events
index 2ed1d59..074d001 100644
--- a/system/trace-events
+++ b/system/trace-events
@@ -44,3 +44,6 @@ dirtylimit_state_finalize(void)
dirtylimit_throttle_pct(int cpu_index, uint64_t pct, int64_t time_us) "CPU[%d] throttle percent: %" PRIu64 ", throttle adjust time %"PRIi64 " us"
dirtylimit_set_vcpu(int cpu_index, uint64_t quota) "CPU[%d] set dirty page rate limit %"PRIu64
dirtylimit_vcpu_execute(int cpu_index, int64_t sleep_time_us) "CPU[%d] sleep %"PRIi64 " us"
+
+# cpu-throttle.c
+cpu_throttle_set(int new_throttle_pct) "set guest CPU throttled by %d%%"
diff --git a/system/vl.c b/system/vl.c
index 9e8f16f..d217b3d 100644
--- a/system/vl.c
+++ b/system/vl.c
@@ -1679,10 +1679,10 @@ static MachineClass *select_machine(QDict *qdict, Error **errp)
if (machine_type) {
machine_class = find_machine(machine_type, machines);
- qdict_del(qdict, "type");
if (!machine_class) {
- error_setg(errp, "unsupported machine type: \"%s\"", optarg);
+ error_setg(errp, "unsupported machine type: \"%s\"", machine_type);
}
+ qdict_del(qdict, "type");
} else {
machine_class = find_default_machine(machines);
if (!machine_class) {
@@ -1841,7 +1841,8 @@ static void object_option_parse(const char *str)
type = qemu_opt_get(opts, "qom-type");
if (!type) {
- error_setg(&error_fatal, QERR_MISSING_PARAMETER, "qom-type");
+ error_report(QERR_MISSING_PARAMETER, "qom-type");
+ exit(1);
}
if (user_creatable_print_help(type, opts)) {
exit(0);
@@ -1971,11 +1972,12 @@ static void qemu_create_early_backends(void)
qemu_console_early_init();
- if (dpy.has_gl && dpy.gl != DISPLAYGL_MODE_OFF && display_opengl == 0) {
+ if (dpy.has_gl && dpy.gl != DISPLAY_GL_MODE_OFF && display_opengl == 0) {
#if defined(CONFIG_OPENGL)
- error_report("OpenGL is not supported by the display");
+ error_report("OpenGL is not supported by display backend '%s'",
+ DisplayType_str(dpy.type));
#else
- error_report("OpenGL support is disabled");
+ error_report("OpenGL support was not enabled in this build of QEMU");
#endif
exit(1);
}
@@ -2909,17 +2911,6 @@ void qemu_init(int argc, char **argv)
nographic = true;
dpy.type = DISPLAY_TYPE_NONE;
break;
- case QEMU_OPTION_portrait:
- graphic_rotate = 90;
- break;
- case QEMU_OPTION_rotate:
- graphic_rotate = strtol(optarg, (char **) &optarg, 10);
- if (graphic_rotate != 0 && graphic_rotate != 90 &&
- graphic_rotate != 180 && graphic_rotate != 270) {
- error_report("only 90, 180, 270 deg rotation is available");
- exit(1);
- }
- break;
case QEMU_OPTION_kernel:
qdict_put_str(machine_opts_dict, "kernel", optarg);
break;
diff --git a/target/Kconfig b/target/Kconfig
index 7f64112..d0c7b59 100644
--- a/target/Kconfig
+++ b/target/Kconfig
@@ -1,7 +1,6 @@
source alpha/Kconfig
source arm/Kconfig
source avr/Kconfig
-source cris/Kconfig
source hppa/Kconfig
source i386/Kconfig
source loongarch/Kconfig
diff --git a/target/alpha/cpu-param.h b/target/alpha/cpu-param.h
index 5ce213a..c21ddf1 100644
--- a/target/alpha/cpu-param.h
+++ b/target/alpha/cpu-param.h
@@ -2,7 +2,7 @@
* Alpha cpu parameters for qemu.
*
* Copyright (c) 2007 Jocelyn Mayer
- * SPDX-License-Identifier: LGPL-2.0+
+ * SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef ALPHA_CPU_PARAM_H
diff --git a/target/alpha/cpu.h b/target/alpha/cpu.h
index f9e2ecb..3556d32 100644
--- a/target/alpha/cpu.h
+++ b/target/alpha/cpu.h
@@ -267,7 +267,6 @@ struct ArchCPU {
/**
* AlphaCPUClass:
* @parent_realize: The parent class' realize handler.
- * @parent_reset: The parent class' reset handler.
*
* An Alpha CPU model.
*/
@@ -275,7 +274,6 @@ struct AlphaCPUClass {
CPUClass parent_class;
DeviceRealize parent_realize;
- DeviceReset parent_reset;
};
#ifndef CONFIG_USER_ONLY
diff --git a/target/alpha/gdbstub.c b/target/alpha/gdbstub.c
index 13694fd..1a7e2dd 100644
--- a/target/alpha/gdbstub.c
+++ b/target/alpha/gdbstub.c
@@ -59,7 +59,7 @@ int alpha_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
int alpha_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
CPUAlphaState *env = cpu_env(cs);
- target_ulong tmp = ldtul_p(mem_buf);
+ target_ulong tmp = ldq_le_p(mem_buf);
CPU_DoubleU d;
switch (n) {
diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
index c59ca10..04ce281 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -21,6 +21,7 @@
#define TARGET_ARM_FEATURES_H
#include "hw/registerfields.h"
+#include "qemu/host-utils.h"
/*
* Naming convention for isar_feature functions:
@@ -556,6 +557,11 @@ static inline bool isar_feature_aa64_bf16(const ARMISARegisters *id)
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, BF16) != 0;
}
+static inline bool isar_feature_aa64_ebf16(const ARMISARegisters *id)
+{
+ return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, BF16) > 1;
+}
+
static inline bool isar_feature_aa64_rcpc_8_3(const ARMISARegisters *id)
{
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, LRCPC) != 0;
@@ -1022,6 +1028,55 @@ static inline bool isar_feature_any_evt(const ARMISARegisters *id)
return isar_feature_aa64_evt(id) || isar_feature_aa32_evt(id);
}
+typedef enum {
+ CCSIDR_FORMAT_LEGACY,
+ CCSIDR_FORMAT_CCIDX,
+} CCSIDRFormat;
+
+static inline uint64_t make_ccsidr(CCSIDRFormat format, unsigned assoc,
+ unsigned linesize, unsigned cachesize,
+ uint8_t flags)
+{
+ unsigned lg_linesize = ctz32(linesize);
+ unsigned sets;
+ uint64_t ccsidr = 0;
+
+ assert(assoc != 0);
+ assert(is_power_of_2(linesize));
+ assert(lg_linesize >= 4 && lg_linesize <= 7 + 4);
+
+ /* sets * associativity * linesize == cachesize. */
+ sets = cachesize / (assoc * linesize);
+ assert(cachesize % (assoc * linesize) == 0);
+
+ if (format == CCSIDR_FORMAT_LEGACY) {
+ /*
+ * The 32-bit CCSIDR format is:
+ * [27:13] number of sets - 1
+ * [12:3] associativity - 1
+ * [2:0] log2(linesize) - 4
+ * so 0 == 16 bytes, 1 == 32 bytes, 2 == 64 bytes, etc
+ */
+ ccsidr = deposit32(ccsidr, 28, 4, flags);
+ ccsidr = deposit32(ccsidr, 13, 15, sets - 1);
+ ccsidr = deposit32(ccsidr, 3, 10, assoc - 1);
+ ccsidr = deposit32(ccsidr, 0, 3, lg_linesize - 4);
+ } else {
+ /*
+ * The 64-bit CCSIDR_EL1 format is:
+ * [55:32] number of sets - 1
+ * [23:3] associativity - 1
+ * [2:0] log2(linesize) - 4
+ * so 0 == 16 bytes, 1 == 32 bytes, 2 == 64 bytes, etc
+ */
+ ccsidr = deposit64(ccsidr, 32, 24, sets - 1);
+ ccsidr = deposit64(ccsidr, 3, 21, assoc - 1);
+ ccsidr = deposit64(ccsidr, 0, 3, lg_linesize - 4);
+ }
+
+ return ccsidr;
+}
+
/*
* Forward to the above feature tests given an ARMCPU pointer.
*/
diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h
index 2d5f3aa..bed2961 100644
--- a/target/arm/cpu-param.h
+++ b/target/arm/cpu-param.h
@@ -2,7 +2,7 @@
* ARM cpu parameters for qemu.
*
* Copyright (c) 2003 Fabrice Bellard
- * SPDX-License-Identifier: LGPL-2.0+
+ * SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef ARM_CPU_PARAM_H
@@ -21,9 +21,13 @@
#ifdef CONFIG_USER_ONLY
# ifdef TARGET_AARCH64
# define TARGET_TAGGED_ADDRESSES
+# ifdef __FreeBSD__
+# define TARGET_PAGE_BITS 12
+# else
/* Allow user-only to vary page size from 4k */
# define TARGET_PAGE_BITS_VARY
# define TARGET_PAGE_BITS_MIN 12
+# endif
# else
# define TARGET_PAGE_BITS 12
# endif
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 19191c2..1320fd8 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2663,7 +2663,7 @@ static const TCGCPUOps arm_tcg_ops = {
.record_sigsegv = arm_cpu_record_sigsegv,
.record_sigbus = arm_cpu_record_sigbus,
#else
- .tlb_fill = arm_cpu_tlb_fill,
+ .tlb_fill_align = arm_cpu_tlb_fill_align,
.cpu_exec_interrupt = arm_cpu_exec_interrupt,
.cpu_exec_halt = arm_cpu_exec_halt,
.do_interrupt = arm_cpu_do_interrupt,
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index a12859f..f065756 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1707,6 +1707,7 @@ void vfp_set_fpscr(CPUARMState *env, uint32_t val);
#define FPCR_OFE (1 << 10) /* Overflow exception trap enable */
#define FPCR_UFE (1 << 11) /* Underflow exception trap enable */
#define FPCR_IXE (1 << 12) /* Inexact exception trap enable */
+#define FPCR_EBF (1 << 13) /* Extended BFloat16 behaviors */
#define FPCR_IDE (1 << 15) /* Input Denormal exception trap enable */
#define FPCR_LEN_MASK (7 << 16) /* LEN, A-profile only */
#define FPCR_FZ16 (1 << 19) /* ARMv8.2+, FP16 flush-to-zero */
@@ -2772,14 +2773,19 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync);
* + NonSecure EL1 & 0 stage 2
* + NonSecure EL2
* + NonSecure EL2 & 0 (ARMv8.1-VHE)
- * + Secure EL1 & 0
- * + Secure EL3
+ * + Secure EL1 & 0 stage 1
+ * + Secure EL1 & 0 stage 2 (FEAT_SEL2)
+ * + Secure EL2 (FEAT_SEL2)
+ * + Secure EL2 & 0 (FEAT_SEL2)
+ * + Realm EL1 & 0 stage 1 (FEAT_RME)
+ * + Realm EL1 & 0 stage 2 (FEAT_RME)
+ * + Realm EL2 (FEAT_RME)
+ * + EL3
* If EL3 is 32-bit:
* + NonSecure PL1 & 0 stage 1
* + NonSecure PL1 & 0 stage 2
* + NonSecure PL2
- * + Secure PL0
- * + Secure PL1
+ * + Secure PL1 & 0
* (reminder: for 32 bit EL3, Secure PL1 is *EL3*, not EL1.)
*
* For QEMU, an mmu_idx is not quite the same as a translation regime because:
@@ -2797,37 +2803,42 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync);
* The only use of stage 2 translations is either as part of an s1+2
* lookup or when loading the descriptors during a stage 1 page table walk,
* and in both those cases we don't use the TLB.
- * 4. we can also safely fold together the "32 bit EL3" and "64 bit EL3"
- * translation regimes, because they map reasonably well to each other
- * and they can't both be active at the same time.
- * 5. we want to be able to use the TLB for accesses done as part of a
+ * 4. we want to be able to use the TLB for accesses done as part of a
* stage1 page table walk, rather than having to walk the stage2 page
* table over and over.
- * 6. we need separate EL1/EL2 mmu_idx for handling the Privileged Access
+ * 5. we need separate EL1/EL2 mmu_idx for handling the Privileged Access
* Never (PAN) bit within PSTATE.
- * 7. we fold together the secure and non-secure regimes for A-profile,
+ * 6. we fold together most secure and non-secure regimes for A-profile,
* because there are no banked system registers for aarch64, so the
* process of switching between secure and non-secure is
* already heavyweight.
+ * 7. we cannot fold together Stage 2 Secure and Stage 2 NonSecure,
+ * because both are in use simultaneously for Secure EL2.
*
* This gives us the following list of cases:
*
- * EL0 EL1&0 stage 1+2 (aka NS PL0)
- * EL1 EL1&0 stage 1+2 (aka NS PL1)
- * EL1 EL1&0 stage 1+2 +PAN
+ * EL0 EL1&0 stage 1+2 (or AArch32 PL0 PL1&0 stage 1+2)
+ * EL1 EL1&0 stage 1+2 (or AArch32 PL1 PL1&0 stage 1+2)
+ * EL1 EL1&0 stage 1+2 +PAN (or AArch32 PL1 PL1&0 stage 1+2 +PAN)
* EL0 EL2&0
* EL2 EL2&0
* EL2 EL2&0 +PAN
* EL2 (aka NS PL2)
- * EL3 (aka S PL1)
- * Physical (NS & S)
- * Stage2 (NS & S)
+ * EL3 (not used when EL3 is AArch32)
+ * Stage2 Secure
+ * Stage2 NonSecure
+ * plus one TLB per Physical address space: S, NS, Realm, Root
*
- * for a total of 12 different mmu_idx.
+ * for a total of 14 different mmu_idx.
+ *
+ * Note that when EL3 is AArch32, the usage is potentially confusing
+ * because the MMU indexes are named for their AArch64 use, so code
+ * using the ARMMMUIdx_E10_1 might be at EL3, not EL1. This is because
+ * Secure PL1 is always at EL3.
*
* R profile CPUs have an MPU, but can use the same set of MMU indexes
* as A profile. They only need to distinguish EL0 and EL1 (and
- * EL2 if we ever model a Cortex-R52).
+ * EL2 for cores like the Cortex-R52).
*
* M profile CPUs are rather different as they do not have a true MMU.
* They have the following different MMU indexes:
@@ -3117,6 +3128,10 @@ FIELD(TBFLAG_A32, NS, 10, 1)
* This requires an SME trap from AArch32 mode when using NEON.
*/
FIELD(TBFLAG_A32, SME_TRAP_NONSTREAMING, 11, 1)
+/*
+ * Indicates whether we are in the Secure PL1&0 translation regime
+ */
+FIELD(TBFLAG_A32, S_PL1_0, 12, 1)
/*
* Bit usage when in AArch32 state, for M-profile only.
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 262a1d6..458d1ce 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -23,6 +23,7 @@
#include "cpu.h"
#include "cpregs.h"
#include "qemu/module.h"
+#include "qemu/units.h"
#include "sysemu/kvm.h"
#include "sysemu/hvf.h"
#include "sysemu/qtest.h"
@@ -642,9 +643,12 @@ static void aarch64_a57_initfn(Object *obj)
cpu->isar.dbgdevid1 = 0x2;
cpu->isar.reset_pmcr_el0 = 0x41013000;
cpu->clidr = 0x0a200023;
- cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */
- cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */
- cpu->ccsidr[2] = 0x70ffe07a; /* 2048KB L2 cache */
+ /* 32KB L1 dcache */
+ cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 32 * KiB, 7);
+ /* 48KB L1 icache */
+ cpu->ccsidr[1] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 3, 64, 48 * KiB, 2);
+ /* 2048KB L2 cache */
+ cpu->ccsidr[2] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 16, 64, 2 * MiB, 7);
cpu->dcz_blocksize = 4; /* 64 bytes */
cpu->gic_num_lrs = 4;
cpu->gic_vpribits = 5;
@@ -700,9 +704,12 @@ static void aarch64_a53_initfn(Object *obj)
cpu->isar.dbgdevid1 = 0x1;
cpu->isar.reset_pmcr_el0 = 0x41033000;
cpu->clidr = 0x0a200023;
- cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */
- cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */
- cpu->ccsidr[2] = 0x707fe07a; /* 1024KB L2 cache */
+ /* 32KB L1 dcache */
+ cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 32 * KiB, 7);
+ /* 32KB L1 icache */
+ cpu->ccsidr[1] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 1, 64, 32 * KiB, 2);
+ /* 1024KB L2 cache */
+ cpu->ccsidr[2] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 16, 64, 1 * MiB, 7);
cpu->dcz_blocksize = 4; /* 64 bytes */
cpu->gic_num_lrs = 4;
cpu->gic_vpribits = 5;
diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
index c3a9b5e..554b873 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -477,11 +477,9 @@ static GDBFeature *arm_gen_dynamic_m_secextreg_feature(CPUState *cs,
void arm_cpu_register_gdb_commands(ARMCPU *cpu)
{
- GArray *query_table =
- g_array_new(FALSE, FALSE, sizeof(GdbCmdParseEntry));
- GArray *set_table =
- g_array_new(FALSE, FALSE, sizeof(GdbCmdParseEntry));
- GString *qsupported_features = g_string_new(NULL);
+ g_autoptr(GPtrArray) query_table = g_ptr_array_new();
+ g_autoptr(GPtrArray) set_table = g_ptr_array_new();
+ g_autoptr(GString) qsupported_features = g_string_new(NULL);
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
#ifdef TARGET_AARCH64
@@ -492,16 +490,12 @@ void arm_cpu_register_gdb_commands(ARMCPU *cpu)
/* Set arch-specific handlers for 'q' commands. */
if (query_table->len) {
- gdb_extend_query_table(&g_array_index(query_table,
- GdbCmdParseEntry, 0),
- query_table->len);
+ gdb_extend_query_table(query_table);
}
/* Set arch-specific handlers for 'Q' commands. */
if (set_table->len) {
- gdb_extend_set_table(&g_array_index(set_table,
- GdbCmdParseEntry, 0),
- set_table->len);
+ gdb_extend_set_table(set_table);
}
/* Set arch-specific qSupported feature. */
diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c
index 2e2bc27..1a4dbec 100644
--- a/target/arm/gdbstub64.c
+++ b/target/arm/gdbstub64.c
@@ -404,6 +404,7 @@ int aarch64_gdb_get_tag_ctl_reg(CPUState *cs, GByteArray *buf, int reg)
int aarch64_gdb_set_tag_ctl_reg(CPUState *cs, uint8_t *buf, int reg)
{
+#if defined(CONFIG_LINUX)
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
@@ -425,12 +426,18 @@ int aarch64_gdb_set_tag_ctl_reg(CPUState *cs, uint8_t *buf, int reg)
arm_set_mte_tcf0(env, tcf);
return 1;
+#else
+ return 0;
+#endif
}
+#endif /* CONFIG_USER_ONLY */
+#ifdef CONFIG_TCG
static void handle_q_memtag(GArray *params, void *user_ctx)
{
ARMCPU *cpu = ARM_CPU(user_ctx);
CPUARMState *env = &cpu->env;
+ uint32_t mmu_index;
uint64_t addr = gdb_get_cmd_param(params, 0)->val_ull;
uint64_t len = gdb_get_cmd_param(params, 1)->val_ul;
@@ -454,8 +461,10 @@ static void handle_q_memtag(GArray *params, void *user_ctx)
gdb_put_packet("E03");
}
+ /* Find out the current translation regime for probe. */
+ mmu_index = cpu_mmu_index(env_cpu(env), false);
/* Note that tags are packed here (2 tags packed in one byte). */
- tags = allocation_tag_mem_probe(env, 0, addr, MMU_DATA_LOAD, 8 /* 64-bit */,
+ tags = allocation_tag_mem_probe(env, mmu_index, addr, MMU_DATA_LOAD, 1,
MMU_DATA_LOAD, true, 0);
if (!tags) {
/* Address is not in a tagged region. */
@@ -474,13 +483,16 @@ static void handle_q_isaddresstagged(GArray *params, void *user_ctx)
{
ARMCPU *cpu = ARM_CPU(user_ctx);
CPUARMState *env = &cpu->env;
+ uint32_t mmu_index;
uint64_t addr = gdb_get_cmd_param(params, 0)->val_ull;
uint8_t *tags;
const char *reply;
- tags = allocation_tag_mem_probe(env, 0, addr, MMU_DATA_LOAD, 8 /* 64-bit */,
+ /* Find out the current translation regime for probe. */
+ mmu_index = cpu_mmu_index(env_cpu(env), false);
+ tags = allocation_tag_mem_probe(env, mmu_index, addr, MMU_DATA_LOAD, 1,
MMU_DATA_LOAD, true, 0);
reply = tags ? "01" : "00";
@@ -491,6 +503,7 @@ static void handle_Q_memtag(GArray *params, void *user_ctx)
{
ARMCPU *cpu = ARM_CPU(user_ctx);
CPUARMState *env = &cpu->env;
+ uint32_t mmu_index;
uint64_t start_addr = gdb_get_cmd_param(params, 0)->val_ull;
uint64_t len = gdb_get_cmd_param(params, 1)->val_ul;
@@ -523,8 +536,10 @@ static void handle_Q_memtag(GArray *params, void *user_ctx)
* Get all tags in the page starting from the tag of the start address.
* Note that there are two tags packed into a single byte here.
*/
- tags = allocation_tag_mem_probe(env, 0, start_addr, MMU_DATA_STORE,
- 8 /* 64-bit */, MMU_DATA_STORE, true, 0);
+ /* Find out the current translation regime for probe. */
+ mmu_index = cpu_mmu_index(env_cpu(env), false);
+ tags = allocation_tag_mem_probe(env, mmu_index, start_addr, MMU_DATA_STORE,
+ 1, MMU_DATA_STORE, true, 0);
if (!tags) {
/* Address is not in a tagged region. */
gdb_put_packet("E04");
@@ -564,7 +579,7 @@ enum Command {
NUM_CMDS
};
-static GdbCmdParseEntry cmd_handler_table[NUM_CMDS] = {
+static const GdbCmdParseEntry cmd_handler_table[NUM_CMDS] = {
[qMemTags] = {
.handler = handle_q_memtag,
.cmd_startswith = true,
@@ -587,20 +602,19 @@ static GdbCmdParseEntry cmd_handler_table[NUM_CMDS] = {
.need_cpu_context = true
},
};
-#endif /* CONFIG_USER_ONLY */
+#endif /* CONFIG_TCG */
void aarch64_cpu_register_gdb_commands(ARMCPU *cpu, GString *qsupported,
- GArray *qtable, GArray *stable)
+ GPtrArray *qtable, GPtrArray *stable)
{
-#ifdef CONFIG_USER_ONLY
/* MTE */
+#ifdef CONFIG_TCG
if (cpu_isar_feature(aa64_mte, cpu)) {
g_string_append(qsupported, ";memory-tagging+");
- g_array_append_val(qtable, cmd_handler_table[qMemTags]);
- g_array_append_val(qtable, cmd_handler_table[qIsAddressTagged]);
-
- g_array_append_val(stable, cmd_handler_table[QMemTags]);
+ g_ptr_array_add(qtable, (gpointer) &cmd_handler_table[qMemTags]);
+ g_ptr_array_add(qtable, (gpointer) &cmd_handler_table[qIsAddressTagged]);
+ g_ptr_array_add(stable, (gpointer) &cmd_handler_table[QMemTags]);
}
#endif
}
diff --git a/target/arm/helper.c b/target/arm/helper.c
index ce31957..0a731a3 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -19,7 +19,7 @@
#include "qemu/crc32c.h"
#include "qemu/qemu-print.h"
#include "exec/exec-all.h"
-#include <zlib.h> /* For crc32 */
+#include <zlib.h> /* for crc32 */
#include "hw/irq.h"
#include "sysemu/cpu-timers.h"
#include "sysemu/kvm.h"
@@ -3599,11 +3599,12 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value,
GetPhysAddrResult res = {};
/*
- * I_MXTJT: Granule protection checks are not performed on the final address
- * of a successful translation.
+ * I_MXTJT: Granule protection checks are not performed on the final
+ * address of a successful translation. This is a translation not a
+ * memory reference, so "memop = none = 0".
*/
- ret = get_phys_addr_with_space_nogpc(env, value, access_type, mmu_idx, ss,
- &res, &fi);
+ ret = get_phys_addr_with_space_nogpc(env, value, access_type, 0,
+ mmu_idx, ss, &res, &fi);
/*
* ATS operations only do S1 or S1+S2 translations, so we never
@@ -3700,7 +3701,7 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value,
*/
format64 = arm_s1_regime_using_lpae_format(env, mmu_idx);
- if (arm_feature(env, ARM_FEATURE_EL2)) {
+ if (arm_feature(env, ARM_FEATURE_EL2) && !arm_aa32_secure_pl1_0(env)) {
if (mmu_idx == ARMMMUIdx_E10_0 ||
mmu_idx == ARMMMUIdx_E10_1 ||
mmu_idx == ARMMMUIdx_E10_1_PAN) {
@@ -3774,13 +3775,11 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
case 0:
/* stage 1 current state PL1: ATS1CPR, ATS1CPW, ATS1CPRP, ATS1CPWP */
switch (el) {
- case 3:
- mmu_idx = ARMMMUIdx_E3;
- break;
case 2:
g_assert(ss != ARMSS_Secure); /* ARMv8.4-SecEL2 is 64-bit only */
/* fall through */
case 1:
+ case 3:
if (ri->crm == 9 && arm_pan_enabled(env)) {
mmu_idx = ARMMMUIdx_Stage1_E1_PAN;
} else {
@@ -7232,7 +7231,7 @@ uint32_t sve_vqm1_for_el_sm(CPUARMState *env, int el, bool sm)
if (el <= 1 && !el_is_in_host(env, el)) {
len = MIN(len, 0xf & (uint32_t)cr[1]);
}
- if (el <= 2 && arm_feature(env, ARM_FEATURE_EL2)) {
+ if (el <= 2 && arm_is_el2_enabled(env)) {
len = MIN(len, 0xf & (uint32_t)cr[2]);
}
if (arm_feature(env, ARM_FEATURE_EL3)) {
@@ -11861,8 +11860,11 @@ void arm_cpu_do_interrupt(CPUState *cs)
uint64_t arm_sctlr(CPUARMState *env, int el)
{
- /* Only EL0 needs to be adjusted for EL1&0 or EL2&0. */
- if (el == 0) {
+ if (arm_aa32_secure_pl1_0(env)) {
+ /* In Secure PL1&0 SCTLR_S is always controlling */
+ el = 3;
+ } else if (el == 0) {
+ /* Only EL0 needs to be adjusted for EL1&0 or EL2&0. */
ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, 0);
el = mmu_idx == ARMMMUIdx_E20_0 ? 2 : 1;
}
@@ -12522,8 +12524,12 @@ int fp_exception_el(CPUARMState *env, int cur_el)
return 0;
}
-/* Return the exception level we're running at if this is our mmu_idx */
-int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx)
+/*
+ * Return the exception level we're running at if this is our mmu_idx.
+ * s_pl1_0 should be true if this is the AArch32 Secure PL1&0 translation
+ * regime.
+ */
+int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx, bool s_pl1_0)
{
if (mmu_idx & ARM_MMU_IDX_M) {
return mmu_idx & ARM_MMU_IDX_M_PRIV;
@@ -12535,7 +12541,7 @@ int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx)
return 0;
case ARMMMUIdx_E10_1:
case ARMMMUIdx_E10_1_PAN:
- return 1;
+ return s_pl1_0 ? 3 : 1;
case ARMMMUIdx_E2:
case ARMMMUIdx_E20_2:
case ARMMMUIdx_E20_2_PAN:
@@ -12573,6 +12579,15 @@ ARMMMUIdx arm_mmu_idx_el(CPUARMState *env, int el)
idx = ARMMMUIdx_E10_0;
}
break;
+ case 3:
+ /*
+ * AArch64 EL3 has its own translation regime; AArch32 EL3
+ * uses the Secure PL1&0 translation regime.
+ */
+ if (arm_el_is_aa64(env, 3)) {
+ return ARMMMUIdx_E3;
+ }
+ /* fall through */
case 1:
if (arm_pan_enabled(env)) {
idx = ARMMMUIdx_E10_1_PAN;
@@ -12592,8 +12607,6 @@ ARMMMUIdx arm_mmu_idx_el(CPUARMState *env, int el)
idx = ARMMMUIdx_E2;
}
break;
- case 3:
- return ARMMMUIdx_E3;
default:
g_assert_not_reached();
}
diff --git a/target/arm/helper.h b/target/arm/helper.h
index 970d059..58919b6 100644
--- a/target/arm/helper.h
+++ b/target/arm/helper.h
@@ -324,6 +324,18 @@ DEF_HELPER_FLAGS_5(neon_uqrshl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32
DEF_HELPER_FLAGS_5(neon_uqrshl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_5(neon_uqrshl_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_5(neon_uqrshl_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(neon_sqshli_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(neon_sqshli_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(neon_sqshli_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(neon_sqshli_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(neon_uqshli_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(neon_uqshli_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(neon_uqshli_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(neon_uqshli_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(neon_sqshlui_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(neon_sqshlui_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(neon_sqshlui_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_4(neon_sqshlui_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_srshl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_srshl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
@@ -363,17 +375,17 @@ DEF_HELPER_3(neon_qrdmulh_s32, i32, env, i32, i32)
DEF_HELPER_4(neon_qrdmlah_s32, i32, env, s32, s32, s32)
DEF_HELPER_4(neon_qrdmlsh_s32, i32, env, s32, s32, s32)
-DEF_HELPER_1(neon_narrow_u8, i32, i64)
-DEF_HELPER_1(neon_narrow_u16, i32, i64)
-DEF_HELPER_2(neon_unarrow_sat8, i32, env, i64)
-DEF_HELPER_2(neon_narrow_sat_u8, i32, env, i64)
-DEF_HELPER_2(neon_narrow_sat_s8, i32, env, i64)
-DEF_HELPER_2(neon_unarrow_sat16, i32, env, i64)
-DEF_HELPER_2(neon_narrow_sat_u16, i32, env, i64)
-DEF_HELPER_2(neon_narrow_sat_s16, i32, env, i64)
-DEF_HELPER_2(neon_unarrow_sat32, i32, env, i64)
-DEF_HELPER_2(neon_narrow_sat_u32, i32, env, i64)
-DEF_HELPER_2(neon_narrow_sat_s32, i32, env, i64)
+DEF_HELPER_1(neon_narrow_u8, i64, i64)
+DEF_HELPER_1(neon_narrow_u16, i64, i64)
+DEF_HELPER_2(neon_unarrow_sat8, i64, env, i64)
+DEF_HELPER_2(neon_narrow_sat_u8, i64, env, i64)
+DEF_HELPER_2(neon_narrow_sat_s8, i64, env, i64)
+DEF_HELPER_2(neon_unarrow_sat16, i64, env, i64)
+DEF_HELPER_2(neon_narrow_sat_u16, i64, env, i64)
+DEF_HELPER_2(neon_narrow_sat_s16, i64, env, i64)
+DEF_HELPER_2(neon_unarrow_sat32, i64, env, i64)
+DEF_HELPER_2(neon_narrow_sat_u32, i64, env, i64)
+DEF_HELPER_2(neon_narrow_sat_s32, i64, env, i64)
DEF_HELPER_1(neon_narrow_high_u8, i32, i64)
DEF_HELPER_1(neon_narrow_high_u16, i32, i64)
DEF_HELPER_1(neon_narrow_round_high_u8, i32, i64)
@@ -1027,13 +1039,13 @@ DEF_HELPER_FLAGS_5(gvec_ummla_b, TCG_CALL_NO_RWG,
DEF_HELPER_FLAGS_5(gvec_usmmla_b, TCG_CALL_NO_RWG,
void, ptr, ptr, ptr, ptr, i32)
-DEF_HELPER_FLAGS_5(gvec_bfdot, TCG_CALL_NO_RWG,
- void, ptr, ptr, ptr, ptr, i32)
-DEF_HELPER_FLAGS_5(gvec_bfdot_idx, TCG_CALL_NO_RWG,
- void, ptr, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_6(gvec_bfdot, TCG_CALL_NO_RWG,
+ void, ptr, ptr, ptr, ptr, env, i32)
+DEF_HELPER_FLAGS_6(gvec_bfdot_idx, TCG_CALL_NO_RWG,
+ void, ptr, ptr, ptr, ptr, env, i32)
-DEF_HELPER_FLAGS_5(gvec_bfmmla, TCG_CALL_NO_RWG,
- void, ptr, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_6(gvec_bfmmla, TCG_CALL_NO_RWG,
+ void, ptr, ptr, ptr, ptr, env, i32)
DEF_HELPER_FLAGS_6(gvec_bfmlal, TCG_CALL_NO_RWG,
void, ptr, ptr, ptr, ptr, ptr, i32)
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index eb090e6..6cea483 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -22,6 +22,7 @@
#include <mach/mach_time.h>
#include "exec/address-spaces.h"
+#include "hw/boards.h"
#include "hw/irq.h"
#include "qemu/main-loop.h"
#include "sysemu/cpus.h"
@@ -297,6 +298,8 @@ void hvf_arm_init_debug(void)
static void hvf_wfi(CPUState *cpu);
+static uint32_t chosen_ipa_bit_size;
+
typedef struct HVFVTimer {
/* Vtimer value during migration and paused state */
uint64_t vtimer_val;
@@ -839,6 +842,16 @@ static uint64_t hvf_get_reg(CPUState *cpu, int rt)
return val;
}
+static void clamp_id_aa64mmfr0_parange_to_ipa_size(uint64_t *id_aa64mmfr0)
+{
+ uint32_t ipa_size = chosen_ipa_bit_size ?
+ chosen_ipa_bit_size : hvf_arm_get_max_ipa_bit_size();
+
+ /* Clamp down the PARange to the IPA size the kernel supports. */
+ uint8_t index = round_down_to_parange_index(ipa_size);
+ *id_aa64mmfr0 = (*id_aa64mmfr0 & ~R_ID_AA64MMFR0_PARANGE_MASK) | index;
+}
+
static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
{
ARMISARegisters host_isar = {};
@@ -882,6 +895,8 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
r |= hv_vcpu_get_sys_reg(fd, HV_SYS_REG_MIDR_EL1, &ahcf->midr);
r |= hv_vcpu_destroy(fd);
+ clamp_id_aa64mmfr0_parange_to_ipa_size(&host_isar.id_aa64mmfr0);
+
ahcf->isar = host_isar;
/*
@@ -904,6 +919,30 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
return r == HV_SUCCESS;
}
+uint32_t hvf_arm_get_default_ipa_bit_size(void)
+{
+ uint32_t default_ipa_size;
+ hv_return_t ret = hv_vm_config_get_default_ipa_size(&default_ipa_size);
+ assert_hvf_ok(ret);
+
+ return default_ipa_size;
+}
+
+uint32_t hvf_arm_get_max_ipa_bit_size(void)
+{
+ uint32_t max_ipa_size;
+ hv_return_t ret = hv_vm_config_get_max_ipa_size(&max_ipa_size);
+ assert_hvf_ok(ret);
+
+ /*
+ * We clamp any IPA size we want to back the VM with to a valid PARange
+ * value so the guest doesn't try and map memory outside of the valid range.
+ * This logic just clamps the passed in IPA bit size to the first valid
+ * PARange value <= to it.
+ */
+ return round_down_to_parange_bit_size(max_ipa_size);
+}
+
void hvf_arm_set_cpu_features_from_host(ARMCPU *cpu)
{
if (!arm_host_cpu_features.dtb_compatible) {
@@ -929,6 +968,25 @@ void hvf_arch_vcpu_destroy(CPUState *cpu)
{
}
+hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range)
+{
+ hv_return_t ret;
+ hv_vm_config_t config = hv_vm_config_create();
+
+ ret = hv_vm_config_set_ipa_size(config, pa_range);
+ if (ret != HV_SUCCESS) {
+ goto cleanup;
+ }
+ chosen_ipa_bit_size = pa_range;
+
+ ret = hv_vm_create(config);
+
+cleanup:
+ os_release(config);
+
+ return ret;
+}
+
int hvf_arch_init_vcpu(CPUState *cpu)
{
ARMCPU *arm_cpu = ARM_CPU(cpu);
@@ -995,6 +1053,11 @@ int hvf_arch_init_vcpu(CPUState *cpu)
&arm_cpu->isar.id_aa64mmfr0);
assert_hvf_ok(ret);
+ clamp_id_aa64mmfr0_parange_to_ipa_size(&arm_cpu->isar.id_aa64mmfr0);
+ ret = hv_vcpu_set_sys_reg(cpu->accel->fd, HV_SYS_REG_ID_AA64MMFR0_EL1,
+ arm_cpu->isar.id_aa64mmfr0);
+ assert_hvf_ok(ret);
+
return 0;
}
@@ -1199,57 +1262,61 @@ static bool hvf_sysreg_read_cp(CPUState *cpu, uint32_t reg, uint64_t *val)
return false;
}
-static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt)
+static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint64_t *val)
{
ARMCPU *arm_cpu = ARM_CPU(cpu);
CPUARMState *env = &arm_cpu->env;
- uint64_t val = 0;
+
+ if (arm_feature(env, ARM_FEATURE_PMU)) {
+ switch (reg) {
+ case SYSREG_PMCR_EL0:
+ *val = env->cp15.c9_pmcr;
+ return 0;
+ case SYSREG_PMCCNTR_EL0:
+ pmu_op_start(env);
+ *val = env->cp15.c15_ccnt;
+ pmu_op_finish(env);
+ return 0;
+ case SYSREG_PMCNTENCLR_EL0:
+ *val = env->cp15.c9_pmcnten;
+ return 0;
+ case SYSREG_PMOVSCLR_EL0:
+ *val = env->cp15.c9_pmovsr;
+ return 0;
+ case SYSREG_PMSELR_EL0:
+ *val = env->cp15.c9_pmselr;
+ return 0;
+ case SYSREG_PMINTENCLR_EL1:
+ *val = env->cp15.c9_pminten;
+ return 0;
+ case SYSREG_PMCCFILTR_EL0:
+ *val = env->cp15.pmccfiltr_el0;
+ return 0;
+ case SYSREG_PMCNTENSET_EL0:
+ *val = env->cp15.c9_pmcnten;
+ return 0;
+ case SYSREG_PMUSERENR_EL0:
+ *val = env->cp15.c9_pmuserenr;
+ return 0;
+ case SYSREG_PMCEID0_EL0:
+ case SYSREG_PMCEID1_EL0:
+ /* We can't really count anything yet, declare all events invalid */
+ *val = 0;
+ return 0;
+ }
+ }
switch (reg) {
case SYSREG_CNTPCT_EL0:
- val = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) /
+ *val = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) /
gt_cntfrq_period_ns(arm_cpu);
- break;
- case SYSREG_PMCR_EL0:
- val = env->cp15.c9_pmcr;
- break;
- case SYSREG_PMCCNTR_EL0:
- pmu_op_start(env);
- val = env->cp15.c15_ccnt;
- pmu_op_finish(env);
- break;
- case SYSREG_PMCNTENCLR_EL0:
- val = env->cp15.c9_pmcnten;
- break;
- case SYSREG_PMOVSCLR_EL0:
- val = env->cp15.c9_pmovsr;
- break;
- case SYSREG_PMSELR_EL0:
- val = env->cp15.c9_pmselr;
- break;
- case SYSREG_PMINTENCLR_EL1:
- val = env->cp15.c9_pminten;
- break;
- case SYSREG_PMCCFILTR_EL0:
- val = env->cp15.pmccfiltr_el0;
- break;
- case SYSREG_PMCNTENSET_EL0:
- val = env->cp15.c9_pmcnten;
- break;
- case SYSREG_PMUSERENR_EL0:
- val = env->cp15.c9_pmuserenr;
- break;
- case SYSREG_PMCEID0_EL0:
- case SYSREG_PMCEID1_EL0:
- /* We can't really count anything yet, declare all events invalid */
- val = 0;
- break;
+ return 0;
case SYSREG_OSLSR_EL1:
- val = env->cp15.oslsr_el1;
- break;
+ *val = env->cp15.oslsr_el1;
+ return 0;
case SYSREG_OSDLR_EL1:
/* Dummy register */
- break;
+ return 0;
case SYSREG_ICC_AP0R0_EL1:
case SYSREG_ICC_AP0R1_EL1:
case SYSREG_ICC_AP0R2_EL1:
@@ -1276,9 +1343,8 @@ static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt)
case SYSREG_ICC_SRE_EL1:
case SYSREG_ICC_CTLR_EL1:
/* Call the TCG sysreg handler. This is only safe for GICv3 regs. */
- if (!hvf_sysreg_read_cp(cpu, reg, &val)) {
- hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized());
- return 1;
+ if (hvf_sysreg_read_cp(cpu, reg, val)) {
+ return 0;
}
break;
case SYSREG_DBGBVR0_EL1:
@@ -1297,8 +1363,8 @@ static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt)
case SYSREG_DBGBVR13_EL1:
case SYSREG_DBGBVR14_EL1:
case SYSREG_DBGBVR15_EL1:
- val = env->cp15.dbgbvr[SYSREG_CRM(reg)];
- break;
+ *val = env->cp15.dbgbvr[SYSREG_CRM(reg)];
+ return 0;
case SYSREG_DBGBCR0_EL1:
case SYSREG_DBGBCR1_EL1:
case SYSREG_DBGBCR2_EL1:
@@ -1315,8 +1381,8 @@ static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt)
case SYSREG_DBGBCR13_EL1:
case SYSREG_DBGBCR14_EL1:
case SYSREG_DBGBCR15_EL1:
- val = env->cp15.dbgbcr[SYSREG_CRM(reg)];
- break;
+ *val = env->cp15.dbgbcr[SYSREG_CRM(reg)];
+ return 0;
case SYSREG_DBGWVR0_EL1:
case SYSREG_DBGWVR1_EL1:
case SYSREG_DBGWVR2_EL1:
@@ -1333,8 +1399,8 @@ static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt)
case SYSREG_DBGWVR13_EL1:
case SYSREG_DBGWVR14_EL1:
case SYSREG_DBGWVR15_EL1:
- val = env->cp15.dbgwvr[SYSREG_CRM(reg)];
- break;
+ *val = env->cp15.dbgwvr[SYSREG_CRM(reg)];
+ return 0;
case SYSREG_DBGWCR0_EL1:
case SYSREG_DBGWCR1_EL1:
case SYSREG_DBGWCR2_EL1:
@@ -1351,35 +1417,25 @@ static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt)
case SYSREG_DBGWCR13_EL1:
case SYSREG_DBGWCR14_EL1:
case SYSREG_DBGWCR15_EL1:
- val = env->cp15.dbgwcr[SYSREG_CRM(reg)];
- break;
+ *val = env->cp15.dbgwcr[SYSREG_CRM(reg)];
+ return 0;
default:
if (is_id_sysreg(reg)) {
/* ID system registers read as RES0 */
- val = 0;
- break;
+ *val = 0;
+ return 0;
}
- cpu_synchronize_state(cpu);
- trace_hvf_unhandled_sysreg_read(env->pc, reg,
- SYSREG_OP0(reg),
- SYSREG_OP1(reg),
- SYSREG_CRN(reg),
- SYSREG_CRM(reg),
- SYSREG_OP2(reg));
- hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized());
- return 1;
- }
-
- trace_hvf_sysreg_read(reg,
- SYSREG_OP0(reg),
- SYSREG_OP1(reg),
- SYSREG_CRN(reg),
- SYSREG_CRM(reg),
- SYSREG_OP2(reg),
- val);
- hvf_set_reg(cpu, rt, val);
+ }
- return 0;
+ cpu_synchronize_state(cpu);
+ trace_hvf_unhandled_sysreg_read(env->pc, reg,
+ SYSREG_OP0(reg),
+ SYSREG_OP1(reg),
+ SYSREG_CRN(reg),
+ SYSREG_CRM(reg),
+ SYSREG_OP2(reg));
+ hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized());
+ return 1;
}
static void pmu_update_irq(CPUARMState *env)
@@ -1498,70 +1554,75 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val)
SYSREG_OP2(reg),
val);
- switch (reg) {
- case SYSREG_PMCCNTR_EL0:
- pmu_op_start(env);
- env->cp15.c15_ccnt = val;
- pmu_op_finish(env);
- break;
- case SYSREG_PMCR_EL0:
- pmu_op_start(env);
-
- if (val & PMCRC) {
- /* The counter has been reset */
- env->cp15.c15_ccnt = 0;
- }
+ if (arm_feature(env, ARM_FEATURE_PMU)) {
+ switch (reg) {
+ case SYSREG_PMCCNTR_EL0:
+ pmu_op_start(env);
+ env->cp15.c15_ccnt = val;
+ pmu_op_finish(env);
+ return 0;
+ case SYSREG_PMCR_EL0:
+ pmu_op_start(env);
+
+ if (val & PMCRC) {
+ /* The counter has been reset */
+ env->cp15.c15_ccnt = 0;
+ }
- if (val & PMCRP) {
- unsigned int i;
- for (i = 0; i < pmu_num_counters(env); i++) {
- env->cp15.c14_pmevcntr[i] = 0;
+ if (val & PMCRP) {
+ unsigned int i;
+ for (i = 0; i < pmu_num_counters(env); i++) {
+ env->cp15.c14_pmevcntr[i] = 0;
+ }
}
- }
- env->cp15.c9_pmcr &= ~PMCR_WRITABLE_MASK;
- env->cp15.c9_pmcr |= (val & PMCR_WRITABLE_MASK);
+ env->cp15.c9_pmcr &= ~PMCR_WRITABLE_MASK;
+ env->cp15.c9_pmcr |= (val & PMCR_WRITABLE_MASK);
+
+ pmu_op_finish(env);
+ return 0;
+ case SYSREG_PMUSERENR_EL0:
+ env->cp15.c9_pmuserenr = val & 0xf;
+ return 0;
+ case SYSREG_PMCNTENSET_EL0:
+ env->cp15.c9_pmcnten |= (val & pmu_counter_mask(env));
+ return 0;
+ case SYSREG_PMCNTENCLR_EL0:
+ env->cp15.c9_pmcnten &= ~(val & pmu_counter_mask(env));
+ return 0;
+ case SYSREG_PMINTENCLR_EL1:
+ pmu_op_start(env);
+ env->cp15.c9_pminten |= val;
+ pmu_op_finish(env);
+ return 0;
+ case SYSREG_PMOVSCLR_EL0:
+ pmu_op_start(env);
+ env->cp15.c9_pmovsr &= ~val;
+ pmu_op_finish(env);
+ return 0;
+ case SYSREG_PMSWINC_EL0:
+ pmu_op_start(env);
+ pmswinc_write(env, val);
+ pmu_op_finish(env);
+ return 0;
+ case SYSREG_PMSELR_EL0:
+ env->cp15.c9_pmselr = val & 0x1f;
+ return 0;
+ case SYSREG_PMCCFILTR_EL0:
+ pmu_op_start(env);
+ env->cp15.pmccfiltr_el0 = val & PMCCFILTR_EL0;
+ pmu_op_finish(env);
+ return 0;
+ }
+ }
- pmu_op_finish(env);
- break;
- case SYSREG_PMUSERENR_EL0:
- env->cp15.c9_pmuserenr = val & 0xf;
- break;
- case SYSREG_PMCNTENSET_EL0:
- env->cp15.c9_pmcnten |= (val & pmu_counter_mask(env));
- break;
- case SYSREG_PMCNTENCLR_EL0:
- env->cp15.c9_pmcnten &= ~(val & pmu_counter_mask(env));
- break;
- case SYSREG_PMINTENCLR_EL1:
- pmu_op_start(env);
- env->cp15.c9_pminten |= val;
- pmu_op_finish(env);
- break;
- case SYSREG_PMOVSCLR_EL0:
- pmu_op_start(env);
- env->cp15.c9_pmovsr &= ~val;
- pmu_op_finish(env);
- break;
- case SYSREG_PMSWINC_EL0:
- pmu_op_start(env);
- pmswinc_write(env, val);
- pmu_op_finish(env);
- break;
- case SYSREG_PMSELR_EL0:
- env->cp15.c9_pmselr = val & 0x1f;
- break;
- case SYSREG_PMCCFILTR_EL0:
- pmu_op_start(env);
- env->cp15.pmccfiltr_el0 = val & PMCCFILTR_EL0;
- pmu_op_finish(env);
- break;
+ switch (reg) {
case SYSREG_OSLAR_EL1:
env->cp15.oslsr_el1 = val & 1;
- break;
+ return 0;
case SYSREG_OSDLR_EL1:
/* Dummy register */
- break;
+ return 0;
case SYSREG_ICC_AP0R0_EL1:
case SYSREG_ICC_AP0R1_EL1:
case SYSREG_ICC_AP0R2_EL1:
@@ -1588,13 +1649,13 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val)
case SYSREG_ICC_SGI1R_EL1:
case SYSREG_ICC_SRE_EL1:
/* Call the TCG sysreg handler. This is only safe for GICv3 regs. */
- if (!hvf_sysreg_write_cp(cpu, reg, val)) {
- hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized());
+ if (hvf_sysreg_write_cp(cpu, reg, val)) {
+ return 0;
}
break;
case SYSREG_MDSCR_EL1:
env->cp15.mdscr_el1 = val;
- break;
+ return 0;
case SYSREG_DBGBVR0_EL1:
case SYSREG_DBGBVR1_EL1:
case SYSREG_DBGBVR2_EL1:
@@ -1612,7 +1673,7 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val)
case SYSREG_DBGBVR14_EL1:
case SYSREG_DBGBVR15_EL1:
env->cp15.dbgbvr[SYSREG_CRM(reg)] = val;
- break;
+ return 0;
case SYSREG_DBGBCR0_EL1:
case SYSREG_DBGBCR1_EL1:
case SYSREG_DBGBCR2_EL1:
@@ -1630,7 +1691,7 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val)
case SYSREG_DBGBCR14_EL1:
case SYSREG_DBGBCR15_EL1:
env->cp15.dbgbcr[SYSREG_CRM(reg)] = val;
- break;
+ return 0;
case SYSREG_DBGWVR0_EL1:
case SYSREG_DBGWVR1_EL1:
case SYSREG_DBGWVR2_EL1:
@@ -1648,7 +1709,7 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val)
case SYSREG_DBGWVR14_EL1:
case SYSREG_DBGWVR15_EL1:
env->cp15.dbgwvr[SYSREG_CRM(reg)] = val;
- break;
+ return 0;
case SYSREG_DBGWCR0_EL1:
case SYSREG_DBGWCR1_EL1:
case SYSREG_DBGWCR2_EL1:
@@ -1666,20 +1727,18 @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val)
case SYSREG_DBGWCR14_EL1:
case SYSREG_DBGWCR15_EL1:
env->cp15.dbgwcr[SYSREG_CRM(reg)] = val;
- break;
- default:
- cpu_synchronize_state(cpu);
- trace_hvf_unhandled_sysreg_write(env->pc, reg,
- SYSREG_OP0(reg),
- SYSREG_OP1(reg),
- SYSREG_CRN(reg),
- SYSREG_CRM(reg),
- SYSREG_OP2(reg));
- hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized());
- return 1;
+ return 0;
}
- return 0;
+ cpu_synchronize_state(cpu);
+ trace_hvf_unhandled_sysreg_write(env->pc, reg,
+ SYSREG_OP0(reg),
+ SYSREG_OP1(reg),
+ SYSREG_CRN(reg),
+ SYSREG_CRM(reg),
+ SYSREG_OP2(reg));
+ hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized());
+ return 1;
}
static int hvf_inject_interrupts(CPUState *cpu)
@@ -1944,7 +2003,17 @@ int hvf_vcpu_exec(CPUState *cpu)
int sysreg_ret = 0;
if (isread) {
- sysreg_ret = hvf_sysreg_read(cpu, reg, rt);
+ sysreg_ret = hvf_sysreg_read(cpu, reg, &val);
+ if (!sysreg_ret) {
+ trace_hvf_sysreg_read(reg,
+ SYSREG_OP0(reg),
+ SYSREG_OP1(reg),
+ SYSREG_CRN(reg),
+ SYSREG_CRM(reg),
+ SYSREG_OP2(reg),
+ val);
+ hvf_set_reg(cpu, rt, val);
+ }
} else {
val = hvf_get_reg(cpu, rt);
sysreg_ret = hvf_sysreg_write(cpu, reg, val);
diff --git a/target/arm/hvf_arm.h b/target/arm/hvf_arm.h
index e848c1d..26c717b 100644
--- a/target/arm/hvf_arm.h
+++ b/target/arm/hvf_arm.h
@@ -22,4 +22,23 @@ void hvf_arm_init_debug(void);
void hvf_arm_set_cpu_features_from_host(ARMCPU *cpu);
+#ifdef CONFIG_HVF
+
+uint32_t hvf_arm_get_default_ipa_bit_size(void);
+uint32_t hvf_arm_get_max_ipa_bit_size(void);
+
+#else
+
+static inline uint32_t hvf_arm_get_default_ipa_bit_size(void)
+{
+ return 0;
+}
+
+static inline uint32_t hvf_arm_get_max_ipa_bit_size(void)
+{
+ return 0;
+}
+
+#endif
+
#endif
diff --git a/target/arm/hyp_gdbstub.c b/target/arm/hyp_gdbstub.c
index f120d55..1e86126 100644
--- a/target/arm/hyp_gdbstub.c
+++ b/target/arm/hyp_gdbstub.c
@@ -158,7 +158,6 @@ int insert_hw_watchpoint(target_ulong addr, target_ulong len, int type)
break;
default:
g_assert_not_reached();
- break;
}
if (len <= 8) {
/* we align the address and set the bits in BAS */
diff --git a/target/arm/internals.h b/target/arm/internals.h
index da22d04..299a96a 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -276,6 +276,20 @@ FIELD(CNTHCTL, CNTPMASK, 19, 1)
#define M_FAKE_FSR_SFAULT 0xe /* SecureFault INVTRAN, INVEP or AUVIOL */
/**
+ * arm_aa32_secure_pl1_0(): Return true if in Secure PL1&0 regime
+ *
+ * Return true if the CPU is in the Secure PL1&0 translation regime.
+ * This requires that EL3 exists and is AArch32 and we are currently
+ * Secure. If this is the case then the ARMMMUIdx_E10* apply and
+ * mean we are in EL3, not EL1.
+ */
+static inline bool arm_aa32_secure_pl1_0(CPUARMState *env)
+{
+ return arm_feature(env, ARM_FEATURE_EL3) &&
+ !arm_el_is_aa64(env, 3) && arm_is_secure(env);
+}
+
+/**
* raise_exception: Raise the specified exception.
* Raise a guest exception with the specified value, syndrome register
* and target exception level. This should be called from helper functions,
@@ -359,8 +373,8 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu);
void arm_translate_init(void);
void arm_cpu_register_gdb_commands(ARMCPU *cpu);
-void aarch64_cpu_register_gdb_commands(ARMCPU *cpu, GString *, GArray *,
- GArray *);
+void aarch64_cpu_register_gdb_commands(ARMCPU *cpu, GString *,
+ GPtrArray *, GPtrArray *);
void arm_restore_state_to_opc(CPUState *cs,
const TranslationBlock *tb,
@@ -436,6 +450,25 @@ static inline void update_spsel(CPUARMState *env, uint32_t imm)
*/
unsigned int arm_pamax(ARMCPU *cpu);
+/*
+ * round_down_to_parange_index
+ * @bit_size: uint8_t
+ *
+ * Rounds down the bit_size supplied to the first supported ARM physical
+ * address range and returns the index for this. The index is intended to
+ * be used to set ID_AA64MMFR0_EL1's PARANGE bits.
+ */
+uint8_t round_down_to_parange_index(uint8_t bit_size);
+
+/*
+ * round_down_to_parange_bit_size
+ * @bit_size: uint8_t
+ *
+ * Rounds down the bit_size supplied to the first supported ARM physical
+ * address range bit size and returns this.
+ */
+uint8_t round_down_to_parange_bit_size(uint8_t bit_size);
+
/* Return true if extended addresses are enabled.
* This is always the case if our translation regime is 64 bit,
* but depends on TTBCR.EAE for 32 bit.
@@ -783,9 +816,9 @@ void arm_cpu_record_sigsegv(CPUState *cpu, vaddr addr,
void arm_cpu_record_sigbus(CPUState *cpu, vaddr addr,
MMUAccessType access_type, uintptr_t ra);
#else
-bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
- MMUAccessType access_type, int mmu_idx,
- bool probe, uintptr_t retaddr);
+bool arm_cpu_tlb_fill_align(CPUState *cs, CPUTLBEntryFull *out, vaddr addr,
+ MMUAccessType access_type, int mmu_idx,
+ MemOp memop, int size, bool probe, uintptr_t ra);
#endif
static inline int arm_to_core_mmu_idx(ARMMMUIdx mmu_idx)
@@ -808,7 +841,12 @@ static inline ARMMMUIdx core_to_aa64_mmu_idx(int mmu_idx)
return mmu_idx | ARM_MMU_IDX_A;
}
-int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx);
+/**
+ * Return the exception level we're running at if our current MMU index
+ * is @mmu_idx. @s_pl1_0 should be true if this is the AArch32
+ * Secure PL1&0 translation regime.
+ */
+int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx, bool s_pl1_0);
/* Return the MMU index for a v7M CPU in the specified security state */
ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate);
@@ -903,11 +941,11 @@ static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx)
return 3;
case ARMMMUIdx_E10_0:
case ARMMMUIdx_Stage1_E0:
- return arm_el_is_aa64(env, 3) || !arm_is_secure_below_el3(env) ? 1 : 3;
- case ARMMMUIdx_Stage1_E1:
- case ARMMMUIdx_Stage1_E1_PAN:
case ARMMMUIdx_E10_1:
case ARMMMUIdx_E10_1_PAN:
+ case ARMMMUIdx_Stage1_E1:
+ case ARMMMUIdx_Stage1_E1_PAN:
+ return arm_el_is_aa64(env, 3) || !arm_is_secure_below_el3(env) ? 1 : 3;
case ARMMMUIdx_MPrivNegPri:
case ARMMMUIdx_MUserNegPri:
case ARMMMUIdx_MPriv:
@@ -1394,6 +1432,7 @@ typedef struct GetPhysAddrResult {
* @env: CPUARMState
* @address: virtual address to get physical address for
* @access_type: 0 for read, 1 for write, 2 for execute
+ * @memop: memory operation feeding this access, or 0 for none
* @mmu_idx: MMU index indicating required translation regime
* @result: set on translation success.
* @fi: set to fault info if the translation fails
@@ -1411,8 +1450,8 @@ typedef struct GetPhysAddrResult {
* * for PSMAv5 based systems we don't bother to return a full FSR format
* value.
*/
-bool get_phys_addr(CPUARMState *env, target_ulong address,
- MMUAccessType access_type, ARMMMUIdx mmu_idx,
+bool get_phys_addr(CPUARMState *env, vaddr address,
+ MMUAccessType access_type, MemOp memop, ARMMMUIdx mmu_idx,
GetPhysAddrResult *result, ARMMMUFaultInfo *fi)
__attribute__((nonnull));
@@ -1422,6 +1461,7 @@ bool get_phys_addr(CPUARMState *env, target_ulong address,
* @env: CPUARMState
* @address: virtual address to get physical address for
* @access_type: 0 for read, 1 for write, 2 for execute
+ * @memop: memory operation feeding this access, or 0 for none
* @mmu_idx: MMU index indicating required translation regime
* @space: security space for the access
* @result: set on translation success.
@@ -1430,8 +1470,8 @@ bool get_phys_addr(CPUARMState *env, target_ulong address,
* Similar to get_phys_addr, but use the given security space and don't perform
* a Granule Protection Check on the resulting address.
*/
-bool get_phys_addr_with_space_nogpc(CPUARMState *env, target_ulong address,
- MMUAccessType access_type,
+bool get_phys_addr_with_space_nogpc(CPUARMState *env, vaddr address,
+ MMUAccessType access_type, MemOp memop,
ARMMMUIdx mmu_idx, ARMSecuritySpace space,
GetPhysAddrResult *result,
ARMMMUFaultInfo *fi)
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 70f79ed..f1f1b5b 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -280,6 +280,7 @@ static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
if (kvm_arm_pmu_supported()) {
init.features[0] |= 1 << KVM_ARM_VCPU_PMU_V3;
pmu_supported = true;
+ features |= 1ULL << ARM_FEATURE_PMU;
}
if (!kvm_arm_create_scratch_host_vcpu(cpus_to_try, fdarray, &init)) {
@@ -448,7 +449,6 @@ static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
features |= 1ULL << ARM_FEATURE_V8;
features |= 1ULL << ARM_FEATURE_NEON;
features |= 1ULL << ARM_FEATURE_AARCH64;
- features |= 1ULL << ARM_FEATURE_PMU;
features |= 1ULL << ARM_FEATURE_GENERIC_TIMER;
ahcf->features = features;
@@ -1888,13 +1888,8 @@ int kvm_arch_init_vcpu(CPUState *cs)
if (!arm_feature(env, ARM_FEATURE_AARCH64)) {
cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_EL1_32BIT;
}
- if (!kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PMU_V3)) {
- cpu->has_pmu = false;
- }
if (cpu->has_pmu) {
cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PMU_V3;
- } else {
- env->features &= ~(1ULL << ARM_FEATURE_PMU);
}
if (cpu_isar_feature(aa64_sve, cpu)) {
assert(kvm_arm_sve_supported());
@@ -2047,7 +2042,7 @@ static int kvm_arch_put_sve(CPUState *cs)
return 0;
}
-int kvm_arch_put_registers(CPUState *cs, int level)
+int kvm_arch_put_registers(CPUState *cs, int level, Error **errp)
{
uint64_t val;
uint32_t fpr;
@@ -2231,7 +2226,7 @@ static int kvm_arch_get_sve(CPUState *cs)
return 0;
}
-int kvm_arch_get_registers(CPUState *cs)
+int kvm_arch_get_registers(CPUState *cs, Error **errp)
{
uint64_t val;
unsigned int el;
diff --git a/target/arm/ptw.c b/target/arm/ptw.c
index 4476b32..dd40268 100644
--- a/target/arm/ptw.c
+++ b/target/arm/ptw.c
@@ -74,14 +74,14 @@ typedef struct S1Translate {
} S1Translate;
static bool get_phys_addr_nogpc(CPUARMState *env, S1Translate *ptw,
- target_ulong address,
- MMUAccessType access_type,
+ vaddr address,
+ MMUAccessType access_type, MemOp memop,
GetPhysAddrResult *result,
ARMMMUFaultInfo *fi);
static bool get_phys_addr_gpc(CPUARMState *env, S1Translate *ptw,
- target_ulong address,
- MMUAccessType access_type,
+ vaddr address,
+ MMUAccessType access_type, MemOp memop,
GetPhysAddrResult *result,
ARMMMUFaultInfo *fi);
@@ -96,6 +96,21 @@ static const uint8_t pamax_map[] = {
[6] = 52,
};
+uint8_t round_down_to_parange_index(uint8_t bit_size)
+{
+ for (int i = ARRAY_SIZE(pamax_map) - 1; i >= 0; i--) {
+ if (pamax_map[i] <= bit_size) {
+ return i;
+ }
+ }
+ g_assert_not_reached();
+}
+
+uint8_t round_down_to_parange_bit_size(uint8_t bit_size)
+{
+ return pamax_map[round_down_to_parange_index(bit_size)];
+}
+
/*
* The cpu-specific constant value of PAMax; also used by hw/arm/virt.
* Note that machvirt_init calls this on a CPU that is inited but not realized!
@@ -564,7 +579,7 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw,
};
GetPhysAddrResult s2 = { };
- if (get_phys_addr_gpc(env, &s2ptw, addr, MMU_DATA_LOAD, &s2, fi)) {
+ if (get_phys_addr_gpc(env, &s2ptw, addr, MMU_DATA_LOAD, 0, &s2, fi)) {
goto fail;
}
@@ -1669,12 +1684,13 @@ static bool nv_nv1_enabled(CPUARMState *env, S1Translate *ptw)
* @ptw: Current and next stage parameters for the walk.
* @address: virtual address to get physical address for
* @access_type: MMU_DATA_LOAD, MMU_DATA_STORE or MMU_INST_FETCH
+ * @memop: memory operation feeding this access, or 0 for none
* @result: set on translation success,
* @fi: set to fault info if the translation fails
*/
static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw,
uint64_t address,
- MMUAccessType access_type,
+ MMUAccessType access_type, MemOp memop,
GetPhysAddrResult *result, ARMMMUFaultInfo *fi)
{
ARMCPU *cpu = env_archcpu(env);
@@ -2013,8 +2029,20 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw,
xn = extract64(attrs, 53, 2);
result->f.prot = get_S2prot(env, ap, xn, ptw->in_s1_is_el0);
}
+
+ result->cacheattrs.is_s2_format = true;
+ result->cacheattrs.attrs = extract32(attrs, 2, 4);
+ /*
+ * Security state does not really affect HCR_EL2.FWB;
+ * we only need to filter FWB for aa32 or other FEAT.
+ */
+ device = S2_attrs_are_device(arm_hcr_el2_eff(env),
+ result->cacheattrs.attrs);
} else {
int nse, ns = extract32(attrs, 5, 1);
+ uint8_t attrindx;
+ uint64_t mair;
+
switch (out_space) {
case ARMSS_Root:
/*
@@ -2086,6 +2114,49 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw,
*/
result->f.prot = get_S1prot(env, mmu_idx, aarch64, ap, xn, pxn,
result->f.attrs.space, out_space);
+
+ /* Index into MAIR registers for cache attributes */
+ attrindx = extract32(attrs, 2, 3);
+ mair = env->cp15.mair_el[regime_el(env, mmu_idx)];
+ assert(attrindx <= 7);
+ result->cacheattrs.is_s2_format = false;
+ result->cacheattrs.attrs = extract64(mair, attrindx * 8, 8);
+
+ /* When in aarch64 mode, and BTI is enabled, remember GP in the TLB. */
+ if (aarch64 && cpu_isar_feature(aa64_bti, cpu)) {
+ result->f.extra.arm.guarded = extract64(attrs, 50, 1); /* GP */
+ }
+ device = S1_attrs_are_device(result->cacheattrs.attrs);
+ }
+
+ /*
+ * Enable alignment checks on Device memory.
+ *
+ * Per R_XCHFJ, the correct ordering for alignment, permission,
+ * and stage 2 faults is:
+ * - Alignment fault caused by the memory type
+ * - Permission fault
+ * - A stage 2 fault on the memory access
+ * Perform the alignment check now, so that we recognize it in
+ * the correct order. Set TLB_CHECK_ALIGNED so that any subsequent
+ * softmmu tlb hit will also check the alignment; clear along the
+ * non-device path so that tlb_fill_flags is consistent in the
+ * event of restart_atomic_update.
+ *
+ * In v7, for a CPU without the Virtualization Extensions this
+ * access is UNPREDICTABLE; we choose to make it take the alignment
+ * fault as is required for a v7VE CPU. (QEMU doesn't emulate any
+ * CPUs with ARM_FEATURE_LPAE but not ARM_FEATURE_V7VE anyway.)
+ */
+ if (device) {
+ unsigned a_bits = memop_atomicity_bits(memop);
+ if (address & ((1 << a_bits) - 1)) {
+ fi->type = ARMFault_Alignment;
+ goto do_fault;
+ }
+ result->f.tlb_fill_flags = TLB_CHECK_ALIGNED;
+ } else {
+ result->f.tlb_fill_flags = 0;
}
if (!(result->f.prot & (1 << access_type))) {
@@ -2115,51 +2186,6 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw,
result->f.attrs.space = out_space;
result->f.attrs.secure = arm_space_is_secure(out_space);
- if (regime_is_stage2(mmu_idx)) {
- result->cacheattrs.is_s2_format = true;
- result->cacheattrs.attrs = extract32(attrs, 2, 4);
- /*
- * Security state does not really affect HCR_EL2.FWB;
- * we only need to filter FWB for aa32 or other FEAT.
- */
- device = S2_attrs_are_device(arm_hcr_el2_eff(env),
- result->cacheattrs.attrs);
- } else {
- /* Index into MAIR registers for cache attributes */
- uint8_t attrindx = extract32(attrs, 2, 3);
- uint64_t mair = env->cp15.mair_el[regime_el(env, mmu_idx)];
- assert(attrindx <= 7);
- result->cacheattrs.is_s2_format = false;
- result->cacheattrs.attrs = extract64(mair, attrindx * 8, 8);
-
- /* When in aarch64 mode, and BTI is enabled, remember GP in the TLB. */
- if (aarch64 && cpu_isar_feature(aa64_bti, cpu)) {
- result->f.extra.arm.guarded = extract64(attrs, 50, 1); /* GP */
- }
- device = S1_attrs_are_device(result->cacheattrs.attrs);
- }
-
- /*
- * Enable alignment checks on Device memory.
- *
- * Per R_XCHFJ, this check is mis-ordered. The correct ordering
- * for alignment, permission, and stage 2 faults should be:
- * - Alignment fault caused by the memory type
- * - Permission fault
- * - A stage 2 fault on the memory access
- * but due to the way the TCG softmmu TLB operates, we will have
- * implicitly done the permission check and the stage2 lookup in
- * finding the TLB entry, so the alignment check cannot be done sooner.
- *
- * In v7, for a CPU without the Virtualization Extensions this
- * access is UNPREDICTABLE; we choose to make it take the alignment
- * fault as is required for a v7VE CPU. (QEMU doesn't emulate any
- * CPUs with ARM_FEATURE_LPAE but not ARM_FEATURE_V7VE anyway.)
- */
- if (device) {
- result->f.tlb_fill_flags |= TLB_CHECK_ALIGNED;
- }
-
/*
* For FEAT_LPA2 and effective DS, the SH field in the attributes
* was re-purposed for output address bits. The SH attribute in
@@ -3202,7 +3228,7 @@ static ARMCacheAttrs combine_cacheattrs(uint64_t hcr,
*/
static bool get_phys_addr_disabled(CPUARMState *env,
S1Translate *ptw,
- target_ulong address,
+ vaddr address,
MMUAccessType access_type,
GetPhysAddrResult *result,
ARMMMUFaultInfo *fi)
@@ -3285,8 +3311,8 @@ static bool get_phys_addr_disabled(CPUARMState *env,
}
static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw,
- target_ulong address,
- MMUAccessType access_type,
+ vaddr address,
+ MMUAccessType access_type, MemOp memop,
GetPhysAddrResult *result,
ARMMMUFaultInfo *fi)
{
@@ -3298,7 +3324,8 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw,
ARMSecuritySpace ipa_space;
uint64_t hcr;
- ret = get_phys_addr_nogpc(env, ptw, address, access_type, result, fi);
+ ret = get_phys_addr_nogpc(env, ptw, address, access_type,
+ memop, result, fi);
/* If S1 fails, return early. */
if (ret) {
@@ -3324,7 +3351,8 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw,
cacheattrs1 = result->cacheattrs;
memset(result, 0, sizeof(*result));
- ret = get_phys_addr_nogpc(env, ptw, ipa, access_type, result, fi);
+ ret = get_phys_addr_nogpc(env, ptw, ipa, access_type,
+ memop, result, fi);
fi->s2addr = ipa;
/* Combine the S1 and S2 perms. */
@@ -3390,8 +3418,8 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw,
}
static bool get_phys_addr_nogpc(CPUARMState *env, S1Translate *ptw,
- target_ulong address,
- MMUAccessType access_type,
+ vaddr address,
+ MMUAccessType access_type, MemOp memop,
GetPhysAddrResult *result,
ARMMMUFaultInfo *fi)
{
@@ -3454,7 +3482,7 @@ static bool get_phys_addr_nogpc(CPUARMState *env, S1Translate *ptw,
if (arm_feature(env, ARM_FEATURE_EL2) &&
!regime_translation_disabled(env, ARMMMUIdx_Stage2, ptw->in_space)) {
return get_phys_addr_twostage(env, ptw, address, access_type,
- result, fi);
+ memop, result, fi);
}
/* fall through */
@@ -3517,7 +3545,8 @@ static bool get_phys_addr_nogpc(CPUARMState *env, S1Translate *ptw,
}
if (regime_using_lpae_format(env, mmu_idx)) {
- return get_phys_addr_lpae(env, ptw, address, access_type, result, fi);
+ return get_phys_addr_lpae(env, ptw, address, access_type,
+ memop, result, fi);
} else if (arm_feature(env, ARM_FEATURE_V7) ||
regime_sctlr(env, mmu_idx) & SCTLR_XP) {
return get_phys_addr_v6(env, ptw, address, access_type, result, fi);
@@ -3527,12 +3556,13 @@ static bool get_phys_addr_nogpc(CPUARMState *env, S1Translate *ptw,
}
static bool get_phys_addr_gpc(CPUARMState *env, S1Translate *ptw,
- target_ulong address,
- MMUAccessType access_type,
+ vaddr address,
+ MMUAccessType access_type, MemOp memop,
GetPhysAddrResult *result,
ARMMMUFaultInfo *fi)
{
- if (get_phys_addr_nogpc(env, ptw, address, access_type, result, fi)) {
+ if (get_phys_addr_nogpc(env, ptw, address, access_type,
+ memop, result, fi)) {
return true;
}
if (!granule_protection_check(env, result->f.phys_addr,
@@ -3543,8 +3573,8 @@ static bool get_phys_addr_gpc(CPUARMState *env, S1Translate *ptw,
return false;
}
-bool get_phys_addr_with_space_nogpc(CPUARMState *env, target_ulong address,
- MMUAccessType access_type,
+bool get_phys_addr_with_space_nogpc(CPUARMState *env, vaddr address,
+ MMUAccessType access_type, MemOp memop,
ARMMMUIdx mmu_idx, ARMSecuritySpace space,
GetPhysAddrResult *result,
ARMMMUFaultInfo *fi)
@@ -3553,11 +3583,12 @@ bool get_phys_addr_with_space_nogpc(CPUARMState *env, target_ulong address,
.in_mmu_idx = mmu_idx,
.in_space = space,
};
- return get_phys_addr_nogpc(env, &ptw, address, access_type, result, fi);
+ return get_phys_addr_nogpc(env, &ptw, address, access_type,
+ memop, result, fi);
}
-bool get_phys_addr(CPUARMState *env, target_ulong address,
- MMUAccessType access_type, ARMMMUIdx mmu_idx,
+bool get_phys_addr(CPUARMState *env, vaddr address,
+ MMUAccessType access_type, MemOp memop, ARMMMUIdx mmu_idx,
GetPhysAddrResult *result, ARMMMUFaultInfo *fi)
{
S1Translate ptw = {
@@ -3576,7 +3607,11 @@ bool get_phys_addr(CPUARMState *env, target_ulong address,
case ARMMMUIdx_Stage1_E1:
case ARMMMUIdx_Stage1_E1_PAN:
case ARMMMUIdx_E2:
- ss = arm_security_space_below_el3(env);
+ if (arm_aa32_secure_pl1_0(env)) {
+ ss = ARMSS_Secure;
+ } else {
+ ss = arm_security_space_below_el3(env);
+ }
break;
case ARMMMUIdx_Stage2:
/*
@@ -3622,7 +3657,8 @@ bool get_phys_addr(CPUARMState *env, target_ulong address,
}
ptw.in_space = ss;
- return get_phys_addr_gpc(env, &ptw, address, access_type, result, fi);
+ return get_phys_addr_gpc(env, &ptw, address, access_type,
+ memop, result, fi);
}
hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr,
@@ -3641,7 +3677,7 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr,
ARMMMUFaultInfo fi = {};
bool ret;
- ret = get_phys_addr_gpc(env, &ptw, addr, MMU_DATA_LOAD, &res, &fi);
+ ret = get_phys_addr_gpc(env, &ptw, addr, MMU_DATA_LOAD, 0, &res, &fi);
*attrs = res.f.attrs;
if (ret) {
diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode
index 62df4c4..331a8e1 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -30,10 +30,12 @@
&rri_sf rd rn imm sf
&i imm
&rr_e rd rn esz
+&rri_e rd rn imm esz
&rrr_e rd rn rm esz
&rrx_e rd rn rm idx esz
&rrrr_e rd rn rm ra esz
&qrr_e q rd rn esz
+&qrri_e q rd rn imm esz
&qrrr_e q rd rn rm esz
&qrrx_e q rd rn rm idx esz
&qrrrr_e q rd rn rm ra esz
@@ -54,11 +56,15 @@
@rrx_d ........ .. . rm:5 .... idx:1 . rn:5 rd:5 &rrx_e esz=3
@rr_q1e0 ........ ........ ...... rn:5 rd:5 &qrr_e q=1 esz=0
+@rr_q1e2 ........ ........ ...... rn:5 rd:5 &qrr_e q=1 esz=2
@r2r_q1e0 ........ ........ ...... rm:5 rd:5 &qrrr_e rn=%rd q=1 esz=0
@rrr_q1e0 ........ ... rm:5 ...... rn:5 rd:5 &qrrr_e q=1 esz=0
@rrr_q1e3 ........ ... rm:5 ...... rn:5 rd:5 &qrrr_e q=1 esz=3
@rrrr_q1e3 ........ ... rm:5 . ra:5 rn:5 rd:5 &qrrrr_e q=1 esz=3
+@qrr_h . q:1 ...... .. ...... ...... rn:5 rd:5 &qrr_e esz=1
+@qrr_e . q:1 ...... esz:2 ...... ...... rn:5 rd:5 &qrr_e
+
@qrrr_b . q:1 ...... ... rm:5 ...... rn:5 rd:5 &qrrr_e esz=0
@qrrr_h . q:1 ...... ... rm:5 ...... rn:5 rd:5 &qrrr_e esz=1
@qrrr_s . q:1 ...... ... rm:5 ...... rn:5 rd:5 &qrrr_e esz=2
@@ -1136,3 +1142,254 @@ FMADD 0001 1111 .. 0 ..... 0 ..... ..... ..... @rrrr_hsd
FMSUB 0001 1111 .. 0 ..... 1 ..... ..... ..... @rrrr_hsd
FNMADD 0001 1111 .. 1 ..... 0 ..... ..... ..... @rrrr_hsd
FNMSUB 0001 1111 .. 1 ..... 1 ..... ..... ..... @rrrr_hsd
+
+# Advanced SIMD Extract
+
+EXT_d 0010 1110 00 0 rm:5 00 imm:3 0 rn:5 rd:5
+EXT_q 0110 1110 00 0 rm:5 0 imm:4 0 rn:5 rd:5
+
+# Advanced SIMD Table Lookup
+
+TBL_TBX 0 q:1 00 1110 000 rm:5 0 len:2 tbx:1 00 rn:5 rd:5
+
+# Advanced SIMD Permute
+
+UZP1 0.00 1110 .. 0 ..... 0 001 10 ..... ..... @qrrr_e
+UZP2 0.00 1110 .. 0 ..... 0 101 10 ..... ..... @qrrr_e
+TRN1 0.00 1110 .. 0 ..... 0 010 10 ..... ..... @qrrr_e
+TRN2 0.00 1110 .. 0 ..... 0 110 10 ..... ..... @qrrr_e
+ZIP1 0.00 1110 .. 0 ..... 0 011 10 ..... ..... @qrrr_e
+ZIP2 0.00 1110 .. 0 ..... 0 111 10 ..... ..... @qrrr_e
+
+# Advanced SIMD Across Lanes
+
+ADDV 0.00 1110 .. 11000 11011 10 ..... ..... @qrr_e
+SADDLV 0.00 1110 .. 11000 00011 10 ..... ..... @qrr_e
+UADDLV 0.10 1110 .. 11000 00011 10 ..... ..... @qrr_e
+SMAXV 0.00 1110 .. 11000 01010 10 ..... ..... @qrr_e
+UMAXV 0.10 1110 .. 11000 01010 10 ..... ..... @qrr_e
+SMINV 0.00 1110 .. 11000 11010 10 ..... ..... @qrr_e
+UMINV 0.10 1110 .. 11000 11010 10 ..... ..... @qrr_e
+
+FMAXNMV_h 0.00 1110 00 11000 01100 10 ..... ..... @qrr_h
+FMAXNMV_s 0110 1110 00 11000 01100 10 ..... ..... @rr_q1e2
+
+FMINNMV_h 0.00 1110 10 11000 01100 10 ..... ..... @qrr_h
+FMINNMV_s 0110 1110 10 11000 01100 10 ..... ..... @rr_q1e2
+
+FMAXV_h 0.00 1110 00 11000 01111 10 ..... ..... @qrr_h
+FMAXV_s 0110 1110 00 11000 01111 10 ..... ..... @rr_q1e2
+
+FMINV_h 0.00 1110 10 11000 01111 10 ..... ..... @qrr_h
+FMINV_s 0110 1110 10 11000 01111 10 ..... ..... @rr_q1e2
+
+# Floating-point Immediate
+
+FMOVI_s 0001 1110 .. 1 imm:8 100 00000 rd:5 esz=%esz_hsd
+
+# Advanced SIMD Modified Immediate / Shift by Immediate
+
+%abcdefgh 16:3 5:5
+
+# Right shifts are encoded as N - shift, where N is the element size in bits.
+%neon_rshift_i6 16:6 !function=rsub_64
+%neon_rshift_i5 16:5 !function=rsub_32
+%neon_rshift_i4 16:4 !function=rsub_16
+%neon_rshift_i3 16:3 !function=rsub_8
+
+@q_shri_b . q:1 .. ..... 0001 ... ..... . rn:5 rd:5 \
+ &qrri_e esz=0 imm=%neon_rshift_i3
+@q_shri_h . q:1 .. ..... 001 .... ..... . rn:5 rd:5 \
+ &qrri_e esz=1 imm=%neon_rshift_i4
+@q_shri_s . q:1 .. ..... 01 ..... ..... . rn:5 rd:5 \
+ &qrri_e esz=2 imm=%neon_rshift_i5
+@q_shri_d . 1 .. ..... 1 ...... ..... . rn:5 rd:5 \
+ &qrri_e esz=3 imm=%neon_rshift_i6 q=1
+
+@q_shli_b . q:1 .. ..... 0001 imm:3 ..... . rn:5 rd:5 &qrri_e esz=0
+@q_shli_h . q:1 .. ..... 001 imm:4 ..... . rn:5 rd:5 &qrri_e esz=1
+@q_shli_s . q:1 .. ..... 01 imm:5 ..... . rn:5 rd:5 &qrri_e esz=2
+@q_shli_d . 1 .. ..... 1 imm:6 ..... . rn:5 rd:5 &qrri_e esz=3 q=1
+
+FMOVI_v_h 0 q:1 00 1111 00000 ... 1111 11 ..... rd:5 %abcdefgh
+
+# MOVI, MVNI, ORR, BIC, FMOV are all intermixed via cmode.
+Vimm 0 q:1 op:1 0 1111 00000 ... cmode:4 01 ..... rd:5 %abcdefgh
+
+SSHR_v 0.00 11110 .... ... 00000 1 ..... ..... @q_shri_b
+SSHR_v 0.00 11110 .... ... 00000 1 ..... ..... @q_shri_h
+SSHR_v 0.00 11110 .... ... 00000 1 ..... ..... @q_shri_s
+SSHR_v 0.00 11110 .... ... 00000 1 ..... ..... @q_shri_d
+
+USHR_v 0.10 11110 .... ... 00000 1 ..... ..... @q_shri_b
+USHR_v 0.10 11110 .... ... 00000 1 ..... ..... @q_shri_h
+USHR_v 0.10 11110 .... ... 00000 1 ..... ..... @q_shri_s
+USHR_v 0.10 11110 .... ... 00000 1 ..... ..... @q_shri_d
+
+SSRA_v 0.00 11110 .... ... 00010 1 ..... ..... @q_shri_b
+SSRA_v 0.00 11110 .... ... 00010 1 ..... ..... @q_shri_h
+SSRA_v 0.00 11110 .... ... 00010 1 ..... ..... @q_shri_s
+SSRA_v 0.00 11110 .... ... 00010 1 ..... ..... @q_shri_d
+
+USRA_v 0.10 11110 .... ... 00010 1 ..... ..... @q_shri_b
+USRA_v 0.10 11110 .... ... 00010 1 ..... ..... @q_shri_h
+USRA_v 0.10 11110 .... ... 00010 1 ..... ..... @q_shri_s
+USRA_v 0.10 11110 .... ... 00010 1 ..... ..... @q_shri_d
+
+SRSHR_v 0.00 11110 .... ... 00100 1 ..... ..... @q_shri_b
+SRSHR_v 0.00 11110 .... ... 00100 1 ..... ..... @q_shri_h
+SRSHR_v 0.00 11110 .... ... 00100 1 ..... ..... @q_shri_s
+SRSHR_v 0.00 11110 .... ... 00100 1 ..... ..... @q_shri_d
+
+URSHR_v 0.10 11110 .... ... 00100 1 ..... ..... @q_shri_b
+URSHR_v 0.10 11110 .... ... 00100 1 ..... ..... @q_shri_h
+URSHR_v 0.10 11110 .... ... 00100 1 ..... ..... @q_shri_s
+URSHR_v 0.10 11110 .... ... 00100 1 ..... ..... @q_shri_d
+
+SRSRA_v 0.00 11110 .... ... 00110 1 ..... ..... @q_shri_b
+SRSRA_v 0.00 11110 .... ... 00110 1 ..... ..... @q_shri_h
+SRSRA_v 0.00 11110 .... ... 00110 1 ..... ..... @q_shri_s
+SRSRA_v 0.00 11110 .... ... 00110 1 ..... ..... @q_shri_d
+
+URSRA_v 0.10 11110 .... ... 00110 1 ..... ..... @q_shri_b
+URSRA_v 0.10 11110 .... ... 00110 1 ..... ..... @q_shri_h
+URSRA_v 0.10 11110 .... ... 00110 1 ..... ..... @q_shri_s
+URSRA_v 0.10 11110 .... ... 00110 1 ..... ..... @q_shri_d
+
+SRI_v 0.10 11110 .... ... 01000 1 ..... ..... @q_shri_b
+SRI_v 0.10 11110 .... ... 01000 1 ..... ..... @q_shri_h
+SRI_v 0.10 11110 .... ... 01000 1 ..... ..... @q_shri_s
+SRI_v 0.10 11110 .... ... 01000 1 ..... ..... @q_shri_d
+
+SHL_v 0.00 11110 .... ... 01010 1 ..... ..... @q_shli_b
+SHL_v 0.00 11110 .... ... 01010 1 ..... ..... @q_shli_h
+SHL_v 0.00 11110 .... ... 01010 1 ..... ..... @q_shli_s
+SHL_v 0.00 11110 .... ... 01010 1 ..... ..... @q_shli_d
+
+SLI_v 0.10 11110 .... ... 01010 1 ..... ..... @q_shli_b
+SLI_v 0.10 11110 .... ... 01010 1 ..... ..... @q_shli_h
+SLI_v 0.10 11110 .... ... 01010 1 ..... ..... @q_shli_s
+SLI_v 0.10 11110 .... ... 01010 1 ..... ..... @q_shli_d
+
+SSHLL_v 0.00 11110 .... ... 10100 1 ..... ..... @q_shli_b
+SSHLL_v 0.00 11110 .... ... 10100 1 ..... ..... @q_shli_h
+SSHLL_v 0.00 11110 .... ... 10100 1 ..... ..... @q_shli_s
+
+USHLL_v 0.10 11110 .... ... 10100 1 ..... ..... @q_shli_b
+USHLL_v 0.10 11110 .... ... 10100 1 ..... ..... @q_shli_h
+USHLL_v 0.10 11110 .... ... 10100 1 ..... ..... @q_shli_s
+
+SHRN_v 0.00 11110 .... ... 10000 1 ..... ..... @q_shri_b
+SHRN_v 0.00 11110 .... ... 10000 1 ..... ..... @q_shri_h
+SHRN_v 0.00 11110 .... ... 10000 1 ..... ..... @q_shri_s
+
+RSHRN_v 0.00 11110 .... ... 10001 1 ..... ..... @q_shri_b
+RSHRN_v 0.00 11110 .... ... 10001 1 ..... ..... @q_shri_h
+RSHRN_v 0.00 11110 .... ... 10001 1 ..... ..... @q_shri_s
+
+SQSHL_vi 0.00 11110 .... ... 01110 1 ..... ..... @q_shli_b
+SQSHL_vi 0.00 11110 .... ... 01110 1 ..... ..... @q_shli_h
+SQSHL_vi 0.00 11110 .... ... 01110 1 ..... ..... @q_shli_s
+SQSHL_vi 0.00 11110 .... ... 01110 1 ..... ..... @q_shli_d
+
+UQSHL_vi 0.10 11110 .... ... 01110 1 ..... ..... @q_shli_b
+UQSHL_vi 0.10 11110 .... ... 01110 1 ..... ..... @q_shli_h
+UQSHL_vi 0.10 11110 .... ... 01110 1 ..... ..... @q_shli_s
+UQSHL_vi 0.10 11110 .... ... 01110 1 ..... ..... @q_shli_d
+
+SQSHLU_vi 0.10 11110 .... ... 01100 1 ..... ..... @q_shli_b
+SQSHLU_vi 0.10 11110 .... ... 01100 1 ..... ..... @q_shli_h
+SQSHLU_vi 0.10 11110 .... ... 01100 1 ..... ..... @q_shli_s
+SQSHLU_vi 0.10 11110 .... ... 01100 1 ..... ..... @q_shli_d
+
+SQSHRN_v 0.00 11110 .... ... 10010 1 ..... ..... @q_shri_b
+SQSHRN_v 0.00 11110 .... ... 10010 1 ..... ..... @q_shri_h
+SQSHRN_v 0.00 11110 .... ... 10010 1 ..... ..... @q_shri_s
+
+UQSHRN_v 0.10 11110 .... ... 10010 1 ..... ..... @q_shri_b
+UQSHRN_v 0.10 11110 .... ... 10010 1 ..... ..... @q_shri_h
+UQSHRN_v 0.10 11110 .... ... 10010 1 ..... ..... @q_shri_s
+
+SQSHRUN_v 0.10 11110 .... ... 10000 1 ..... ..... @q_shri_b
+SQSHRUN_v 0.10 11110 .... ... 10000 1 ..... ..... @q_shri_h
+SQSHRUN_v 0.10 11110 .... ... 10000 1 ..... ..... @q_shri_s
+
+SQRSHRN_v 0.00 11110 .... ... 10011 1 ..... ..... @q_shri_b
+SQRSHRN_v 0.00 11110 .... ... 10011 1 ..... ..... @q_shri_h
+SQRSHRN_v 0.00 11110 .... ... 10011 1 ..... ..... @q_shri_s
+
+UQRSHRN_v 0.10 11110 .... ... 10011 1 ..... ..... @q_shri_b
+UQRSHRN_v 0.10 11110 .... ... 10011 1 ..... ..... @q_shri_h
+UQRSHRN_v 0.10 11110 .... ... 10011 1 ..... ..... @q_shri_s
+
+SQRSHRUN_v 0.10 11110 .... ... 10001 1 ..... ..... @q_shri_b
+SQRSHRUN_v 0.10 11110 .... ... 10001 1 ..... ..... @q_shri_h
+SQRSHRUN_v 0.10 11110 .... ... 10001 1 ..... ..... @q_shri_s
+
+# Advanced SIMD scalar shift by immediate
+
+@shri_b .... ..... 0001 ... ..... . rn:5 rd:5 \
+ &rri_e esz=0 imm=%neon_rshift_i3
+@shri_h .... ..... 001 .... ..... . rn:5 rd:5 \
+ &rri_e esz=1 imm=%neon_rshift_i4
+@shri_s .... ..... 01 ..... ..... . rn:5 rd:5 \
+ &rri_e esz=2 imm=%neon_rshift_i5
+@shri_d .... ..... 1 ...... ..... . rn:5 rd:5 \
+ &rri_e esz=3 imm=%neon_rshift_i6
+
+@shli_b .... ..... 0001 imm:3 ..... . rn:5 rd:5 &rri_e esz=0
+@shli_h .... ..... 001 imm:4 ..... . rn:5 rd:5 &rri_e esz=1
+@shli_s .... ..... 01 imm:5 ..... . rn:5 rd:5 &rri_e esz=2
+@shli_d .... ..... 1 imm:6 ..... . rn:5 rd:5 &rri_e esz=3
+
+SSHR_s 0101 11110 .... ... 00000 1 ..... ..... @shri_d
+USHR_s 0111 11110 .... ... 00000 1 ..... ..... @shri_d
+SSRA_s 0101 11110 .... ... 00010 1 ..... ..... @shri_d
+USRA_s 0111 11110 .... ... 00010 1 ..... ..... @shri_d
+SRSHR_s 0101 11110 .... ... 00100 1 ..... ..... @shri_d
+URSHR_s 0111 11110 .... ... 00100 1 ..... ..... @shri_d
+SRSRA_s 0101 11110 .... ... 00110 1 ..... ..... @shri_d
+URSRA_s 0111 11110 .... ... 00110 1 ..... ..... @shri_d
+SRI_s 0111 11110 .... ... 01000 1 ..... ..... @shri_d
+
+SHL_s 0101 11110 .... ... 01010 1 ..... ..... @shli_d
+SLI_s 0111 11110 .... ... 01010 1 ..... ..... @shli_d
+
+SQSHL_si 0101 11110 .... ... 01110 1 ..... ..... @shli_b
+SQSHL_si 0101 11110 .... ... 01110 1 ..... ..... @shli_h
+SQSHL_si 0101 11110 .... ... 01110 1 ..... ..... @shli_s
+SQSHL_si 0101 11110 .... ... 01110 1 ..... ..... @shli_d
+
+UQSHL_si 0111 11110 .... ... 01110 1 ..... ..... @shli_b
+UQSHL_si 0111 11110 .... ... 01110 1 ..... ..... @shli_h
+UQSHL_si 0111 11110 .... ... 01110 1 ..... ..... @shli_s
+UQSHL_si 0111 11110 .... ... 01110 1 ..... ..... @shli_d
+
+SQSHLU_si 0111 11110 .... ... 01100 1 ..... ..... @shli_b
+SQSHLU_si 0111 11110 .... ... 01100 1 ..... ..... @shli_h
+SQSHLU_si 0111 11110 .... ... 01100 1 ..... ..... @shli_s
+SQSHLU_si 0111 11110 .... ... 01100 1 ..... ..... @shli_d
+
+SQSHRN_si 0101 11110 .... ... 10010 1 ..... ..... @shri_b
+SQSHRN_si 0101 11110 .... ... 10010 1 ..... ..... @shri_h
+SQSHRN_si 0101 11110 .... ... 10010 1 ..... ..... @shri_s
+
+UQSHRN_si 0111 11110 .... ... 10010 1 ..... ..... @shri_b
+UQSHRN_si 0111 11110 .... ... 10010 1 ..... ..... @shri_h
+UQSHRN_si 0111 11110 .... ... 10010 1 ..... ..... @shri_s
+
+SQSHRUN_si 0111 11110 .... ... 10000 1 ..... ..... @shri_b
+SQSHRUN_si 0111 11110 .... ... 10000 1 ..... ..... @shri_h
+SQSHRUN_si 0111 11110 .... ... 10000 1 ..... ..... @shri_s
+
+SQRSHRN_si 0101 11110 .... ... 10011 1 ..... ..... @shri_b
+SQRSHRN_si 0101 11110 .... ... 10011 1 ..... ..... @shri_h
+SQRSHRN_si 0101 11110 .... ... 10011 1 ..... ..... @shri_s
+
+UQRSHRN_si 0111 11110 .... ... 10011 1 ..... ..... @shri_b
+UQRSHRN_si 0111 11110 .... ... 10011 1 ..... ..... @shri_h
+UQRSHRN_si 0111 11110 .... ... 10011 1 ..... ..... @shri_s
+
+SQRSHRUN_si 0111 11110 .... ... 10001 1 ..... ..... @shri_b
+SQRSHRUN_si 0111 11110 .... ... 10001 1 ..... ..... @shri_h
+SQRSHRUN_si 0111 11110 .... ... 10001 1 ..... ..... @shri_s
diff --git a/target/arm/tcg/cpu-v7m.c b/target/arm/tcg/cpu-v7m.c
index 5496f14..58e5457 100644
--- a/target/arm/tcg/cpu-v7m.c
+++ b/target/arm/tcg/cpu-v7m.c
@@ -242,7 +242,7 @@ static const TCGCPUOps arm_v7m_tcg_ops = {
.record_sigsegv = arm_cpu_record_sigsegv,
.record_sigbus = arm_cpu_record_sigbus,
#else
- .tlb_fill = arm_cpu_tlb_fill,
+ .tlb_fill_align = arm_cpu_tlb_fill_align,
.cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt,
.cpu_exec_halt = arm_cpu_exec_halt,
.do_interrupt = arm_v7m_cpu_do_interrupt,
diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
index fe232eb..0168920 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -29,32 +29,6 @@
#include "cpu-features.h"
#include "cpregs.h"
-static uint64_t make_ccsidr64(unsigned assoc, unsigned linesize,
- unsigned cachesize)
-{
- unsigned lg_linesize = ctz32(linesize);
- unsigned sets;
-
- /*
- * The 64-bit CCSIDR_EL1 format is:
- * [55:32] number of sets - 1
- * [23:3] associativity - 1
- * [2:0] log2(linesize) - 4
- * so 0 == 16 bytes, 1 == 32 bytes, 2 == 64 bytes, etc
- */
- assert(assoc != 0);
- assert(is_power_of_2(linesize));
- assert(lg_linesize >= 4 && lg_linesize <= 7 + 4);
-
- /* sets * associativity * linesize == cachesize. */
- sets = cachesize / (assoc * linesize);
- assert(cachesize % (assoc * linesize) == 0);
-
- return ((uint64_t)(sets - 1) << 32)
- | ((assoc - 1) << 3)
- | (lg_linesize - 4);
-}
-
static void aarch64_a35_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
@@ -106,9 +80,12 @@ static void aarch64_a35_initfn(Object *obj)
cpu->isar.reset_pmcr_el0 = 0x410a3000;
/* From B2.29 Cache ID registers */
- cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */
- cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */
- cpu->ccsidr[2] = 0x703fe03a; /* 512KB L2 cache */
+ /* 32KB L1 dcache */
+ cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 32 * KiB, 7);
+ /* 32KB L1 icache */
+ cpu->ccsidr[1] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 32 * KiB, 2);
+ /* 512KB L2 cache */
+ cpu->ccsidr[2] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 16, 64, 512 * KiB, 7);
/* From B3.5 VGIC Type register */
cpu->gic_num_lrs = 4;
@@ -272,9 +249,12 @@ static void aarch64_a55_initfn(Object *obj)
cpu->revidr = 0;
/* From B2.23 CCSIDR_EL1 */
- cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */
- cpu->ccsidr[1] = 0x200fe01a; /* 32KB L1 icache */
- cpu->ccsidr[2] = 0x703fe07a; /* 512KB L2 cache */
+ /* 32KB L1 dcache */
+ cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 32 * KiB, 7);
+ /* 32KB L1 icache */
+ cpu->ccsidr[1] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 32 * KiB, 2);
+ /* 512KB L2 cache */
+ cpu->ccsidr[2] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 16, 64, 512 * KiB, 7);
/* From B2.96 SCTLR_EL3 */
cpu->reset_sctlr = 0x30c50838;
@@ -338,9 +318,12 @@ static void aarch64_a72_initfn(Object *obj)
cpu->isar.dbgdevid1 = 0x2;
cpu->isar.reset_pmcr_el0 = 0x41023000;
cpu->clidr = 0x0a200023;
- cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */
- cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */
- cpu->ccsidr[2] = 0x707fe07a; /* 1MB L2 cache */
+ /* 32KB L1 dcache */
+ cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 32 * KiB, 7);
+ /* 48KB L1 dcache */
+ cpu->ccsidr[1] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 3, 64, 48 * KiB, 2);
+ /* 1MB L2 cache */
+ cpu->ccsidr[2] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 16, 64, 1 * MiB, 7);
cpu->dcz_blocksize = 4; /* 64 bytes */
cpu->gic_num_lrs = 4;
cpu->gic_vpribits = 5;
@@ -397,9 +380,12 @@ static void aarch64_a76_initfn(Object *obj)
cpu->revidr = 0;
/* From B2.18 CCSIDR_EL1 */
- cpu->ccsidr[0] = 0x701fe01a; /* 64KB L1 dcache */
- cpu->ccsidr[1] = 0x201fe01a; /* 64KB L1 icache */
- cpu->ccsidr[2] = 0x707fe03a; /* 512KB L2 cache */
+ /* 64KB L1 dcache */
+ cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 64 * KiB, 7);
+ /* 64KB L1 icache */
+ cpu->ccsidr[1] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 64 * KiB, 2);
+ /* 512KB L2 cache */
+ cpu->ccsidr[2] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 8, 64, 512 * KiB, 7);
/* From B2.93 SCTLR_EL3 */
cpu->reset_sctlr = 0x30c50838;
@@ -449,9 +435,12 @@ static void aarch64_a64fx_initfn(Object *obj)
cpu->isar.id_aa64isar1 = 0x0000000000010001;
cpu->isar.id_aa64zfr0 = 0x0000000000000000;
cpu->clidr = 0x0000000080000023;
- cpu->ccsidr[0] = 0x7007e01c; /* 64KB L1 dcache */
- cpu->ccsidr[1] = 0x2007e01c; /* 64KB L1 icache */
- cpu->ccsidr[2] = 0x70ffe07c; /* 8MB L2 cache */
+ /* 64KB L1 dcache */
+ cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 256, 64 * KiB, 7);
+ /* 64KB L1 icache */
+ cpu->ccsidr[1] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 256, 64 * KiB, 2);
+ /* 8MB L2 cache */
+ cpu->ccsidr[2] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 16, 256, 8 * MiB, 7);
cpu->dcz_blocksize = 6; /* 256 bytes */
cpu->gic_num_lrs = 4;
cpu->gic_vpribits = 5;
@@ -637,9 +626,12 @@ static void aarch64_neoverse_n1_initfn(Object *obj)
cpu->revidr = 0;
/* From B2.23 CCSIDR_EL1 */
- cpu->ccsidr[0] = 0x701fe01a; /* 64KB L1 dcache */
- cpu->ccsidr[1] = 0x201fe01a; /* 64KB L1 icache */
- cpu->ccsidr[2] = 0x70ffe03a; /* 1MB L2 cache */
+ /* 64KB L1 dcache */
+ cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 64 * KiB, 7);
+ /* 64KB L1 icache */
+ cpu->ccsidr[1] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 64 * KiB, 2);
+ /* 1MB L2 dcache */
+ cpu->ccsidr[2] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 8, 64, 1 * MiB, 7);
/* From B2.98 SCTLR_EL3 */
cpu->reset_sctlr = 0x30c50838;
@@ -685,7 +677,7 @@ static void aarch64_neoverse_v1_initfn(Object *obj)
cpu->isar.id_aa64dfr0 = 0x000001f210305519ull;
cpu->isar.id_aa64dfr1 = 0x00000000;
cpu->isar.id_aa64isar0 = 0x1011111110212120ull; /* with FEAT_RNG */
- cpu->isar.id_aa64isar1 = 0x0111000001211032ull;
+ cpu->isar.id_aa64isar1 = 0x0011100001211032ull;
cpu->isar.id_aa64mmfr0 = 0x0000000000101125ull;
cpu->isar.id_aa64mmfr1 = 0x0000000010212122ull;
cpu->isar.id_aa64mmfr2 = 0x0220011102101011ull;
@@ -721,9 +713,12 @@ static void aarch64_neoverse_v1_initfn(Object *obj)
* L2: 8-way set associative, 64 byte line size, either 512K or 1MB.
* L3: No L3 (this matches the CLIDR_EL1 value).
*/
- cpu->ccsidr[0] = make_ccsidr64(4, 64, 64 * KiB); /* L1 dcache */
- cpu->ccsidr[1] = cpu->ccsidr[0]; /* L1 icache */
- cpu->ccsidr[2] = make_ccsidr64(8, 64, 1 * MiB); /* L2 cache */
+ /* 64KB L1 dcache */
+ cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_CCIDX, 4, 64, 64 * KiB, 0);
+ /* 64KB L1 icache */
+ cpu->ccsidr[1] = cpu->ccsidr[0];
+ /* 1MB L2 cache */
+ cpu->ccsidr[2] = make_ccsidr(CCSIDR_FORMAT_CCIDX, 8, 64, 1 * MiB, 0);
/* From 3.2.115 SCTLR_EL3 */
cpu->reset_sctlr = 0x30c50838;
@@ -959,9 +954,12 @@ static void aarch64_a710_initfn(Object *obj)
* L1: 4-way set associative 64-byte line size, total either 32K or 64K.
* L2: 8-way set associative 64 byte line size, total either 256K or 512K.
*/
- cpu->ccsidr[0] = make_ccsidr64(4, 64, 64 * KiB); /* L1 dcache */
- cpu->ccsidr[1] = cpu->ccsidr[0]; /* L1 icache */
- cpu->ccsidr[2] = make_ccsidr64(8, 64, 512 * KiB); /* L2 cache */
+ /* L1 dcache */
+ cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_CCIDX, 4, 64, 64 * KiB, 0);
+ /* L1 icache */
+ cpu->ccsidr[1] = cpu->ccsidr[0];
+ /* L2 cache */
+ cpu->ccsidr[2] = make_ccsidr(CCSIDR_FORMAT_CCIDX, 8, 64, 512 * KiB, 0);
/* FIXME: Not documented -- copied from neoverse-v1 */
cpu->reset_sctlr = 0x30c50838;
@@ -1057,10 +1055,12 @@ static void aarch64_neoverse_n2_initfn(Object *obj)
* L1: 4-way set associative 64-byte line size, total 64K.
* L2: 8-way set associative 64 byte line size, total either 512K or 1024K.
*/
- cpu->ccsidr[0] = make_ccsidr64(4, 64, 64 * KiB); /* L1 dcache */
- cpu->ccsidr[1] = cpu->ccsidr[0]; /* L1 icache */
- cpu->ccsidr[2] = make_ccsidr64(8, 64, 512 * KiB); /* L2 cache */
-
+ /* L1 dcache */
+ cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_CCIDX, 4, 64, 64 * KiB, 0);
+ /* L1 icache */
+ cpu->ccsidr[1] = cpu->ccsidr[0];
+ /* L2 cache */
+ cpu->ccsidr[2] = make_ccsidr(CCSIDR_FORMAT_CCIDX, 8, 64, 512 * KiB, 0);
/* FIXME: Not documented -- copied from neoverse-v1 */
cpu->reset_sctlr = 0x30c50838;
@@ -1160,7 +1160,7 @@ void aarch64_max_tcg_initfn(Object *obj)
t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1); /* FEAT_FRINTTS */
t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1); /* FEAT_SB */
t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1); /* FEAT_SPECRES */
- t = FIELD_DP64(t, ID_AA64ISAR1, BF16, 1); /* FEAT_BF16 */
+ t = FIELD_DP64(t, ID_AA64ISAR1, BF16, 2); /* FEAT_BF16, FEAT_EBF16 */
t = FIELD_DP64(t, ID_AA64ISAR1, DGH, 1); /* FEAT_DGH */
t = FIELD_DP64(t, ID_AA64ISAR1, I8MM, 1); /* FEAT_I8MM */
cpu->isar.id_aa64isar1 = t;
@@ -1244,7 +1244,7 @@ void aarch64_max_tcg_initfn(Object *obj)
t = FIELD_DP64(t, ID_AA64ZFR0, SVEVER, 1);
t = FIELD_DP64(t, ID_AA64ZFR0, AES, 2); /* FEAT_SVE_PMULL128 */
t = FIELD_DP64(t, ID_AA64ZFR0, BITPERM, 1); /* FEAT_SVE_BitPerm */
- t = FIELD_DP64(t, ID_AA64ZFR0, BFLOAT16, 1); /* FEAT_BF16 */
+ t = FIELD_DP64(t, ID_AA64ZFR0, BFLOAT16, 2); /* FEAT_BF16, FEAT_EBF16 */
t = FIELD_DP64(t, ID_AA64ZFR0, SHA3, 1); /* FEAT_SVE_SHA3 */
t = FIELD_DP64(t, ID_AA64ZFR0, SM4, 1); /* FEAT_SVE_SM4 */
t = FIELD_DP64(t, ID_AA64ZFR0, I8MM, 1); /* FEAT_I8MM */
diff --git a/target/arm/tcg/gengvec.c b/target/arm/tcg/gengvec.c
index 56a1dc1..f652520 100644
--- a/target/arm/tcg/gengvec.c
+++ b/target/arm/tcg/gengvec.c
@@ -88,6 +88,25 @@ GEN_CMP0(gen_gvec_cgt0, TCG_COND_GT)
#undef GEN_CMP0
+void gen_gvec_sshr(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
+ int64_t shift, uint32_t opr_sz, uint32_t max_sz)
+{
+ /* Signed shift out of range results in all-sign-bits */
+ shift = MIN(shift, (8 << vece) - 1);
+ tcg_gen_gvec_sari(vece, rd_ofs, rm_ofs, shift, opr_sz, max_sz);
+}
+
+void gen_gvec_ushr(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
+ int64_t shift, uint32_t opr_sz, uint32_t max_sz)
+{
+ /* Unsigned shift out of range results in all-zero-bits */
+ if (shift >= (8 << vece)) {
+ tcg_gen_gvec_dup_imm(vece, rd_ofs, opr_sz, max_sz, 0);
+ } else {
+ tcg_gen_gvec_shri(vece, rd_ofs, rm_ofs, shift, opr_sz, max_sz);
+ }
+}
+
static void gen_ssra8_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift)
{
tcg_gen_vec_sar8i_i64(a, a, shift);
@@ -285,7 +304,7 @@ void gen_srshr32_i32(TCGv_i32 d, TCGv_i32 a, int32_t sh)
tcg_gen_add_i32(d, d, t);
}
- void gen_srshr64_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh)
+void gen_srshr64_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh)
{
TCGv_i64 t = tcg_temp_new_i64();
@@ -297,10 +316,9 @@ void gen_srshr32_i32(TCGv_i32 d, TCGv_i32 a, int32_t sh)
static void gen_srshr_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t sh)
{
TCGv_vec t = tcg_temp_new_vec_matching(d);
- TCGv_vec ones = tcg_temp_new_vec_matching(d);
+ TCGv_vec ones = tcg_constant_vec_matching(d, vece, 1);
tcg_gen_shri_vec(vece, t, a, sh - 1);
- tcg_gen_dupi_vec(vece, ones, 1);
tcg_gen_and_vec(vece, t, t, ones);
tcg_gen_sari_vec(vece, d, a, sh);
tcg_gen_add_vec(vece, d, d, t);
@@ -492,10 +510,9 @@ void gen_urshr64_i64(TCGv_i64 d, TCGv_i64 a, int64_t sh)
static void gen_urshr_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t shift)
{
TCGv_vec t = tcg_temp_new_vec_matching(d);
- TCGv_vec ones = tcg_temp_new_vec_matching(d);
+ TCGv_vec ones = tcg_constant_vec_matching(d, vece, 1);
tcg_gen_shri_vec(vece, t, a, shift - 1);
- tcg_gen_dupi_vec(vece, ones, 1);
tcg_gen_and_vec(vece, t, t, ones);
tcg_gen_shri_vec(vece, d, a, shift);
tcg_gen_add_vec(vece, d, d, t);
@@ -685,9 +702,9 @@ static void gen_shr64_ins_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift)
static void gen_shr_ins_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t sh)
{
TCGv_vec t = tcg_temp_new_vec_matching(d);
- TCGv_vec m = tcg_temp_new_vec_matching(d);
+ int64_t mi = MAKE_64BIT_MASK((8 << vece) - sh, sh);
+ TCGv_vec m = tcg_constant_vec_matching(d, vece, mi);
- tcg_gen_dupi_vec(vece, m, MAKE_64BIT_MASK((8 << vece) - sh, sh));
tcg_gen_shri_vec(vece, t, a, sh);
tcg_gen_and_vec(vece, d, d, m);
tcg_gen_or_vec(vece, d, d, t);
@@ -773,10 +790,9 @@ static void gen_shl64_ins_i64(TCGv_i64 d, TCGv_i64 a, int64_t shift)
static void gen_shl_ins_vec(unsigned vece, TCGv_vec d, TCGv_vec a, int64_t sh)
{
TCGv_vec t = tcg_temp_new_vec_matching(d);
- TCGv_vec m = tcg_temp_new_vec_matching(d);
+ TCGv_vec m = tcg_constant_vec_matching(d, vece, MAKE_64BIT_MASK(0, sh));
tcg_gen_shli_vec(vece, t, a, sh);
- tcg_gen_dupi_vec(vece, m, MAKE_64BIT_MASK(0, sh));
tcg_gen_and_vec(vece, d, d, m);
tcg_gen_or_vec(vece, d, d, t);
}
@@ -1044,14 +1060,13 @@ static void gen_ushl_vec(unsigned vece, TCGv_vec dst,
TCGv_vec rval = tcg_temp_new_vec_matching(dst);
TCGv_vec lsh = tcg_temp_new_vec_matching(dst);
TCGv_vec rsh = tcg_temp_new_vec_matching(dst);
- TCGv_vec msk, max;
+ TCGv_vec max, zero;
tcg_gen_neg_vec(vece, rsh, shift);
if (vece == MO_8) {
tcg_gen_mov_vec(lsh, shift);
} else {
- msk = tcg_temp_new_vec_matching(dst);
- tcg_gen_dupi_vec(vece, msk, 0xff);
+ TCGv_vec msk = tcg_constant_vec_matching(dst, vece, 0xff);
tcg_gen_and_vec(vece, lsh, shift, msk);
tcg_gen_and_vec(vece, rsh, rsh, msk);
}
@@ -1064,26 +1079,21 @@ static void gen_ushl_vec(unsigned vece, TCGv_vec dst,
tcg_gen_shlv_vec(vece, lval, src, lsh);
tcg_gen_shrv_vec(vece, rval, src, rsh);
- max = tcg_temp_new_vec_matching(dst);
- tcg_gen_dupi_vec(vece, max, 8 << vece);
-
/*
- * The choice of LT (signed) and GEU (unsigned) are biased toward
+ * The choice of GE (signed) and GEU (unsigned) are biased toward
* the instructions of the x86_64 host. For MO_8, the whole byte
* is significant so we must use an unsigned compare; otherwise we
* have already masked to a byte and so a signed compare works.
* Other tcg hosts have a full set of comparisons and do not care.
*/
+ zero = tcg_constant_vec_matching(dst, vece, 0);
+ max = tcg_constant_vec_matching(dst, vece, 8 << vece);
if (vece == MO_8) {
- tcg_gen_cmp_vec(TCG_COND_GEU, vece, lsh, lsh, max);
- tcg_gen_cmp_vec(TCG_COND_GEU, vece, rsh, rsh, max);
- tcg_gen_andc_vec(vece, lval, lval, lsh);
- tcg_gen_andc_vec(vece, rval, rval, rsh);
+ tcg_gen_cmpsel_vec(TCG_COND_GEU, vece, lval, lsh, max, zero, lval);
+ tcg_gen_cmpsel_vec(TCG_COND_GEU, vece, rval, rsh, max, zero, rval);
} else {
- tcg_gen_cmp_vec(TCG_COND_LT, vece, lsh, lsh, max);
- tcg_gen_cmp_vec(TCG_COND_LT, vece, rsh, rsh, max);
- tcg_gen_and_vec(vece, lval, lval, lsh);
- tcg_gen_and_vec(vece, rval, rval, rsh);
+ tcg_gen_cmpsel_vec(TCG_COND_GE, vece, lval, lsh, max, zero, lval);
+ tcg_gen_cmpsel_vec(TCG_COND_GE, vece, rval, rsh, max, zero, rval);
}
tcg_gen_or_vec(vece, dst, lval, rval);
}
@@ -1093,7 +1103,7 @@ void gen_gvec_ushl(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
{
static const TCGOpcode vecop_list[] = {
INDEX_op_neg_vec, INDEX_op_shlv_vec,
- INDEX_op_shrv_vec, INDEX_op_cmp_vec, 0
+ INDEX_op_shrv_vec, INDEX_op_cmpsel_vec, 0
};
static const GVecGen3 ops[4] = {
{ .fniv = gen_ushl_vec,
@@ -1169,7 +1179,7 @@ static void gen_sshl_vec(unsigned vece, TCGv_vec dst,
TCGv_vec rval = tcg_temp_new_vec_matching(dst);
TCGv_vec lsh = tcg_temp_new_vec_matching(dst);
TCGv_vec rsh = tcg_temp_new_vec_matching(dst);
- TCGv_vec tmp = tcg_temp_new_vec_matching(dst);
+ TCGv_vec max, zero;
/*
* Rely on the TCG guarantee that out of range shifts produce
@@ -1180,29 +1190,28 @@ static void gen_sshl_vec(unsigned vece, TCGv_vec dst,
if (vece == MO_8) {
tcg_gen_mov_vec(lsh, shift);
} else {
- tcg_gen_dupi_vec(vece, tmp, 0xff);
- tcg_gen_and_vec(vece, lsh, shift, tmp);
- tcg_gen_and_vec(vece, rsh, rsh, tmp);
+ TCGv_vec msk = tcg_constant_vec_matching(dst, vece, 0xff);
+ tcg_gen_and_vec(vece, lsh, shift, msk);
+ tcg_gen_and_vec(vece, rsh, rsh, msk);
}
/* Bound rsh so out of bound right shift gets -1. */
- tcg_gen_dupi_vec(vece, tmp, (8 << vece) - 1);
- tcg_gen_umin_vec(vece, rsh, rsh, tmp);
- tcg_gen_cmp_vec(TCG_COND_GT, vece, tmp, lsh, tmp);
+ max = tcg_constant_vec_matching(dst, vece, (8 << vece) - 1);
+ tcg_gen_umin_vec(vece, rsh, rsh, max);
tcg_gen_shlv_vec(vece, lval, src, lsh);
tcg_gen_sarv_vec(vece, rval, src, rsh);
/* Select in-bound left shift. */
- tcg_gen_andc_vec(vece, lval, lval, tmp);
+ zero = tcg_constant_vec_matching(dst, vece, 0);
+ tcg_gen_cmpsel_vec(TCG_COND_GT, vece, lval, lsh, max, zero, lval);
/* Select between left and right shift. */
if (vece == MO_8) {
- tcg_gen_dupi_vec(vece, tmp, 0);
- tcg_gen_cmpsel_vec(TCG_COND_LT, vece, dst, lsh, tmp, rval, lval);
+ tcg_gen_cmpsel_vec(TCG_COND_LT, vece, dst, lsh, zero, rval, lval);
} else {
- tcg_gen_dupi_vec(vece, tmp, 0x80);
- tcg_gen_cmpsel_vec(TCG_COND_LT, vece, dst, lsh, tmp, lval, rval);
+ TCGv_vec sgn = tcg_constant_vec_matching(dst, vece, 0x80);
+ tcg_gen_cmpsel_vec(TCG_COND_LT, vece, dst, lsh, sgn, lval, rval);
}
}
@@ -1211,7 +1220,7 @@ void gen_gvec_sshl(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
{
static const TCGOpcode vecop_list[] = {
INDEX_op_neg_vec, INDEX_op_umin_vec, INDEX_op_shlv_vec,
- INDEX_op_sarv_vec, INDEX_op_cmp_vec, INDEX_op_cmpsel_vec, 0
+ INDEX_op_sarv_vec, INDEX_op_cmpsel_vec, 0
};
static const GVecGen3 ops[4] = {
{ .fniv = gen_sshl_vec,
@@ -1304,6 +1313,42 @@ void gen_neon_uqrshl(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
opr_sz, max_sz, 0, fns[vece]);
}
+void gen_neon_sqshli(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ int64_t c, uint32_t opr_sz, uint32_t max_sz)
+{
+ static gen_helper_gvec_2_ptr * const fns[] = {
+ gen_helper_neon_sqshli_b, gen_helper_neon_sqshli_h,
+ gen_helper_neon_sqshli_s, gen_helper_neon_sqshli_d,
+ };
+ tcg_debug_assert(vece <= MO_64);
+ tcg_debug_assert(c >= 0 && c <= (8 << vece));
+ tcg_gen_gvec_2_ptr(rd_ofs, rn_ofs, tcg_env, opr_sz, max_sz, c, fns[vece]);
+}
+
+void gen_neon_uqshli(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ int64_t c, uint32_t opr_sz, uint32_t max_sz)
+{
+ static gen_helper_gvec_2_ptr * const fns[] = {
+ gen_helper_neon_uqshli_b, gen_helper_neon_uqshli_h,
+ gen_helper_neon_uqshli_s, gen_helper_neon_uqshli_d,
+ };
+ tcg_debug_assert(vece <= MO_64);
+ tcg_debug_assert(c >= 0 && c <= (8 << vece));
+ tcg_gen_gvec_2_ptr(rd_ofs, rn_ofs, tcg_env, opr_sz, max_sz, c, fns[vece]);
+}
+
+void gen_neon_sqshlui(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ int64_t c, uint32_t opr_sz, uint32_t max_sz)
+{
+ static gen_helper_gvec_2_ptr * const fns[] = {
+ gen_helper_neon_sqshlui_b, gen_helper_neon_sqshlui_h,
+ gen_helper_neon_sqshlui_s, gen_helper_neon_sqshlui_d,
+ };
+ tcg_debug_assert(vece <= MO_64);
+ tcg_debug_assert(c >= 0 && c <= (8 << vece));
+ tcg_gen_gvec_2_ptr(rd_ofs, rn_ofs, tcg_env, opr_sz, max_sz, c, fns[vece]);
+}
+
void gen_uqadd_bhs(TCGv_i64 res, TCGv_i64 qc, TCGv_i64 a, TCGv_i64 b, MemOp esz)
{
uint64_t max = MAKE_64BIT_MASK(0, 8 << esz);
diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c
index 0ea8668..56b431f 100644
--- a/target/arm/tcg/helper-a64.c
+++ b/target/arm/tcg/helper-a64.c
@@ -33,7 +33,7 @@
#include "qemu/int128.h"
#include "qemu/atomic128.h"
#include "fpu/softfloat.h"
-#include <zlib.h> /* For crc32 */
+#include <zlib.h> /* for crc32 */
/* C2.4.7 Multiply and divide */
/* special cases for 0 and LLONG_MIN are mandated by the standard */
@@ -928,6 +928,8 @@ uint32_t HELPER(sqrt_f16)(uint32_t a, void *fpstp)
void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
{
+ uintptr_t ra = GETPC();
+
/*
* Implement DC ZVA, which zeroes a fixed-length block of memory.
* Note that we do not implement the (architecturally mandated)
@@ -948,8 +950,6 @@ void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
#ifndef CONFIG_USER_ONLY
if (unlikely(!mem)) {
- uintptr_t ra = GETPC();
-
/*
* Trap if accessing an invalid page. DC_ZVA requires that we supply
* the original pointer for an invalid page. But watchpoints require
@@ -971,7 +971,9 @@ void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
}
#endif
+ set_helper_retaddr(ra);
memset(mem, 0, blocklen);
+ clear_helper_retaddr();
}
void HELPER(unaligned_access)(CPUARMState *env, uint64_t addr,
@@ -1120,7 +1122,9 @@ static uint64_t set_step(CPUARMState *env, uint64_t toaddr,
}
#endif
/* Easy case: just memset the host memory */
+ set_helper_retaddr(ra);
memset(mem, data, setsize);
+ clear_helper_retaddr();
return setsize;
}
@@ -1163,7 +1167,9 @@ static uint64_t set_step_tags(CPUARMState *env, uint64_t toaddr,
}
#endif
/* Easy case: just memset the host memory */
+ set_helper_retaddr(ra);
memset(mem, data, setsize);
+ clear_helper_retaddr();
mte_mops_set_tags(env, toaddr, setsize, *mtedesc);
return setsize;
}
@@ -1497,7 +1503,9 @@ static uint64_t copy_step(CPUARMState *env, uint64_t toaddr, uint64_t fromaddr,
}
#endif
/* Easy case: just memmove the host memory */
+ set_helper_retaddr(ra);
memmove(wmem, rmem, copysize);
+ clear_helper_retaddr();
return copysize;
}
@@ -1572,7 +1580,9 @@ static uint64_t copy_step_rev(CPUARMState *env, uint64_t toaddr,
* Easy case: just memmove the host memory. Note that wmem and
* rmem here point to the *last* byte to copy.
*/
+ set_helper_retaddr(ra);
memmove(wmem - (copysize - 1), rmem - (copysize - 1), copysize);
+ clear_helper_retaddr();
return copysize;
}
@@ -1867,3 +1877,42 @@ void HELPER(cpyfe)(CPUARMState *env, uint32_t syndrome, uint32_t wdesc,
{
do_cpye(env, syndrome, wdesc, rdesc, false, GETPC());
}
+
+static bool is_guarded_page(CPUARMState *env, target_ulong addr, uintptr_t ra)
+{
+#ifdef CONFIG_USER_ONLY
+ return page_get_flags(addr) & PAGE_BTI;
+#else
+ CPUTLBEntryFull *full;
+ void *host;
+ int mmu_idx = cpu_mmu_index(env_cpu(env), true);
+ int flags = probe_access_full(env, addr, 0, MMU_INST_FETCH, mmu_idx,
+ false, &host, &full, ra);
+
+ assert(!(flags & TLB_INVALID_MASK));
+ return full->extra.arm.guarded;
+#endif
+}
+
+void HELPER(guarded_page_check)(CPUARMState *env)
+{
+ /*
+ * We have already verified that bti is enabled, and that the
+ * instruction at PC is not ok for BTYPE. This is always at
+ * the beginning of a block, so PC is always up-to-date and
+ * no unwind is required.
+ */
+ if (is_guarded_page(env, env->pc, 0)) {
+ raise_exception(env, EXCP_UDEF, syn_btitrap(env->btype),
+ exception_target_el(env));
+ }
+}
+
+void HELPER(guarded_page_br)(CPUARMState *env, target_ulong pc)
+{
+ /*
+ * We have already checked for branch via x16 and x17.
+ * What remains for choosing BTYPE is checking for a guarded page.
+ */
+ env->btype = is_guarded_page(env, pc, GETPC()) ? 3 : 1;
+}
diff --git a/target/arm/tcg/helper-a64.h b/target/arm/tcg/helper-a64.h
index 371388f..481007b 100644
--- a/target/arm/tcg/helper-a64.h
+++ b/target/arm/tcg/helper-a64.h
@@ -133,6 +133,9 @@ DEF_HELPER_4(cpyfp, void, env, i32, i32, i32)
DEF_HELPER_4(cpyfm, void, env, i32, i32, i32)
DEF_HELPER_4(cpyfe, void, env, i32, i32, i32)
+DEF_HELPER_FLAGS_1(guarded_page_check, TCG_CALL_NO_WG, void, env)
+DEF_HELPER_FLAGS_2(guarded_page_br, TCG_CALL_NO_RWG, void, env, tl)
+
DEF_HELPER_FLAGS_5(gvec_fdiv_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_5(gvec_fdiv_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_5(gvec_fdiv_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32)
diff --git a/target/arm/tcg/helper-sme.h b/target/arm/tcg/helper-sme.h
index 27eef49..59ecaa1 100644
--- a/target/arm/tcg/helper-sme.h
+++ b/target/arm/tcg/helper-sme.h
@@ -121,13 +121,13 @@ DEF_HELPER_FLAGS_5(sme_addha_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_5(sme_addva_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_7(sme_fmopa_h, TCG_CALL_NO_RWG,
- void, ptr, ptr, ptr, ptr, ptr, ptr, i32)
+ void, ptr, ptr, ptr, ptr, ptr, env, i32)
DEF_HELPER_FLAGS_7(sme_fmopa_s, TCG_CALL_NO_RWG,
void, ptr, ptr, ptr, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_7(sme_fmopa_d, TCG_CALL_NO_RWG,
void, ptr, ptr, ptr, ptr, ptr, ptr, i32)
-DEF_HELPER_FLAGS_6(sme_bfmopa, TCG_CALL_NO_RWG,
- void, ptr, ptr, ptr, ptr, ptr, i32)
+DEF_HELPER_FLAGS_7(sme_bfmopa, TCG_CALL_NO_RWG,
+ void, ptr, ptr, ptr, ptr, ptr, env, i32)
DEF_HELPER_FLAGS_6(sme_smopa_s, TCG_CALL_NO_RWG,
void, ptr, ptr, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_6(sme_umopa_s, TCG_CALL_NO_RWG,
diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c
index f03977b..bab7822 100644
--- a/target/arm/tcg/hflags.c
+++ b/target/arm/tcg/hflags.c
@@ -198,6 +198,10 @@ static CPUARMTBFlags rebuild_hflags_a32(CPUARMState *env, int fp_el,
DP_TBFLAG_A32(flags, SME_TRAP_NONSTREAMING, 1);
}
+ if (arm_aa32_secure_pl1_0(env)) {
+ DP_TBFLAG_A32(flags, S_PL1_0, 1);
+ }
+
return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags);
}
diff --git a/target/arm/tcg/m_helper.c b/target/arm/tcg/m_helper.c
index 23d7f73..f7354f3 100644
--- a/target/arm/tcg/m_helper.c
+++ b/target/arm/tcg/m_helper.c
@@ -222,7 +222,7 @@ static bool v7m_stack_write(ARMCPU *cpu, uint32_t addr, uint32_t value,
int exc;
bool exc_secure;
- if (get_phys_addr(env, addr, MMU_DATA_STORE, mmu_idx, &res, &fi)) {
+ if (get_phys_addr(env, addr, MMU_DATA_STORE, 0, mmu_idx, &res, &fi)) {
/* MPU/SAU lookup failed */
if (fi.type == ARMFault_QEMU_SFault) {
if (mode == STACK_LAZYFP) {
@@ -311,7 +311,7 @@ static bool v7m_stack_read(ARMCPU *cpu, uint32_t *dest, uint32_t addr,
bool exc_secure;
uint32_t value;
- if (get_phys_addr(env, addr, MMU_DATA_LOAD, mmu_idx, &res, &fi)) {
+ if (get_phys_addr(env, addr, MMU_DATA_LOAD, 0, mmu_idx, &res, &fi)) {
/* MPU/SAU lookup failed */
if (fi.type == ARMFault_QEMU_SFault) {
qemu_log_mask(CPU_LOG_INT,
@@ -2009,7 +2009,7 @@ static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx, bool secure,
"...really SecureFault with SFSR.INVEP\n");
return false;
}
- if (get_phys_addr(env, addr, MMU_INST_FETCH, mmu_idx, &res, &fi)) {
+ if (get_phys_addr(env, addr, MMU_INST_FETCH, 0, mmu_idx, &res, &fi)) {
/* the MPU lookup failed */
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_IACCVIOL_MASK;
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM, env->v7m.secure);
@@ -2045,7 +2045,7 @@ static bool v7m_read_sg_stack_word(ARMCPU *cpu, ARMMMUIdx mmu_idx,
ARMMMUFaultInfo fi = {};
uint32_t value;
- if (get_phys_addr(env, addr, MMU_DATA_LOAD, mmu_idx, &res, &fi)) {
+ if (get_phys_addr(env, addr, MMU_DATA_LOAD, 0, mmu_idx, &res, &fi)) {
/* MPU/SAU lookup failed */
if (fi.type == ARMFault_QEMU_SFault) {
qemu_log_mask(CPU_LOG_INT,
diff --git a/target/arm/tcg/neon-dp.decode b/target/arm/tcg/neon-dp.decode
index 788578c..e883c6a 100644
--- a/target/arm/tcg/neon-dp.decode
+++ b/target/arm/tcg/neon-dp.decode
@@ -291,17 +291,17 @@ VSLI_2sh 1111 001 1 1 . ...... .... 0101 . . . 1 .... @2reg_shl_s
VSLI_2sh 1111 001 1 1 . ...... .... 0101 . . . 1 .... @2reg_shl_h
VSLI_2sh 1111 001 1 1 . ...... .... 0101 . . . 1 .... @2reg_shl_b
-VQSHLU_64_2sh 1111 001 1 1 . ...... .... 0110 . . . 1 .... @2reg_shl_d
+VQSHLU_2sh 1111 001 1 1 . ...... .... 0110 . . . 1 .... @2reg_shl_d
VQSHLU_2sh 1111 001 1 1 . ...... .... 0110 . . . 1 .... @2reg_shl_s
VQSHLU_2sh 1111 001 1 1 . ...... .... 0110 . . . 1 .... @2reg_shl_h
VQSHLU_2sh 1111 001 1 1 . ...... .... 0110 . . . 1 .... @2reg_shl_b
-VQSHL_S_64_2sh 1111 001 0 1 . ...... .... 0111 . . . 1 .... @2reg_shl_d
+VQSHL_S_2sh 1111 001 0 1 . ...... .... 0111 . . . 1 .... @2reg_shl_d
VQSHL_S_2sh 1111 001 0 1 . ...... .... 0111 . . . 1 .... @2reg_shl_s
VQSHL_S_2sh 1111 001 0 1 . ...... .... 0111 . . . 1 .... @2reg_shl_h
VQSHL_S_2sh 1111 001 0 1 . ...... .... 0111 . . . 1 .... @2reg_shl_b
-VQSHL_U_64_2sh 1111 001 1 1 . ...... .... 0111 . . . 1 .... @2reg_shl_d
+VQSHL_U_2sh 1111 001 1 1 . ...... .... 0111 . . . 1 .... @2reg_shl_d
VQSHL_U_2sh 1111 001 1 1 . ...... .... 0111 . . . 1 .... @2reg_shl_s
VQSHL_U_2sh 1111 001 1 1 . ...... .... 0111 . . . 1 .... @2reg_shl_h
VQSHL_U_2sh 1111 001 1 1 . ...... .... 0111 . . . 1 .... @2reg_shl_b
diff --git a/target/arm/tcg/neon_helper.c b/target/arm/tcg/neon_helper.c
index 082bfd8..93b2076 100644
--- a/target/arm/tcg/neon_helper.c
+++ b/target/arm/tcg/neon_helper.c
@@ -141,6 +141,19 @@ void HELPER(name)(void *vd, void *vn, void *vm, void *venv, uint32_t desc) \
clear_tail(d, opr_sz, simd_maxsz(desc)); \
}
+#define NEON_GVEC_VOP2i_ENV(name, vtype) \
+void HELPER(name)(void *vd, void *vn, void *venv, uint32_t desc) \
+{ \
+ intptr_t i, opr_sz = simd_oprsz(desc); \
+ int imm = simd_data(desc); \
+ vtype *d = vd, *n = vn; \
+ CPUARMState *env = venv; \
+ for (i = 0; i < opr_sz / sizeof(vtype); i++) { \
+ NEON_FN(d[i], n[i], imm); \
+ } \
+ clear_tail(d, opr_sz, simd_maxsz(desc)); \
+}
+
/* Pairwise operations. */
/* For 32-bit elements each segment only contains a single element, so
the elementwise and pairwise operations are the same. */
@@ -271,22 +284,26 @@ uint64_t HELPER(neon_rshl_u64)(uint64_t val, uint64_t shift)
(dest = do_uqrshl_bhs(src1, (int8_t)src2, 8, false, env->vfp.qc))
NEON_VOP_ENV(qshl_u8, neon_u8, 4)
NEON_GVEC_VOP2_ENV(neon_uqshl_b, uint8_t)
+NEON_GVEC_VOP2i_ENV(neon_uqshli_b, uint8_t)
#undef NEON_FN
#define NEON_FN(dest, src1, src2) \
(dest = do_uqrshl_bhs(src1, (int8_t)src2, 16, false, env->vfp.qc))
NEON_VOP_ENV(qshl_u16, neon_u16, 2)
NEON_GVEC_VOP2_ENV(neon_uqshl_h, uint16_t)
+NEON_GVEC_VOP2i_ENV(neon_uqshli_h, uint16_t)
#undef NEON_FN
#define NEON_FN(dest, src1, src2) \
(dest = do_uqrshl_bhs(src1, (int8_t)src2, 32, false, env->vfp.qc))
NEON_GVEC_VOP2_ENV(neon_uqshl_s, uint32_t)
+NEON_GVEC_VOP2i_ENV(neon_uqshli_s, uint32_t)
#undef NEON_FN
#define NEON_FN(dest, src1, src2) \
(dest = do_uqrshl_d(src1, (int8_t)src2, false, env->vfp.qc))
NEON_GVEC_VOP2_ENV(neon_uqshl_d, uint64_t)
+NEON_GVEC_VOP2i_ENV(neon_uqshli_d, uint64_t)
#undef NEON_FN
uint32_t HELPER(neon_qshl_u32)(CPUARMState *env, uint32_t val, uint32_t shift)
@@ -303,22 +320,26 @@ uint64_t HELPER(neon_qshl_u64)(CPUARMState *env, uint64_t val, uint64_t shift)
(dest = do_sqrshl_bhs(src1, (int8_t)src2, 8, false, env->vfp.qc))
NEON_VOP_ENV(qshl_s8, neon_s8, 4)
NEON_GVEC_VOP2_ENV(neon_sqshl_b, int8_t)
+NEON_GVEC_VOP2i_ENV(neon_sqshli_b, int8_t)
#undef NEON_FN
#define NEON_FN(dest, src1, src2) \
(dest = do_sqrshl_bhs(src1, (int8_t)src2, 16, false, env->vfp.qc))
NEON_VOP_ENV(qshl_s16, neon_s16, 2)
NEON_GVEC_VOP2_ENV(neon_sqshl_h, int16_t)
+NEON_GVEC_VOP2i_ENV(neon_sqshli_h, int16_t)
#undef NEON_FN
#define NEON_FN(dest, src1, src2) \
(dest = do_sqrshl_bhs(src1, (int8_t)src2, 32, false, env->vfp.qc))
NEON_GVEC_VOP2_ENV(neon_sqshl_s, int32_t)
+NEON_GVEC_VOP2i_ENV(neon_sqshli_s, int32_t)
#undef NEON_FN
#define NEON_FN(dest, src1, src2) \
(dest = do_sqrshl_d(src1, (int8_t)src2, false, env->vfp.qc))
NEON_GVEC_VOP2_ENV(neon_sqshl_d, int64_t)
+NEON_GVEC_VOP2i_ENV(neon_sqshli_d, int64_t)
#undef NEON_FN
uint32_t HELPER(neon_qshl_s32)(CPUARMState *env, uint32_t val, uint32_t shift)
@@ -334,11 +355,13 @@ uint64_t HELPER(neon_qshl_s64)(CPUARMState *env, uint64_t val, uint64_t shift)
#define NEON_FN(dest, src1, src2) \
(dest = do_suqrshl_bhs(src1, (int8_t)src2, 8, false, env->vfp.qc))
NEON_VOP_ENV(qshlu_s8, neon_s8, 4)
+NEON_GVEC_VOP2i_ENV(neon_sqshlui_b, int8_t)
#undef NEON_FN
#define NEON_FN(dest, src1, src2) \
(dest = do_suqrshl_bhs(src1, (int8_t)src2, 16, false, env->vfp.qc))
NEON_VOP_ENV(qshlu_s16, neon_s16, 2)
+NEON_GVEC_VOP2i_ENV(neon_sqshlui_h, int16_t)
#undef NEON_FN
uint32_t HELPER(neon_qshlu_s32)(CPUARMState *env, uint32_t val, uint32_t shift)
@@ -352,6 +375,16 @@ uint64_t HELPER(neon_qshlu_s64)(CPUARMState *env, uint64_t val, uint64_t shift)
}
#define NEON_FN(dest, src1, src2) \
+ (dest = do_suqrshl_bhs(src1, (int8_t)src2, 32, false, env->vfp.qc))
+NEON_GVEC_VOP2i_ENV(neon_sqshlui_s, int32_t)
+#undef NEON_FN
+
+#define NEON_FN(dest, src1, src2) \
+ (dest = do_suqrshl_d(src1, (int8_t)src2, false, env->vfp.qc))
+NEON_GVEC_VOP2i_ENV(neon_sqshlui_d, int64_t)
+#undef NEON_FN
+
+#define NEON_FN(dest, src1, src2) \
(dest = do_uqrshl_bhs(src1, (int8_t)src2, 8, true, env->vfp.qc))
NEON_VOP_ENV(qrshl_u8, neon_u8, 4)
NEON_GVEC_VOP2_ENV(neon_uqrshl_b, uint8_t)
@@ -565,13 +598,15 @@ NEON_VOP_ENV(qrdmulh_s32, neon_s32, 1)
#undef NEON_FN
#undef NEON_QDMULH32
-uint32_t HELPER(neon_narrow_u8)(uint64_t x)
+/* Only the low 32-bits of output are significant. */
+uint64_t HELPER(neon_narrow_u8)(uint64_t x)
{
return (x & 0xffu) | ((x >> 8) & 0xff00u) | ((x >> 16) & 0xff0000u)
| ((x >> 24) & 0xff000000u);
}
-uint32_t HELPER(neon_narrow_u16)(uint64_t x)
+/* Only the low 32-bits of output are significant. */
+uint64_t HELPER(neon_narrow_u16)(uint64_t x)
{
return (x & 0xffffu) | ((x >> 16) & 0xffff0000u);
}
@@ -602,7 +637,8 @@ uint32_t HELPER(neon_narrow_round_high_u16)(uint64_t x)
return ((x >> 16) & 0xffff) | ((x >> 32) & 0xffff0000);
}
-uint32_t HELPER(neon_unarrow_sat8)(CPUARMState *env, uint64_t x)
+/* Only the low 32-bits of output are significant. */
+uint64_t HELPER(neon_unarrow_sat8)(CPUARMState *env, uint64_t x)
{
uint16_t s;
uint8_t d;
@@ -629,7 +665,8 @@ uint32_t HELPER(neon_unarrow_sat8)(CPUARMState *env, uint64_t x)
return res;
}
-uint32_t HELPER(neon_narrow_sat_u8)(CPUARMState *env, uint64_t x)
+/* Only the low 32-bits of output are significant. */
+uint64_t HELPER(neon_narrow_sat_u8)(CPUARMState *env, uint64_t x)
{
uint16_t s;
uint8_t d;
@@ -652,7 +689,8 @@ uint32_t HELPER(neon_narrow_sat_u8)(CPUARMState *env, uint64_t x)
return res;
}
-uint32_t HELPER(neon_narrow_sat_s8)(CPUARMState *env, uint64_t x)
+/* Only the low 32-bits of output are significant. */
+uint64_t HELPER(neon_narrow_sat_s8)(CPUARMState *env, uint64_t x)
{
int16_t s;
uint8_t d;
@@ -675,7 +713,8 @@ uint32_t HELPER(neon_narrow_sat_s8)(CPUARMState *env, uint64_t x)
return res;
}
-uint32_t HELPER(neon_unarrow_sat16)(CPUARMState *env, uint64_t x)
+/* Only the low 32-bits of output are significant. */
+uint64_t HELPER(neon_unarrow_sat16)(CPUARMState *env, uint64_t x)
{
uint32_t high;
uint32_t low;
@@ -695,10 +734,11 @@ uint32_t HELPER(neon_unarrow_sat16)(CPUARMState *env, uint64_t x)
high = 0xffff;
SET_QC();
}
- return low | (high << 16);
+ return deposit32(low, 16, 16, high);
}
-uint32_t HELPER(neon_narrow_sat_u16)(CPUARMState *env, uint64_t x)
+/* Only the low 32-bits of output are significant. */
+uint64_t HELPER(neon_narrow_sat_u16)(CPUARMState *env, uint64_t x)
{
uint32_t high;
uint32_t low;
@@ -712,10 +752,11 @@ uint32_t HELPER(neon_narrow_sat_u16)(CPUARMState *env, uint64_t x)
high = 0xffff;
SET_QC();
}
- return low | (high << 16);
+ return deposit32(low, 16, 16, high);
}
-uint32_t HELPER(neon_narrow_sat_s16)(CPUARMState *env, uint64_t x)
+/* Only the low 32-bits of output are significant. */
+uint64_t HELPER(neon_narrow_sat_s16)(CPUARMState *env, uint64_t x)
{
int32_t low;
int32_t high;
@@ -729,10 +770,11 @@ uint32_t HELPER(neon_narrow_sat_s16)(CPUARMState *env, uint64_t x)
high = (high >> 31) ^ 0x7fff;
SET_QC();
}
- return (uint16_t)low | (high << 16);
+ return deposit32(low, 16, 16, high);
}
-uint32_t HELPER(neon_unarrow_sat32)(CPUARMState *env, uint64_t x)
+/* Only the low 32-bits of output are significant. */
+uint64_t HELPER(neon_unarrow_sat32)(CPUARMState *env, uint64_t x)
{
if (x & 0x8000000000000000ull) {
SET_QC();
@@ -745,7 +787,8 @@ uint32_t HELPER(neon_unarrow_sat32)(CPUARMState *env, uint64_t x)
return x;
}
-uint32_t HELPER(neon_narrow_sat_u32)(CPUARMState *env, uint64_t x)
+/* Only the low 32-bits of output are significant. */
+uint64_t HELPER(neon_narrow_sat_u32)(CPUARMState *env, uint64_t x)
{
if (x > 0xffffffffu) {
SET_QC();
@@ -754,13 +797,14 @@ uint32_t HELPER(neon_narrow_sat_u32)(CPUARMState *env, uint64_t x)
return x;
}
-uint32_t HELPER(neon_narrow_sat_s32)(CPUARMState *env, uint64_t x)
+/* Only the low 32-bits of output are significant. */
+uint64_t HELPER(neon_narrow_sat_s32)(CPUARMState *env, uint64_t x)
{
if ((int64_t)x != (int32_t)x) {
SET_QC();
- return ((int64_t)x >> 63) ^ 0x7fffffff;
+ return (uint32_t)((int64_t)x >> 63) ^ 0x7fffffff;
}
- return x;
+ return (uint32_t)x;
}
uint64_t HELPER(neon_widen_u8)(uint32_t x)
diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c
index 5a6dd76..8cf1265 100644
--- a/target/arm/tcg/sme_helper.c
+++ b/target/arm/tcg/sme_helper.c
@@ -517,6 +517,8 @@ void sme_ld1(CPUARMState *env, void *za, uint64_t *vg,
clr_fn(za, 0, reg_off);
}
+ set_helper_retaddr(ra);
+
while (reg_off <= reg_last) {
uint64_t pg = vg[reg_off >> 6];
do {
@@ -529,6 +531,8 @@ void sme_ld1(CPUARMState *env, void *za, uint64_t *vg,
} while (reg_off <= reg_last && (reg_off & 63));
}
+ clear_helper_retaddr();
+
/*
* Use the slow path to manage the cross-page misalignment.
* But we know this is RAM and cannot trap.
@@ -543,6 +547,8 @@ void sme_ld1(CPUARMState *env, void *za, uint64_t *vg,
reg_last = info.reg_off_last[1];
host = info.page[1].host;
+ set_helper_retaddr(ra);
+
do {
uint64_t pg = vg[reg_off >> 6];
do {
@@ -554,6 +560,8 @@ void sme_ld1(CPUARMState *env, void *za, uint64_t *vg,
reg_off += esize;
} while (reg_off & 63);
} while (reg_off <= reg_last);
+
+ clear_helper_retaddr();
}
}
@@ -701,6 +709,8 @@ void sme_st1(CPUARMState *env, void *za, uint64_t *vg,
reg_last = info.reg_off_last[0];
host = info.page[0].host;
+ set_helper_retaddr(ra);
+
while (reg_off <= reg_last) {
uint64_t pg = vg[reg_off >> 6];
do {
@@ -711,6 +721,8 @@ void sme_st1(CPUARMState *env, void *za, uint64_t *vg,
} while (reg_off <= reg_last && (reg_off & 63));
}
+ clear_helper_retaddr();
+
/*
* Use the slow path to manage the cross-page misalignment.
* But we know this is RAM and cannot trap.
@@ -725,6 +737,8 @@ void sme_st1(CPUARMState *env, void *za, uint64_t *vg,
reg_last = info.reg_off_last[1];
host = info.page[1].host;
+ set_helper_retaddr(ra);
+
do {
uint64_t pg = vg[reg_off >> 6];
do {
@@ -734,6 +748,8 @@ void sme_st1(CPUARMState *env, void *za, uint64_t *vg,
reg_off += 1 << esz;
} while (reg_off & 63);
} while (reg_off <= reg_last);
+
+ clear_helper_retaddr();
}
}
@@ -976,12 +992,23 @@ static inline uint32_t f16mop_adj_pair(uint32_t pair, uint32_t pg, uint32_t neg)
}
static float32 f16_dotadd(float32 sum, uint32_t e1, uint32_t e2,
- float_status *s_std, float_status *s_odd)
+ float_status *s_f16, float_status *s_std,
+ float_status *s_odd)
{
- float64 e1r = float16_to_float64(e1 & 0xffff, true, s_std);
- float64 e1c = float16_to_float64(e1 >> 16, true, s_std);
- float64 e2r = float16_to_float64(e2 & 0xffff, true, s_std);
- float64 e2c = float16_to_float64(e2 >> 16, true, s_std);
+ /*
+ * We need three different float_status for different parts of this
+ * operation:
+ * - the input conversion of the float16 values must use the
+ * f16-specific float_status, so that the FPCR.FZ16 control is applied
+ * - operations on float32 including the final accumulation must use
+ * the normal float_status, so that FPCR.FZ is applied
+ * - we have pre-set-up copy of s_std which is set to round-to-odd,
+ * for the multiply (see below)
+ */
+ float64 e1r = float16_to_float64(e1 & 0xffff, true, s_f16);
+ float64 e1c = float16_to_float64(e1 >> 16, true, s_f16);
+ float64 e2r = float16_to_float64(e2 & 0xffff, true, s_f16);
+ float64 e2c = float16_to_float64(e2 >> 16, true, s_f16);
float64 t64;
float32 t32;
@@ -1003,20 +1030,23 @@ static float32 f16_dotadd(float32 sum, uint32_t e1, uint32_t e2,
}
void HELPER(sme_fmopa_h)(void *vza, void *vzn, void *vzm, void *vpn,
- void *vpm, void *vst, uint32_t desc)
+ void *vpm, CPUARMState *env, uint32_t desc)
{
intptr_t row, col, oprsz = simd_maxsz(desc);
uint32_t neg = simd_data(desc) * 0x80008000u;
uint16_t *pn = vpn, *pm = vpm;
- float_status fpst_odd, fpst_std;
+ float_status fpst_odd, fpst_std, fpst_f16;
/*
- * Make a copy of float_status because this operation does not
- * update the cumulative fp exception status. It also produces
- * default nans. Make a second copy with round-to-odd -- see above.
+ * Make copies of fp_status and fp_status_f16, because this operation
+ * does not update the cumulative fp exception status. It also
+ * produces default NaNs. We also need a second copy of fp_status with
+ * round-to-odd -- see above.
*/
- fpst_std = *(float_status *)vst;
+ fpst_f16 = env->vfp.fp_status_f16;
+ fpst_std = env->vfp.fp_status;
set_default_nan_mode(true, &fpst_std);
+ set_default_nan_mode(true, &fpst_f16);
fpst_odd = fpst_std;
set_float_rounding_mode(float_round_to_odd, &fpst_odd);
@@ -1036,7 +1066,8 @@ void HELPER(sme_fmopa_h)(void *vza, void *vzn, void *vzm, void *vpn,
uint32_t m = *(uint32_t *)(vzm + H1_4(col));
m = f16mop_adj_pair(m, pcol, 0);
- *a = f16_dotadd(*a, n, m, &fpst_std, &fpst_odd);
+ *a = f16_dotadd(*a, n, m,
+ &fpst_f16, &fpst_std, &fpst_odd);
}
col += 4;
pcol >>= 4;
@@ -1048,38 +1079,68 @@ void HELPER(sme_fmopa_h)(void *vza, void *vzn, void *vzm, void *vpn,
}
}
-void HELPER(sme_bfmopa)(void *vza, void *vzn, void *vzm, void *vpn,
- void *vpm, uint32_t desc)
+void HELPER(sme_bfmopa)(void *vza, void *vzn, void *vzm,
+ void *vpn, void *vpm, CPUARMState *env, uint32_t desc)
{
intptr_t row, col, oprsz = simd_maxsz(desc);
uint32_t neg = simd_data(desc) * 0x80008000u;
uint16_t *pn = vpn, *pm = vpm;
+ float_status fpst, fpst_odd;
- for (row = 0; row < oprsz; ) {
- uint16_t prow = pn[H2(row >> 4)];
- do {
- void *vza_row = vza + tile_vslice_offset(row);
- uint32_t n = *(uint32_t *)(vzn + H1_4(row));
+ if (is_ebf(env, &fpst, &fpst_odd)) {
+ for (row = 0; row < oprsz; ) {
+ uint16_t prow = pn[H2(row >> 4)];
+ do {
+ void *vza_row = vza + tile_vslice_offset(row);
+ uint32_t n = *(uint32_t *)(vzn + H1_4(row));
- n = f16mop_adj_pair(n, prow, neg);
+ n = f16mop_adj_pair(n, prow, neg);
- for (col = 0; col < oprsz; ) {
- uint16_t pcol = pm[H2(col >> 4)];
- do {
- if (prow & pcol & 0b0101) {
- uint32_t *a = vza_row + H1_4(col);
- uint32_t m = *(uint32_t *)(vzm + H1_4(col));
+ for (col = 0; col < oprsz; ) {
+ uint16_t pcol = pm[H2(col >> 4)];
+ do {
+ if (prow & pcol & 0b0101) {
+ uint32_t *a = vza_row + H1_4(col);
+ uint32_t m = *(uint32_t *)(vzm + H1_4(col));
- m = f16mop_adj_pair(m, pcol, 0);
- *a = bfdotadd(*a, n, m);
- }
- col += 4;
- pcol >>= 4;
- } while (col & 15);
- }
- row += 4;
- prow >>= 4;
- } while (row & 15);
+ m = f16mop_adj_pair(m, pcol, 0);
+ *a = bfdotadd_ebf(*a, n, m, &fpst, &fpst_odd);
+ }
+ col += 4;
+ pcol >>= 4;
+ } while (col & 15);
+ }
+ row += 4;
+ prow >>= 4;
+ } while (row & 15);
+ }
+ } else {
+ for (row = 0; row < oprsz; ) {
+ uint16_t prow = pn[H2(row >> 4)];
+ do {
+ void *vza_row = vza + tile_vslice_offset(row);
+ uint32_t n = *(uint32_t *)(vzn + H1_4(row));
+
+ n = f16mop_adj_pair(n, prow, neg);
+
+ for (col = 0; col < oprsz; ) {
+ uint16_t pcol = pm[H2(col >> 4)];
+ do {
+ if (prow & pcol & 0b0101) {
+ uint32_t *a = vza_row + H1_4(col);
+ uint32_t m = *(uint32_t *)(vzm + H1_4(col));
+
+ m = f16mop_adj_pair(m, pcol, 0);
+ *a = bfdotadd(*a, n, m, &fpst);
+ }
+ col += 4;
+ pcol >>= 4;
+ } while (col & 15);
+ }
+ row += 4;
+ prow >>= 4;
+ } while (row & 15);
+ }
}
}
@@ -1146,10 +1207,10 @@ static uint64_t NAME(uint64_t n, uint64_t m, uint64_t a, uint8_t p, bool neg) \
uint64_t sum = 0; \
/* Apply P to N as a mask, making the inactive elements 0. */ \
n &= expand_pred_h(p); \
- sum += (NTYPE)(n >> 0) * (MTYPE)(m >> 0); \
- sum += (NTYPE)(n >> 16) * (MTYPE)(m >> 16); \
- sum += (NTYPE)(n >> 32) * (MTYPE)(m >> 32); \
- sum += (NTYPE)(n >> 48) * (MTYPE)(m >> 48); \
+ sum += (int64_t)(NTYPE)(n >> 0) * (MTYPE)(m >> 0); \
+ sum += (int64_t)(NTYPE)(n >> 16) * (MTYPE)(m >> 16); \
+ sum += (int64_t)(NTYPE)(n >> 32) * (MTYPE)(m >> 32); \
+ sum += (int64_t)(NTYPE)(n >> 48) * (MTYPE)(m >> 48); \
return neg ? a - sum : a + sum; \
}
diff --git a/target/arm/tcg/sve_helper.c b/target/arm/tcg/sve_helper.c
index dd49e67..f1ee0e0 100644
--- a/target/arm/tcg/sve_helper.c
+++ b/target/arm/tcg/sve_helper.c
@@ -5738,6 +5738,8 @@ void sve_ldN_r(CPUARMState *env, uint64_t *vg, const target_ulong addr,
reg_last = info.reg_off_last[0];
host = info.page[0].host;
+ set_helper_retaddr(retaddr);
+
while (reg_off <= reg_last) {
uint64_t pg = vg[reg_off >> 6];
do {
@@ -5752,6 +5754,8 @@ void sve_ldN_r(CPUARMState *env, uint64_t *vg, const target_ulong addr,
} while (reg_off <= reg_last && (reg_off & 63));
}
+ clear_helper_retaddr();
+
/*
* Use the slow path to manage the cross-page misalignment.
* But we know this is RAM and cannot trap.
@@ -5771,6 +5775,8 @@ void sve_ldN_r(CPUARMState *env, uint64_t *vg, const target_ulong addr,
reg_last = info.reg_off_last[1];
host = info.page[1].host;
+ set_helper_retaddr(retaddr);
+
do {
uint64_t pg = vg[reg_off >> 6];
do {
@@ -5784,6 +5790,8 @@ void sve_ldN_r(CPUARMState *env, uint64_t *vg, const target_ulong addr,
mem_off += N << msz;
} while (reg_off & 63);
} while (reg_off <= reg_last);
+
+ clear_helper_retaddr();
}
}
@@ -5934,15 +5942,11 @@ DO_LDN_2(4, dd, MO_64)
/*
* Load contiguous data, first-fault and no-fault.
*
- * For user-only, one could argue that we should hold the mmap_lock during
- * the operation so that there is no race between page_check_range and the
- * load operation. However, unmapping pages out from under a running thread
- * is extraordinarily unlikely. This theoretical race condition also affects
- * linux-user/ in its get_user/put_user macros.
- *
- * TODO: Construct some helpers, written in assembly, that interact with
- * host_signal_handler to produce memory ops which can properly report errors
- * without racing.
+ * For user-only, we control the race between page_check_range and
+ * another thread's munmap by using set/clear_helper_retaddr. Any
+ * SEGV that occurs between those markers is assumed to be because
+ * the guest page vanished. Keep that block as small as possible
+ * so that unrelated QEMU bugs are not blamed on the guest.
*/
/* Fault on byte I. All bits in FFR from I are cleared. The vector
@@ -6093,6 +6097,8 @@ void sve_ldnfff1_r(CPUARMState *env, void *vg, const target_ulong addr,
reg_last = info.reg_off_last[0];
host = info.page[0].host;
+ set_helper_retaddr(retaddr);
+
do {
uint64_t pg = *(uint64_t *)(vg + (reg_off >> 3));
do {
@@ -6101,9 +6107,11 @@ void sve_ldnfff1_r(CPUARMState *env, void *vg, const target_ulong addr,
(cpu_watchpoint_address_matches
(env_cpu(env), addr + mem_off, 1 << msz)
& BP_MEM_READ)) {
+ clear_helper_retaddr();
goto do_fault;
}
if (mtedesc && !mte_probe(env, mtedesc, addr + mem_off)) {
+ clear_helper_retaddr();
goto do_fault;
}
host_fn(vd, reg_off, host + mem_off);
@@ -6113,6 +6121,8 @@ void sve_ldnfff1_r(CPUARMState *env, void *vg, const target_ulong addr,
} while (reg_off <= reg_last && (reg_off & 63));
} while (reg_off <= reg_last);
+ clear_helper_retaddr();
+
/*
* MemSingleNF is allowed to fail for any reason. We have special
* code above to handle the first element crossing a page boundary.
@@ -6348,6 +6358,8 @@ void sve_stN_r(CPUARMState *env, uint64_t *vg, target_ulong addr,
reg_last = info.reg_off_last[0];
host = info.page[0].host;
+ set_helper_retaddr(retaddr);
+
while (reg_off <= reg_last) {
uint64_t pg = vg[reg_off >> 6];
do {
@@ -6362,6 +6374,8 @@ void sve_stN_r(CPUARMState *env, uint64_t *vg, target_ulong addr,
} while (reg_off <= reg_last && (reg_off & 63));
}
+ clear_helper_retaddr();
+
/*
* Use the slow path to manage the cross-page misalignment.
* But we know this is RAM and cannot trap.
@@ -6381,6 +6395,8 @@ void sve_stN_r(CPUARMState *env, uint64_t *vg, target_ulong addr,
reg_last = info.reg_off_last[1];
host = info.page[1].host;
+ set_helper_retaddr(retaddr);
+
do {
uint64_t pg = vg[reg_off >> 6];
do {
@@ -6394,6 +6410,8 @@ void sve_stN_r(CPUARMState *env, uint64_t *vg, target_ulong addr,
mem_off += N << msz;
} while (reg_off & 63);
} while (reg_off <= reg_last);
+
+ clear_helper_retaddr();
}
}
@@ -6560,7 +6578,9 @@ void sve_ld1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm,
if (unlikely(info.flags & TLB_MMIO)) {
tlb_fn(env, &scratch, reg_off, addr, retaddr);
} else {
+ set_helper_retaddr(retaddr);
host_fn(&scratch, reg_off, info.host);
+ clear_helper_retaddr();
}
} else {
/* Element crosses the page boundary. */
@@ -6782,7 +6802,9 @@ void sve_ldff1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm,
goto fault;
}
+ set_helper_retaddr(retaddr);
host_fn(vd, reg_off, info.host);
+ clear_helper_retaddr();
}
reg_off += esize;
} while (reg_off & 63);
@@ -6986,7 +7008,9 @@ void sve_st1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm,
do {
void *h = host[i];
if (likely(h != NULL)) {
+ set_helper_retaddr(retaddr);
host_fn(vd, reg_off, h);
+ clear_helper_retaddr();
} else if ((vg[reg_off >> 6] >> (reg_off & 63)) & 1) {
target_ulong addr = base + (off_fn(vm, reg_off) << scale);
tlb_fn(env, vd, reg_off, addr, retaddr);
diff --git a/target/arm/tcg/tlb_helper.c b/target/arm/tcg/tlb_helper.c
index 885bf4e..8841f03 100644
--- a/target/arm/tcg/tlb_helper.c
+++ b/target/arm/tcg/tlb_helper.c
@@ -318,14 +318,13 @@ void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
arm_deliver_fault(cpu, addr, access_type, mmu_idx, &fi);
}
-bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
- MMUAccessType access_type, int mmu_idx,
- bool probe, uintptr_t retaddr)
+bool arm_cpu_tlb_fill_align(CPUState *cs, CPUTLBEntryFull *out, vaddr address,
+ MMUAccessType access_type, int mmu_idx,
+ MemOp memop, int size, bool probe, uintptr_t ra)
{
ARMCPU *cpu = ARM_CPU(cs);
GetPhysAddrResult res = {};
ARMMMUFaultInfo local_fi, *fi;
- int ret;
/*
* Allow S1_ptw_translate to see any fault generated here.
@@ -339,37 +338,27 @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
}
/*
- * Walk the page table and (if the mapping exists) add the page
- * to the TLB. On success, return true. Otherwise, if probing,
- * return false. Otherwise populate fsr with ARM DFSR/IFSR fault
- * register format, and signal the fault.
+ * Per R_XCHFJ, alignment fault not due to memory type has
+ * highest precedence. Otherwise, walk the page table and
+ * and collect the page description.
*/
- ret = get_phys_addr(&cpu->env, address, access_type,
- core_to_arm_mmu_idx(&cpu->env, mmu_idx),
- &res, fi);
- if (likely(!ret)) {
- /*
- * Map a single [sub]page. Regions smaller than our declared
- * target page size are handled specially, so for those we
- * pass in the exact addresses.
- */
- if (res.f.lg_page_size >= TARGET_PAGE_BITS) {
- res.f.phys_addr &= TARGET_PAGE_MASK;
- address &= TARGET_PAGE_MASK;
- }
-
+ if (address & ((1 << memop_alignment_bits(memop)) - 1)) {
+ fi->type = ARMFault_Alignment;
+ } else if (!get_phys_addr(&cpu->env, address, access_type, memop,
+ core_to_arm_mmu_idx(&cpu->env, mmu_idx),
+ &res, fi)) {
res.f.extra.arm.pte_attrs = res.cacheattrs.attrs;
res.f.extra.arm.shareability = res.cacheattrs.shareability;
-
- tlb_set_page_full(cs, mmu_idx, address, &res.f);
+ *out = res.f;
return true;
- } else if (probe) {
+ }
+ if (probe) {
return false;
- } else {
- /* now we have a real cpu fault */
- cpu_restore_state(cs, retaddr);
- arm_deliver_fault(cpu, address, access_type, mmu_idx, fi);
}
+
+ /* Now we have a real cpu fault. */
+ cpu_restore_state(cs, ra);
+ arm_deliver_fault(cpu, address, access_type, mmu_idx, fi);
}
#else
void arm_cpu_record_sigsegv(CPUState *cs, vaddr addr,
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
index 148be28..ec0b1ee 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -294,7 +294,7 @@ static TCGv_i64 gen_mte_check1_mmuidx(DisasContext *s, TCGv_i64 addr,
desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid);
desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma);
desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write);
- desc = FIELD_DP32(desc, MTEDESC, ALIGN, get_alignment_bits(memop));
+ desc = FIELD_DP32(desc, MTEDESC, ALIGN, memop_alignment_bits(memop));
desc = FIELD_DP32(desc, MTEDESC, SIZEM1, memop_size(memop) - 1);
ret = tcg_temp_new_i64();
@@ -326,7 +326,7 @@ TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write,
desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid);
desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma);
desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write);
- desc = FIELD_DP32(desc, MTEDESC, ALIGN, get_alignment_bits(single_mop));
+ desc = FIELD_DP32(desc, MTEDESC, ALIGN, memop_alignment_bits(single_mop));
desc = FIELD_DP32(desc, MTEDESC, SIZEM1, total_size - 1);
ret = tcg_temp_new_i64();
@@ -736,6 +736,22 @@ static void gen_gvec_op4_ool(DisasContext *s, bool is_q, int rd, int rn,
}
/*
+ * Expand a 4-operand operation using an out-of-line helper that takes
+ * a pointer to the CPU env.
+ */
+static void gen_gvec_op4_env(DisasContext *s, bool is_q, int rd, int rn,
+ int rm, int ra, int data,
+ gen_helper_gvec_4_ptr *fn)
+{
+ tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, rd),
+ vec_full_reg_offset(s, rn),
+ vec_full_reg_offset(s, rm),
+ vec_full_reg_offset(s, ra),
+ tcg_env,
+ is_q ? 16 : 8, vec_full_reg_size(s), data, fn);
+}
+
+/*
* Expand a 4-operand + fpstatus pointer + simd data value operation using
* an out-of-line helper.
*/
@@ -1507,7 +1523,14 @@ static void set_btype_for_br(DisasContext *s, int rn)
{
if (dc_isar_feature(aa64_bti, s)) {
/* BR to {x16,x17} or !guard -> 1, else 3. */
- set_btype(s, rn == 16 || rn == 17 || !s->guarded_page ? 1 : 3);
+ if (rn == 16 || rn == 17) {
+ set_btype(s, 1);
+ } else {
+ TCGv_i64 pc = tcg_temp_new_i64();
+ gen_pc_plus_diff(s, pc, 0);
+ gen_helper_guarded_page_br(tcg_env, pc);
+ s->btype = -1;
+ }
}
}
@@ -1521,8 +1544,8 @@ static void set_btype_for_blr(DisasContext *s)
static bool trans_BR(DisasContext *s, arg_r *a)
{
- gen_a64_set_pc(s, cpu_reg(s, a->rn));
set_btype_for_br(s, a->rn);
+ gen_a64_set_pc(s, cpu_reg(s, a->rn));
s->base.is_jmp = DISAS_JUMP;
return true;
}
@@ -1581,8 +1604,8 @@ static bool trans_BRAZ(DisasContext *s, arg_braz *a)
}
dst = auth_branch_target(s, cpu_reg(s, a->rn), tcg_constant_i64(0), !a->m);
- gen_a64_set_pc(s, dst);
set_btype_for_br(s, a->rn);
+ gen_a64_set_pc(s, dst);
s->base.is_jmp = DISAS_JUMP;
return true;
}
@@ -4657,6 +4680,88 @@ static bool trans_EXTR(DisasContext *s, arg_extract *a)
return true;
}
+static bool trans_TBL_TBX(DisasContext *s, arg_TBL_TBX *a)
+{
+ if (fp_access_check(s)) {
+ int len = (a->len + 1) * 16;
+
+ tcg_gen_gvec_2_ptr(vec_full_reg_offset(s, a->rd),
+ vec_full_reg_offset(s, a->rm), tcg_env,
+ a->q ? 16 : 8, vec_full_reg_size(s),
+ (len << 6) | (a->tbx << 5) | a->rn,
+ gen_helper_simd_tblx);
+ }
+ return true;
+}
+
+typedef int simd_permute_idx_fn(int i, int part, int elements);
+
+static bool do_simd_permute(DisasContext *s, arg_qrrr_e *a,
+ simd_permute_idx_fn *fn, int part)
+{
+ MemOp esz = a->esz;
+ int datasize = a->q ? 16 : 8;
+ int elements = datasize >> esz;
+ TCGv_i64 tcg_res[2], tcg_ele;
+
+ if (esz == MO_64 && !a->q) {
+ return false;
+ }
+ if (!fp_access_check(s)) {
+ return true;
+ }
+
+ tcg_res[0] = tcg_temp_new_i64();
+ tcg_res[1] = a->q ? tcg_temp_new_i64() : NULL;
+ tcg_ele = tcg_temp_new_i64();
+
+ for (int i = 0; i < elements; i++) {
+ int o, w, idx;
+
+ idx = fn(i, part, elements);
+ read_vec_element(s, tcg_ele, (idx & elements ? a->rm : a->rn),
+ idx & (elements - 1), esz);
+
+ w = (i << (esz + 3)) / 64;
+ o = (i << (esz + 3)) % 64;
+ if (o == 0) {
+ tcg_gen_mov_i64(tcg_res[w], tcg_ele);
+ } else {
+ tcg_gen_deposit_i64(tcg_res[w], tcg_res[w], tcg_ele, o, 8 << esz);
+ }
+ }
+
+ for (int i = a->q; i >= 0; --i) {
+ write_vec_element(s, tcg_res[i], a->rd, i, MO_64);
+ }
+ clear_vec_high(s, a->q, a->rd);
+ return true;
+}
+
+static int permute_load_uzp(int i, int part, int elements)
+{
+ return 2 * i + part;
+}
+
+TRANS(UZP1, do_simd_permute, a, permute_load_uzp, 0)
+TRANS(UZP2, do_simd_permute, a, permute_load_uzp, 1)
+
+static int permute_load_trn(int i, int part, int elements)
+{
+ return (i & 1) * elements + (i & ~1) + part;
+}
+
+TRANS(TRN1, do_simd_permute, a, permute_load_trn, 0)
+TRANS(TRN2, do_simd_permute, a, permute_load_trn, 1)
+
+static int permute_load_zip(int i, int part, int elements)
+{
+ return (i & 1) * elements + ((part * elements + i) >> 1);
+}
+
+TRANS(ZIP1, do_simd_permute, a, permute_load_zip, 0)
+TRANS(ZIP2, do_simd_permute, a, permute_load_zip, 1)
+
/*
* Cryptographic AES, SHA, SHA512
*/
@@ -5601,11 +5706,20 @@ static bool do_dot_vector(DisasContext *s, arg_qrrr_e *a,
return true;
}
+static bool do_dot_vector_env(DisasContext *s, arg_qrrr_e *a,
+ gen_helper_gvec_4_ptr *fn)
+{
+ if (fp_access_check(s)) {
+ gen_gvec_op4_env(s, a->q, a->rd, a->rn, a->rm, a->rd, 0, fn);
+ }
+ return true;
+}
+
TRANS_FEAT(SDOT_v, aa64_dp, do_dot_vector, a, gen_helper_gvec_sdot_b)
TRANS_FEAT(UDOT_v, aa64_dp, do_dot_vector, a, gen_helper_gvec_udot_b)
TRANS_FEAT(USDOT_v, aa64_i8mm, do_dot_vector, a, gen_helper_gvec_usdot_b)
-TRANS_FEAT(BFDOT_v, aa64_bf16, do_dot_vector, a, gen_helper_gvec_bfdot)
-TRANS_FEAT(BFMMLA, aa64_bf16, do_dot_vector, a, gen_helper_gvec_bfmmla)
+TRANS_FEAT(BFDOT_v, aa64_bf16, do_dot_vector_env, a, gen_helper_gvec_bfdot)
+TRANS_FEAT(BFMMLA, aa64_bf16, do_dot_vector_env, a, gen_helper_gvec_bfmmla)
TRANS_FEAT(SMMLA, aa64_i8mm, do_dot_vector, a, gen_helper_gvec_smmla_b)
TRANS_FEAT(UMMLA, aa64_i8mm, do_dot_vector, a, gen_helper_gvec_ummla_b)
TRANS_FEAT(USMMLA, aa64_i8mm, do_dot_vector, a, gen_helper_gvec_usmmla_b)
@@ -6378,13 +6492,22 @@ static bool do_dot_vector_idx(DisasContext *s, arg_qrrx_e *a,
return true;
}
+static bool do_dot_vector_idx_env(DisasContext *s, arg_qrrx_e *a,
+ gen_helper_gvec_4_ptr *fn)
+{
+ if (fp_access_check(s)) {
+ gen_gvec_op4_env(s, a->q, a->rd, a->rn, a->rm, a->rd, a->idx, fn);
+ }
+ return true;
+}
+
TRANS_FEAT(SDOT_vi, aa64_dp, do_dot_vector_idx, a, gen_helper_gvec_sdot_idx_b)
TRANS_FEAT(UDOT_vi, aa64_dp, do_dot_vector_idx, a, gen_helper_gvec_udot_idx_b)
TRANS_FEAT(SUDOT_vi, aa64_i8mm, do_dot_vector_idx, a,
gen_helper_gvec_sudot_idx_b)
TRANS_FEAT(USDOT_vi, aa64_i8mm, do_dot_vector_idx, a,
gen_helper_gvec_usdot_idx_b)
-TRANS_FEAT(BFDOT_vi, aa64_bf16, do_dot_vector_idx, a,
+TRANS_FEAT(BFDOT_vi, aa64_bf16, do_dot_vector_idx_env, a,
gen_helper_gvec_bfdot_idx)
static bool trans_BFMLAL_vi(DisasContext *s, arg_qrrx_e *a)
@@ -6542,6 +6665,54 @@ static bool trans_FCSEL(DisasContext *s, arg_FCSEL *a)
}
/*
+ * Advanced SIMD Extract
+ */
+
+static bool trans_EXT_d(DisasContext *s, arg_EXT_d *a)
+{
+ if (fp_access_check(s)) {
+ TCGv_i64 lo = read_fp_dreg(s, a->rn);
+ if (a->imm != 0) {
+ TCGv_i64 hi = read_fp_dreg(s, a->rm);
+ tcg_gen_extract2_i64(lo, lo, hi, a->imm * 8);
+ }
+ write_fp_dreg(s, a->rd, lo);
+ }
+ return true;
+}
+
+static bool trans_EXT_q(DisasContext *s, arg_EXT_q *a)
+{
+ TCGv_i64 lo, hi;
+ int pos = (a->imm & 7) * 8;
+ int elt = a->imm >> 3;
+
+ if (!fp_access_check(s)) {
+ return true;
+ }
+
+ lo = tcg_temp_new_i64();
+ hi = tcg_temp_new_i64();
+
+ read_vec_element(s, lo, a->rn, elt, MO_64);
+ elt++;
+ read_vec_element(s, hi, elt & 2 ? a->rm : a->rn, elt & 1, MO_64);
+ elt++;
+
+ if (pos != 0) {
+ TCGv_i64 hh = tcg_temp_new_i64();
+ tcg_gen_extract2_i64(lo, lo, hi, pos);
+ read_vec_element(s, hh, a->rm, elt & 1, MO_64);
+ tcg_gen_extract2_i64(hi, hi, hh, pos);
+ }
+
+ write_vec_element(s, lo, a->rd, 0, MO_64);
+ write_vec_element(s, hi, a->rd, 1, MO_64);
+ clear_vec_high(s, true, a->rd);
+ return true;
+}
+
+/*
* Floating-point data-processing (3 source)
*/
@@ -6623,6 +6794,697 @@ TRANS(FNMADD, do_fmadd, a, true, true)
TRANS(FMSUB, do_fmadd, a, false, true)
TRANS(FNMSUB, do_fmadd, a, true, false)
+/*
+ * Advanced SIMD Across Lanes
+ */
+
+static bool do_int_reduction(DisasContext *s, arg_qrr_e *a, bool widen,
+ MemOp src_sign, NeonGenTwo64OpFn *fn)
+{
+ TCGv_i64 tcg_res, tcg_elt;
+ MemOp src_mop = a->esz | src_sign;
+ int elements = (a->q ? 16 : 8) >> a->esz;
+
+ /* Reject MO_64, and MO_32 without Q: a minimum of 4 elements. */
+ if (elements < 4) {
+ return false;
+ }
+ if (!fp_access_check(s)) {
+ return true;
+ }
+
+ tcg_res = tcg_temp_new_i64();
+ tcg_elt = tcg_temp_new_i64();
+
+ read_vec_element(s, tcg_res, a->rn, 0, src_mop);
+ for (int i = 1; i < elements; i++) {
+ read_vec_element(s, tcg_elt, a->rn, i, src_mop);
+ fn(tcg_res, tcg_res, tcg_elt);
+ }
+
+ tcg_gen_ext_i64(tcg_res, tcg_res, a->esz + widen);
+ write_fp_dreg(s, a->rd, tcg_res);
+ return true;
+}
+
+TRANS(ADDV, do_int_reduction, a, false, 0, tcg_gen_add_i64)
+TRANS(SADDLV, do_int_reduction, a, true, MO_SIGN, tcg_gen_add_i64)
+TRANS(UADDLV, do_int_reduction, a, true, 0, tcg_gen_add_i64)
+TRANS(SMAXV, do_int_reduction, a, false, MO_SIGN, tcg_gen_smax_i64)
+TRANS(UMAXV, do_int_reduction, a, false, 0, tcg_gen_umax_i64)
+TRANS(SMINV, do_int_reduction, a, false, MO_SIGN, tcg_gen_smin_i64)
+TRANS(UMINV, do_int_reduction, a, false, 0, tcg_gen_umin_i64)
+
+/*
+ * do_fp_reduction helper
+ *
+ * This mirrors the Reduce() pseudocode in the ARM ARM. It is
+ * important for correct NaN propagation that we do these
+ * operations in exactly the order specified by the pseudocode.
+ *
+ * This is a recursive function.
+ */
+static TCGv_i32 do_reduction_op(DisasContext *s, int rn, MemOp esz,
+ int ebase, int ecount, TCGv_ptr fpst,
+ NeonGenTwoSingleOpFn *fn)
+{
+ if (ecount == 1) {
+ TCGv_i32 tcg_elem = tcg_temp_new_i32();
+ read_vec_element_i32(s, tcg_elem, rn, ebase, esz);
+ return tcg_elem;
+ } else {
+ int half = ecount >> 1;
+ TCGv_i32 tcg_hi, tcg_lo, tcg_res;
+
+ tcg_hi = do_reduction_op(s, rn, esz, ebase + half, half, fpst, fn);
+ tcg_lo = do_reduction_op(s, rn, esz, ebase, half, fpst, fn);
+ tcg_res = tcg_temp_new_i32();
+
+ fn(tcg_res, tcg_lo, tcg_hi, fpst);
+ return tcg_res;
+ }
+}
+
+static bool do_fp_reduction(DisasContext *s, arg_qrr_e *a,
+ NeonGenTwoSingleOpFn *fn)
+{
+ if (fp_access_check(s)) {
+ MemOp esz = a->esz;
+ int elts = (a->q ? 16 : 8) >> esz;
+ TCGv_ptr fpst = fpstatus_ptr(esz == MO_16 ? FPST_FPCR_F16 : FPST_FPCR);
+ TCGv_i32 res = do_reduction_op(s, a->rn, esz, 0, elts, fpst, fn);
+ write_fp_sreg(s, a->rd, res);
+ }
+ return true;
+}
+
+TRANS_FEAT(FMAXNMV_h, aa64_fp16, do_fp_reduction, a, gen_helper_advsimd_maxnumh)
+TRANS_FEAT(FMINNMV_h, aa64_fp16, do_fp_reduction, a, gen_helper_advsimd_minnumh)
+TRANS_FEAT(FMAXV_h, aa64_fp16, do_fp_reduction, a, gen_helper_advsimd_maxh)
+TRANS_FEAT(FMINV_h, aa64_fp16, do_fp_reduction, a, gen_helper_advsimd_minh)
+
+TRANS(FMAXNMV_s, do_fp_reduction, a, gen_helper_vfp_maxnums)
+TRANS(FMINNMV_s, do_fp_reduction, a, gen_helper_vfp_minnums)
+TRANS(FMAXV_s, do_fp_reduction, a, gen_helper_vfp_maxs)
+TRANS(FMINV_s, do_fp_reduction, a, gen_helper_vfp_mins)
+
+/*
+ * Floating-point Immediate
+ */
+
+static bool trans_FMOVI_s(DisasContext *s, arg_FMOVI_s *a)
+{
+ switch (a->esz) {
+ case MO_32:
+ case MO_64:
+ break;
+ case MO_16:
+ if (!dc_isar_feature(aa64_fp16, s)) {
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+ if (fp_access_check(s)) {
+ uint64_t imm = vfp_expand_imm(a->esz, a->imm);
+ write_fp_dreg(s, a->rd, tcg_constant_i64(imm));
+ }
+ return true;
+}
+
+/*
+ * Advanced SIMD Modified Immediate
+ */
+
+static bool trans_FMOVI_v_h(DisasContext *s, arg_FMOVI_v_h *a)
+{
+ if (!dc_isar_feature(aa64_fp16, s)) {
+ return false;
+ }
+ if (fp_access_check(s)) {
+ tcg_gen_gvec_dup_imm(MO_16, vec_full_reg_offset(s, a->rd),
+ a->q ? 16 : 8, vec_full_reg_size(s),
+ vfp_expand_imm(MO_16, a->abcdefgh));
+ }
+ return true;
+}
+
+static void gen_movi(unsigned vece, uint32_t dofs, uint32_t aofs,
+ int64_t c, uint32_t oprsz, uint32_t maxsz)
+{
+ tcg_gen_gvec_dup_imm(MO_64, dofs, oprsz, maxsz, c);
+}
+
+static bool trans_Vimm(DisasContext *s, arg_Vimm *a)
+{
+ GVecGen2iFn *fn;
+
+ /* Handle decode of cmode/op here between ORR/BIC/MOVI */
+ if ((a->cmode & 1) && a->cmode < 12) {
+ /* For op=1, the imm will be inverted, so BIC becomes AND. */
+ fn = a->op ? tcg_gen_gvec_andi : tcg_gen_gvec_ori;
+ } else {
+ /* There is one unallocated cmode/op combination in this space */
+ if (a->cmode == 15 && a->op == 1 && a->q == 0) {
+ return false;
+ }
+ fn = gen_movi;
+ }
+
+ if (fp_access_check(s)) {
+ uint64_t imm = asimd_imm_const(a->abcdefgh, a->cmode, a->op);
+ gen_gvec_fn2i(s, a->q, a->rd, a->rd, imm, fn, MO_64);
+ }
+ return true;
+}
+
+/*
+ * Advanced SIMD Shift by Immediate
+ */
+
+static bool do_vec_shift_imm(DisasContext *s, arg_qrri_e *a, GVecGen2iFn *fn)
+{
+ if (fp_access_check(s)) {
+ gen_gvec_fn2i(s, a->q, a->rd, a->rn, a->imm, fn, a->esz);
+ }
+ return true;
+}
+
+TRANS(SSHR_v, do_vec_shift_imm, a, gen_gvec_sshr)
+TRANS(USHR_v, do_vec_shift_imm, a, gen_gvec_ushr)
+TRANS(SSRA_v, do_vec_shift_imm, a, gen_gvec_ssra)
+TRANS(USRA_v, do_vec_shift_imm, a, gen_gvec_usra)
+TRANS(SRSHR_v, do_vec_shift_imm, a, gen_gvec_srshr)
+TRANS(URSHR_v, do_vec_shift_imm, a, gen_gvec_urshr)
+TRANS(SRSRA_v, do_vec_shift_imm, a, gen_gvec_srsra)
+TRANS(URSRA_v, do_vec_shift_imm, a, gen_gvec_ursra)
+TRANS(SRI_v, do_vec_shift_imm, a, gen_gvec_sri)
+TRANS(SHL_v, do_vec_shift_imm, a, tcg_gen_gvec_shli)
+TRANS(SLI_v, do_vec_shift_imm, a, gen_gvec_sli);
+TRANS(SQSHL_vi, do_vec_shift_imm, a, gen_neon_sqshli)
+TRANS(UQSHL_vi, do_vec_shift_imm, a, gen_neon_uqshli)
+TRANS(SQSHLU_vi, do_vec_shift_imm, a, gen_neon_sqshlui)
+
+static bool do_vec_shift_imm_wide(DisasContext *s, arg_qrri_e *a, bool is_u)
+{
+ TCGv_i64 tcg_rn, tcg_rd;
+ int esz = a->esz;
+ int esize;
+
+ if (!fp_access_check(s)) {
+ return true;
+ }
+
+ /*
+ * For the LL variants the store is larger than the load,
+ * so if rd == rn we would overwrite parts of our input.
+ * So load everything right now and use shifts in the main loop.
+ */
+ tcg_rd = tcg_temp_new_i64();
+ tcg_rn = tcg_temp_new_i64();
+ read_vec_element(s, tcg_rn, a->rn, a->q, MO_64);
+
+ esize = 8 << esz;
+ for (int i = 0, elements = 8 >> esz; i < elements; i++) {
+ if (is_u) {
+ tcg_gen_extract_i64(tcg_rd, tcg_rn, i * esize, esize);
+ } else {
+ tcg_gen_sextract_i64(tcg_rd, tcg_rn, i * esize, esize);
+ }
+ tcg_gen_shli_i64(tcg_rd, tcg_rd, a->imm);
+ write_vec_element(s, tcg_rd, a->rd, i, esz + 1);
+ }
+ clear_vec_high(s, true, a->rd);
+ return true;
+}
+
+TRANS(SSHLL_v, do_vec_shift_imm_wide, a, false)
+TRANS(USHLL_v, do_vec_shift_imm_wide, a, true)
+
+static void gen_sshr_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift)
+{
+ assert(shift >= 0 && shift <= 64);
+ tcg_gen_sari_i64(dst, src, MIN(shift, 63));
+}
+
+static void gen_ushr_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift)
+{
+ assert(shift >= 0 && shift <= 64);
+ if (shift == 64) {
+ tcg_gen_movi_i64(dst, 0);
+ } else {
+ tcg_gen_shri_i64(dst, src, shift);
+ }
+}
+
+static void gen_ssra_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift)
+{
+ gen_sshr_d(src, src, shift);
+ tcg_gen_add_i64(dst, dst, src);
+}
+
+static void gen_usra_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift)
+{
+ gen_ushr_d(src, src, shift);
+ tcg_gen_add_i64(dst, dst, src);
+}
+
+static void gen_srshr_bhs(TCGv_i64 dst, TCGv_i64 src, int64_t shift)
+{
+ assert(shift >= 0 && shift <= 32);
+ if (shift) {
+ TCGv_i64 rnd = tcg_constant_i64(1ull << (shift - 1));
+ tcg_gen_add_i64(dst, src, rnd);
+ tcg_gen_sari_i64(dst, dst, shift);
+ } else {
+ tcg_gen_mov_i64(dst, src);
+ }
+}
+
+static void gen_urshr_bhs(TCGv_i64 dst, TCGv_i64 src, int64_t shift)
+{
+ assert(shift >= 0 && shift <= 32);
+ if (shift) {
+ TCGv_i64 rnd = tcg_constant_i64(1ull << (shift - 1));
+ tcg_gen_add_i64(dst, src, rnd);
+ tcg_gen_shri_i64(dst, dst, shift);
+ } else {
+ tcg_gen_mov_i64(dst, src);
+ }
+}
+
+static void gen_srshr_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift)
+{
+ assert(shift >= 0 && shift <= 64);
+ if (shift == 0) {
+ tcg_gen_mov_i64(dst, src);
+ } else if (shift == 64) {
+ /* Extension of sign bit (0,-1) plus sign bit (0,1) is zero. */
+ tcg_gen_movi_i64(dst, 0);
+ } else {
+ TCGv_i64 rnd = tcg_temp_new_i64();
+ tcg_gen_extract_i64(rnd, src, shift - 1, 1);
+ tcg_gen_sari_i64(dst, src, shift);
+ tcg_gen_add_i64(dst, dst, rnd);
+ }
+}
+
+static void gen_urshr_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift)
+{
+ assert(shift >= 0 && shift <= 64);
+ if (shift == 0) {
+ tcg_gen_mov_i64(dst, src);
+ } else if (shift == 64) {
+ /* Rounding will propagate bit 63 into bit 64. */
+ tcg_gen_shri_i64(dst, src, 63);
+ } else {
+ TCGv_i64 rnd = tcg_temp_new_i64();
+ tcg_gen_extract_i64(rnd, src, shift - 1, 1);
+ tcg_gen_shri_i64(dst, src, shift);
+ tcg_gen_add_i64(dst, dst, rnd);
+ }
+}
+
+static void gen_srsra_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift)
+{
+ gen_srshr_d(src, src, shift);
+ tcg_gen_add_i64(dst, dst, src);
+}
+
+static void gen_ursra_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift)
+{
+ gen_urshr_d(src, src, shift);
+ tcg_gen_add_i64(dst, dst, src);
+}
+
+static void gen_sri_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift)
+{
+ /* If shift is 64, dst is unchanged. */
+ if (shift != 64) {
+ tcg_gen_shri_i64(src, src, shift);
+ tcg_gen_deposit_i64(dst, dst, src, 0, 64 - shift);
+ }
+}
+
+static void gen_sli_d(TCGv_i64 dst, TCGv_i64 src, int64_t shift)
+{
+ tcg_gen_deposit_i64(dst, dst, src, shift, 64 - shift);
+}
+
+static bool do_vec_shift_imm_narrow(DisasContext *s, arg_qrri_e *a,
+ WideShiftImmFn * const fns[3], MemOp sign)
+{
+ TCGv_i64 tcg_rn, tcg_rd;
+ int esz = a->esz;
+ int esize;
+ WideShiftImmFn *fn;
+
+ tcg_debug_assert(esz >= MO_8 && esz <= MO_32);
+
+ if (!fp_access_check(s)) {
+ return true;
+ }
+
+ tcg_rn = tcg_temp_new_i64();
+ tcg_rd = tcg_temp_new_i64();
+ tcg_gen_movi_i64(tcg_rd, 0);
+
+ fn = fns[esz];
+ esize = 8 << esz;
+ for (int i = 0, elements = 8 >> esz; i < elements; i++) {
+ read_vec_element(s, tcg_rn, a->rn, i, (esz + 1) | sign);
+ fn(tcg_rn, tcg_rn, a->imm);
+ tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_rn, esize * i, esize);
+ }
+
+ write_vec_element(s, tcg_rd, a->rd, a->q, MO_64);
+ clear_vec_high(s, a->q, a->rd);
+ return true;
+}
+
+static void gen_sqshrn_b(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ tcg_gen_sari_i64(d, s, i);
+ tcg_gen_ext16u_i64(d, d);
+ gen_helper_neon_narrow_sat_s8(d, tcg_env, d);
+}
+
+static void gen_sqshrn_h(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ tcg_gen_sari_i64(d, s, i);
+ tcg_gen_ext32u_i64(d, d);
+ gen_helper_neon_narrow_sat_s16(d, tcg_env, d);
+}
+
+static void gen_sqshrn_s(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ gen_sshr_d(d, s, i);
+ gen_helper_neon_narrow_sat_s32(d, tcg_env, d);
+}
+
+static void gen_uqshrn_b(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ tcg_gen_shri_i64(d, s, i);
+ gen_helper_neon_narrow_sat_u8(d, tcg_env, d);
+}
+
+static void gen_uqshrn_h(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ tcg_gen_shri_i64(d, s, i);
+ gen_helper_neon_narrow_sat_u16(d, tcg_env, d);
+}
+
+static void gen_uqshrn_s(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ gen_ushr_d(d, s, i);
+ gen_helper_neon_narrow_sat_u32(d, tcg_env, d);
+}
+
+static void gen_sqshrun_b(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ tcg_gen_sari_i64(d, s, i);
+ tcg_gen_ext16u_i64(d, d);
+ gen_helper_neon_unarrow_sat8(d, tcg_env, d);
+}
+
+static void gen_sqshrun_h(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ tcg_gen_sari_i64(d, s, i);
+ tcg_gen_ext32u_i64(d, d);
+ gen_helper_neon_unarrow_sat16(d, tcg_env, d);
+}
+
+static void gen_sqshrun_s(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ gen_sshr_d(d, s, i);
+ gen_helper_neon_unarrow_sat32(d, tcg_env, d);
+}
+
+static void gen_sqrshrn_b(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ gen_srshr_bhs(d, s, i);
+ tcg_gen_ext16u_i64(d, d);
+ gen_helper_neon_narrow_sat_s8(d, tcg_env, d);
+}
+
+static void gen_sqrshrn_h(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ gen_srshr_bhs(d, s, i);
+ tcg_gen_ext32u_i64(d, d);
+ gen_helper_neon_narrow_sat_s16(d, tcg_env, d);
+}
+
+static void gen_sqrshrn_s(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ gen_srshr_d(d, s, i);
+ gen_helper_neon_narrow_sat_s32(d, tcg_env, d);
+}
+
+static void gen_uqrshrn_b(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ gen_urshr_bhs(d, s, i);
+ gen_helper_neon_narrow_sat_u8(d, tcg_env, d);
+}
+
+static void gen_uqrshrn_h(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ gen_urshr_bhs(d, s, i);
+ gen_helper_neon_narrow_sat_u16(d, tcg_env, d);
+}
+
+static void gen_uqrshrn_s(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ gen_urshr_d(d, s, i);
+ gen_helper_neon_narrow_sat_u32(d, tcg_env, d);
+}
+
+static void gen_sqrshrun_b(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ gen_srshr_bhs(d, s, i);
+ tcg_gen_ext16u_i64(d, d);
+ gen_helper_neon_unarrow_sat8(d, tcg_env, d);
+}
+
+static void gen_sqrshrun_h(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ gen_srshr_bhs(d, s, i);
+ tcg_gen_ext32u_i64(d, d);
+ gen_helper_neon_unarrow_sat16(d, tcg_env, d);
+}
+
+static void gen_sqrshrun_s(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ gen_srshr_d(d, s, i);
+ gen_helper_neon_unarrow_sat32(d, tcg_env, d);
+}
+
+static WideShiftImmFn * const shrn_fns[] = {
+ tcg_gen_shri_i64,
+ tcg_gen_shri_i64,
+ gen_ushr_d,
+};
+TRANS(SHRN_v, do_vec_shift_imm_narrow, a, shrn_fns, 0)
+
+static WideShiftImmFn * const rshrn_fns[] = {
+ gen_urshr_bhs,
+ gen_urshr_bhs,
+ gen_urshr_d,
+};
+TRANS(RSHRN_v, do_vec_shift_imm_narrow, a, rshrn_fns, 0)
+
+static WideShiftImmFn * const sqshrn_fns[] = {
+ gen_sqshrn_b,
+ gen_sqshrn_h,
+ gen_sqshrn_s,
+};
+TRANS(SQSHRN_v, do_vec_shift_imm_narrow, a, sqshrn_fns, MO_SIGN)
+
+static WideShiftImmFn * const uqshrn_fns[] = {
+ gen_uqshrn_b,
+ gen_uqshrn_h,
+ gen_uqshrn_s,
+};
+TRANS(UQSHRN_v, do_vec_shift_imm_narrow, a, uqshrn_fns, 0)
+
+static WideShiftImmFn * const sqshrun_fns[] = {
+ gen_sqshrun_b,
+ gen_sqshrun_h,
+ gen_sqshrun_s,
+};
+TRANS(SQSHRUN_v, do_vec_shift_imm_narrow, a, sqshrun_fns, MO_SIGN)
+
+static WideShiftImmFn * const sqrshrn_fns[] = {
+ gen_sqrshrn_b,
+ gen_sqrshrn_h,
+ gen_sqrshrn_s,
+};
+TRANS(SQRSHRN_v, do_vec_shift_imm_narrow, a, sqrshrn_fns, MO_SIGN)
+
+static WideShiftImmFn * const uqrshrn_fns[] = {
+ gen_uqrshrn_b,
+ gen_uqrshrn_h,
+ gen_uqrshrn_s,
+};
+TRANS(UQRSHRN_v, do_vec_shift_imm_narrow, a, uqrshrn_fns, 0)
+
+static WideShiftImmFn * const sqrshrun_fns[] = {
+ gen_sqrshrun_b,
+ gen_sqrshrun_h,
+ gen_sqrshrun_s,
+};
+TRANS(SQRSHRUN_v, do_vec_shift_imm_narrow, a, sqrshrun_fns, MO_SIGN)
+
+/*
+ * Advanced SIMD Scalar Shift by Immediate
+ */
+
+static bool do_scalar_shift_imm(DisasContext *s, arg_rri_e *a,
+ WideShiftImmFn *fn, bool accumulate,
+ MemOp sign)
+{
+ if (fp_access_check(s)) {
+ TCGv_i64 rd = tcg_temp_new_i64();
+ TCGv_i64 rn = tcg_temp_new_i64();
+
+ read_vec_element(s, rn, a->rn, 0, a->esz | sign);
+ if (accumulate) {
+ read_vec_element(s, rd, a->rd, 0, a->esz | sign);
+ }
+ fn(rd, rn, a->imm);
+ write_fp_dreg(s, a->rd, rd);
+ }
+ return true;
+}
+
+TRANS(SSHR_s, do_scalar_shift_imm, a, gen_sshr_d, false, 0)
+TRANS(USHR_s, do_scalar_shift_imm, a, gen_ushr_d, false, 0)
+TRANS(SSRA_s, do_scalar_shift_imm, a, gen_ssra_d, true, 0)
+TRANS(USRA_s, do_scalar_shift_imm, a, gen_usra_d, true, 0)
+TRANS(SRSHR_s, do_scalar_shift_imm, a, gen_srshr_d, false, 0)
+TRANS(URSHR_s, do_scalar_shift_imm, a, gen_urshr_d, false, 0)
+TRANS(SRSRA_s, do_scalar_shift_imm, a, gen_srsra_d, true, 0)
+TRANS(URSRA_s, do_scalar_shift_imm, a, gen_ursra_d, true, 0)
+TRANS(SRI_s, do_scalar_shift_imm, a, gen_sri_d, true, 0)
+
+TRANS(SHL_s, do_scalar_shift_imm, a, tcg_gen_shli_i64, false, 0)
+TRANS(SLI_s, do_scalar_shift_imm, a, gen_sli_d, true, 0)
+
+static void trunc_i64_env_imm(TCGv_i64 d, TCGv_i64 s, int64_t i,
+ NeonGenTwoOpEnvFn *fn)
+{
+ TCGv_i32 t = tcg_temp_new_i32();
+ tcg_gen_extrl_i64_i32(t, s);
+ fn(t, tcg_env, t, tcg_constant_i32(i));
+ tcg_gen_extu_i32_i64(d, t);
+}
+
+static void gen_sqshli_b(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ trunc_i64_env_imm(d, s, i, gen_helper_neon_qshl_s8);
+}
+
+static void gen_sqshli_h(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ trunc_i64_env_imm(d, s, i, gen_helper_neon_qshl_s16);
+}
+
+static void gen_sqshli_s(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ trunc_i64_env_imm(d, s, i, gen_helper_neon_qshl_s32);
+}
+
+static void gen_sqshli_d(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ gen_helper_neon_qshl_s64(d, tcg_env, s, tcg_constant_i64(i));
+}
+
+static void gen_uqshli_b(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ trunc_i64_env_imm(d, s, i, gen_helper_neon_qshl_u8);
+}
+
+static void gen_uqshli_h(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ trunc_i64_env_imm(d, s, i, gen_helper_neon_qshl_u16);
+}
+
+static void gen_uqshli_s(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ trunc_i64_env_imm(d, s, i, gen_helper_neon_qshl_u32);
+}
+
+static void gen_uqshli_d(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ gen_helper_neon_qshl_u64(d, tcg_env, s, tcg_constant_i64(i));
+}
+
+static void gen_sqshlui_b(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ trunc_i64_env_imm(d, s, i, gen_helper_neon_qshlu_s8);
+}
+
+static void gen_sqshlui_h(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ trunc_i64_env_imm(d, s, i, gen_helper_neon_qshlu_s16);
+}
+
+static void gen_sqshlui_s(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ trunc_i64_env_imm(d, s, i, gen_helper_neon_qshlu_s32);
+}
+
+static void gen_sqshlui_d(TCGv_i64 d, TCGv_i64 s, int64_t i)
+{
+ gen_helper_neon_qshlu_s64(d, tcg_env, s, tcg_constant_i64(i));
+}
+
+static WideShiftImmFn * const f_scalar_sqshli[] = {
+ gen_sqshli_b, gen_sqshli_h, gen_sqshli_s, gen_sqshli_d
+};
+
+static WideShiftImmFn * const f_scalar_uqshli[] = {
+ gen_uqshli_b, gen_uqshli_h, gen_uqshli_s, gen_uqshli_d
+};
+
+static WideShiftImmFn * const f_scalar_sqshlui[] = {
+ gen_sqshlui_b, gen_sqshlui_h, gen_sqshlui_s, gen_sqshlui_d
+};
+
+/* Note that the helpers sign-extend their inputs, so don't do it here. */
+TRANS(SQSHL_si, do_scalar_shift_imm, a, f_scalar_sqshli[a->esz], false, 0)
+TRANS(UQSHL_si, do_scalar_shift_imm, a, f_scalar_uqshli[a->esz], false, 0)
+TRANS(SQSHLU_si, do_scalar_shift_imm, a, f_scalar_sqshlui[a->esz], false, 0)
+
+static bool do_scalar_shift_imm_narrow(DisasContext *s, arg_rri_e *a,
+ WideShiftImmFn * const fns[3],
+ MemOp sign, bool zext)
+{
+ MemOp esz = a->esz;
+
+ tcg_debug_assert(esz >= MO_8 && esz <= MO_32);
+
+ if (fp_access_check(s)) {
+ TCGv_i64 rd = tcg_temp_new_i64();
+ TCGv_i64 rn = tcg_temp_new_i64();
+
+ read_vec_element(s, rn, a->rn, 0, (esz + 1) | sign);
+ fns[esz](rd, rn, a->imm);
+ if (zext) {
+ tcg_gen_ext_i64(rd, rd, esz);
+ }
+ write_fp_dreg(s, a->rd, rd);
+ }
+ return true;
+}
+
+TRANS(SQSHRN_si, do_scalar_shift_imm_narrow, a, sqshrn_fns, MO_SIGN, true)
+TRANS(SQRSHRN_si, do_scalar_shift_imm_narrow, a, sqrshrn_fns, MO_SIGN, true)
+TRANS(UQSHRN_si, do_scalar_shift_imm_narrow, a, uqshrn_fns, 0, false)
+TRANS(UQRSHRN_si, do_scalar_shift_imm_narrow, a, uqrshrn_fns, 0, false)
+TRANS(SQSHRUN_si, do_scalar_shift_imm_narrow, a, sqshrun_fns, MO_SIGN, false)
+TRANS(SQRSHRUN_si, do_scalar_shift_imm_narrow, a, sqrshrun_fns, MO_SIGN, false)
+
/* Shift a TCGv src by TCGv shift_amount, put result in dst.
* Note that it is the caller's responsibility to ensure that the
* shift amount is in range (ie 0..31 or 0..63) and provide the ARM
@@ -8360,53 +9222,6 @@ static void disas_fp_1src(DisasContext *s, uint32_t insn)
}
}
-/* Floating point immediate
- * 31 30 29 28 24 23 22 21 20 13 12 10 9 5 4 0
- * +---+---+---+-----------+------+---+------------+-------+------+------+
- * | M | 0 | S | 1 1 1 1 0 | type | 1 | imm8 | 1 0 0 | imm5 | Rd |
- * +---+---+---+-----------+------+---+------------+-------+------+------+
- */
-static void disas_fp_imm(DisasContext *s, uint32_t insn)
-{
- int rd = extract32(insn, 0, 5);
- int imm5 = extract32(insn, 5, 5);
- int imm8 = extract32(insn, 13, 8);
- int type = extract32(insn, 22, 2);
- int mos = extract32(insn, 29, 3);
- uint64_t imm;
- MemOp sz;
-
- if (mos || imm5) {
- unallocated_encoding(s);
- return;
- }
-
- switch (type) {
- case 0:
- sz = MO_32;
- break;
- case 1:
- sz = MO_64;
- break;
- case 3:
- sz = MO_16;
- if (dc_isar_feature(aa64_fp16, s)) {
- break;
- }
- /* fallthru */
- default:
- unallocated_encoding(s);
- return;
- }
-
- if (!fp_access_check(s)) {
- return;
- }
-
- imm = vfp_expand_imm(sz, imm8);
- write_fp_dreg(s, rd, tcg_constant_i64(imm));
-}
-
/* Handle floating point <=> fixed point conversions. Note that we can
* also deal with fp <=> integer conversions as a special case (scale == 64)
* OPTME: consider handling that special case specially or at least skipping
@@ -8826,7 +9641,7 @@ static void disas_data_proc_fp(DisasContext *s, uint32_t insn)
switch (ctz32(extract32(insn, 12, 4))) {
case 0: /* [15:12] == xxx1 */
/* Floating point immediate */
- disas_fp_imm(s, insn);
+ unallocated_encoding(s); /* in decodetree */
break;
case 1: /* [15:12] == xx10 */
/* Floating point compare */
@@ -8849,874 +9664,6 @@ static void disas_data_proc_fp(DisasContext *s, uint32_t insn)
}
}
-static void do_ext64(DisasContext *s, TCGv_i64 tcg_left, TCGv_i64 tcg_right,
- int pos)
-{
- /* Extract 64 bits from the middle of two concatenated 64 bit
- * vector register slices left:right. The extracted bits start
- * at 'pos' bits into the right (least significant) side.
- * We return the result in tcg_right, and guarantee not to
- * trash tcg_left.
- */
- TCGv_i64 tcg_tmp = tcg_temp_new_i64();
- assert(pos > 0 && pos < 64);
-
- tcg_gen_shri_i64(tcg_right, tcg_right, pos);
- tcg_gen_shli_i64(tcg_tmp, tcg_left, 64 - pos);
- tcg_gen_or_i64(tcg_right, tcg_right, tcg_tmp);
-}
-
-/* EXT
- * 31 30 29 24 23 22 21 20 16 15 14 11 10 9 5 4 0
- * +---+---+-------------+-----+---+------+---+------+---+------+------+
- * | 0 | Q | 1 0 1 1 1 0 | op2 | 0 | Rm | 0 | imm4 | 0 | Rn | Rd |
- * +---+---+-------------+-----+---+------+---+------+---+------+------+
- */
-static void disas_simd_ext(DisasContext *s, uint32_t insn)
-{
- int is_q = extract32(insn, 30, 1);
- int op2 = extract32(insn, 22, 2);
- int imm4 = extract32(insn, 11, 4);
- int rm = extract32(insn, 16, 5);
- int rn = extract32(insn, 5, 5);
- int rd = extract32(insn, 0, 5);
- int pos = imm4 << 3;
- TCGv_i64 tcg_resl, tcg_resh;
-
- if (op2 != 0 || (!is_q && extract32(imm4, 3, 1))) {
- unallocated_encoding(s);
- return;
- }
-
- if (!fp_access_check(s)) {
- return;
- }
-
- tcg_resh = tcg_temp_new_i64();
- tcg_resl = tcg_temp_new_i64();
-
- /* Vd gets bits starting at pos bits into Vm:Vn. This is
- * either extracting 128 bits from a 128:128 concatenation, or
- * extracting 64 bits from a 64:64 concatenation.
- */
- if (!is_q) {
- read_vec_element(s, tcg_resl, rn, 0, MO_64);
- if (pos != 0) {
- read_vec_element(s, tcg_resh, rm, 0, MO_64);
- do_ext64(s, tcg_resh, tcg_resl, pos);
- }
- } else {
- TCGv_i64 tcg_hh;
- typedef struct {
- int reg;
- int elt;
- } EltPosns;
- EltPosns eltposns[] = { {rn, 0}, {rn, 1}, {rm, 0}, {rm, 1} };
- EltPosns *elt = eltposns;
-
- if (pos >= 64) {
- elt++;
- pos -= 64;
- }
-
- read_vec_element(s, tcg_resl, elt->reg, elt->elt, MO_64);
- elt++;
- read_vec_element(s, tcg_resh, elt->reg, elt->elt, MO_64);
- elt++;
- if (pos != 0) {
- do_ext64(s, tcg_resh, tcg_resl, pos);
- tcg_hh = tcg_temp_new_i64();
- read_vec_element(s, tcg_hh, elt->reg, elt->elt, MO_64);
- do_ext64(s, tcg_hh, tcg_resh, pos);
- }
- }
-
- write_vec_element(s, tcg_resl, rd, 0, MO_64);
- if (is_q) {
- write_vec_element(s, tcg_resh, rd, 1, MO_64);
- }
- clear_vec_high(s, is_q, rd);
-}
-
-/* TBL/TBX
- * 31 30 29 24 23 22 21 20 16 15 14 13 12 11 10 9 5 4 0
- * +---+---+-------------+-----+---+------+---+-----+----+-----+------+------+
- * | 0 | Q | 0 0 1 1 1 0 | op2 | 0 | Rm | 0 | len | op | 0 0 | Rn | Rd |
- * +---+---+-------------+-----+---+------+---+-----+----+-----+------+------+
- */
-static void disas_simd_tb(DisasContext *s, uint32_t insn)
-{
- int op2 = extract32(insn, 22, 2);
- int is_q = extract32(insn, 30, 1);
- int rm = extract32(insn, 16, 5);
- int rn = extract32(insn, 5, 5);
- int rd = extract32(insn, 0, 5);
- int is_tbx = extract32(insn, 12, 1);
- int len = (extract32(insn, 13, 2) + 1) * 16;
-
- if (op2 != 0) {
- unallocated_encoding(s);
- return;
- }
-
- if (!fp_access_check(s)) {
- return;
- }
-
- tcg_gen_gvec_2_ptr(vec_full_reg_offset(s, rd),
- vec_full_reg_offset(s, rm), tcg_env,
- is_q ? 16 : 8, vec_full_reg_size(s),
- (len << 6) | (is_tbx << 5) | rn,
- gen_helper_simd_tblx);
-}
-
-/* ZIP/UZP/TRN
- * 31 30 29 24 23 22 21 20 16 15 14 12 11 10 9 5 4 0
- * +---+---+-------------+------+---+------+---+------------------+------+
- * | 0 | Q | 0 0 1 1 1 0 | size | 0 | Rm | 0 | opc | 1 0 | Rn | Rd |
- * +---+---+-------------+------+---+------+---+------------------+------+
- */
-static void disas_simd_zip_trn(DisasContext *s, uint32_t insn)
-{
- int rd = extract32(insn, 0, 5);
- int rn = extract32(insn, 5, 5);
- int rm = extract32(insn, 16, 5);
- int size = extract32(insn, 22, 2);
- /* opc field bits [1:0] indicate ZIP/UZP/TRN;
- * bit 2 indicates 1 vs 2 variant of the insn.
- */
- int opcode = extract32(insn, 12, 2);
- bool part = extract32(insn, 14, 1);
- bool is_q = extract32(insn, 30, 1);
- int esize = 8 << size;
- int i;
- int datasize = is_q ? 128 : 64;
- int elements = datasize / esize;
- TCGv_i64 tcg_res[2], tcg_ele;
-
- if (opcode == 0 || (size == 3 && !is_q)) {
- unallocated_encoding(s);
- return;
- }
-
- if (!fp_access_check(s)) {
- return;
- }
-
- tcg_res[0] = tcg_temp_new_i64();
- tcg_res[1] = is_q ? tcg_temp_new_i64() : NULL;
- tcg_ele = tcg_temp_new_i64();
-
- for (i = 0; i < elements; i++) {
- int o, w;
-
- switch (opcode) {
- case 1: /* UZP1/2 */
- {
- int midpoint = elements / 2;
- if (i < midpoint) {
- read_vec_element(s, tcg_ele, rn, 2 * i + part, size);
- } else {
- read_vec_element(s, tcg_ele, rm,
- 2 * (i - midpoint) + part, size);
- }
- break;
- }
- case 2: /* TRN1/2 */
- if (i & 1) {
- read_vec_element(s, tcg_ele, rm, (i & ~1) + part, size);
- } else {
- read_vec_element(s, tcg_ele, rn, (i & ~1) + part, size);
- }
- break;
- case 3: /* ZIP1/2 */
- {
- int base = part * elements / 2;
- if (i & 1) {
- read_vec_element(s, tcg_ele, rm, base + (i >> 1), size);
- } else {
- read_vec_element(s, tcg_ele, rn, base + (i >> 1), size);
- }
- break;
- }
- default:
- g_assert_not_reached();
- }
-
- w = (i * esize) / 64;
- o = (i * esize) % 64;
- if (o == 0) {
- tcg_gen_mov_i64(tcg_res[w], tcg_ele);
- } else {
- tcg_gen_shli_i64(tcg_ele, tcg_ele, o);
- tcg_gen_or_i64(tcg_res[w], tcg_res[w], tcg_ele);
- }
- }
-
- for (i = 0; i <= is_q; ++i) {
- write_vec_element(s, tcg_res[i], rd, i, MO_64);
- }
- clear_vec_high(s, is_q, rd);
-}
-
-/*
- * do_reduction_op helper
- *
- * This mirrors the Reduce() pseudocode in the ARM ARM. It is
- * important for correct NaN propagation that we do these
- * operations in exactly the order specified by the pseudocode.
- *
- * This is a recursive function, TCG temps should be freed by the
- * calling function once it is done with the values.
- */
-static TCGv_i32 do_reduction_op(DisasContext *s, int fpopcode, int rn,
- int esize, int size, int vmap, TCGv_ptr fpst)
-{
- if (esize == size) {
- int element;
- MemOp msize = esize == 16 ? MO_16 : MO_32;
- TCGv_i32 tcg_elem;
-
- /* We should have one register left here */
- assert(ctpop8(vmap) == 1);
- element = ctz32(vmap);
- assert(element < 8);
-
- tcg_elem = tcg_temp_new_i32();
- read_vec_element_i32(s, tcg_elem, rn, element, msize);
- return tcg_elem;
- } else {
- int bits = size / 2;
- int shift = ctpop8(vmap) / 2;
- int vmap_lo = (vmap >> shift) & vmap;
- int vmap_hi = (vmap & ~vmap_lo);
- TCGv_i32 tcg_hi, tcg_lo, tcg_res;
-
- tcg_hi = do_reduction_op(s, fpopcode, rn, esize, bits, vmap_hi, fpst);
- tcg_lo = do_reduction_op(s, fpopcode, rn, esize, bits, vmap_lo, fpst);
- tcg_res = tcg_temp_new_i32();
-
- switch (fpopcode) {
- case 0x0c: /* fmaxnmv half-precision */
- gen_helper_advsimd_maxnumh(tcg_res, tcg_lo, tcg_hi, fpst);
- break;
- case 0x0f: /* fmaxv half-precision */
- gen_helper_advsimd_maxh(tcg_res, tcg_lo, tcg_hi, fpst);
- break;
- case 0x1c: /* fminnmv half-precision */
- gen_helper_advsimd_minnumh(tcg_res, tcg_lo, tcg_hi, fpst);
- break;
- case 0x1f: /* fminv half-precision */
- gen_helper_advsimd_minh(tcg_res, tcg_lo, tcg_hi, fpst);
- break;
- case 0x2c: /* fmaxnmv */
- gen_helper_vfp_maxnums(tcg_res, tcg_lo, tcg_hi, fpst);
- break;
- case 0x2f: /* fmaxv */
- gen_helper_vfp_maxs(tcg_res, tcg_lo, tcg_hi, fpst);
- break;
- case 0x3c: /* fminnmv */
- gen_helper_vfp_minnums(tcg_res, tcg_lo, tcg_hi, fpst);
- break;
- case 0x3f: /* fminv */
- gen_helper_vfp_mins(tcg_res, tcg_lo, tcg_hi, fpst);
- break;
- default:
- g_assert_not_reached();
- }
- return tcg_res;
- }
-}
-
-/* AdvSIMD across lanes
- * 31 30 29 28 24 23 22 21 17 16 12 11 10 9 5 4 0
- * +---+---+---+-----------+------+-----------+--------+-----+------+------+
- * | 0 | Q | U | 0 1 1 1 0 | size | 1 1 0 0 0 | opcode | 1 0 | Rn | Rd |
- * +---+---+---+-----------+------+-----------+--------+-----+------+------+
- */
-static void disas_simd_across_lanes(DisasContext *s, uint32_t insn)
-{
- int rd = extract32(insn, 0, 5);
- int rn = extract32(insn, 5, 5);
- int size = extract32(insn, 22, 2);
- int opcode = extract32(insn, 12, 5);
- bool is_q = extract32(insn, 30, 1);
- bool is_u = extract32(insn, 29, 1);
- bool is_fp = false;
- bool is_min = false;
- int esize;
- int elements;
- int i;
- TCGv_i64 tcg_res, tcg_elt;
-
- switch (opcode) {
- case 0x1b: /* ADDV */
- if (is_u) {
- unallocated_encoding(s);
- return;
- }
- /* fall through */
- case 0x3: /* SADDLV, UADDLV */
- case 0xa: /* SMAXV, UMAXV */
- case 0x1a: /* SMINV, UMINV */
- if (size == 3 || (size == 2 && !is_q)) {
- unallocated_encoding(s);
- return;
- }
- break;
- case 0xc: /* FMAXNMV, FMINNMV */
- case 0xf: /* FMAXV, FMINV */
- /* Bit 1 of size field encodes min vs max and the actual size
- * depends on the encoding of the U bit. If not set (and FP16
- * enabled) then we do half-precision float instead of single
- * precision.
- */
- is_min = extract32(size, 1, 1);
- is_fp = true;
- if (!is_u && dc_isar_feature(aa64_fp16, s)) {
- size = 1;
- } else if (!is_u || !is_q || extract32(size, 0, 1)) {
- unallocated_encoding(s);
- return;
- } else {
- size = 2;
- }
- break;
- default:
- unallocated_encoding(s);
- return;
- }
-
- if (!fp_access_check(s)) {
- return;
- }
-
- esize = 8 << size;
- elements = (is_q ? 128 : 64) / esize;
-
- tcg_res = tcg_temp_new_i64();
- tcg_elt = tcg_temp_new_i64();
-
- /* These instructions operate across all lanes of a vector
- * to produce a single result. We can guarantee that a 64
- * bit intermediate is sufficient:
- * + for [US]ADDLV the maximum element size is 32 bits, and
- * the result type is 64 bits
- * + for FMAX*V, FMIN*V, ADDV the intermediate type is the
- * same as the element size, which is 32 bits at most
- * For the integer operations we can choose to work at 64
- * or 32 bits and truncate at the end; for simplicity
- * we use 64 bits always. The floating point
- * ops do require 32 bit intermediates, though.
- */
- if (!is_fp) {
- read_vec_element(s, tcg_res, rn, 0, size | (is_u ? 0 : MO_SIGN));
-
- for (i = 1; i < elements; i++) {
- read_vec_element(s, tcg_elt, rn, i, size | (is_u ? 0 : MO_SIGN));
-
- switch (opcode) {
- case 0x03: /* SADDLV / UADDLV */
- case 0x1b: /* ADDV */
- tcg_gen_add_i64(tcg_res, tcg_res, tcg_elt);
- break;
- case 0x0a: /* SMAXV / UMAXV */
- if (is_u) {
- tcg_gen_umax_i64(tcg_res, tcg_res, tcg_elt);
- } else {
- tcg_gen_smax_i64(tcg_res, tcg_res, tcg_elt);
- }
- break;
- case 0x1a: /* SMINV / UMINV */
- if (is_u) {
- tcg_gen_umin_i64(tcg_res, tcg_res, tcg_elt);
- } else {
- tcg_gen_smin_i64(tcg_res, tcg_res, tcg_elt);
- }
- break;
- default:
- g_assert_not_reached();
- }
-
- }
- } else {
- /* Floating point vector reduction ops which work across 32
- * bit (single) or 16 bit (half-precision) intermediates.
- * Note that correct NaN propagation requires that we do these
- * operations in exactly the order specified by the pseudocode.
- */
- TCGv_ptr fpst = fpstatus_ptr(size == MO_16 ? FPST_FPCR_F16 : FPST_FPCR);
- int fpopcode = opcode | is_min << 4 | is_u << 5;
- int vmap = (1 << elements) - 1;
- TCGv_i32 tcg_res32 = do_reduction_op(s, fpopcode, rn, esize,
- (is_q ? 128 : 64), vmap, fpst);
- tcg_gen_extu_i32_i64(tcg_res, tcg_res32);
- }
-
- /* Now truncate the result to the width required for the final output */
- if (opcode == 0x03) {
- /* SADDLV, UADDLV: result is 2*esize */
- size++;
- }
-
- switch (size) {
- case 0:
- tcg_gen_ext8u_i64(tcg_res, tcg_res);
- break;
- case 1:
- tcg_gen_ext16u_i64(tcg_res, tcg_res);
- break;
- case 2:
- tcg_gen_ext32u_i64(tcg_res, tcg_res);
- break;
- case 3:
- break;
- default:
- g_assert_not_reached();
- }
-
- write_fp_dreg(s, rd, tcg_res);
-}
-
-/* AdvSIMD modified immediate
- * 31 30 29 28 19 18 16 15 12 11 10 9 5 4 0
- * +---+---+----+---------------------+-----+-------+----+---+-------+------+
- * | 0 | Q | op | 0 1 1 1 1 0 0 0 0 0 | abc | cmode | o2 | 1 | defgh | Rd |
- * +---+---+----+---------------------+-----+-------+----+---+-------+------+
- *
- * There are a number of operations that can be carried out here:
- * MOVI - move (shifted) imm into register
- * MVNI - move inverted (shifted) imm into register
- * ORR - bitwise OR of (shifted) imm with register
- * BIC - bitwise clear of (shifted) imm with register
- * With ARMv8.2 we also have:
- * FMOV half-precision
- */
-static void disas_simd_mod_imm(DisasContext *s, uint32_t insn)
-{
- int rd = extract32(insn, 0, 5);
- int cmode = extract32(insn, 12, 4);
- int o2 = extract32(insn, 11, 1);
- uint64_t abcdefgh = extract32(insn, 5, 5) | (extract32(insn, 16, 3) << 5);
- bool is_neg = extract32(insn, 29, 1);
- bool is_q = extract32(insn, 30, 1);
- uint64_t imm = 0;
-
- if (o2) {
- if (cmode != 0xf || is_neg) {
- unallocated_encoding(s);
- return;
- }
- /* FMOV (vector, immediate) - half-precision */
- if (!dc_isar_feature(aa64_fp16, s)) {
- unallocated_encoding(s);
- return;
- }
- imm = vfp_expand_imm(MO_16, abcdefgh);
- /* now duplicate across the lanes */
- imm = dup_const(MO_16, imm);
- } else {
- if (cmode == 0xf && is_neg && !is_q) {
- unallocated_encoding(s);
- return;
- }
- imm = asimd_imm_const(abcdefgh, cmode, is_neg);
- }
-
- if (!fp_access_check(s)) {
- return;
- }
-
- if (!((cmode & 0x9) == 0x1 || (cmode & 0xd) == 0x9)) {
- /* MOVI or MVNI, with MVNI negation handled above. */
- tcg_gen_gvec_dup_imm(MO_64, vec_full_reg_offset(s, rd), is_q ? 16 : 8,
- vec_full_reg_size(s), imm);
- } else {
- /* ORR or BIC, with BIC negation to AND handled above. */
- if (is_neg) {
- gen_gvec_fn2i(s, is_q, rd, rd, imm, tcg_gen_gvec_andi, MO_64);
- } else {
- gen_gvec_fn2i(s, is_q, rd, rd, imm, tcg_gen_gvec_ori, MO_64);
- }
- }
-}
-
-/*
- * Common SSHR[RA]/USHR[RA] - Shift right (optional rounding/accumulate)
- *
- * This code is handles the common shifting code and is used by both
- * the vector and scalar code.
- */
-static void handle_shri_with_rndacc(TCGv_i64 tcg_res, TCGv_i64 tcg_src,
- TCGv_i64 tcg_rnd, bool accumulate,
- bool is_u, int size, int shift)
-{
- bool extended_result = false;
- bool round = tcg_rnd != NULL;
- int ext_lshift = 0;
- TCGv_i64 tcg_src_hi;
-
- if (round && size == 3) {
- extended_result = true;
- ext_lshift = 64 - shift;
- tcg_src_hi = tcg_temp_new_i64();
- } else if (shift == 64) {
- if (!accumulate && is_u) {
- /* result is zero */
- tcg_gen_movi_i64(tcg_res, 0);
- return;
- }
- }
-
- /* Deal with the rounding step */
- if (round) {
- if (extended_result) {
- TCGv_i64 tcg_zero = tcg_constant_i64(0);
- if (!is_u) {
- /* take care of sign extending tcg_res */
- tcg_gen_sari_i64(tcg_src_hi, tcg_src, 63);
- tcg_gen_add2_i64(tcg_src, tcg_src_hi,
- tcg_src, tcg_src_hi,
- tcg_rnd, tcg_zero);
- } else {
- tcg_gen_add2_i64(tcg_src, tcg_src_hi,
- tcg_src, tcg_zero,
- tcg_rnd, tcg_zero);
- }
- } else {
- tcg_gen_add_i64(tcg_src, tcg_src, tcg_rnd);
- }
- }
-
- /* Now do the shift right */
- if (round && extended_result) {
- /* extended case, >64 bit precision required */
- if (ext_lshift == 0) {
- /* special case, only high bits matter */
- tcg_gen_mov_i64(tcg_src, tcg_src_hi);
- } else {
- tcg_gen_shri_i64(tcg_src, tcg_src, shift);
- tcg_gen_shli_i64(tcg_src_hi, tcg_src_hi, ext_lshift);
- tcg_gen_or_i64(tcg_src, tcg_src, tcg_src_hi);
- }
- } else {
- if (is_u) {
- if (shift == 64) {
- /* essentially shifting in 64 zeros */
- tcg_gen_movi_i64(tcg_src, 0);
- } else {
- tcg_gen_shri_i64(tcg_src, tcg_src, shift);
- }
- } else {
- if (shift == 64) {
- /* effectively extending the sign-bit */
- tcg_gen_sari_i64(tcg_src, tcg_src, 63);
- } else {
- tcg_gen_sari_i64(tcg_src, tcg_src, shift);
- }
- }
- }
-
- if (accumulate) {
- tcg_gen_add_i64(tcg_res, tcg_res, tcg_src);
- } else {
- tcg_gen_mov_i64(tcg_res, tcg_src);
- }
-}
-
-/* SSHR[RA]/USHR[RA] - Scalar shift right (optional rounding/accumulate) */
-static void handle_scalar_simd_shri(DisasContext *s,
- bool is_u, int immh, int immb,
- int opcode, int rn, int rd)
-{
- const int size = 3;
- int immhb = immh << 3 | immb;
- int shift = 2 * (8 << size) - immhb;
- bool accumulate = false;
- bool round = false;
- bool insert = false;
- TCGv_i64 tcg_rn;
- TCGv_i64 tcg_rd;
- TCGv_i64 tcg_round;
-
- if (!extract32(immh, 3, 1)) {
- unallocated_encoding(s);
- return;
- }
-
- if (!fp_access_check(s)) {
- return;
- }
-
- switch (opcode) {
- case 0x02: /* SSRA / USRA (accumulate) */
- accumulate = true;
- break;
- case 0x04: /* SRSHR / URSHR (rounding) */
- round = true;
- break;
- case 0x06: /* SRSRA / URSRA (accum + rounding) */
- accumulate = round = true;
- break;
- case 0x08: /* SRI */
- insert = true;
- break;
- }
-
- if (round) {
- tcg_round = tcg_constant_i64(1ULL << (shift - 1));
- } else {
- tcg_round = NULL;
- }
-
- tcg_rn = read_fp_dreg(s, rn);
- tcg_rd = (accumulate || insert) ? read_fp_dreg(s, rd) : tcg_temp_new_i64();
-
- if (insert) {
- /* shift count same as element size is valid but does nothing;
- * special case to avoid potential shift by 64.
- */
- int esize = 8 << size;
- if (shift != esize) {
- tcg_gen_shri_i64(tcg_rn, tcg_rn, shift);
- tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_rn, 0, esize - shift);
- }
- } else {
- handle_shri_with_rndacc(tcg_rd, tcg_rn, tcg_round,
- accumulate, is_u, size, shift);
- }
-
- write_fp_dreg(s, rd, tcg_rd);
-}
-
-/* SHL/SLI - Scalar shift left */
-static void handle_scalar_simd_shli(DisasContext *s, bool insert,
- int immh, int immb, int opcode,
- int rn, int rd)
-{
- int size = 32 - clz32(immh) - 1;
- int immhb = immh << 3 | immb;
- int shift = immhb - (8 << size);
- TCGv_i64 tcg_rn;
- TCGv_i64 tcg_rd;
-
- if (!extract32(immh, 3, 1)) {
- unallocated_encoding(s);
- return;
- }
-
- if (!fp_access_check(s)) {
- return;
- }
-
- tcg_rn = read_fp_dreg(s, rn);
- tcg_rd = insert ? read_fp_dreg(s, rd) : tcg_temp_new_i64();
-
- if (insert) {
- tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_rn, shift, 64 - shift);
- } else {
- tcg_gen_shli_i64(tcg_rd, tcg_rn, shift);
- }
-
- write_fp_dreg(s, rd, tcg_rd);
-}
-
-/* SQSHRN/SQSHRUN - Saturating (signed/unsigned) shift right with
- * (signed/unsigned) narrowing */
-static void handle_vec_simd_sqshrn(DisasContext *s, bool is_scalar, bool is_q,
- bool is_u_shift, bool is_u_narrow,
- int immh, int immb, int opcode,
- int rn, int rd)
-{
- int immhb = immh << 3 | immb;
- int size = 32 - clz32(immh) - 1;
- int esize = 8 << size;
- int shift = (2 * esize) - immhb;
- int elements = is_scalar ? 1 : (64 / esize);
- bool round = extract32(opcode, 0, 1);
- MemOp ldop = (size + 1) | (is_u_shift ? 0 : MO_SIGN);
- TCGv_i64 tcg_rn, tcg_rd, tcg_round;
- TCGv_i32 tcg_rd_narrowed;
- TCGv_i64 tcg_final;
-
- static NeonGenNarrowEnvFn * const signed_narrow_fns[4][2] = {
- { gen_helper_neon_narrow_sat_s8,
- gen_helper_neon_unarrow_sat8 },
- { gen_helper_neon_narrow_sat_s16,
- gen_helper_neon_unarrow_sat16 },
- { gen_helper_neon_narrow_sat_s32,
- gen_helper_neon_unarrow_sat32 },
- { NULL, NULL },
- };
- static NeonGenNarrowEnvFn * const unsigned_narrow_fns[4] = {
- gen_helper_neon_narrow_sat_u8,
- gen_helper_neon_narrow_sat_u16,
- gen_helper_neon_narrow_sat_u32,
- NULL
- };
- NeonGenNarrowEnvFn *narrowfn;
-
- int i;
-
- assert(size < 4);
-
- if (extract32(immh, 3, 1)) {
- unallocated_encoding(s);
- return;
- }
-
- if (!fp_access_check(s)) {
- return;
- }
-
- if (is_u_shift) {
- narrowfn = unsigned_narrow_fns[size];
- } else {
- narrowfn = signed_narrow_fns[size][is_u_narrow ? 1 : 0];
- }
-
- tcg_rn = tcg_temp_new_i64();
- tcg_rd = tcg_temp_new_i64();
- tcg_rd_narrowed = tcg_temp_new_i32();
- tcg_final = tcg_temp_new_i64();
-
- if (round) {
- tcg_round = tcg_constant_i64(1ULL << (shift - 1));
- } else {
- tcg_round = NULL;
- }
-
- for (i = 0; i < elements; i++) {
- read_vec_element(s, tcg_rn, rn, i, ldop);
- handle_shri_with_rndacc(tcg_rd, tcg_rn, tcg_round,
- false, is_u_shift, size+1, shift);
- narrowfn(tcg_rd_narrowed, tcg_env, tcg_rd);
- tcg_gen_extu_i32_i64(tcg_rd, tcg_rd_narrowed);
- if (i == 0) {
- tcg_gen_extract_i64(tcg_final, tcg_rd, 0, esize);
- } else {
- tcg_gen_deposit_i64(tcg_final, tcg_final, tcg_rd, esize * i, esize);
- }
- }
-
- if (!is_q) {
- write_vec_element(s, tcg_final, rd, 0, MO_64);
- } else {
- write_vec_element(s, tcg_final, rd, 1, MO_64);
- }
- clear_vec_high(s, is_q, rd);
-}
-
-/* SQSHLU, UQSHL, SQSHL: saturating left shifts */
-static void handle_simd_qshl(DisasContext *s, bool scalar, bool is_q,
- bool src_unsigned, bool dst_unsigned,
- int immh, int immb, int rn, int rd)
-{
- int immhb = immh << 3 | immb;
- int size = 32 - clz32(immh) - 1;
- int shift = immhb - (8 << size);
- int pass;
-
- assert(immh != 0);
- assert(!(scalar && is_q));
-
- if (!scalar) {
- if (!is_q && extract32(immh, 3, 1)) {
- unallocated_encoding(s);
- return;
- }
-
- /* Since we use the variable-shift helpers we must
- * replicate the shift count into each element of
- * the tcg_shift value.
- */
- switch (size) {
- case 0:
- shift |= shift << 8;
- /* fall through */
- case 1:
- shift |= shift << 16;
- break;
- case 2:
- case 3:
- break;
- default:
- g_assert_not_reached();
- }
- }
-
- if (!fp_access_check(s)) {
- return;
- }
-
- if (size == 3) {
- TCGv_i64 tcg_shift = tcg_constant_i64(shift);
- static NeonGenTwo64OpEnvFn * const fns[2][2] = {
- { gen_helper_neon_qshl_s64, gen_helper_neon_qshlu_s64 },
- { NULL, gen_helper_neon_qshl_u64 },
- };
- NeonGenTwo64OpEnvFn *genfn = fns[src_unsigned][dst_unsigned];
- int maxpass = is_q ? 2 : 1;
-
- for (pass = 0; pass < maxpass; pass++) {
- TCGv_i64 tcg_op = tcg_temp_new_i64();
-
- read_vec_element(s, tcg_op, rn, pass, MO_64);
- genfn(tcg_op, tcg_env, tcg_op, tcg_shift);
- write_vec_element(s, tcg_op, rd, pass, MO_64);
- }
- clear_vec_high(s, is_q, rd);
- } else {
- TCGv_i32 tcg_shift = tcg_constant_i32(shift);
- static NeonGenTwoOpEnvFn * const fns[2][2][3] = {
- {
- { gen_helper_neon_qshl_s8,
- gen_helper_neon_qshl_s16,
- gen_helper_neon_qshl_s32 },
- { gen_helper_neon_qshlu_s8,
- gen_helper_neon_qshlu_s16,
- gen_helper_neon_qshlu_s32 }
- }, {
- { NULL, NULL, NULL },
- { gen_helper_neon_qshl_u8,
- gen_helper_neon_qshl_u16,
- gen_helper_neon_qshl_u32 }
- }
- };
- NeonGenTwoOpEnvFn *genfn = fns[src_unsigned][dst_unsigned][size];
- MemOp memop = scalar ? size : MO_32;
- int maxpass = scalar ? 1 : is_q ? 4 : 2;
-
- for (pass = 0; pass < maxpass; pass++) {
- TCGv_i32 tcg_op = tcg_temp_new_i32();
-
- read_vec_element_i32(s, tcg_op, rn, pass, memop);
- genfn(tcg_op, tcg_env, tcg_op, tcg_shift);
- if (scalar) {
- switch (size) {
- case 0:
- tcg_gen_ext8u_i32(tcg_op, tcg_op);
- break;
- case 1:
- tcg_gen_ext16u_i32(tcg_op, tcg_op);
- break;
- case 2:
- break;
- default:
- g_assert_not_reached();
- }
- write_fp_sreg(s, rd, tcg_op);
- } else {
- write_vec_element_i32(s, tcg_op, rd, pass, MO_32);
- }
- }
-
- if (!scalar) {
- clear_vec_high(s, is_q, rd);
- }
- }
-}
-
/* Common vector code for handling integer to FP conversion */
static void handle_simd_intfp_conv(DisasContext *s, int rd, int rn,
int elements, int is_signed,
@@ -9978,53 +9925,26 @@ static void disas_simd_scalar_shift_imm(DisasContext *s, uint32_t insn)
}
switch (opcode) {
- case 0x08: /* SRI */
- if (!is_u) {
- unallocated_encoding(s);
- return;
- }
- /* fall through */
- case 0x00: /* SSHR / USHR */
- case 0x02: /* SSRA / USRA */
- case 0x04: /* SRSHR / URSHR */
- case 0x06: /* SRSRA / URSRA */
- handle_scalar_simd_shri(s, is_u, immh, immb, opcode, rn, rd);
- break;
- case 0x0a: /* SHL / SLI */
- handle_scalar_simd_shli(s, is_u, immh, immb, opcode, rn, rd);
- break;
case 0x1c: /* SCVTF, UCVTF */
handle_simd_shift_intfp_conv(s, true, false, is_u, immh, immb,
opcode, rn, rd);
break;
- case 0x10: /* SQSHRUN, SQSHRUN2 */
- case 0x11: /* SQRSHRUN, SQRSHRUN2 */
- if (!is_u) {
- unallocated_encoding(s);
- return;
- }
- handle_vec_simd_sqshrn(s, true, false, false, true,
- immh, immb, opcode, rn, rd);
- break;
- case 0x12: /* SQSHRN, SQSHRN2, UQSHRN */
- case 0x13: /* SQRSHRN, SQRSHRN2, UQRSHRN, UQRSHRN2 */
- handle_vec_simd_sqshrn(s, true, false, is_u, is_u,
- immh, immb, opcode, rn, rd);
- break;
- case 0xc: /* SQSHLU */
- if (!is_u) {
- unallocated_encoding(s);
- return;
- }
- handle_simd_qshl(s, true, false, false, true, immh, immb, rn, rd);
- break;
- case 0xe: /* SQSHL, UQSHL */
- handle_simd_qshl(s, true, false, is_u, is_u, immh, immb, rn, rd);
- break;
case 0x1f: /* FCVTZS, FCVTZU */
handle_simd_shift_fpint_conv(s, true, false, is_u, immh, immb, rn, rd);
break;
default:
+ case 0x00: /* SSHR / USHR */
+ case 0x02: /* SSRA / USRA */
+ case 0x04: /* SRSHR / URSHR */
+ case 0x06: /* SRSRA / URSRA */
+ case 0x08: /* SRI */
+ case 0x0a: /* SHL / SLI */
+ case 0x0c: /* SQSHLU */
+ case 0x0e: /* SQSHL, UQSHL */
+ case 0x10: /* SQSHRUN */
+ case 0x11: /* SQRSHRUN */
+ case 0x12: /* SQSHRN, UQSHRN */
+ case 0x13: /* SQRSHRN, UQRSHRN */
unallocated_encoding(s);
break;
}
@@ -10339,35 +10259,35 @@ static void handle_2misc_narrow(DisasContext *s, bool scalar,
* in the source becomes a size element in the destination).
*/
int pass;
- TCGv_i32 tcg_res[2];
+ TCGv_i64 tcg_res[2];
int destelt = is_q ? 2 : 0;
int passes = scalar ? 1 : 2;
if (scalar) {
- tcg_res[1] = tcg_constant_i32(0);
+ tcg_res[1] = tcg_constant_i64(0);
}
for (pass = 0; pass < passes; pass++) {
TCGv_i64 tcg_op = tcg_temp_new_i64();
- NeonGenNarrowFn *genfn = NULL;
- NeonGenNarrowEnvFn *genenvfn = NULL;
+ NeonGenOne64OpFn *genfn = NULL;
+ NeonGenOne64OpEnvFn *genenvfn = NULL;
if (scalar) {
read_vec_element(s, tcg_op, rn, pass, size + 1);
} else {
read_vec_element(s, tcg_op, rn, pass, MO_64);
}
- tcg_res[pass] = tcg_temp_new_i32();
+ tcg_res[pass] = tcg_temp_new_i64();
switch (opcode) {
case 0x12: /* XTN, SQXTUN */
{
- static NeonGenNarrowFn * const xtnfns[3] = {
+ static NeonGenOne64OpFn * const xtnfns[3] = {
gen_helper_neon_narrow_u8,
gen_helper_neon_narrow_u16,
- tcg_gen_extrl_i64_i32,
+ tcg_gen_ext32u_i64,
};
- static NeonGenNarrowEnvFn * const sqxtunfns[3] = {
+ static NeonGenOne64OpEnvFn * const sqxtunfns[3] = {
gen_helper_neon_unarrow_sat8,
gen_helper_neon_unarrow_sat16,
gen_helper_neon_unarrow_sat32,
@@ -10381,7 +10301,7 @@ static void handle_2misc_narrow(DisasContext *s, bool scalar,
}
case 0x14: /* SQXTN, UQXTN */
{
- static NeonGenNarrowEnvFn * const fns[3][2] = {
+ static NeonGenOne64OpEnvFn * const fns[3][2] = {
{ gen_helper_neon_narrow_sat_s8,
gen_helper_neon_narrow_sat_u8 },
{ gen_helper_neon_narrow_sat_s16,
@@ -10395,7 +10315,9 @@ static void handle_2misc_narrow(DisasContext *s, bool scalar,
case 0x16: /* FCVTN, FCVTN2 */
/* 32 bit to 16 bit or 64 bit to 32 bit float conversion */
if (size == 2) {
- gen_helper_vfp_fcvtsd(tcg_res[pass], tcg_op, tcg_env);
+ TCGv_i32 tmp = tcg_temp_new_i32();
+ gen_helper_vfp_fcvtsd(tmp, tcg_op, tcg_env);
+ tcg_gen_extu_i32_i64(tcg_res[pass], tmp);
} else {
TCGv_i32 tcg_lo = tcg_temp_new_i32();
TCGv_i32 tcg_hi = tcg_temp_new_i32();
@@ -10405,21 +10327,29 @@ static void handle_2misc_narrow(DisasContext *s, bool scalar,
tcg_gen_extr_i64_i32(tcg_lo, tcg_hi, tcg_op);
gen_helper_vfp_fcvt_f32_to_f16(tcg_lo, tcg_lo, fpst, ahp);
gen_helper_vfp_fcvt_f32_to_f16(tcg_hi, tcg_hi, fpst, ahp);
- tcg_gen_deposit_i32(tcg_res[pass], tcg_lo, tcg_hi, 16, 16);
+ tcg_gen_deposit_i32(tcg_lo, tcg_lo, tcg_hi, 16, 16);
+ tcg_gen_extu_i32_i64(tcg_res[pass], tcg_lo);
}
break;
case 0x36: /* BFCVTN, BFCVTN2 */
{
TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR);
- gen_helper_bfcvt_pair(tcg_res[pass], tcg_op, fpst);
+ TCGv_i32 tmp = tcg_temp_new_i32();
+ gen_helper_bfcvt_pair(tmp, tcg_op, fpst);
+ tcg_gen_extu_i32_i64(tcg_res[pass], tmp);
}
break;
case 0x56: /* FCVTXN, FCVTXN2 */
- /* 64 bit to 32 bit float conversion
- * with von Neumann rounding (round to odd)
- */
- assert(size == 2);
- gen_helper_fcvtx_f64_to_f32(tcg_res[pass], tcg_op, tcg_env);
+ {
+ /*
+ * 64 bit to 32 bit float conversion
+ * with von Neumann rounding (round to odd)
+ */
+ TCGv_i32 tmp = tcg_temp_new_i32();
+ assert(size == 2);
+ gen_helper_fcvtx_f64_to_f32(tmp, tcg_op, tcg_env);
+ tcg_gen_extu_i32_i64(tcg_res[pass], tmp);
+ }
break;
default:
g_assert_not_reached();
@@ -10433,7 +10363,7 @@ static void handle_2misc_narrow(DisasContext *s, bool scalar,
}
for (pass = 0; pass < 2; pass++) {
- write_vec_element_i32(s, tcg_res[pass], rd, destelt + pass, MO_32);
+ write_vec_element(s, tcg_res[pass], rd, destelt + pass, MO_32);
}
clear_vec_high(s, is_q, rd);
}
@@ -10626,184 +10556,6 @@ static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn)
}
}
-/* SSHR[RA]/USHR[RA] - Vector shift right (optional rounding/accumulate) */
-static void handle_vec_simd_shri(DisasContext *s, bool is_q, bool is_u,
- int immh, int immb, int opcode, int rn, int rd)
-{
- int size = 32 - clz32(immh) - 1;
- int immhb = immh << 3 | immb;
- int shift = 2 * (8 << size) - immhb;
- GVecGen2iFn *gvec_fn;
-
- if (extract32(immh, 3, 1) && !is_q) {
- unallocated_encoding(s);
- return;
- }
- tcg_debug_assert(size <= 3);
-
- if (!fp_access_check(s)) {
- return;
- }
-
- switch (opcode) {
- case 0x02: /* SSRA / USRA (accumulate) */
- gvec_fn = is_u ? gen_gvec_usra : gen_gvec_ssra;
- break;
-
- case 0x08: /* SRI */
- gvec_fn = gen_gvec_sri;
- break;
-
- case 0x00: /* SSHR / USHR */
- if (is_u) {
- if (shift == 8 << size) {
- /* Shift count the same size as element size produces zero. */
- tcg_gen_gvec_dup_imm(size, vec_full_reg_offset(s, rd),
- is_q ? 16 : 8, vec_full_reg_size(s), 0);
- return;
- }
- gvec_fn = tcg_gen_gvec_shri;
- } else {
- /* Shift count the same size as element size produces all sign. */
- if (shift == 8 << size) {
- shift -= 1;
- }
- gvec_fn = tcg_gen_gvec_sari;
- }
- break;
-
- case 0x04: /* SRSHR / URSHR (rounding) */
- gvec_fn = is_u ? gen_gvec_urshr : gen_gvec_srshr;
- break;
-
- case 0x06: /* SRSRA / URSRA (accum + rounding) */
- gvec_fn = is_u ? gen_gvec_ursra : gen_gvec_srsra;
- break;
-
- default:
- g_assert_not_reached();
- }
-
- gen_gvec_fn2i(s, is_q, rd, rn, shift, gvec_fn, size);
-}
-
-/* SHL/SLI - Vector shift left */
-static void handle_vec_simd_shli(DisasContext *s, bool is_q, bool insert,
- int immh, int immb, int opcode, int rn, int rd)
-{
- int size = 32 - clz32(immh) - 1;
- int immhb = immh << 3 | immb;
- int shift = immhb - (8 << size);
-
- /* Range of size is limited by decode: immh is a non-zero 4 bit field */
- assert(size >= 0 && size <= 3);
-
- if (extract32(immh, 3, 1) && !is_q) {
- unallocated_encoding(s);
- return;
- }
-
- if (!fp_access_check(s)) {
- return;
- }
-
- if (insert) {
- gen_gvec_fn2i(s, is_q, rd, rn, shift, gen_gvec_sli, size);
- } else {
- gen_gvec_fn2i(s, is_q, rd, rn, shift, tcg_gen_gvec_shli, size);
- }
-}
-
-/* USHLL/SHLL - Vector shift left with widening */
-static void handle_vec_simd_wshli(DisasContext *s, bool is_q, bool is_u,
- int immh, int immb, int opcode, int rn, int rd)
-{
- int size = 32 - clz32(immh) - 1;
- int immhb = immh << 3 | immb;
- int shift = immhb - (8 << size);
- int dsize = 64;
- int esize = 8 << size;
- int elements = dsize/esize;
- TCGv_i64 tcg_rn = tcg_temp_new_i64();
- TCGv_i64 tcg_rd = tcg_temp_new_i64();
- int i;
-
- if (size >= 3) {
- unallocated_encoding(s);
- return;
- }
-
- if (!fp_access_check(s)) {
- return;
- }
-
- /* For the LL variants the store is larger than the load,
- * so if rd == rn we would overwrite parts of our input.
- * So load everything right now and use shifts in the main loop.
- */
- read_vec_element(s, tcg_rn, rn, is_q ? 1 : 0, MO_64);
-
- for (i = 0; i < elements; i++) {
- tcg_gen_shri_i64(tcg_rd, tcg_rn, i * esize);
- ext_and_shift_reg(tcg_rd, tcg_rd, size | (!is_u << 2), 0);
- tcg_gen_shli_i64(tcg_rd, tcg_rd, shift);
- write_vec_element(s, tcg_rd, rd, i, size + 1);
- }
-}
-
-/* SHRN/RSHRN - Shift right with narrowing (and potential rounding) */
-static void handle_vec_simd_shrn(DisasContext *s, bool is_q,
- int immh, int immb, int opcode, int rn, int rd)
-{
- int immhb = immh << 3 | immb;
- int size = 32 - clz32(immh) - 1;
- int dsize = 64;
- int esize = 8 << size;
- int elements = dsize/esize;
- int shift = (2 * esize) - immhb;
- bool round = extract32(opcode, 0, 1);
- TCGv_i64 tcg_rn, tcg_rd, tcg_final;
- TCGv_i64 tcg_round;
- int i;
-
- if (extract32(immh, 3, 1)) {
- unallocated_encoding(s);
- return;
- }
-
- if (!fp_access_check(s)) {
- return;
- }
-
- tcg_rn = tcg_temp_new_i64();
- tcg_rd = tcg_temp_new_i64();
- tcg_final = tcg_temp_new_i64();
- read_vec_element(s, tcg_final, rd, is_q ? 1 : 0, MO_64);
-
- if (round) {
- tcg_round = tcg_constant_i64(1ULL << (shift - 1));
- } else {
- tcg_round = NULL;
- }
-
- for (i = 0; i < elements; i++) {
- read_vec_element(s, tcg_rn, rn, i, size+1);
- handle_shri_with_rndacc(tcg_rd, tcg_rn, tcg_round,
- false, true, size+1, shift);
-
- tcg_gen_deposit_i64(tcg_final, tcg_final, tcg_rd, esize * i, esize);
- }
-
- if (!is_q) {
- write_vec_element(s, tcg_final, rd, 0, MO_64);
- } else {
- write_vec_element(s, tcg_final, rd, 1, MO_64);
- }
-
- clear_vec_high(s, is_q, rd);
-}
-
-
/* AdvSIMD shift by immediate
* 31 30 29 28 23 22 19 18 16 15 11 10 9 5 4 0
* +---+---+---+-------------+------+------+--------+---+------+------+
@@ -10820,60 +10572,33 @@ static void disas_simd_shift_imm(DisasContext *s, uint32_t insn)
bool is_u = extract32(insn, 29, 1);
bool is_q = extract32(insn, 30, 1);
- /* data_proc_simd[] has sent immh == 0 to disas_simd_mod_imm. */
- assert(immh != 0);
+ if (immh == 0) {
+ unallocated_encoding(s);
+ return;
+ }
switch (opcode) {
- case 0x08: /* SRI */
- if (!is_u) {
- unallocated_encoding(s);
- return;
- }
- /* fall through */
+ case 0x1c: /* SCVTF / UCVTF */
+ handle_simd_shift_intfp_conv(s, false, is_q, is_u, immh, immb,
+ opcode, rn, rd);
+ break;
+ case 0x1f: /* FCVTZS/ FCVTZU */
+ handle_simd_shift_fpint_conv(s, false, is_q, is_u, immh, immb, rn, rd);
+ return;
+ default:
case 0x00: /* SSHR / USHR */
case 0x02: /* SSRA / USRA (accumulate) */
case 0x04: /* SRSHR / URSHR (rounding) */
case 0x06: /* SRSRA / URSRA (accum + rounding) */
- handle_vec_simd_shri(s, is_q, is_u, immh, immb, opcode, rn, rd);
- break;
+ case 0x08: /* SRI */
case 0x0a: /* SHL / SLI */
- handle_vec_simd_shli(s, is_q, is_u, immh, immb, opcode, rn, rd);
- break;
- case 0x10: /* SHRN */
+ case 0x0c: /* SQSHLU */
+ case 0x0e: /* SQSHL, UQSHL */
+ case 0x10: /* SHRN / SQSHRUN */
case 0x11: /* RSHRN / SQRSHRUN */
- if (is_u) {
- handle_vec_simd_sqshrn(s, false, is_q, false, true, immh, immb,
- opcode, rn, rd);
- } else {
- handle_vec_simd_shrn(s, is_q, immh, immb, opcode, rn, rd);
- }
- break;
case 0x12: /* SQSHRN / UQSHRN */
case 0x13: /* SQRSHRN / UQRSHRN */
- handle_vec_simd_sqshrn(s, false, is_q, is_u, is_u, immh, immb,
- opcode, rn, rd);
- break;
case 0x14: /* SSHLL / USHLL */
- handle_vec_simd_wshli(s, is_q, is_u, immh, immb, opcode, rn, rd);
- break;
- case 0x1c: /* SCVTF / UCVTF */
- handle_simd_shift_intfp_conv(s, false, is_q, is_u, immh, immb,
- opcode, rn, rd);
- break;
- case 0xc: /* SQSHLU */
- if (!is_u) {
- unallocated_encoding(s);
- return;
- }
- handle_simd_qshl(s, false, is_q, false, true, immh, immb, rn, rd);
- break;
- case 0xe: /* SQSHL, UQSHL */
- handle_simd_qshl(s, false, is_q, is_u, is_u, immh, immb, rn, rd);
- break;
- case 0x1f: /* FCVTZS/ FCVTZU */
- handle_simd_shift_fpint_conv(s, false, is_q, is_u, immh, immb, rn, rd);
- return;
- default:
unallocated_encoding(s);
return;
}
@@ -11829,13 +11554,7 @@ static void disas_simd_two_reg_misc_fp16(DisasContext *s, uint32_t insn)
static const AArch64DecodeTable data_proc_simd[] = {
/* pattern , mask , fn */
{ 0x0e200800, 0x9f3e0c00, disas_simd_two_reg_misc },
- { 0x0e300800, 0x9f3e0c00, disas_simd_across_lanes },
- /* simd_mod_imm decode is a subset of simd_shift_imm, so must precede it */
- { 0x0f000400, 0x9ff80400, disas_simd_mod_imm },
{ 0x0f000400, 0x9f800400, disas_simd_shift_imm },
- { 0x0e000000, 0xbf208c00, disas_simd_tb },
- { 0x0e000800, 0xbf208c00, disas_simd_zip_trn },
- { 0x2e000000, 0xbf208400, disas_simd_ext },
{ 0x5e200800, 0xdf3e0c00, disas_simd_scalar_two_reg_misc },
{ 0x5f000400, 0xdf800400, disas_simd_scalar_shift_imm },
{ 0x0e780800, 0x8f7e0c00, disas_simd_two_reg_misc_fp16 },
@@ -11879,37 +11598,6 @@ static bool trans_FAIL(DisasContext *s, arg_OK *a)
}
/**
- * is_guarded_page:
- * @env: The cpu environment
- * @s: The DisasContext
- *
- * Return true if the page is guarded.
- */
-static bool is_guarded_page(CPUARMState *env, DisasContext *s)
-{
- uint64_t addr = s->base.pc_first;
-#ifdef CONFIG_USER_ONLY
- return page_get_flags(addr) & PAGE_BTI;
-#else
- CPUTLBEntryFull *full;
- void *host;
- int mmu_idx = arm_to_core_mmu_idx(s->mmu_idx);
- int flags;
-
- /*
- * We test this immediately after reading an insn, which means
- * that the TLB entry must be present and valid, and thus this
- * access will never raise an exception.
- */
- flags = probe_access_full(env, addr, 0, MMU_INST_FETCH, mmu_idx,
- false, &host, &full, 0);
- assert(!(flags & TLB_INVALID_MASK));
-
- return full->extra.arm.guarded;
-#endif
-}
-
-/**
* btype_destination_ok:
* @insn: The instruction at the branch destination
* @bt: SCTLR_ELx.BT
@@ -12002,7 +11690,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
dc->tbii = EX_TBFLAG_A64(tb_flags, TBII);
dc->tbid = EX_TBFLAG_A64(tb_flags, TBID);
dc->tcma = EX_TBFLAG_A64(tb_flags, TCMA);
- dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
+ dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx, false);
#if !defined(CONFIG_USER_ONLY)
dc->user = (dc->current_el == 0);
#endif
@@ -12151,19 +11839,6 @@ static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
if (dc_isar_feature(aa64_bti, s)) {
if (s->base.num_insns == 1) {
- /*
- * At the first insn of the TB, compute s->guarded_page.
- * We delayed computing this until successfully reading
- * the first insn of the TB, above. This (mostly) ensures
- * that the softmmu tlb entry has been populated, and the
- * page table GP bit is available.
- *
- * Note that we need to compute this even if btype == 0,
- * because this value is used for BR instructions later
- * where ENV is not available.
- */
- s->guarded_page = is_guarded_page(env, s);
-
/* First insn can have btype set to non-zero. */
tcg_debug_assert(s->btype >= 0);
@@ -12172,12 +11847,13 @@ static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
* priority -- below debugging exceptions but above most
* everything else. This allows us to handle this now
* instead of waiting until the insn is otherwise decoded.
+ *
+ * We can check all but the guarded page check here;
+ * defer the latter to a helper.
*/
if (s->btype != 0
- && s->guarded_page
&& !btype_destination_ok(insn, s->bt, s->btype)) {
- gen_exception_insn(s, 0, EXCP_UDEF, syn_btitrap(s->btype));
- return;
+ gen_helper_guarded_page_check(tcg_env);
}
} else {
/* Not the first insn: btype must be 0. */
diff --git a/target/arm/tcg/translate-neon.c b/target/arm/tcg/translate-neon.c
index 915c9e5..9c8829a 100644
--- a/target/arm/tcg/translate-neon.c
+++ b/target/arm/tcg/translate-neon.c
@@ -148,6 +148,37 @@ static bool do_neon_ddda(DisasContext *s, int q, int vd, int vn, int vm,
return true;
}
+static bool do_neon_ddda_env(DisasContext *s, int q, int vd, int vn, int vm,
+ int data, gen_helper_gvec_4_ptr *fn_gvec)
+{
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (((vd | vn | vm) & 0x10) && !dc_isar_feature(aa32_simd_r32, s)) {
+ return false;
+ }
+
+ /*
+ * UNDEF accesses to odd registers for each bit of Q.
+ * Q will be 0b111 for all Q-reg instructions, otherwise
+ * when we have mixed Q- and D-reg inputs.
+ */
+ if (((vd & 1) * 4 | (vn & 1) * 2 | (vm & 1)) & q) {
+ return false;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ int opr_sz = q ? 16 : 8;
+ tcg_gen_gvec_4_ptr(vfp_reg_offset(1, vd),
+ vfp_reg_offset(1, vn),
+ vfp_reg_offset(1, vm),
+ vfp_reg_offset(1, vd),
+ tcg_env,
+ opr_sz, opr_sz, data, fn_gvec);
+ return true;
+}
+
static bool do_neon_ddda_fpst(DisasContext *s, int q, int vd, int vn, int vm,
int data, ARMFPStatusFlavour fp_flavour,
gen_helper_gvec_4_ptr *fn_gvec_ptr)
@@ -266,8 +297,8 @@ static bool trans_VDOT_b16(DisasContext *s, arg_VDOT_b16 *a)
if (!dc_isar_feature(aa32_bf16, s)) {
return false;
}
- return do_neon_ddda(s, a->q * 7, a->vd, a->vn, a->vm, 0,
- gen_helper_gvec_bfdot);
+ return do_neon_ddda_env(s, a->q * 7, a->vd, a->vn, a->vm, 0,
+ gen_helper_gvec_bfdot);
}
static bool trans_VFML(DisasContext *s, arg_VFML *a)
@@ -360,8 +391,8 @@ static bool trans_VDOT_b16_scal(DisasContext *s, arg_VDOT_b16_scal *a)
if (!dc_isar_feature(aa32_bf16, s)) {
return false;
}
- return do_neon_ddda(s, a->q * 6, a->vd, a->vn, a->vm, a->index,
- gen_helper_gvec_bfdot_idx);
+ return do_neon_ddda_env(s, a->q * 6, a->vd, a->vn, a->vm, a->index,
+ gen_helper_gvec_bfdot_idx);
}
static bool trans_VFML_scalar(DisasContext *s, arg_VFML_scalar *a)
@@ -1068,144 +1099,18 @@ DO_2SH(VRSHR_S, gen_gvec_srshr)
DO_2SH(VRSHR_U, gen_gvec_urshr)
DO_2SH(VRSRA_S, gen_gvec_srsra)
DO_2SH(VRSRA_U, gen_gvec_ursra)
-
-static bool trans_VSHR_S_2sh(DisasContext *s, arg_2reg_shift *a)
-{
- /* Signed shift out of range results in all-sign-bits */
- a->shift = MIN(a->shift, (8 << a->size) - 1);
- return do_vector_2sh(s, a, tcg_gen_gvec_sari);
-}
-
-static void gen_zero_rd_2sh(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
- int64_t shift, uint32_t oprsz, uint32_t maxsz)
-{
- tcg_gen_gvec_dup_imm(vece, rd_ofs, oprsz, maxsz, 0);
-}
-
-static bool trans_VSHR_U_2sh(DisasContext *s, arg_2reg_shift *a)
-{
- /* Shift out of range is architecturally valid and results in zero. */
- if (a->shift >= (8 << a->size)) {
- return do_vector_2sh(s, a, gen_zero_rd_2sh);
- } else {
- return do_vector_2sh(s, a, tcg_gen_gvec_shri);
- }
-}
-
-static bool do_2shift_env_64(DisasContext *s, arg_2reg_shift *a,
- NeonGenTwo64OpEnvFn *fn)
-{
- /*
- * 2-reg-and-shift operations, size == 3 case, where the
- * function needs to be passed tcg_env.
- */
- TCGv_i64 constimm;
- int pass;
-
- if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
- return false;
- }
-
- /* UNDEF accesses to D16-D31 if they don't exist. */
- if (!dc_isar_feature(aa32_simd_r32, s) &&
- ((a->vd | a->vm) & 0x10)) {
- return false;
- }
-
- if ((a->vm | a->vd) & a->q) {
- return false;
- }
-
- if (!vfp_access_check(s)) {
- return true;
- }
-
- /*
- * To avoid excessive duplication of ops we implement shift
- * by immediate using the variable shift operations.
- */
- constimm = tcg_constant_i64(dup_const(a->size, a->shift));
-
- for (pass = 0; pass < a->q + 1; pass++) {
- TCGv_i64 tmp = tcg_temp_new_i64();
-
- read_neon_element64(tmp, a->vm, pass, MO_64);
- fn(tmp, tcg_env, tmp, constimm);
- write_neon_element64(tmp, a->vd, pass, MO_64);
- }
- return true;
-}
-
-static bool do_2shift_env_32(DisasContext *s, arg_2reg_shift *a,
- NeonGenTwoOpEnvFn *fn)
-{
- /*
- * 2-reg-and-shift operations, size < 3 case, where the
- * helper needs to be passed tcg_env.
- */
- TCGv_i32 constimm, tmp;
- int pass;
-
- if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
- return false;
- }
-
- /* UNDEF accesses to D16-D31 if they don't exist. */
- if (!dc_isar_feature(aa32_simd_r32, s) &&
- ((a->vd | a->vm) & 0x10)) {
- return false;
- }
-
- if ((a->vm | a->vd) & a->q) {
- return false;
- }
-
- if (!vfp_access_check(s)) {
- return true;
- }
-
- /*
- * To avoid excessive duplication of ops we implement shift
- * by immediate using the variable shift operations.
- */
- constimm = tcg_constant_i32(dup_const(a->size, a->shift));
- tmp = tcg_temp_new_i32();
-
- for (pass = 0; pass < (a->q ? 4 : 2); pass++) {
- read_neon_element32(tmp, a->vm, pass, MO_32);
- fn(tmp, tcg_env, tmp, constimm);
- write_neon_element32(tmp, a->vd, pass, MO_32);
- }
- return true;
-}
-
-#define DO_2SHIFT_ENV(INSN, FUNC) \
- static bool trans_##INSN##_64_2sh(DisasContext *s, arg_2reg_shift *a) \
- { \
- return do_2shift_env_64(s, a, gen_helper_neon_##FUNC##64); \
- } \
- static bool trans_##INSN##_2sh(DisasContext *s, arg_2reg_shift *a) \
- { \
- static NeonGenTwoOpEnvFn * const fns[] = { \
- gen_helper_neon_##FUNC##8, \
- gen_helper_neon_##FUNC##16, \
- gen_helper_neon_##FUNC##32, \
- }; \
- assert(a->size < ARRAY_SIZE(fns)); \
- return do_2shift_env_32(s, a, fns[a->size]); \
- }
-
-DO_2SHIFT_ENV(VQSHLU, qshlu_s)
-DO_2SHIFT_ENV(VQSHL_U, qshl_u)
-DO_2SHIFT_ENV(VQSHL_S, qshl_s)
+DO_2SH(VSHR_S, gen_gvec_sshr)
+DO_2SH(VSHR_U, gen_gvec_ushr)
+DO_2SH(VQSHLU, gen_neon_sqshlui)
+DO_2SH(VQSHL_U, gen_neon_uqshli)
+DO_2SH(VQSHL_S, gen_neon_sqshli)
static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a,
NeonGenTwo64OpFn *shiftfn,
- NeonGenNarrowEnvFn *narrowfn)
+ NeonGenOne64OpEnvFn *narrowfn)
{
/* 2-reg-and-shift narrowing-shift operations, size == 3 case */
- TCGv_i64 constimm, rm1, rm2;
- TCGv_i32 rd;
+ TCGv_i64 constimm, rm1, rm2, rd;
if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
return false;
@@ -1232,7 +1137,7 @@ static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a,
constimm = tcg_constant_i64(-a->shift);
rm1 = tcg_temp_new_i64();
rm2 = tcg_temp_new_i64();
- rd = tcg_temp_new_i32();
+ rd = tcg_temp_new_i64();
/* Load both inputs first to avoid potential overwrite if rm == rd */
read_neon_element64(rm1, a->vm, 0, MO_64);
@@ -1240,18 +1145,18 @@ static bool do_2shift_narrow_64(DisasContext *s, arg_2reg_shift *a,
shiftfn(rm1, rm1, constimm);
narrowfn(rd, tcg_env, rm1);
- write_neon_element32(rd, a->vd, 0, MO_32);
+ write_neon_element64(rd, a->vd, 0, MO_32);
shiftfn(rm2, rm2, constimm);
narrowfn(rd, tcg_env, rm2);
- write_neon_element32(rd, a->vd, 1, MO_32);
+ write_neon_element64(rd, a->vd, 1, MO_32);
return true;
}
static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a,
NeonGenTwoOpFn *shiftfn,
- NeonGenNarrowEnvFn *narrowfn)
+ NeonGenOne64OpEnvFn *narrowfn)
{
/* 2-reg-and-shift narrowing-shift operations, size < 3 case */
TCGv_i32 constimm, rm1, rm2, rm3, rm4;
@@ -1306,16 +1211,16 @@ static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a,
tcg_gen_concat_i32_i64(rtmp, rm1, rm2);
- narrowfn(rm1, tcg_env, rtmp);
- write_neon_element32(rm1, a->vd, 0, MO_32);
+ narrowfn(rtmp, tcg_env, rtmp);
+ write_neon_element64(rtmp, a->vd, 0, MO_32);
shiftfn(rm3, rm3, constimm);
shiftfn(rm4, rm4, constimm);
tcg_gen_concat_i32_i64(rtmp, rm3, rm4);
- narrowfn(rm3, tcg_env, rtmp);
- write_neon_element32(rm3, a->vd, 1, MO_32);
+ narrowfn(rtmp, tcg_env, rtmp);
+ write_neon_element64(rtmp, a->vd, 1, MO_32);
return true;
}
@@ -1330,17 +1235,17 @@ static bool do_2shift_narrow_32(DisasContext *s, arg_2reg_shift *a,
return do_2shift_narrow_32(s, a, FUNC, NARROWFUNC); \
}
-static void gen_neon_narrow_u32(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src)
+static void gen_neon_narrow_u32(TCGv_i64 dest, TCGv_ptr env, TCGv_i64 src)
{
- tcg_gen_extrl_i64_i32(dest, src);
+ tcg_gen_ext32u_i64(dest, src);
}
-static void gen_neon_narrow_u16(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src)
+static void gen_neon_narrow_u16(TCGv_i64 dest, TCGv_ptr env, TCGv_i64 src)
{
gen_helper_neon_narrow_u16(dest, src);
}
-static void gen_neon_narrow_u8(TCGv_i32 dest, TCGv_ptr env, TCGv_i64 src)
+static void gen_neon_narrow_u8(TCGv_i64 dest, TCGv_ptr env, TCGv_i64 src)
{
gen_helper_neon_narrow_u8(dest, src);
}
@@ -2931,10 +2836,9 @@ static bool trans_VZIP(DisasContext *s, arg_2misc *a)
}
static bool do_vmovn(DisasContext *s, arg_2misc *a,
- NeonGenNarrowEnvFn *narrowfn)
+ NeonGenOne64OpEnvFn *narrowfn)
{
- TCGv_i64 rm;
- TCGv_i32 rd0, rd1;
+ TCGv_i64 rm, rd0, rd1;
if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
return false;
@@ -2959,22 +2863,22 @@ static bool do_vmovn(DisasContext *s, arg_2misc *a,
}
rm = tcg_temp_new_i64();
- rd0 = tcg_temp_new_i32();
- rd1 = tcg_temp_new_i32();
+ rd0 = tcg_temp_new_i64();
+ rd1 = tcg_temp_new_i64();
read_neon_element64(rm, a->vm, 0, MO_64);
narrowfn(rd0, tcg_env, rm);
read_neon_element64(rm, a->vm, 1, MO_64);
narrowfn(rd1, tcg_env, rm);
- write_neon_element32(rd0, a->vd, 0, MO_32);
- write_neon_element32(rd1, a->vd, 1, MO_32);
+ write_neon_element64(rd0, a->vd, 0, MO_32);
+ write_neon_element64(rd1, a->vd, 1, MO_32);
return true;
}
#define DO_VMOVN(INSN, FUNC) \
static bool trans_##INSN(DisasContext *s, arg_2misc *a) \
{ \
- static NeonGenNarrowEnvFn * const narrowfn[] = { \
+ static NeonGenOne64OpEnvFn * const narrowfn[] = { \
FUNC##8, \
FUNC##16, \
FUNC##32, \
@@ -3699,8 +3603,8 @@ static bool trans_VMMLA_b16(DisasContext *s, arg_VMMLA_b16 *a)
if (!dc_isar_feature(aa32_bf16, s)) {
return false;
}
- return do_neon_ddda(s, 7, a->vd, a->vn, a->vm, 0,
- gen_helper_gvec_bfmmla);
+ return do_neon_ddda_env(s, 7, a->vd, a->vn, a->vm, 0,
+ gen_helper_gvec_bfmmla);
}
static bool trans_VFMA_b16(DisasContext *s, arg_VFMA_b16 *a)
diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c
index 185a8a9..01ece57 100644
--- a/target/arm/tcg/translate-sme.c
+++ b/target/arm/tcg/translate-sme.c
@@ -49,7 +49,15 @@ static TCGv_ptr get_tile_rowcol(DisasContext *s, int esz, int rs,
/* Prepare a power-of-two modulo via extraction of @len bits. */
len = ctz32(streaming_vec_reg_size(s)) - esz;
- if (vertical) {
+ if (!len) {
+ /*
+ * SVL is 128 and the element size is 128. There is exactly
+ * one 128x128 tile in the ZA storage, and so we calculate
+ * (Rs + imm) MOD 1, which is always 0. We need to special case
+ * this because TCG doesn't allow deposit ops with len 0.
+ */
+ tcg_gen_movi_i32(tmp, 0);
+ } else if (vertical) {
/*
* Compute the byte offset of the index within the tile:
* (index % (svl / size)) * size
@@ -326,15 +334,35 @@ static bool do_outprod_fpst(DisasContext *s, arg_op *a, MemOp esz,
return true;
}
-TRANS_FEAT(FMOPA_h, aa64_sme, do_outprod_fpst, a,
- MO_32, FPST_FPCR_F16, gen_helper_sme_fmopa_h)
+static bool do_outprod_env(DisasContext *s, arg_op *a, MemOp esz,
+ gen_helper_gvec_5_ptr *fn)
+{
+ int svl = streaming_vec_reg_size(s);
+ uint32_t desc = simd_desc(svl, svl, a->sub);
+ TCGv_ptr za, zn, zm, pn, pm;
+
+ if (!sme_smza_enabled_check(s)) {
+ return true;
+ }
+
+ za = get_tile(s, esz, a->zad);
+ zn = vec_full_reg_ptr(s, a->zn);
+ zm = vec_full_reg_ptr(s, a->zm);
+ pn = pred_full_reg_ptr(s, a->pn);
+ pm = pred_full_reg_ptr(s, a->pm);
+
+ fn(za, zn, zm, pn, pm, tcg_env, tcg_constant_i32(desc));
+ return true;
+}
+
+TRANS_FEAT(FMOPA_h, aa64_sme, do_outprod_env, a,
+ MO_32, gen_helper_sme_fmopa_h)
TRANS_FEAT(FMOPA_s, aa64_sme, do_outprod_fpst, a,
MO_32, FPST_FPCR, gen_helper_sme_fmopa_s)
TRANS_FEAT(FMOPA_d, aa64_sme_f64f64, do_outprod_fpst, a,
MO_64, FPST_FPCR, gen_helper_sme_fmopa_d)
-/* TODO: FEAT_EBF16 */
-TRANS_FEAT(BFMOPA, aa64_sme, do_outprod, a, MO_32, gen_helper_sme_bfmopa)
+TRANS_FEAT(BFMOPA, aa64_sme, do_outprod_env, a, MO_32, gen_helper_sme_bfmopa)
TRANS_FEAT(SMOPA_s, aa64_sme, do_outprod, a, MO_32, gen_helper_sme_smopa_s)
TRANS_FEAT(UMOPA_s, aa64_sme, do_outprod, a, MO_32, gen_helper_sme_umopa_s)
diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c
index 798ab2b..49d32fa 100644
--- a/target/arm/tcg/translate-sve.c
+++ b/target/arm/tcg/translate-sve.c
@@ -50,13 +50,27 @@ static int tszimm_esz(DisasContext *s, int x)
static int tszimm_shr(DisasContext *s, int x)
{
- return (16 << tszimm_esz(s, x)) - x;
+ /*
+ * We won't use the tszimm_shr() value if tszimm_esz() returns -1 (the
+ * trans function will check for esz < 0), so we can return any
+ * value we like from here in that case as long as we avoid UB.
+ */
+ int esz = tszimm_esz(s, x);
+ if (esz < 0) {
+ return esz;
+ }
+ return (16 << esz) - x;
}
/* See e.g. LSL (immediate, predicated). */
static int tszimm_shl(DisasContext *s, int x)
{
- return x - (8 << tszimm_esz(s, x));
+ /* As with tszimm_shr(), value will be unused if esz < 0 */
+ int esz = tszimm_esz(s, x);
+ if (esz < 0) {
+ return esz;
+ }
+ return x - (8 << esz);
}
/* The SH bit is in bit 8. Extract the low 8 and shift. */
@@ -238,6 +252,25 @@ static bool gen_gvec_fpst_zzzz(DisasContext *s, gen_helper_gvec_4_ptr *fn,
return ret;
}
+static bool gen_gvec_env_zzzz(DisasContext *s, gen_helper_gvec_4_ptr *fn,
+ int rd, int rn, int rm, int ra,
+ int data)
+{
+ return gen_gvec_ptr_zzzz(s, fn, rd, rn, rm, ra, data, tcg_env);
+}
+
+static bool gen_gvec_env_arg_zzzz(DisasContext *s, gen_helper_gvec_4_ptr *fn,
+ arg_rrrr_esz *a, int data)
+{
+ return gen_gvec_env_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, data);
+}
+
+static bool gen_gvec_env_arg_zzxz(DisasContext *s, gen_helper_gvec_4_ptr *fn,
+ arg_rrxr_esz *a)
+{
+ return gen_gvec_env_zzzz(s, fn, a->rd, a->rn, a->rm, a->ra, a->index);
+}
+
/* Invoke an out-of-line helper on 4 Zregs, 1 Preg, plus fpst. */
static bool gen_gvec_fpst_zzzzp(DisasContext *s, gen_helper_gvec_5_ptr *fn,
int rd, int rn, int rm, int ra, int pg,
@@ -6048,9 +6081,9 @@ static void gen_sshll_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t imm)
if (top) {
if (shl == halfbits) {
- TCGv_vec t = tcg_temp_new_vec_matching(d);
- tcg_gen_dupi_vec(vece, t, MAKE_64BIT_MASK(halfbits, halfbits));
- tcg_gen_and_vec(vece, d, n, t);
+ tcg_gen_and_vec(vece, d, n,
+ tcg_constant_vec_matching(d, vece,
+ MAKE_64BIT_MASK(halfbits, halfbits)));
} else {
tcg_gen_sari_vec(vece, d, n, halfbits);
tcg_gen_shli_vec(vece, d, d, shl);
@@ -6105,18 +6138,18 @@ static void gen_ushll_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t imm)
if (top) {
if (shl == halfbits) {
- TCGv_vec t = tcg_temp_new_vec_matching(d);
- tcg_gen_dupi_vec(vece, t, MAKE_64BIT_MASK(halfbits, halfbits));
- tcg_gen_and_vec(vece, d, n, t);
+ tcg_gen_and_vec(vece, d, n,
+ tcg_constant_vec_matching(d, vece,
+ MAKE_64BIT_MASK(halfbits, halfbits)));
} else {
tcg_gen_shri_vec(vece, d, n, halfbits);
tcg_gen_shli_vec(vece, d, d, shl);
}
} else {
if (shl == 0) {
- TCGv_vec t = tcg_temp_new_vec_matching(d);
- tcg_gen_dupi_vec(vece, t, MAKE_64BIT_MASK(0, halfbits));
- tcg_gen_and_vec(vece, d, n, t);
+ tcg_gen_and_vec(vece, d, n,
+ tcg_constant_vec_matching(d, vece,
+ MAKE_64BIT_MASK(0, halfbits)));
} else {
tcg_gen_shli_vec(vece, d, n, halfbits);
tcg_gen_shri_vec(vece, d, d, halfbits - shl);
@@ -6284,18 +6317,14 @@ static const TCGOpcode sqxtn_list[] = {
static void gen_sqxtnb_vec(unsigned vece, TCGv_vec d, TCGv_vec n)
{
- TCGv_vec t = tcg_temp_new_vec_matching(d);
int halfbits = 4 << vece;
int64_t mask = (1ull << halfbits) - 1;
int64_t min = -1ull << (halfbits - 1);
int64_t max = -min - 1;
- tcg_gen_dupi_vec(vece, t, min);
- tcg_gen_smax_vec(vece, d, n, t);
- tcg_gen_dupi_vec(vece, t, max);
- tcg_gen_smin_vec(vece, d, d, t);
- tcg_gen_dupi_vec(vece, t, mask);
- tcg_gen_and_vec(vece, d, d, t);
+ tcg_gen_smax_vec(vece, d, n, tcg_constant_vec_matching(d, vece, min));
+ tcg_gen_smin_vec(vece, d, d, tcg_constant_vec_matching(d, vece, max));
+ tcg_gen_and_vec(vece, d, d, tcg_constant_vec_matching(d, vece, mask));
}
static const GVecGen2 sqxtnb_ops[3] = {
@@ -6316,19 +6345,15 @@ TRANS_FEAT(SQXTNB, aa64_sve2, do_narrow_extract, a, sqxtnb_ops)
static void gen_sqxtnt_vec(unsigned vece, TCGv_vec d, TCGv_vec n)
{
- TCGv_vec t = tcg_temp_new_vec_matching(d);
int halfbits = 4 << vece;
int64_t mask = (1ull << halfbits) - 1;
int64_t min = -1ull << (halfbits - 1);
int64_t max = -min - 1;
- tcg_gen_dupi_vec(vece, t, min);
- tcg_gen_smax_vec(vece, n, n, t);
- tcg_gen_dupi_vec(vece, t, max);
- tcg_gen_smin_vec(vece, n, n, t);
+ tcg_gen_smax_vec(vece, n, n, tcg_constant_vec_matching(d, vece, min));
+ tcg_gen_smin_vec(vece, n, n, tcg_constant_vec_matching(d, vece, max));
tcg_gen_shli_vec(vece, n, n, halfbits);
- tcg_gen_dupi_vec(vece, t, mask);
- tcg_gen_bitsel_vec(vece, d, t, d, n);
+ tcg_gen_bitsel_vec(vece, d, tcg_constant_vec_matching(d, vece, mask), d, n);
}
static const GVecGen2 sqxtnt_ops[3] = {
@@ -6356,12 +6381,10 @@ static const TCGOpcode uqxtn_list[] = {
static void gen_uqxtnb_vec(unsigned vece, TCGv_vec d, TCGv_vec n)
{
- TCGv_vec t = tcg_temp_new_vec_matching(d);
int halfbits = 4 << vece;
int64_t max = (1ull << halfbits) - 1;
- tcg_gen_dupi_vec(vece, t, max);
- tcg_gen_umin_vec(vece, d, n, t);
+ tcg_gen_umin_vec(vece, d, n, tcg_constant_vec_matching(d, vece, max));
}
static const GVecGen2 uqxtnb_ops[3] = {
@@ -6382,14 +6405,13 @@ TRANS_FEAT(UQXTNB, aa64_sve2, do_narrow_extract, a, uqxtnb_ops)
static void gen_uqxtnt_vec(unsigned vece, TCGv_vec d, TCGv_vec n)
{
- TCGv_vec t = tcg_temp_new_vec_matching(d);
int halfbits = 4 << vece;
int64_t max = (1ull << halfbits) - 1;
+ TCGv_vec maxv = tcg_constant_vec_matching(d, vece, max);
- tcg_gen_dupi_vec(vece, t, max);
- tcg_gen_umin_vec(vece, n, n, t);
+ tcg_gen_umin_vec(vece, n, n, maxv);
tcg_gen_shli_vec(vece, n, n, halfbits);
- tcg_gen_bitsel_vec(vece, d, t, d, n);
+ tcg_gen_bitsel_vec(vece, d, maxv, d, n);
}
static const GVecGen2 uqxtnt_ops[3] = {
@@ -6417,14 +6439,11 @@ static const TCGOpcode sqxtun_list[] = {
static void gen_sqxtunb_vec(unsigned vece, TCGv_vec d, TCGv_vec n)
{
- TCGv_vec t = tcg_temp_new_vec_matching(d);
int halfbits = 4 << vece;
int64_t max = (1ull << halfbits) - 1;
- tcg_gen_dupi_vec(vece, t, 0);
- tcg_gen_smax_vec(vece, d, n, t);
- tcg_gen_dupi_vec(vece, t, max);
- tcg_gen_umin_vec(vece, d, d, t);
+ tcg_gen_smax_vec(vece, d, n, tcg_constant_vec_matching(d, vece, 0));
+ tcg_gen_umin_vec(vece, d, d, tcg_constant_vec_matching(d, vece, max));
}
static const GVecGen2 sqxtunb_ops[3] = {
@@ -6445,16 +6464,14 @@ TRANS_FEAT(SQXTUNB, aa64_sve2, do_narrow_extract, a, sqxtunb_ops)
static void gen_sqxtunt_vec(unsigned vece, TCGv_vec d, TCGv_vec n)
{
- TCGv_vec t = tcg_temp_new_vec_matching(d);
int halfbits = 4 << vece;
int64_t max = (1ull << halfbits) - 1;
+ TCGv_vec maxv = tcg_constant_vec_matching(d, vece, max);
- tcg_gen_dupi_vec(vece, t, 0);
- tcg_gen_smax_vec(vece, n, n, t);
- tcg_gen_dupi_vec(vece, t, max);
- tcg_gen_umin_vec(vece, n, n, t);
+ tcg_gen_smax_vec(vece, n, n, tcg_constant_vec_matching(d, vece, 0));
+ tcg_gen_umin_vec(vece, n, n, maxv);
tcg_gen_shli_vec(vece, n, n, halfbits);
- tcg_gen_bitsel_vec(vece, d, t, d, n);
+ tcg_gen_bitsel_vec(vece, d, maxv, d, n);
}
static const GVecGen2 sqxtunt_ops[3] = {
@@ -6518,13 +6535,11 @@ static void gen_shrnb64_i64(TCGv_i64 d, TCGv_i64 n, int64_t shr)
static void gen_shrnb_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr)
{
- TCGv_vec t = tcg_temp_new_vec_matching(d);
int halfbits = 4 << vece;
uint64_t mask = MAKE_64BIT_MASK(0, halfbits);
tcg_gen_shri_vec(vece, n, n, shr);
- tcg_gen_dupi_vec(vece, t, mask);
- tcg_gen_and_vec(vece, d, n, t);
+ tcg_gen_and_vec(vece, d, n, tcg_constant_vec_matching(d, vece, mask));
}
static const TCGOpcode shrnb_vec_list[] = { INDEX_op_shri_vec, 0 };
@@ -6576,13 +6591,11 @@ static void gen_shrnt64_i64(TCGv_i64 d, TCGv_i64 n, int64_t shr)
static void gen_shrnt_vec(unsigned vece, TCGv_vec d, TCGv_vec n, int64_t shr)
{
- TCGv_vec t = tcg_temp_new_vec_matching(d);
int halfbits = 4 << vece;
uint64_t mask = MAKE_64BIT_MASK(0, halfbits);
tcg_gen_shli_vec(vece, n, n, halfbits - shr);
- tcg_gen_dupi_vec(vece, t, mask);
- tcg_gen_bitsel_vec(vece, d, t, d, n);
+ tcg_gen_bitsel_vec(vece, d, tcg_constant_vec_matching(d, vece, mask), d, n);
}
static const TCGOpcode shrnt_vec_list[] = { INDEX_op_shli_vec, 0 };
@@ -6625,14 +6638,12 @@ TRANS_FEAT(RSHRNT, aa64_sve2, do_shr_narrow, a, rshrnt_ops)
static void gen_sqshrunb_vec(unsigned vece, TCGv_vec d,
TCGv_vec n, int64_t shr)
{
- TCGv_vec t = tcg_temp_new_vec_matching(d);
int halfbits = 4 << vece;
+ uint64_t max = MAKE_64BIT_MASK(0, halfbits);
tcg_gen_sari_vec(vece, n, n, shr);
- tcg_gen_dupi_vec(vece, t, 0);
- tcg_gen_smax_vec(vece, n, n, t);
- tcg_gen_dupi_vec(vece, t, MAKE_64BIT_MASK(0, halfbits));
- tcg_gen_umin_vec(vece, d, n, t);
+ tcg_gen_smax_vec(vece, n, n, tcg_constant_vec_matching(d, vece, 0));
+ tcg_gen_umin_vec(vece, d, n, tcg_constant_vec_matching(d, vece, max));
}
static const TCGOpcode sqshrunb_vec_list[] = {
@@ -6657,16 +6668,15 @@ TRANS_FEAT(SQSHRUNB, aa64_sve2, do_shr_narrow, a, sqshrunb_ops)
static void gen_sqshrunt_vec(unsigned vece, TCGv_vec d,
TCGv_vec n, int64_t shr)
{
- TCGv_vec t = tcg_temp_new_vec_matching(d);
int halfbits = 4 << vece;
+ uint64_t max = MAKE_64BIT_MASK(0, halfbits);
+ TCGv_vec maxv = tcg_constant_vec_matching(d, vece, max);
tcg_gen_sari_vec(vece, n, n, shr);
- tcg_gen_dupi_vec(vece, t, 0);
- tcg_gen_smax_vec(vece, n, n, t);
- tcg_gen_dupi_vec(vece, t, MAKE_64BIT_MASK(0, halfbits));
- tcg_gen_umin_vec(vece, n, n, t);
+ tcg_gen_smax_vec(vece, n, n, tcg_constant_vec_matching(d, vece, 0));
+ tcg_gen_umin_vec(vece, n, n, maxv);
tcg_gen_shli_vec(vece, n, n, halfbits);
- tcg_gen_bitsel_vec(vece, d, t, d, n);
+ tcg_gen_bitsel_vec(vece, d, maxv, d, n);
}
static const TCGOpcode sqshrunt_vec_list[] = {
@@ -6709,18 +6719,15 @@ TRANS_FEAT(SQRSHRUNT, aa64_sve2, do_shr_narrow, a, sqrshrunt_ops)
static void gen_sqshrnb_vec(unsigned vece, TCGv_vec d,
TCGv_vec n, int64_t shr)
{
- TCGv_vec t = tcg_temp_new_vec_matching(d);
int halfbits = 4 << vece;
int64_t max = MAKE_64BIT_MASK(0, halfbits - 1);
int64_t min = -max - 1;
+ int64_t mask = MAKE_64BIT_MASK(0, halfbits);
tcg_gen_sari_vec(vece, n, n, shr);
- tcg_gen_dupi_vec(vece, t, min);
- tcg_gen_smax_vec(vece, n, n, t);
- tcg_gen_dupi_vec(vece, t, max);
- tcg_gen_smin_vec(vece, n, n, t);
- tcg_gen_dupi_vec(vece, t, MAKE_64BIT_MASK(0, halfbits));
- tcg_gen_and_vec(vece, d, n, t);
+ tcg_gen_smax_vec(vece, n, n, tcg_constant_vec_matching(d, vece, min));
+ tcg_gen_smin_vec(vece, n, n, tcg_constant_vec_matching(d, vece, max));
+ tcg_gen_and_vec(vece, d, n, tcg_constant_vec_matching(d, vece, mask));
}
static const TCGOpcode sqshrnb_vec_list[] = {
@@ -6745,19 +6752,16 @@ TRANS_FEAT(SQSHRNB, aa64_sve2, do_shr_narrow, a, sqshrnb_ops)
static void gen_sqshrnt_vec(unsigned vece, TCGv_vec d,
TCGv_vec n, int64_t shr)
{
- TCGv_vec t = tcg_temp_new_vec_matching(d);
int halfbits = 4 << vece;
int64_t max = MAKE_64BIT_MASK(0, halfbits - 1);
int64_t min = -max - 1;
+ int64_t mask = MAKE_64BIT_MASK(0, halfbits);
tcg_gen_sari_vec(vece, n, n, shr);
- tcg_gen_dupi_vec(vece, t, min);
- tcg_gen_smax_vec(vece, n, n, t);
- tcg_gen_dupi_vec(vece, t, max);
- tcg_gen_smin_vec(vece, n, n, t);
+ tcg_gen_smax_vec(vece, n, n, tcg_constant_vec_matching(d, vece, min));
+ tcg_gen_smin_vec(vece, n, n, tcg_constant_vec_matching(d, vece, max));
tcg_gen_shli_vec(vece, n, n, halfbits);
- tcg_gen_dupi_vec(vece, t, MAKE_64BIT_MASK(0, halfbits));
- tcg_gen_bitsel_vec(vece, d, t, d, n);
+ tcg_gen_bitsel_vec(vece, d, tcg_constant_vec_matching(d, vece, mask), d, n);
}
static const TCGOpcode sqshrnt_vec_list[] = {
@@ -6800,12 +6804,11 @@ TRANS_FEAT(SQRSHRNT, aa64_sve2, do_shr_narrow, a, sqrshrnt_ops)
static void gen_uqshrnb_vec(unsigned vece, TCGv_vec d,
TCGv_vec n, int64_t shr)
{
- TCGv_vec t = tcg_temp_new_vec_matching(d);
int halfbits = 4 << vece;
+ int64_t max = MAKE_64BIT_MASK(0, halfbits);
tcg_gen_shri_vec(vece, n, n, shr);
- tcg_gen_dupi_vec(vece, t, MAKE_64BIT_MASK(0, halfbits));
- tcg_gen_umin_vec(vece, d, n, t);
+ tcg_gen_umin_vec(vece, d, n, tcg_constant_vec_matching(d, vece, max));
}
static const TCGOpcode uqshrnb_vec_list[] = {
@@ -6830,14 +6833,14 @@ TRANS_FEAT(UQSHRNB, aa64_sve2, do_shr_narrow, a, uqshrnb_ops)
static void gen_uqshrnt_vec(unsigned vece, TCGv_vec d,
TCGv_vec n, int64_t shr)
{
- TCGv_vec t = tcg_temp_new_vec_matching(d);
int halfbits = 4 << vece;
+ int64_t max = MAKE_64BIT_MASK(0, halfbits);
+ TCGv_vec maxv = tcg_constant_vec_matching(d, vece, max);
tcg_gen_shri_vec(vece, n, n, shr);
- tcg_gen_dupi_vec(vece, t, MAKE_64BIT_MASK(0, halfbits));
- tcg_gen_umin_vec(vece, n, n, t);
+ tcg_gen_umin_vec(vece, n, n, maxv);
tcg_gen_shli_vec(vece, n, n, halfbits);
- tcg_gen_bitsel_vec(vece, d, t, d, n);
+ tcg_gen_bitsel_vec(vece, d, maxv, d, n);
}
static const TCGOpcode uqshrnt_vec_list[] = {
@@ -7099,12 +7102,12 @@ TRANS_FEAT_NONSTREAMING(USMMLA, aa64_sve_i8mm, gen_gvec_ool_arg_zzzz,
TRANS_FEAT_NONSTREAMING(UMMLA, aa64_sve_i8mm, gen_gvec_ool_arg_zzzz,
gen_helper_gvec_ummla_b, a, 0)
-TRANS_FEAT(BFDOT_zzzz, aa64_sve_bf16, gen_gvec_ool_arg_zzzz,
+TRANS_FEAT(BFDOT_zzzz, aa64_sve_bf16, gen_gvec_env_arg_zzzz,
gen_helper_gvec_bfdot, a, 0)
-TRANS_FEAT(BFDOT_zzxz, aa64_sve_bf16, gen_gvec_ool_arg_zzxz,
+TRANS_FEAT(BFDOT_zzxz, aa64_sve_bf16, gen_gvec_env_arg_zzxz,
gen_helper_gvec_bfdot_idx, a)
-TRANS_FEAT_NONSTREAMING(BFMMLA, aa64_sve_bf16, gen_gvec_ool_arg_zzzz,
+TRANS_FEAT_NONSTREAMING(BFMMLA, aa64_sve_bf16, gen_gvec_env_arg_zzzz,
gen_helper_gvec_bfmmla, a, 0)
static bool do_BFMLAL_zzzw(DisasContext *s, arg_rrrr_esz *a, bool sel)
diff --git a/target/arm/tcg/translate-vfp.c b/target/arm/tcg/translate-vfp.c
index cd5b848..b6fa28a 100644
--- a/target/arm/tcg/translate-vfp.c
+++ b/target/arm/tcg/translate-vfp.c
@@ -2190,8 +2190,8 @@ static bool do_vfm_sp(DisasContext *s, arg_VFMA_sp *a, bool neg_n, bool neg_d)
static bool do_vfm_dp(DisasContext *s, arg_VFMA_dp *a, bool neg_n, bool neg_d)
{
/*
- * VFNMA : fd = muladd(-fd, fn, fm)
- * VFNMS : fd = muladd(-fd, -fn, fm)
+ * VFNMA : fd = muladd(-fd, -fn, fm)
+ * VFNMS : fd = muladd(-fd, fn, fm)
* VFMA : fd = muladd( fd, fn, fm)
* VFMS : fd = muladd( fd, -fn, fm)
*
@@ -2262,8 +2262,8 @@ static bool do_vfm_dp(DisasContext *s, arg_VFMA_dp *a, bool neg_n, bool neg_d)
#define MAKE_VFM_TRANS_FNS(PREC) \
MAKE_ONE_VFM_TRANS_FN(VFMA, PREC, false, false) \
MAKE_ONE_VFM_TRANS_FN(VFMS, PREC, true, false) \
- MAKE_ONE_VFM_TRANS_FN(VFNMA, PREC, false, true) \
- MAKE_ONE_VFM_TRANS_FN(VFNMS, PREC, true, true)
+ MAKE_ONE_VFM_TRANS_FN(VFNMS, PREC, false, true) \
+ MAKE_ONE_VFM_TRANS_FN(VFNMA, PREC, true, true)
MAKE_VFM_TRANS_FNS(hp)
MAKE_VFM_TRANS_FNS(sp)
diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c
index c5bc691..e2748ff 100644
--- a/target/arm/tcg/translate.c
+++ b/target/arm/tcg/translate.c
@@ -7546,10 +7546,6 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
core_mmu_idx = EX_TBFLAG_ANY(tb_flags, MMUIDX);
dc->mmu_idx = core_to_arm_mmu_idx(env, core_mmu_idx);
- dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
-#if !defined(CONFIG_USER_ONLY)
- dc->user = (dc->current_el == 0);
-#endif
dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL);
dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM);
dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL);
@@ -7580,7 +7576,12 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
}
dc->sme_trap_nonstreaming =
EX_TBFLAG_A32(tb_flags, SME_TRAP_NONSTREAMING);
+ dc->s_pl1_0 = EX_TBFLAG_A32(tb_flags, S_PL1_0);
}
+ dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx, dc->s_pl1_0);
+#if !defined(CONFIG_USER_ONLY)
+ dc->user = (dc->current_el == 0);
+#endif
dc->lse2 = false; /* applies only to aarch64 */
dc->cp_regs = cpu->cp_regs;
dc->features = env->features;
diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h
index a8672c8..5a2e10d 100644
--- a/target/arm/tcg/translate.h
+++ b/target/arm/tcg/translate.h
@@ -163,10 +163,10 @@ typedef struct DisasContext {
uint8_t dcz_blocksize;
/* A copy of cpu->gm_blocksize. */
uint8_t gm_blocksize;
- /* True if this page is guarded. */
- bool guarded_page;
/* True if the current insn_start has been updated. */
bool insn_start_updated;
+ /* True if this is the AArch32 Secure PL1&0 translation regime */
+ bool s_pl1_0;
/* Bottom two bits of XScale c15_cpar coprocessor access control reg */
int c15_cpar;
/* Offset from VNCR_EL2 when FEAT_NV2 redirects this reg to memory */
@@ -471,6 +471,13 @@ void gen_neon_sqrshl(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
void gen_neon_uqrshl(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz);
+void gen_neon_sqshli(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ int64_t c, uint32_t opr_sz, uint32_t max_sz);
+void gen_neon_uqshli(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ int64_t c, uint32_t opr_sz, uint32_t max_sz);
+void gen_neon_sqshlui(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
+ int64_t c, uint32_t opr_sz, uint32_t max_sz);
+
void gen_gvec_shadd(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz);
void gen_gvec_uhadd(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
@@ -514,6 +521,11 @@ void gen_sqsub_d(TCGv_i64 d, TCGv_i64 q, TCGv_i64 a, TCGv_i64 b);
void gen_gvec_sqsub_qc(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz);
+void gen_gvec_sshr(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
+ int64_t shift, uint32_t opr_sz, uint32_t max_sz);
+void gen_gvec_ushr(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
+ int64_t shift, uint32_t opr_sz, uint32_t max_sz);
+
void gen_gvec_ssra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
int64_t shift, uint32_t opr_sz, uint32_t max_sz);
void gen_gvec_usra(unsigned vece, uint32_t rd_ofs, uint32_t rm_ofs,
@@ -593,13 +605,13 @@ typedef void NeonGenThreeOpEnvFn(TCGv_i32, TCGv_env, TCGv_i32,
typedef void NeonGenTwo64OpFn(TCGv_i64, TCGv_i64, TCGv_i64);
typedef void NeonGenTwo64OpEnvFn(TCGv_i64, TCGv_ptr, TCGv_i64, TCGv_i64);
typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64);
-typedef void NeonGenNarrowEnvFn(TCGv_i32, TCGv_ptr, TCGv_i64);
typedef void NeonGenWidenFn(TCGv_i64, TCGv_i32);
typedef void NeonGenTwoOpWidenFn(TCGv_i64, TCGv_i32, TCGv_i32);
typedef void NeonGenOneSingleOpFn(TCGv_i32, TCGv_i32, TCGv_ptr);
typedef void NeonGenTwoSingleOpFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr);
typedef void NeonGenTwoDoubleOpFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr);
typedef void NeonGenOne64OpFn(TCGv_i64, TCGv_i64);
+typedef void NeonGenOne64OpEnvFn(TCGv_i64, TCGv_env, TCGv_i64);
typedef void CryptoTwoOpFn(TCGv_ptr, TCGv_ptr);
typedef void CryptoThreeOpIntFn(TCGv_ptr, TCGv_ptr, TCGv_i32);
typedef void CryptoThreeOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr);
diff --git a/target/arm/tcg/vec_helper.c b/target/arm/tcg/vec_helper.c
index 98604d1..22ddb96 100644
--- a/target/arm/tcg/vec_helper.c
+++ b/target/arm/tcg/vec_helper.c
@@ -2790,44 +2790,115 @@ DO_MMLA_B(gvec_usmmla_b, do_usmmla_b)
* BFloat16 Dot Product
*/
-float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2)
+bool is_ebf(CPUARMState *env, float_status *statusp, float_status *oddstatusp)
{
- /* FPCR is ignored for BFDOT and BFMMLA. */
- float_status bf_status = {
+ /*
+ * For BFDOT, BFMMLA, etc, the behaviour depends on FPCR.EBF.
+ * For EBF = 0, we ignore the FPCR bits which determine rounding
+ * mode and denormal-flushing, and we do unfused multiplies and
+ * additions with intermediate rounding of all products and sums.
+ * For EBF = 1, we honour FPCR rounding mode and denormal-flushing bits,
+ * and we perform a fused two-way sum-of-products without intermediate
+ * rounding of the products.
+ * In either case, we don't set fp exception flags.
+ *
+ * EBF is AArch64 only, so even if it's set in the FPCR it has
+ * no effect on AArch32 instructions.
+ */
+ bool ebf = is_a64(env) && env->vfp.fpcr & FPCR_EBF;
+ *statusp = (float_status){
.tininess_before_rounding = float_tininess_before_rounding,
.float_rounding_mode = float_round_to_odd_inf,
.flush_to_zero = true,
.flush_inputs_to_zero = true,
.default_nan_mode = true,
};
+
+ if (ebf) {
+ float_status *fpst = &env->vfp.fp_status;
+ set_flush_to_zero(get_flush_to_zero(fpst), statusp);
+ set_flush_inputs_to_zero(get_flush_inputs_to_zero(fpst), statusp);
+ set_float_rounding_mode(get_float_rounding_mode(fpst), statusp);
+
+ /* EBF=1 needs to do a step with round-to-odd semantics */
+ *oddstatusp = *statusp;
+ set_float_rounding_mode(float_round_to_odd, oddstatusp);
+ }
+
+ return ebf;
+}
+
+float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst)
+{
float32 t1, t2;
/*
* Extract each BFloat16 from the element pair, and shift
* them such that they become float32.
*/
- t1 = float32_mul(e1 << 16, e2 << 16, &bf_status);
- t2 = float32_mul(e1 & 0xffff0000u, e2 & 0xffff0000u, &bf_status);
- t1 = float32_add(t1, t2, &bf_status);
- t1 = float32_add(sum, t1, &bf_status);
+ t1 = float32_mul(e1 << 16, e2 << 16, fpst);
+ t2 = float32_mul(e1 & 0xffff0000u, e2 & 0xffff0000u, fpst);
+ t1 = float32_add(t1, t2, fpst);
+ t1 = float32_add(sum, t1, fpst);
return t1;
}
-void HELPER(gvec_bfdot)(void *vd, void *vn, void *vm, void *va, uint32_t desc)
+float32 bfdotadd_ebf(float32 sum, uint32_t e1, uint32_t e2,
+ float_status *fpst, float_status *fpst_odd)
+{
+ /*
+ * Compare f16_dotadd() in sme_helper.c, but here we have
+ * bfloat16 inputs. In particular that means that we do not
+ * want the FPCR.FZ16 flush semantics, so we use the normal
+ * float_status for the input handling here.
+ */
+ float64 e1r = float32_to_float64(e1 << 16, fpst);
+ float64 e1c = float32_to_float64(e1 & 0xffff0000u, fpst);
+ float64 e2r = float32_to_float64(e2 << 16, fpst);
+ float64 e2c = float32_to_float64(e2 & 0xffff0000u, fpst);
+ float64 t64;
+ float32 t32;
+
+ /*
+ * The ARM pseudocode function FPDot performs both multiplies
+ * and the add with a single rounding operation. Emulate this
+ * by performing the first multiply in round-to-odd, then doing
+ * the second multiply as fused multiply-add, and rounding to
+ * float32 all in one step.
+ */
+ t64 = float64_mul(e1r, e2r, fpst_odd);
+ t64 = float64r32_muladd(e1c, e2c, t64, 0, fpst);
+
+ /* This conversion is exact, because we've already rounded. */
+ t32 = float64_to_float32(t64, fpst);
+
+ /* The final accumulation step is not fused. */
+ return float32_add(sum, t32, fpst);
+}
+
+void HELPER(gvec_bfdot)(void *vd, void *vn, void *vm, void *va,
+ CPUARMState *env, uint32_t desc)
{
intptr_t i, opr_sz = simd_oprsz(desc);
float32 *d = vd, *a = va;
uint32_t *n = vn, *m = vm;
+ float_status fpst, fpst_odd;
- for (i = 0; i < opr_sz / 4; ++i) {
- d[i] = bfdotadd(a[i], n[i], m[i]);
+ if (is_ebf(env, &fpst, &fpst_odd)) {
+ for (i = 0; i < opr_sz / 4; ++i) {
+ d[i] = bfdotadd_ebf(a[i], n[i], m[i], &fpst, &fpst_odd);
+ }
+ } else {
+ for (i = 0; i < opr_sz / 4; ++i) {
+ d[i] = bfdotadd(a[i], n[i], m[i], &fpst);
+ }
}
clear_tail(d, opr_sz, simd_maxsz(desc));
}
void HELPER(gvec_bfdot_idx)(void *vd, void *vn, void *vm,
- void *va, uint32_t desc)
+ void *va, CPUARMState *env, uint32_t desc)
{
intptr_t i, j, opr_sz = simd_oprsz(desc);
intptr_t index = simd_data(desc);
@@ -2835,53 +2906,100 @@ void HELPER(gvec_bfdot_idx)(void *vd, void *vn, void *vm,
intptr_t eltspersegment = MIN(16 / 4, elements);
float32 *d = vd, *a = va;
uint32_t *n = vn, *m = vm;
+ float_status fpst, fpst_odd;
- for (i = 0; i < elements; i += eltspersegment) {
- uint32_t m_idx = m[i + H4(index)];
+ if (is_ebf(env, &fpst, &fpst_odd)) {
+ for (i = 0; i < elements; i += eltspersegment) {
+ uint32_t m_idx = m[i + H4(index)];
- for (j = i; j < i + eltspersegment; j++) {
- d[j] = bfdotadd(a[j], n[j], m_idx);
+ for (j = i; j < i + eltspersegment; j++) {
+ d[j] = bfdotadd_ebf(a[j], n[j], m_idx, &fpst, &fpst_odd);
+ }
+ }
+ } else {
+ for (i = 0; i < elements; i += eltspersegment) {
+ uint32_t m_idx = m[i + H4(index)];
+
+ for (j = i; j < i + eltspersegment; j++) {
+ d[j] = bfdotadd(a[j], n[j], m_idx, &fpst);
+ }
}
}
clear_tail(d, opr_sz, simd_maxsz(desc));
}
-void HELPER(gvec_bfmmla)(void *vd, void *vn, void *vm, void *va, uint32_t desc)
+void HELPER(gvec_bfmmla)(void *vd, void *vn, void *vm, void *va,
+ CPUARMState *env, uint32_t desc)
{
intptr_t s, opr_sz = simd_oprsz(desc);
float32 *d = vd, *a = va;
uint32_t *n = vn, *m = vm;
+ float_status fpst, fpst_odd;
- for (s = 0; s < opr_sz / 4; s += 4) {
- float32 sum00, sum01, sum10, sum11;
+ if (is_ebf(env, &fpst, &fpst_odd)) {
+ for (s = 0; s < opr_sz / 4; s += 4) {
+ float32 sum00, sum01, sum10, sum11;
- /*
- * Process the entire segment at once, writing back the
- * results only after we've consumed all of the inputs.
- *
- * Key to indices by column:
- * i j i k j k
- */
- sum00 = a[s + H4(0 + 0)];
- sum00 = bfdotadd(sum00, n[s + H4(0 + 0)], m[s + H4(0 + 0)]);
- sum00 = bfdotadd(sum00, n[s + H4(0 + 1)], m[s + H4(0 + 1)]);
-
- sum01 = a[s + H4(0 + 1)];
- sum01 = bfdotadd(sum01, n[s + H4(0 + 0)], m[s + H4(2 + 0)]);
- sum01 = bfdotadd(sum01, n[s + H4(0 + 1)], m[s + H4(2 + 1)]);
-
- sum10 = a[s + H4(2 + 0)];
- sum10 = bfdotadd(sum10, n[s + H4(2 + 0)], m[s + H4(0 + 0)]);
- sum10 = bfdotadd(sum10, n[s + H4(2 + 1)], m[s + H4(0 + 1)]);
-
- sum11 = a[s + H4(2 + 1)];
- sum11 = bfdotadd(sum11, n[s + H4(2 + 0)], m[s + H4(2 + 0)]);
- sum11 = bfdotadd(sum11, n[s + H4(2 + 1)], m[s + H4(2 + 1)]);
-
- d[s + H4(0 + 0)] = sum00;
- d[s + H4(0 + 1)] = sum01;
- d[s + H4(2 + 0)] = sum10;
- d[s + H4(2 + 1)] = sum11;
+ /*
+ * Process the entire segment at once, writing back the
+ * results only after we've consumed all of the inputs.
+ *
+ * Key to indices by column:
+ * i j i k j k
+ */
+ sum00 = a[s + H4(0 + 0)];
+ sum00 = bfdotadd_ebf(sum00, n[s + H4(0 + 0)], m[s + H4(0 + 0)], &fpst, &fpst_odd);
+ sum00 = bfdotadd_ebf(sum00, n[s + H4(0 + 1)], m[s + H4(0 + 1)], &fpst, &fpst_odd);
+
+ sum01 = a[s + H4(0 + 1)];
+ sum01 = bfdotadd_ebf(sum01, n[s + H4(0 + 0)], m[s + H4(2 + 0)], &fpst, &fpst_odd);
+ sum01 = bfdotadd_ebf(sum01, n[s + H4(0 + 1)], m[s + H4(2 + 1)], &fpst, &fpst_odd);
+
+ sum10 = a[s + H4(2 + 0)];
+ sum10 = bfdotadd_ebf(sum10, n[s + H4(2 + 0)], m[s + H4(0 + 0)], &fpst, &fpst_odd);
+ sum10 = bfdotadd_ebf(sum10, n[s + H4(2 + 1)], m[s + H4(0 + 1)], &fpst, &fpst_odd);
+
+ sum11 = a[s + H4(2 + 1)];
+ sum11 = bfdotadd_ebf(sum11, n[s + H4(2 + 0)], m[s + H4(2 + 0)], &fpst, &fpst_odd);
+ sum11 = bfdotadd_ebf(sum11, n[s + H4(2 + 1)], m[s + H4(2 + 1)], &fpst, &fpst_odd);
+
+ d[s + H4(0 + 0)] = sum00;
+ d[s + H4(0 + 1)] = sum01;
+ d[s + H4(2 + 0)] = sum10;
+ d[s + H4(2 + 1)] = sum11;
+ }
+ } else {
+ for (s = 0; s < opr_sz / 4; s += 4) {
+ float32 sum00, sum01, sum10, sum11;
+
+ /*
+ * Process the entire segment at once, writing back the
+ * results only after we've consumed all of the inputs.
+ *
+ * Key to indices by column:
+ * i j i k j k
+ */
+ sum00 = a[s + H4(0 + 0)];
+ sum00 = bfdotadd(sum00, n[s + H4(0 + 0)], m[s + H4(0 + 0)], &fpst);
+ sum00 = bfdotadd(sum00, n[s + H4(0 + 1)], m[s + H4(0 + 1)], &fpst);
+
+ sum01 = a[s + H4(0 + 1)];
+ sum01 = bfdotadd(sum01, n[s + H4(0 + 0)], m[s + H4(2 + 0)], &fpst);
+ sum01 = bfdotadd(sum01, n[s + H4(0 + 1)], m[s + H4(2 + 1)], &fpst);
+
+ sum10 = a[s + H4(2 + 0)];
+ sum10 = bfdotadd(sum10, n[s + H4(2 + 0)], m[s + H4(0 + 0)], &fpst);
+ sum10 = bfdotadd(sum10, n[s + H4(2 + 1)], m[s + H4(0 + 1)], &fpst);
+
+ sum11 = a[s + H4(2 + 1)];
+ sum11 = bfdotadd(sum11, n[s + H4(2 + 0)], m[s + H4(2 + 0)], &fpst);
+ sum11 = bfdotadd(sum11, n[s + H4(2 + 1)], m[s + H4(2 + 1)], &fpst);
+
+ d[s + H4(0 + 0)] = sum00;
+ d[s + H4(0 + 1)] = sum01;
+ d[s + H4(2 + 0)] = sum10;
+ d[s + H4(2 + 1)] = sum11;
+ }
}
clear_tail(d, opr_sz, simd_maxsz(desc));
}
diff --git a/target/arm/tcg/vec_internal.h b/target/arm/tcg/vec_internal.h
index 3ca1b94..094f5c1 100644
--- a/target/arm/tcg/vec_internal.h
+++ b/target/arm/tcg/vec_internal.h
@@ -223,13 +223,46 @@ int64_t do_sqrdmlah_d(int64_t, int64_t, int64_t, bool, bool);
* bfdotadd:
* @sum: addend
* @e1, @e2: multiplicand vectors
+ * @fpst: floating-point status to use
*
* BFloat16 2-way dot product of @e1 & @e2, accumulating with @sum.
* The @e1 and @e2 operands correspond to the 32-bit source vector
* slots and contain two Bfloat16 values each.
*
- * Corresponds to the ARM pseudocode function BFDotAdd.
+ * Corresponds to the ARM pseudocode function BFDotAdd, specialized
+ * for the FPCR.EBF == 0 case.
*/
-float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2);
+float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst);
+/**
+ * bfdotadd_ebf:
+ * @sum: addend
+ * @e1, @e2: multiplicand vectors
+ * @fpst: floating-point status to use
+ * @fpst_odd: floating-point status to use for round-to-odd operations
+ *
+ * BFloat16 2-way dot product of @e1 & @e2, accumulating with @sum.
+ * The @e1 and @e2 operands correspond to the 32-bit source vector
+ * slots and contain two Bfloat16 values each.
+ *
+ * Corresponds to the ARM pseudocode function BFDotAdd, specialized
+ * for the FPCR.EBF == 1 case.
+ */
+float32 bfdotadd_ebf(float32 sum, uint32_t e1, uint32_t e2,
+ float_status *fpst, float_status *fpst_odd);
+
+/**
+ * is_ebf:
+ * @env: CPU state
+ * @statusp: pointer to floating point status to fill in
+ * @oddstatusp: pointer to floating point status to fill in for round-to-odd
+ *
+ * Determine whether a BFDotAdd operation should use FPCR.EBF = 0
+ * or FPCR.EBF = 1 semantics. On return, has initialized *statusp
+ * and *oddstatusp to suitable float_status arguments to use with either
+ * bfdotadd() or bfdotadd_ebf().
+ * Returns true for EBF = 1, false for EBF = 0. (The caller should use this
+ * to decide whether to call bfdotadd() or bfdotadd_ebf().)
+ */
+bool is_ebf(CPUARMState *env, float_status *statusp, float_status *oddstatusp);
#endif /* TARGET_ARM_VEC_INTERNAL_H */
diff --git a/target/arm/tcg/vfp.decode b/target/arm/tcg/vfp.decode
index 5405e80..2dd87a2 100644
--- a/target/arm/tcg/vfp.decode
+++ b/target/arm/tcg/vfp.decode
@@ -141,18 +141,18 @@ VDIV_dp ---- 1110 1.00 .... .... 1011 .0.0 .... @vfp_dnm_d
VFMA_hp ---- 1110 1.10 .... .... 1001 .0. 0 .... @vfp_dnm_s
VFMS_hp ---- 1110 1.10 .... .... 1001 .1. 0 .... @vfp_dnm_s
-VFNMA_hp ---- 1110 1.01 .... .... 1001 .0. 0 .... @vfp_dnm_s
-VFNMS_hp ---- 1110 1.01 .... .... 1001 .1. 0 .... @vfp_dnm_s
+VFNMS_hp ---- 1110 1.01 .... .... 1001 .0. 0 .... @vfp_dnm_s
+VFNMA_hp ---- 1110 1.01 .... .... 1001 .1. 0 .... @vfp_dnm_s
VFMA_sp ---- 1110 1.10 .... .... 1010 .0. 0 .... @vfp_dnm_s
VFMS_sp ---- 1110 1.10 .... .... 1010 .1. 0 .... @vfp_dnm_s
-VFNMA_sp ---- 1110 1.01 .... .... 1010 .0. 0 .... @vfp_dnm_s
-VFNMS_sp ---- 1110 1.01 .... .... 1010 .1. 0 .... @vfp_dnm_s
+VFNMS_sp ---- 1110 1.01 .... .... 1010 .0. 0 .... @vfp_dnm_s
+VFNMA_sp ---- 1110 1.01 .... .... 1010 .1. 0 .... @vfp_dnm_s
VFMA_dp ---- 1110 1.10 .... .... 1011 .0.0 .... @vfp_dnm_d
VFMS_dp ---- 1110 1.10 .... .... 1011 .1.0 .... @vfp_dnm_d
-VFNMA_dp ---- 1110 1.01 .... .... 1011 .0.0 .... @vfp_dnm_d
-VFNMS_dp ---- 1110 1.01 .... .... 1011 .1.0 .... @vfp_dnm_d
+VFNMS_dp ---- 1110 1.01 .... .... 1011 .0.0 .... @vfp_dnm_d
+VFNMA_dp ---- 1110 1.01 .... .... 1011 .1.0 .... @vfp_dnm_d
VMOV_imm_hp ---- 1110 1.11 .... .... 1001 0000 .... \
vd=%vd_sp imm=%vmov_imm
diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c
index b3698da..203d373 100644
--- a/target/arm/vfp_helper.c
+++ b/target/arm/vfp_helper.c
@@ -254,6 +254,10 @@ static void vfp_set_fpcr_masked(CPUARMState *env, uint32_t val, uint32_t mask)
val &= ~FPCR_FZ16;
}
+ if (!cpu_isar_feature(aa64_ebf16, cpu)) {
+ val &= ~FPCR_EBF;
+ }
+
vfp_set_fpcr_to_host(env, val, mask);
if (mask & (FPCR_LEN_MASK | FPCR_STRIDE_MASK)) {
@@ -278,12 +282,12 @@ static void vfp_set_fpcr_masked(CPUARMState *env, uint32_t val, uint32_t mask)
* We don't implement trapped exception handling, so the
* trap enable bits, IDE|IXE|UFE|OFE|DZE|IOE are all RAZ/WI (not RES0!)
*
- * The FPCR bits we keep in vfp.fpcr are AHP, DN, FZ, RMode
+ * The FPCR bits we keep in vfp.fpcr are AHP, DN, FZ, RMode, EBF
* and FZ16. Len, Stride and LTPSIZE we just handled. Store those bits
* there, and zero any of the other FPCR bits and the RES0 and RAZ/WI
* bits.
*/
- val &= FPCR_AHP | FPCR_DN | FPCR_FZ | FPCR_RMODE_MASK | FPCR_FZ16;
+ val &= FPCR_AHP | FPCR_DN | FPCR_FZ | FPCR_RMODE_MASK | FPCR_FZ16 | FPCR_EBF;
env->vfp.fpcr &= ~mask;
env->vfp.fpcr |= val;
}
diff --git a/target/avr/gdbstub.c b/target/avr/gdbstub.c
index d6d3c14..aea7128 100644
--- a/target/avr/gdbstub.c
+++ b/target/avr/gdbstub.c
@@ -69,13 +69,13 @@ int avr_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
/* SP */
if (n == 33) {
- env->sp = lduw_p(mem_buf);
+ env->sp = lduw_le_p(mem_buf);
return 2;
}
/* PC */
if (n == 34) {
- env->pc_w = ldl_p(mem_buf) / 2;
+ env->pc_w = ldl_le_p(mem_buf) / 2;
return 4;
}
diff --git a/target/cris/Kconfig b/target/cris/Kconfig
deleted file mode 100644
index 3fdc309..0000000
--- a/target/cris/Kconfig
+++ /dev/null
@@ -1,2 +0,0 @@
-config CRIS
- bool
diff --git a/target/cris/cpu-param.h b/target/cris/cpu-param.h
deleted file mode 100644
index b31b742..0000000
--- a/target/cris/cpu-param.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * CRIS cpu parameters for qemu.
- *
- * Copyright (c) 2007 AXIS Communications AB
- * SPDX-License-Identifier: LGPL-2.0+
- */
-
-#ifndef CRIS_CPU_PARAM_H
-#define CRIS_CPU_PARAM_H
-
-#define TARGET_LONG_BITS 32
-#define TARGET_PAGE_BITS 13
-#define TARGET_PHYS_ADDR_SPACE_BITS 32
-#define TARGET_VIRT_ADDR_SPACE_BITS 32
-
-#endif
diff --git a/target/cris/cpu-qom.h b/target/cris/cpu-qom.h
deleted file mode 100644
index 741ca97..0000000
--- a/target/cris/cpu-qom.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * QEMU CRIS CPU QOM header (target agnostic)
- *
- * 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_CRIS_CPU_QOM_H
-#define QEMU_CRIS_CPU_QOM_H
-
-#include "hw/core/cpu.h"
-
-#define TYPE_CRIS_CPU "cris-cpu"
-
-OBJECT_DECLARE_CPU_TYPE(CRISCPU, CRISCPUClass, CRIS_CPU)
-
-#define CRIS_CPU_TYPE_SUFFIX "-" TYPE_CRIS_CPU
-#define CRIS_CPU_TYPE_NAME(name) (name CRIS_CPU_TYPE_SUFFIX)
-
-#endif
diff --git a/target/cris/cpu.c b/target/cris/cpu.c
deleted file mode 100644
index ff31ca7..0000000
--- a/target/cris/cpu.c
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * QEMU CRIS CPU
- *
- * Copyright (c) 2008 AXIS Communications AB
- * Written by Edgar E. Iglesias.
- *
- * 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"
-#include "mmu.h"
-
-
-static void cris_cpu_set_pc(CPUState *cs, vaddr value)
-{
- CRISCPU *cpu = CRIS_CPU(cs);
-
- cpu->env.pc = value;
-}
-
-static vaddr cris_cpu_get_pc(CPUState *cs)
-{
- CRISCPU *cpu = CRIS_CPU(cs);
-
- return cpu->env.pc;
-}
-
-static void cris_restore_state_to_opc(CPUState *cs,
- const TranslationBlock *tb,
- const uint64_t *data)
-{
- CRISCPU *cpu = CRIS_CPU(cs);
-
- cpu->env.pc = data[0];
-}
-
-static bool cris_cpu_has_work(CPUState *cs)
-{
- return cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI);
-}
-
-static int cris_cpu_mmu_index(CPUState *cs, bool ifetch)
-{
- return !!(cpu_env(cs)->pregs[PR_CCS] & U_FLAG);
-}
-
-static void cris_cpu_reset_hold(Object *obj, ResetType type)
-{
- CPUState *cs = CPU(obj);
- CRISCPUClass *ccc = CRIS_CPU_GET_CLASS(obj);
- CPUCRISState *env = cpu_env(cs);
- uint32_t vr;
-
- if (ccc->parent_phases.hold) {
- ccc->parent_phases.hold(obj, type);
- }
-
- vr = env->pregs[PR_VR];
- memset(env, 0, offsetof(CPUCRISState, end_reset_fields));
- env->pregs[PR_VR] = vr;
-
-#if defined(CONFIG_USER_ONLY)
- /* start in user mode with interrupts enabled. */
- env->pregs[PR_CCS] |= U_FLAG | I_FLAG | P_FLAG;
-#else
- cris_mmu_init(env);
- env->pregs[PR_CCS] = 0;
-#endif
-}
-
-static ObjectClass *cris_cpu_class_by_name(const char *cpu_model)
-{
- ObjectClass *oc;
- char *typename;
-
-#if defined(CONFIG_USER_ONLY)
- if (strcasecmp(cpu_model, "any") == 0) {
- return object_class_by_name(CRIS_CPU_TYPE_NAME("crisv32"));
- }
-#endif
-
- typename = g_strdup_printf(CRIS_CPU_TYPE_NAME("%s"), cpu_model);
- oc = object_class_by_name(typename);
- g_free(typename);
-
- return oc;
-}
-
-static void cris_cpu_realizefn(DeviceState *dev, Error **errp)
-{
- CPUState *cs = CPU(dev);
- CRISCPUClass *ccc = CRIS_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);
-
- ccc->parent_realize(dev, errp);
-}
-
-#ifndef CONFIG_USER_ONLY
-static void cris_cpu_set_irq(void *opaque, int irq, int level)
-{
- CRISCPU *cpu = opaque;
- CPUState *cs = CPU(cpu);
- int type = irq == CRIS_CPU_IRQ ? CPU_INTERRUPT_HARD : CPU_INTERRUPT_NMI;
-
- if (irq == CRIS_CPU_IRQ) {
- /*
- * The PIC passes us the vector for the IRQ as the value it sends
- * over the qemu_irq line
- */
- cpu->env.interrupt_vector = level;
- }
-
- if (level) {
- cpu_interrupt(cs, type);
- } else {
- cpu_reset_interrupt(cs, type);
- }
-}
-#endif
-
-static void cris_disas_set_info(CPUState *cpu, disassemble_info *info)
-{
- if (cpu_env(cpu)->pregs[PR_VR] != 32) {
- info->mach = bfd_mach_cris_v0_v10;
- info->print_insn = print_insn_crisv10;
- } else {
- info->mach = bfd_mach_cris_v32;
- info->print_insn = print_insn_crisv32;
- }
-}
-
-static void cris_cpu_initfn(Object *obj)
-{
- CRISCPU *cpu = CRIS_CPU(obj);
- CRISCPUClass *ccc = CRIS_CPU_GET_CLASS(obj);
- CPUCRISState *env = &cpu->env;
-
- env->pregs[PR_VR] = ccc->vr;
-
-#ifndef CONFIG_USER_ONLY
- /* IRQ and NMI lines. */
- qdev_init_gpio_in(DEVICE(cpu), cris_cpu_set_irq, 2);
-#endif
-}
-
-#ifndef CONFIG_USER_ONLY
-#include "hw/core/sysemu-cpu-ops.h"
-
-static const struct SysemuCPUOps cris_sysemu_ops = {
- .get_phys_page_debug = cris_cpu_get_phys_page_debug,
-};
-#endif
-
-#include "hw/core/tcg-cpu-ops.h"
-
-static const TCGCPUOps crisv10_tcg_ops = {
- .initialize = cris_initialize_crisv10_tcg,
- .restore_state_to_opc = cris_restore_state_to_opc,
-
-#ifndef CONFIG_USER_ONLY
- .tlb_fill = cris_cpu_tlb_fill,
- .cpu_exec_interrupt = cris_cpu_exec_interrupt,
- .cpu_exec_halt = cris_cpu_has_work,
- .do_interrupt = crisv10_cpu_do_interrupt,
-#endif /* !CONFIG_USER_ONLY */
-};
-
-static const TCGCPUOps crisv32_tcg_ops = {
- .initialize = cris_initialize_tcg,
- .restore_state_to_opc = cris_restore_state_to_opc,
-
-#ifndef CONFIG_USER_ONLY
- .tlb_fill = cris_cpu_tlb_fill,
- .cpu_exec_interrupt = cris_cpu_exec_interrupt,
- .cpu_exec_halt = cris_cpu_has_work,
- .do_interrupt = cris_cpu_do_interrupt,
-#endif /* !CONFIG_USER_ONLY */
-};
-
-static void crisv8_cpu_class_init(ObjectClass *oc, void *data)
-{
- CPUClass *cc = CPU_CLASS(oc);
- CRISCPUClass *ccc = CRIS_CPU_CLASS(oc);
-
- ccc->vr = 8;
- cc->gdb_read_register = crisv10_cpu_gdb_read_register;
- cc->tcg_ops = &crisv10_tcg_ops;
-}
-
-static void crisv9_cpu_class_init(ObjectClass *oc, void *data)
-{
- CPUClass *cc = CPU_CLASS(oc);
- CRISCPUClass *ccc = CRIS_CPU_CLASS(oc);
-
- ccc->vr = 9;
- cc->gdb_read_register = crisv10_cpu_gdb_read_register;
- cc->tcg_ops = &crisv10_tcg_ops;
-}
-
-static void crisv10_cpu_class_init(ObjectClass *oc, void *data)
-{
- CPUClass *cc = CPU_CLASS(oc);
- CRISCPUClass *ccc = CRIS_CPU_CLASS(oc);
-
- ccc->vr = 10;
- cc->gdb_read_register = crisv10_cpu_gdb_read_register;
- cc->tcg_ops = &crisv10_tcg_ops;
-}
-
-static void crisv11_cpu_class_init(ObjectClass *oc, void *data)
-{
- CPUClass *cc = CPU_CLASS(oc);
- CRISCPUClass *ccc = CRIS_CPU_CLASS(oc);
-
- ccc->vr = 11;
- cc->gdb_read_register = crisv10_cpu_gdb_read_register;
- cc->tcg_ops = &crisv10_tcg_ops;
-}
-
-static void crisv17_cpu_class_init(ObjectClass *oc, void *data)
-{
- CPUClass *cc = CPU_CLASS(oc);
- CRISCPUClass *ccc = CRIS_CPU_CLASS(oc);
-
- ccc->vr = 17;
- cc->gdb_read_register = crisv10_cpu_gdb_read_register;
- cc->tcg_ops = &crisv10_tcg_ops;
-}
-
-static void crisv32_cpu_class_init(ObjectClass *oc, void *data)
-{
- CPUClass *cc = CPU_CLASS(oc);
- CRISCPUClass *ccc = CRIS_CPU_CLASS(oc);
-
- ccc->vr = 32;
- cc->tcg_ops = &crisv32_tcg_ops;
-}
-
-static void cris_cpu_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- CPUClass *cc = CPU_CLASS(oc);
- CRISCPUClass *ccc = CRIS_CPU_CLASS(oc);
- ResettableClass *rc = RESETTABLE_CLASS(oc);
-
- device_class_set_parent_realize(dc, cris_cpu_realizefn,
- &ccc->parent_realize);
-
- resettable_class_set_parent_phases(rc, NULL, cris_cpu_reset_hold, NULL,
- &ccc->parent_phases);
-
- cc->class_by_name = cris_cpu_class_by_name;
- cc->has_work = cris_cpu_has_work;
- cc->mmu_index = cris_cpu_mmu_index;
- cc->dump_state = cris_cpu_dump_state;
- cc->set_pc = cris_cpu_set_pc;
- cc->get_pc = cris_cpu_get_pc;
- cc->gdb_read_register = cris_cpu_gdb_read_register;
- cc->gdb_write_register = cris_cpu_gdb_write_register;
-#ifndef CONFIG_USER_ONLY
- dc->vmsd = &vmstate_cris_cpu;
- cc->sysemu_ops = &cris_sysemu_ops;
-#endif
-
- cc->gdb_num_core_regs = 49;
- cc->gdb_stop_before_watchpoint = true;
-
- cc->disas_set_info = cris_disas_set_info;
-}
-
-#define DEFINE_CRIS_CPU_TYPE(cpu_model, initfn) \
- { \
- .parent = TYPE_CRIS_CPU, \
- .class_init = initfn, \
- .name = CRIS_CPU_TYPE_NAME(cpu_model), \
- }
-
-static const TypeInfo cris_cpu_model_type_infos[] = {
- {
- .name = TYPE_CRIS_CPU,
- .parent = TYPE_CPU,
- .instance_size = sizeof(CRISCPU),
- .instance_align = __alignof(CRISCPU),
- .instance_init = cris_cpu_initfn,
- .abstract = true,
- .class_size = sizeof(CRISCPUClass),
- .class_init = cris_cpu_class_init,
- },
- DEFINE_CRIS_CPU_TYPE("crisv8", crisv8_cpu_class_init),
- DEFINE_CRIS_CPU_TYPE("crisv9", crisv9_cpu_class_init),
- DEFINE_CRIS_CPU_TYPE("crisv10", crisv10_cpu_class_init),
- DEFINE_CRIS_CPU_TYPE("crisv11", crisv11_cpu_class_init),
- DEFINE_CRIS_CPU_TYPE("crisv17", crisv17_cpu_class_init),
- DEFINE_CRIS_CPU_TYPE("crisv32", crisv32_cpu_class_init),
-};
-
-DEFINE_TYPES(cris_cpu_model_type_infos)
diff --git a/target/cris/cpu.h b/target/cris/cpu.h
deleted file mode 100644
index 3904e54..0000000
--- a/target/cris/cpu.h
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * CRIS virtual CPU header
- *
- * Copyright (c) 2007 AXIS Communications AB
- * Written by Edgar E. Iglesias
- *
- * 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
- * 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 CRIS_CPU_H
-#define CRIS_CPU_H
-
-#include "cpu-qom.h"
-#include "exec/cpu-defs.h"
-
-#define EXCP_NMI 1
-#define EXCP_GURU 2
-#define EXCP_BUSFAULT 3
-#define EXCP_IRQ 4
-#define EXCP_BREAK 5
-
-/* CRIS-specific interrupt pending bits. */
-#define CPU_INTERRUPT_NMI CPU_INTERRUPT_TGT_EXT_3
-
-/* CRUS CPU device objects interrupt lines. */
-/* PIC passes the vector for the IRQ as the value of it sends over qemu_irq */
-#define CRIS_CPU_IRQ 0
-#define CRIS_CPU_NMI 1
-
-/* Register aliases. R0 - R15 */
-#define R_FP 8
-#define R_SP 14
-#define R_ACR 15
-
-/* Support regs, P0 - P15 */
-#define PR_BZ 0
-#define PR_VR 1
-#define PR_PID 2
-#define PR_SRS 3
-#define PR_WZ 4
-#define PR_EXS 5
-#define PR_EDA 6
-#define PR_PREFIX 6 /* On CRISv10 P6 is reserved, we use it as prefix. */
-#define PR_MOF 7
-#define PR_DZ 8
-#define PR_EBP 9
-#define PR_ERP 10
-#define PR_SRP 11
-#define PR_NRP 12
-#define PR_CCS 13
-#define PR_USP 14
-#define PRV10_BRP 14
-#define PR_SPC 15
-
-/* CPU flags. */
-#define Q_FLAG 0x80000000
-#define M_FLAG_V32 0x40000000
-#define PFIX_FLAG 0x800 /* CRISv10 Only. */
-#define F_FLAG_V10 0x400
-#define P_FLAG_V10 0x200
-#define S_FLAG 0x200
-#define R_FLAG 0x100
-#define P_FLAG 0x80
-#define M_FLAG_V10 0x80
-#define U_FLAG 0x40
-#define I_FLAG 0x20
-#define X_FLAG 0x10
-#define N_FLAG 0x08
-#define Z_FLAG 0x04
-#define V_FLAG 0x02
-#define C_FLAG 0x01
-#define ALU_FLAGS 0x1F
-
-/* Condition codes. */
-#define CC_CC 0
-#define CC_CS 1
-#define CC_NE 2
-#define CC_EQ 3
-#define CC_VC 4
-#define CC_VS 5
-#define CC_PL 6
-#define CC_MI 7
-#define CC_LS 8
-#define CC_HI 9
-#define CC_GE 10
-#define CC_LT 11
-#define CC_GT 12
-#define CC_LE 13
-#define CC_A 14
-#define CC_P 15
-
-typedef struct {
- uint32_t hi;
- uint32_t lo;
-} TLBSet;
-
-typedef struct CPUArchState {
- uint32_t regs[16];
- /* P0 - P15 are referred to as special registers in the docs. */
- uint32_t pregs[16];
-
- /* Pseudo register for the PC. Not directly accessible on CRIS. */
- uint32_t pc;
-
- /* Pseudo register for the kernel stack. */
- uint32_t ksp;
-
- /* Branch. */
- int dslot;
- int btaken;
- uint32_t btarget;
-
- /* Condition flag tracking. */
- uint32_t cc_op;
- uint32_t cc_mask;
- uint32_t cc_dest;
- uint32_t cc_src;
- uint32_t cc_result;
- /* size of the operation, 1 = byte, 2 = word, 4 = dword. */
- int cc_size;
- /* X flag at the time of cc snapshot. */
- int cc_x;
-
- /* CRIS has certain insns that lockout interrupts. */
- int locked_irq;
- int interrupt_vector;
- int fault_vector;
- int trap_vector;
-
- /* FIXME: add a check in the translator to avoid writing to support
- register sets beyond the 4th. The ISA allows up to 256! but in
- practice there is no core that implements more than 4.
-
- Support function registers are used to control units close to the
- core. Accesses do not pass down the normal hierarchy.
- */
- uint32_t sregs[4][16];
-
- /* Linear feedback shift reg in the mmu. Used to provide pseudo
- randomness for the 'hint' the mmu gives to sw for choosing valid
- sets on TLB refills. */
- uint32_t mmu_rand_lfsr;
-
- /*
- * We just store the stores to the tlbset here for later evaluation
- * when the hw needs access to them.
- *
- * One for I and another for D.
- */
- TLBSet tlbsets[2][4][16];
-
- /* Fields up to this point are cleared by a CPU reset */
- struct {} end_reset_fields;
-
- /* Members from load_info on are preserved across resets. */
- void *load_info;
-} CPUCRISState;
-
-/**
- * CRISCPU:
- * @env: #CPUCRISState
- *
- * A CRIS CPU.
- */
-struct ArchCPU {
- CPUState parent_obj;
-
- CPUCRISState env;
-};
-
-/**
- * CRISCPUClass:
- * @parent_realize: The parent class' realize handler.
- * @parent_phases: The parent class' reset phase handlers.
- * @vr: Version Register value.
- *
- * A CRIS CPU model.
- */
-struct CRISCPUClass {
- CPUClass parent_class;
-
- DeviceRealize parent_realize;
- ResettablePhases parent_phases;
-
- uint32_t vr;
-};
-
-#ifndef CONFIG_USER_ONLY
-extern const VMStateDescription vmstate_cris_cpu;
-
-void cris_cpu_do_interrupt(CPUState *cpu);
-void crisv10_cpu_do_interrupt(CPUState *cpu);
-bool cris_cpu_exec_interrupt(CPUState *cpu, int int_req);
-
-bool cris_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
- MMUAccessType access_type, int mmu_idx,
- bool probe, uintptr_t retaddr);
-hwaddr cris_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
-#endif
-
-void cris_cpu_dump_state(CPUState *cs, FILE *f, int flags);
-
-int crisv10_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
-int cris_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
-int cris_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
-
-void cris_initialize_tcg(void);
-void cris_initialize_crisv10_tcg(void);
-
-/* Instead of computing the condition codes after each CRIS instruction,
- * QEMU just stores one operand (called CC_SRC), the result
- * (called CC_DEST) and the type of operation (called CC_OP). When the
- * condition codes are needed, the condition codes can be calculated
- * using this information. Condition codes are not generated if they
- * are only needed for conditional branches.
- */
-enum {
- CC_OP_DYNAMIC, /* Use env->cc_op */
- CC_OP_FLAGS,
- CC_OP_CMP,
- CC_OP_MOVE,
- CC_OP_ADD,
- CC_OP_ADDC,
- CC_OP_MCP,
- CC_OP_ADDU,
- CC_OP_SUB,
- CC_OP_SUBU,
- CC_OP_NEG,
- CC_OP_BTST,
- CC_OP_MULS,
- CC_OP_MULU,
- CC_OP_DSTEP,
- CC_OP_MSTEP,
- CC_OP_BOUND,
-
- CC_OP_OR,
- CC_OP_AND,
- CC_OP_XOR,
- CC_OP_LSL,
- CC_OP_LSR,
- CC_OP_ASR,
- CC_OP_LZ
-};
-
-/* CRIS uses 8k pages. */
-#define MMAP_SHIFT TARGET_PAGE_BITS
-
-#define CPU_RESOLVING_TYPE TYPE_CRIS_CPU
-
-/* MMU modes definitions */
-#define MMU_USER_IDX 1
-
-/* Support function regs. */
-#define SFR_RW_GC_CFG 0][0
-#define SFR_RW_MM_CFG env->pregs[PR_SRS]][0
-#define SFR_RW_MM_KBASE_LO env->pregs[PR_SRS]][1
-#define SFR_RW_MM_KBASE_HI env->pregs[PR_SRS]][2
-#define SFR_R_MM_CAUSE env->pregs[PR_SRS]][3
-#define SFR_RW_MM_TLB_SEL env->pregs[PR_SRS]][4
-#define SFR_RW_MM_TLB_LO env->pregs[PR_SRS]][5
-#define SFR_RW_MM_TLB_HI env->pregs[PR_SRS]][6
-
-#include "exec/cpu-all.h"
-
-static inline void cpu_get_tb_cpu_state(CPUCRISState *env, vaddr *pc,
- uint64_t *cs_base, uint32_t *flags)
-{
- *pc = env->pc;
- *cs_base = 0;
- *flags = env->dslot |
- (env->pregs[PR_CCS] & (S_FLAG | P_FLAG | U_FLAG
- | X_FLAG | PFIX_FLAG));
-}
-
-#endif
diff --git a/target/cris/crisv10-decode.h b/target/cris/crisv10-decode.h
deleted file mode 100644
index 9c531f3..0000000
--- a/target/cris/crisv10-decode.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * CRISv10 insn decoding macros.
- *
- * Copyright (c) 2010 AXIS Communications AB
- * Written by Edgar E. Iglesias.
- *
- * 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 TARGET_CRIS_CRISV10_DECODE_H
-#define TARGET_CRIS_CRISV10_DECODE_H
-
-#define CRISV10_MODE_QIMMEDIATE 0
-#define CRISV10_MODE_REG 1
-#define CRISV10_MODE_INDIRECT 2
-#define CRISV10_MODE_AUTOINC 3
-
-/* Quick Immediate. */
-#define CRISV10_QIMM_BCC_R0 0
-#define CRISV10_QIMM_BCC_R1 1
-#define CRISV10_QIMM_BCC_R2 2
-#define CRISV10_QIMM_BCC_R3 3
-
-#define CRISV10_QIMM_BDAP_R0 4
-#define CRISV10_QIMM_BDAP_R1 5
-#define CRISV10_QIMM_BDAP_R2 6
-#define CRISV10_QIMM_BDAP_R3 7
-
-#define CRISV10_QIMM_ADDQ 8
-#define CRISV10_QIMM_MOVEQ 9
-#define CRISV10_QIMM_SUBQ 10
-#define CRISV10_QIMM_CMPQ 11
-#define CRISV10_QIMM_ANDQ 12
-#define CRISV10_QIMM_ORQ 13
-#define CRISV10_QIMM_ASHQ 14
-#define CRISV10_QIMM_LSHQ 15
-
-
-#define CRISV10_REG_ADDX 0
-#define CRISV10_REG_MOVX 1
-#define CRISV10_REG_SUBX 2
-#define CRISV10_REG_LSL 3
-#define CRISV10_REG_ADDI 4
-#define CRISV10_REG_BIAP 5
-#define CRISV10_REG_NEG 6
-#define CRISV10_REG_BOUND 7
-#define CRISV10_REG_ADD 8
-#define CRISV10_REG_MOVE_R 9
-#define CRISV10_REG_MOVE_SPR_R 9
-#define CRISV10_REG_MOVE_R_SPR 8
-#define CRISV10_REG_SUB 10
-#define CRISV10_REG_CMP 11
-#define CRISV10_REG_AND 12
-#define CRISV10_REG_OR 13
-#define CRISV10_REG_ASR 14
-#define CRISV10_REG_LSR 15
-
-#define CRISV10_REG_BTST 3
-#define CRISV10_REG_SCC 4
-#define CRISV10_REG_SETF 6
-#define CRISV10_REG_CLEARF 7
-#define CRISV10_REG_BIAP 5
-#define CRISV10_REG_ABS 10
-#define CRISV10_REG_DSTEP 11
-#define CRISV10_REG_LZ 12
-#define CRISV10_REG_NOT 13
-#define CRISV10_REG_SWAP 13
-#define CRISV10_REG_XOR 14
-#define CRISV10_REG_MSTEP 15
-
-/* Indirect, var size. */
-#define CRISV10_IND_TEST 14
-#define CRISV10_IND_MUL 4
-#define CRISV10_IND_BDAP_M 5
-#define CRISV10_IND_ADD 8
-#define CRISV10_IND_MOVE_M_R 9
-
-
-/* indirect fixed size. */
-#define CRISV10_IND_ADDX 0
-#define CRISV10_IND_MOVX 1
-#define CRISV10_IND_SUBX 2
-#define CRISV10_IND_CMPX 3
-#define CRISV10_IND_JUMP_M 4
-#define CRISV10_IND_DIP 5
-#define CRISV10_IND_JUMP_R 6
-#define CRISV17_IND_ADDC 6
-#define CRISV10_IND_BOUND 7
-#define CRISV10_IND_BCC_M 7
-#define CRISV10_IND_MOVE_M_SPR 8
-#define CRISV10_IND_MOVE_SPR_M 9
-#define CRISV10_IND_SUB 10
-#define CRISV10_IND_CMP 11
-#define CRISV10_IND_AND 12
-#define CRISV10_IND_OR 13
-#define CRISV10_IND_MOVE_R_M 15
-
-#define CRISV10_IND_MOVEM_M_R 14
-#define CRISV10_IND_MOVEM_R_M 15
-
-#endif
diff --git a/target/cris/crisv32-decode.h b/target/cris/crisv32-decode.h
deleted file mode 100644
index fa0a7f0..0000000
--- a/target/cris/crisv32-decode.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * CRIS insn decoding macros.
- *
- * Copyright (c) 2007 AXIS Communications AB
- * Written by Edgar E. Iglesias.
- *
- * 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 CRISV32_DECODE_H
-#define CRISV32_DECODE_H
-
-/* Convenient binary macros. */
-#define HEX__(n) 0x##n##LU
-#define B8__(x) ((x&0x0000000FLU)?1:0) \
- + ((x&0x000000F0LU)?2:0) \
- + ((x&0x00000F00LU)?4:0) \
- + ((x&0x0000F000LU)?8:0) \
- + ((x&0x000F0000LU)?16:0) \
- + ((x&0x00F00000LU)?32:0) \
- + ((x&0x0F000000LU)?64:0) \
- + ((x&0xF0000000LU)?128:0)
-#define B8(d) ((unsigned char)B8__(HEX__(d)))
-
-/* Quick imm. */
-#define DEC_BCCQ {B8(00000000), B8(11110000)}
-#define DEC_ADDOQ {B8(00010000), B8(11110000)}
-#define DEC_ADDQ {B8(00100000), B8(11111100)}
-#define DEC_MOVEQ {B8(00100100), B8(11111100)}
-#define DEC_SUBQ {B8(00101000), B8(11111100)}
-#define DEC_CMPQ {B8(00101100), B8(11111100)}
-#define DEC_ANDQ {B8(00110000), B8(11111100)}
-#define DEC_ORQ {B8(00110100), B8(11111100)}
-#define DEC_BTSTQ {B8(00111000), B8(11111110)}
-#define DEC_ASRQ {B8(00111010), B8(11111110)}
-#define DEC_LSLQ {B8(00111100), B8(11111110)}
-#define DEC_LSRQ {B8(00111110), B8(11111110)}
-
-/* Register. */
-#define DEC_MOVU_R {B8(01000100), B8(11111110)}
-#define DEC_MOVU_R {B8(01000100), B8(11111110)}
-#define DEC_MOVS_R {B8(01000110), B8(11111110)}
-#define DEC_MOVE_R {B8(01100100), B8(11111100)}
-#define DEC_MOVE_RP {B8(01100011), B8(11111111)}
-#define DEC_MOVE_PR {B8(01100111), B8(11111111)}
-#define DEC_DSTEP_R {B8(01101111), B8(11111111)}
-#define DEC_MOVE_RS {B8(10110111), B8(11111111)}
-#define DEC_MOVE_SR {B8(11110111), B8(11111111)}
-#define DEC_ADDU_R {B8(01000000), B8(11111110)}
-#define DEC_ADDS_R {B8(01000010), B8(11111110)}
-#define DEC_ADD_R {B8(01100000), B8(11111100)}
-#define DEC_ADDI_R {B8(01010000), B8(11111100)}
-#define DEC_MULS_R {B8(11010000), B8(11111100)}
-#define DEC_MULU_R {B8(10010000), B8(11111100)}
-#define DEC_ADDI_ACR {B8(01010100), B8(11111100)}
-#define DEC_NEG_R {B8(01011000), B8(11111100)}
-#define DEC_BOUND_R {B8(01011100), B8(11111100)}
-#define DEC_SUBU_R {B8(01001000), B8(11111110)}
-#define DEC_SUBS_R {B8(01001010), B8(11111110)}
-#define DEC_SUB_R {B8(01101000), B8(11111100)}
-#define DEC_CMP_R {B8(01101100), B8(11111100)}
-#define DEC_AND_R {B8(01110000), B8(11111100)}
-#define DEC_ABS_R {B8(01101011), B8(11111111)}
-#define DEC_LZ_R {B8(01110011), B8(11111111)}
-#define DEC_MCP_R {B8(01111111), B8(11111111)}
-#define DEC_SWAP_R {B8(01110111), B8(11111111)}
-#define DEC_XOR_R {B8(01111011), B8(11111111)}
-#define DEC_LSL_R {B8(01001100), B8(11111100)}
-#define DEC_LSR_R {B8(01111100), B8(11111100)}
-#define DEC_ASR_R {B8(01111000), B8(11111100)}
-#define DEC_OR_R {B8(01110100), B8(11111100)}
-#define DEC_BTST_R {B8(01001111), B8(11111111)}
-
-/* Fixed. */
-#define DEC_SETF {B8(01011011), B8(11111111)}
-#define DEC_CLEARF {B8(01011111), B8(11111111)}
-
-/* Memory. */
-#define DEC_ADDU_M {B8(10000000), B8(10111110)}
-#define DEC_ADDS_M {B8(10000010), B8(10111110)}
-#define DEC_MOVU_M {B8(10000100), B8(10111110)}
-#define DEC_MOVS_M {B8(10000110), B8(10111110)}
-#define DEC_SUBU_M {B8(10001000), B8(10111110)}
-#define DEC_SUBS_M {B8(10001010), B8(10111110)}
-#define DEC_CMPU_M {B8(10001100), B8(10111110)}
-#define DEC_CMPS_M {B8(10001110), B8(10111110)}
-#define DEC_ADDO_M {B8(10010100), B8(10111100)}
-#define DEC_BOUND_M {B8(10011100), B8(10111100)}
-#define DEC_ADD_M {B8(10100000), B8(10111100)}
-#define DEC_MOVE_MR {B8(10100100), B8(10111100)}
-#define DEC_SUB_M {B8(10101000), B8(10111100)}
-#define DEC_CMP_M {B8(10101100), B8(10111100)}
-#define DEC_AND_M {B8(10110000), B8(10111100)}
-#define DEC_OR_M {B8(10110100), B8(10111100)}
-#define DEC_TEST_M {B8(10111000), B8(10111100)}
-#define DEC_MOVE_RM {B8(10111100), B8(10111100)}
-
-#define DEC_ADDC_R {B8(01010111), B8(11111111)}
-#define DEC_ADDC_MR {B8(10011010), B8(10111111)}
-#define DEC_LAPCQ {B8(10010111), B8(11111111)}
-#define DEC_LAPC_IM {B8(11010111), B8(11111111)}
-
-#define DEC_MOVE_MP {B8(10100011), B8(10111111)}
-#define DEC_MOVE_PM {B8(10100111), B8(10111111)}
-
-#define DEC_SCC_R {B8(01010011), B8(11111111)}
-#define DEC_RFE_ETC {B8(10010011), B8(11111111)}
-#define DEC_JUMP_P {B8(10011111), B8(11111111)}
-#define DEC_BCC_IM {B8(11011111), B8(11111111)}
-#define DEC_JAS_R {B8(10011011), B8(11111111)}
-#define DEC_JASC_R {B8(10110011), B8(11111111)}
-#define DEC_JAS_IM {B8(11011011), B8(11111111)}
-#define DEC_JASC_IM {B8(11110011), B8(11111111)}
-#define DEC_BAS_IM {B8(11101011), B8(11111111)}
-#define DEC_BASC_IM {B8(11101111), B8(11111111)}
-#define DEC_MOVEM_MR {B8(10111011), B8(10111111)}
-#define DEC_MOVEM_RM {B8(10111111), B8(10111111)}
-
-#define DEC_FTAG_FIDX_D_M {B8(10101011), B8(11111111)}
-#define DEC_FTAG_FIDX_I_M {B8(11010011), B8(11111111)}
-
-#endif
diff --git a/target/cris/gdbstub.c b/target/cris/gdbstub.c
deleted file mode 100644
index 9e87069..0000000
--- a/target/cris/gdbstub.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * CRIS 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 "gdbstub/helpers.h"
-
-int crisv10_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
-{
- CPUCRISState *env = cpu_env(cs);
-
- if (n < 15) {
- return gdb_get_reg32(mem_buf, env->regs[n]);
- }
-
- if (n == 15) {
- return gdb_get_reg32(mem_buf, env->pc);
- }
-
- if (n < 32) {
- switch (n) {
- case 16:
- return gdb_get_reg8(mem_buf, env->pregs[n - 16]);
- case 17:
- return gdb_get_reg8(mem_buf, env->pregs[n - 16]);
- case 20:
- case 21:
- return gdb_get_reg16(mem_buf, env->pregs[n - 16]);
- default:
- if (n >= 23) {
- return gdb_get_reg32(mem_buf, env->pregs[n - 16]);
- }
- break;
- }
- }
- return 0;
-}
-
-int cris_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
-{
- CPUCRISState *env = cpu_env(cs);
- uint8_t srs;
-
- srs = env->pregs[PR_SRS];
- if (n < 16) {
- return gdb_get_reg32(mem_buf, env->regs[n]);
- }
-
- if (n >= 21 && n < 32) {
- return gdb_get_reg32(mem_buf, env->pregs[n - 16]);
- }
- if (n >= 33 && n < 49) {
- return gdb_get_reg32(mem_buf, env->sregs[srs][n - 33]);
- }
- switch (n) {
- case 16:
- return gdb_get_reg8(mem_buf, env->pregs[0]);
- case 17:
- return gdb_get_reg8(mem_buf, env->pregs[1]);
- case 18:
- return gdb_get_reg32(mem_buf, env->pregs[2]);
- case 19:
- return gdb_get_reg8(mem_buf, srs);
- case 20:
- return gdb_get_reg16(mem_buf, env->pregs[4]);
- case 32:
- return gdb_get_reg32(mem_buf, env->pc);
- }
-
- return 0;
-}
-
-int cris_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
-{
- CPUCRISState *env = cpu_env(cs);
- uint32_t tmp;
-
- if (n > 49) {
- return 0;
- }
-
- tmp = ldl_p(mem_buf);
-
- if (n < 16) {
- env->regs[n] = tmp;
- }
-
- if (n >= 21 && n < 32) {
- env->pregs[n - 16] = tmp;
- }
-
- /* FIXME: Should support function regs be writable? */
- switch (n) {
- case 16:
- return 1;
- case 17:
- return 1;
- case 18:
- env->pregs[PR_PID] = tmp;
- break;
- case 19:
- return 1;
- case 20:
- return 2;
- case 32:
- env->pc = tmp;
- break;
- }
-
- return 4;
-}
diff --git a/target/cris/helper.c b/target/cris/helper.c
deleted file mode 100644
index 1c3f868..0000000
--- a/target/cris/helper.c
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * CRIS helper routines.
- *
- * Copyright (c) 2007 AXIS Communications AB
- * Written by Edgar E. Iglesias.
- *
- * 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/log.h"
-#include "cpu.h"
-#include "hw/core/tcg-cpu-ops.h"
-#include "mmu.h"
-#include "qemu/host-utils.h"
-#include "exec/exec-all.h"
-#include "exec/cpu_ldst.h"
-#include "exec/helper-proto.h"
-
-
-//#define CRIS_HELPER_DEBUG
-
-
-#ifdef CRIS_HELPER_DEBUG
-#define D(x) x
-#define D_LOG(...) qemu_log(__VA_ARGS__)
-#else
-#define D(x)
-#define D_LOG(...) do { } while (0)
-#endif
-
-static void cris_shift_ccs(CPUCRISState *env)
-{
- uint32_t ccs;
- /* Apply the ccs shift. */
- ccs = env->pregs[PR_CCS];
- ccs = ((ccs & 0xc0000000) | ((ccs << 12) >> 2)) & ~0x3ff;
- env->pregs[PR_CCS] = ccs;
-}
-
-bool cris_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
- MMUAccessType access_type, int mmu_idx,
- bool probe, uintptr_t retaddr)
-{
- CPUCRISState *env = cpu_env(cs);
- struct cris_mmu_result res;
- int prot, miss;
- target_ulong phy;
-
- miss = cris_mmu_translate(&res, env, address & TARGET_PAGE_MASK,
- access_type, mmu_idx, 0);
- if (likely(!miss)) {
- /*
- * Mask off the cache selection bit. The ETRAX busses do not
- * see the top bit.
- */
- phy = res.phy & ~0x80000000;
- prot = res.prot;
- tlb_set_page(cs, address & TARGET_PAGE_MASK, phy,
- prot, mmu_idx, TARGET_PAGE_SIZE);
- return true;
- }
-
- if (probe) {
- return false;
- }
-
- if (cs->exception_index == EXCP_BUSFAULT) {
- cpu_abort(cs, "CRIS: Illegal recursive bus fault."
- "addr=%" VADDR_PRIx " access_type=%d\n",
- address, access_type);
- }
-
- env->pregs[PR_EDA] = address;
- cs->exception_index = EXCP_BUSFAULT;
- env->fault_vector = res.bf_vec;
- if (retaddr) {
- if (cpu_restore_state(cs, retaddr)) {
- /* Evaluate flags after retranslation. */
- helper_top_evaluate_flags(env);
- }
- }
- cpu_loop_exit(cs);
-}
-
-void crisv10_cpu_do_interrupt(CPUState *cs)
-{
- CPUCRISState *env = cpu_env(cs);
- int ex_vec = -1;
-
- D_LOG("exception index=%d interrupt_req=%d\n",
- cs->exception_index,
- cs->interrupt_request);
-
- if (env->dslot) {
- /* CRISv10 never takes interrupts while in a delay-slot. */
- cpu_abort(cs, "CRIS: Interrupt on delay-slot\n");
- }
-
- assert(!(env->pregs[PR_CCS] & PFIX_FLAG));
- switch (cs->exception_index) {
- case EXCP_BREAK:
- /* These exceptions are generated by the core itself.
- ERP should point to the insn following the brk. */
- ex_vec = env->trap_vector;
- env->pregs[PRV10_BRP] = env->pc;
- break;
-
- case EXCP_NMI:
- /* NMI is hardwired to vector zero. */
- ex_vec = 0;
- env->pregs[PR_CCS] &= ~M_FLAG_V10;
- env->pregs[PRV10_BRP] = env->pc;
- break;
-
- case EXCP_BUSFAULT:
- cpu_abort(cs, "Unhandled busfault");
- break;
-
- default:
- /* The interrupt controller gives us the vector. */
- ex_vec = env->interrupt_vector;
- /* Normal interrupts are taken between
- TB's. env->pc is valid here. */
- env->pregs[PR_ERP] = env->pc;
- break;
- }
-
- if (env->pregs[PR_CCS] & U_FLAG) {
- /* Swap stack pointers. */
- env->pregs[PR_USP] = env->regs[R_SP];
- env->regs[R_SP] = env->ksp;
- }
-
- /* Now that we are in kernel mode, load the handlers address. */
- env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4);
- env->locked_irq = 1;
- env->pregs[PR_CCS] |= F_FLAG_V10; /* set F. */
-
- qemu_log_mask(CPU_LOG_INT, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n",
- __func__, env->pc, ex_vec,
- env->pregs[PR_CCS],
- env->pregs[PR_PID],
- env->pregs[PR_ERP]);
-}
-
-void cris_cpu_do_interrupt(CPUState *cs)
-{
- CPUCRISState *env = cpu_env(cs);
- int ex_vec = -1;
-
- D_LOG("exception index=%d interrupt_req=%d\n",
- cs->exception_index,
- cs->interrupt_request);
-
- switch (cs->exception_index) {
- case EXCP_BREAK:
- /* These exceptions are generated by the core itself.
- ERP should point to the insn following the brk. */
- ex_vec = env->trap_vector;
- env->pregs[PR_ERP] = env->pc;
- break;
-
- case EXCP_NMI:
- /* NMI is hardwired to vector zero. */
- ex_vec = 0;
- env->pregs[PR_CCS] &= ~M_FLAG_V32;
- env->pregs[PR_NRP] = env->pc;
- break;
-
- case EXCP_BUSFAULT:
- ex_vec = env->fault_vector;
- env->pregs[PR_ERP] = env->pc;
- break;
-
- default:
- /* The interrupt controller gives us the vector. */
- ex_vec = env->interrupt_vector;
- /* Normal interrupts are taken between
- TB's. env->pc is valid here. */
- env->pregs[PR_ERP] = env->pc;
- break;
- }
-
- /* Fill in the IDX field. */
- env->pregs[PR_EXS] = (ex_vec & 0xff) << 8;
-
- if (env->dslot) {
- D_LOG("excp isr=%x PC=%x ds=%d SP=%x"
- " ERP=%x pid=%x ccs=%x cc=%d %x\n",
- ex_vec, env->pc, env->dslot,
- env->regs[R_SP],
- env->pregs[PR_ERP], env->pregs[PR_PID],
- env->pregs[PR_CCS],
- env->cc_op, env->cc_mask);
- /* We loose the btarget, btaken state here so rexec the
- branch. */
- env->pregs[PR_ERP] -= env->dslot;
- /* Exception starts with dslot cleared. */
- env->dslot = 0;
- }
-
- if (env->pregs[PR_CCS] & U_FLAG) {
- /* Swap stack pointers. */
- env->pregs[PR_USP] = env->regs[R_SP];
- env->regs[R_SP] = env->ksp;
- }
-
- /* Apply the CRIS CCS shift. Clears U if set. */
- cris_shift_ccs(env);
-
- /* Now that we are in kernel mode, load the handlers address.
- This load may not fault, real hw leaves that behaviour as
- undefined. */
- env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4);
-
- /* Clear the excption_index to avoid spurious hw_aborts for recursive
- bus faults. */
- cs->exception_index = -1;
-
- D_LOG("%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n",
- __func__, env->pc, ex_vec,
- env->pregs[PR_CCS],
- env->pregs[PR_PID],
- env->pregs[PR_ERP]);
-}
-
-hwaddr cris_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
-{
- CRISCPU *cpu = CRIS_CPU(cs);
- uint32_t phy = addr;
- struct cris_mmu_result res;
- int miss;
-
- miss = cris_mmu_translate(&res, &cpu->env, addr, MMU_DATA_LOAD, 0, 1);
- /* If D TLB misses, try I TLB. */
- if (miss) {
- miss = cris_mmu_translate(&res, &cpu->env, addr, MMU_INST_FETCH, 0, 1);
- }
-
- if (!miss) {
- phy = res.phy;
- }
- D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy));
- return phy;
-}
-
-bool cris_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
-{
- CPUClass *cc = CPU_GET_CLASS(cs);
- CPUCRISState *env = cpu_env(cs);
- bool ret = false;
-
- if (interrupt_request & CPU_INTERRUPT_HARD
- && (env->pregs[PR_CCS] & I_FLAG)
- && !env->locked_irq) {
- cs->exception_index = EXCP_IRQ;
- cc->tcg_ops->do_interrupt(cs);
- ret = true;
- }
- if (interrupt_request & CPU_INTERRUPT_NMI) {
- unsigned int m_flag_archval;
- if (env->pregs[PR_VR] < 32) {
- m_flag_archval = M_FLAG_V10;
- } else {
- m_flag_archval = M_FLAG_V32;
- }
- if ((env->pregs[PR_CCS] & m_flag_archval)) {
- cs->exception_index = EXCP_NMI;
- cc->tcg_ops->do_interrupt(cs);
- ret = true;
- }
- }
-
- return ret;
-}
diff --git a/target/cris/helper.h b/target/cris/helper.h
deleted file mode 100644
index 3abf608..0000000
--- a/target/cris/helper.h
+++ /dev/null
@@ -1,23 +0,0 @@
-DEF_HELPER_2(raise_exception, noreturn, env, i32)
-DEF_HELPER_2(tlb_flush_pid, void, env, i32)
-DEF_HELPER_2(spc_write, void, env, i32)
-DEF_HELPER_1(rfe, void, env)
-DEF_HELPER_1(rfn, void, env)
-
-DEF_HELPER_3(movl_sreg_reg, void, env, i32, i32)
-DEF_HELPER_3(movl_reg_sreg, void, env, i32, i32)
-
-DEF_HELPER_FLAGS_4(btst, TCG_CALL_NO_SE, i32, env, i32, i32, i32)
-
-DEF_HELPER_FLAGS_4(evaluate_flags_muls, TCG_CALL_NO_SE, i32, env, i32, i32, i32)
-DEF_HELPER_FLAGS_4(evaluate_flags_mulu, TCG_CALL_NO_SE, i32, env, i32, i32, i32)
-DEF_HELPER_FLAGS_5(evaluate_flags_mcp, TCG_CALL_NO_SE, i32, env,
- i32, i32, i32, i32)
-DEF_HELPER_FLAGS_5(evaluate_flags_alu_4, TCG_CALL_NO_SE, i32, env,
- i32, i32, i32, i32)
-DEF_HELPER_FLAGS_5(evaluate_flags_sub_4, TCG_CALL_NO_SE, i32, env,
- i32, i32, i32, i32)
-DEF_HELPER_FLAGS_3(evaluate_flags_move_4, TCG_CALL_NO_SE, i32, env, i32, i32)
-DEF_HELPER_FLAGS_3(evaluate_flags_move_2, TCG_CALL_NO_SE, i32, env, i32, i32)
-DEF_HELPER_1(evaluate_flags, void, env)
-DEF_HELPER_1(top_evaluate_flags, void, env)
diff --git a/target/cris/machine.c b/target/cris/machine.c
deleted file mode 100644
index 7b9bde8..0000000
--- a/target/cris/machine.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * CRIS virtual CPU state save/load support
- *
- * Copyright (c) 2012 Red Hat, Inc.
- * Written by Juan Quintela <quintela@redhat.com>
- *
- * 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
- * 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 "migration/cpu.h"
-
-static const VMStateDescription vmstate_tlbset = {
- .name = "cpu/tlbset",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32(lo, TLBSet),
- VMSTATE_UINT32(hi, TLBSet),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_cris_env = {
- .name = "env",
- .version_id = 2,
- .minimum_version_id = 2,
- .fields = (const VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, CPUCRISState, 16),
- VMSTATE_UINT32_ARRAY(pregs, CPUCRISState, 16),
- VMSTATE_UINT32(pc, CPUCRISState),
- VMSTATE_UINT32(ksp, CPUCRISState),
- VMSTATE_INT32(dslot, CPUCRISState),
- VMSTATE_INT32(btaken, CPUCRISState),
- VMSTATE_UINT32(btarget, CPUCRISState),
- VMSTATE_UINT32(cc_op, CPUCRISState),
- VMSTATE_UINT32(cc_mask, CPUCRISState),
- VMSTATE_UINT32(cc_dest, CPUCRISState),
- VMSTATE_UINT32(cc_src, CPUCRISState),
- VMSTATE_UINT32(cc_result, CPUCRISState),
- VMSTATE_INT32(cc_size, CPUCRISState),
- VMSTATE_INT32(cc_x, CPUCRISState),
- VMSTATE_INT32(locked_irq, CPUCRISState),
- VMSTATE_INT32(interrupt_vector, CPUCRISState),
- VMSTATE_INT32(fault_vector, CPUCRISState),
- VMSTATE_INT32(trap_vector, CPUCRISState),
- VMSTATE_UINT32_ARRAY(sregs[0], CPUCRISState, 16),
- VMSTATE_UINT32_ARRAY(sregs[1], CPUCRISState, 16),
- VMSTATE_UINT32_ARRAY(sregs[2], CPUCRISState, 16),
- VMSTATE_UINT32_ARRAY(sregs[3], CPUCRISState, 16),
- VMSTATE_UINT32(mmu_rand_lfsr, CPUCRISState),
- VMSTATE_STRUCT_ARRAY(tlbsets[0][0], CPUCRISState, 16, 0,
- vmstate_tlbset, TLBSet),
- VMSTATE_STRUCT_ARRAY(tlbsets[0][1], CPUCRISState, 16, 0,
- vmstate_tlbset, TLBSet),
- VMSTATE_STRUCT_ARRAY(tlbsets[0][2], CPUCRISState, 16, 0,
- vmstate_tlbset, TLBSet),
- VMSTATE_STRUCT_ARRAY(tlbsets[0][3], CPUCRISState, 16, 0,
- vmstate_tlbset, TLBSet),
- VMSTATE_STRUCT_ARRAY(tlbsets[1][0], CPUCRISState, 16, 0,
- vmstate_tlbset, TLBSet),
- VMSTATE_STRUCT_ARRAY(tlbsets[1][1], CPUCRISState, 16, 0,
- vmstate_tlbset, TLBSet),
- VMSTATE_STRUCT_ARRAY(tlbsets[1][2], CPUCRISState, 16, 0,
- vmstate_tlbset, TLBSet),
- VMSTATE_STRUCT_ARRAY(tlbsets[1][3], CPUCRISState, 16, 0,
- vmstate_tlbset, TLBSet),
- VMSTATE_END_OF_LIST()
- }
-};
-
-const VMStateDescription vmstate_cris_cpu = {
- .name = "cpu",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (const VMStateField[]) {
- VMSTATE_CPU(),
- VMSTATE_STRUCT(env, CRISCPU, 1, vmstate_cris_env, CPUCRISState),
- VMSTATE_END_OF_LIST()
- }
-};
diff --git a/target/cris/meson.build b/target/cris/meson.build
deleted file mode 100644
index bbfcdf7..0000000
--- a/target/cris/meson.build
+++ /dev/null
@@ -1,17 +0,0 @@
-cris_ss = ss.source_set()
-cris_ss.add(files(
- 'cpu.c',
- 'gdbstub.c',
- 'op_helper.c',
- 'translate.c',
-))
-
-cris_system_ss = ss.source_set()
-cris_system_ss.add(files(
- 'helper.c',
- 'machine.c',
- 'mmu.c',
-))
-
-target_arch += {'cris': cris_ss}
-target_system_arch += {'cris': cris_system_ss}
diff --git a/target/cris/mmu.c b/target/cris/mmu.c
deleted file mode 100644
index d51008c..0000000
--- a/target/cris/mmu.c
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * CRIS mmu emulation.
- *
- * Copyright (c) 2007 AXIS Communications AB
- * Written by Edgar E. Iglesias.
- *
- * 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/page-protection.h"
-#include "mmu.h"
-
-#ifdef DEBUG
-#define D(x) x
-#define D_LOG(...) qemu_log(__VA_ARGS__)
-#else
-#define D(x) do { } while (0)
-#define D_LOG(...) do { } while (0)
-#endif
-
-void cris_mmu_init(CPUCRISState *env)
-{
- env->mmu_rand_lfsr = 0xcccc;
-}
-
-#define SR_POLYNOM 0x8805
-static inline unsigned int compute_polynom(unsigned int sr)
-{
- unsigned int i;
- unsigned int f;
-
- f = 0;
- for (i = 0; i < 16; i++) {
- f += ((SR_POLYNOM >> i) & 1) & ((sr >> i) & 1);
- }
-
- return f;
-}
-
-static void cris_mmu_update_rand_lfsr(CPUCRISState *env)
-{
- unsigned int f;
-
- /* Update lfsr at every fault. */
- f = compute_polynom(env->mmu_rand_lfsr);
- env->mmu_rand_lfsr >>= 1;
- env->mmu_rand_lfsr |= (f << 15);
- env->mmu_rand_lfsr &= 0xffff;
-}
-
-static inline int cris_mmu_enabled(uint32_t rw_gc_cfg)
-{
- return (rw_gc_cfg & 12) != 0;
-}
-
-static inline int cris_mmu_segmented_addr(int seg, uint32_t rw_mm_cfg)
-{
- return (1 << seg) & rw_mm_cfg;
-}
-
-static uint32_t cris_mmu_translate_seg(CPUCRISState *env, int seg)
-{
- uint32_t base;
- int i;
-
- if (seg < 8) {
- base = env->sregs[SFR_RW_MM_KBASE_LO];
- } else {
- base = env->sregs[SFR_RW_MM_KBASE_HI];
- }
-
- i = seg & 7;
- base >>= i * 4;
- base &= 15;
-
- base <<= 28;
- return base;
-}
-
-/* Used by the tlb decoder. */
-#define EXTRACT_FIELD(src, start, end) \
- (((src) >> start) & ((1 << (end - start + 1)) - 1))
-
-static inline void set_field(uint32_t *dst, unsigned int val,
- unsigned int offset, unsigned int width)
-{
- uint32_t mask;
-
- mask = (1 << width) - 1;
- mask <<= offset;
- val <<= offset;
-
- val &= mask;
- *dst &= ~(mask);
- *dst |= val;
-}
-
-#ifdef DEBUG
-static void dump_tlb(CPUCRISState *env, int mmu)
-{
- int set;
- int idx;
- uint32_t hi, lo, tlb_vpn, tlb_pfn;
-
- for (set = 0; set < 4; set++) {
- for (idx = 0; idx < 16; idx++) {
- lo = env->tlbsets[mmu][set][idx].lo;
- hi = env->tlbsets[mmu][set][idx].hi;
- tlb_vpn = EXTRACT_FIELD(hi, 13, 31);
- tlb_pfn = EXTRACT_FIELD(lo, 13, 31);
-
- printf("TLB: [%d][%d] hi=%x lo=%x v=%x p=%x\n",
- set, idx, hi, lo, tlb_vpn, tlb_pfn);
- }
- }
-}
-#endif
-
-static int cris_mmu_translate_page(struct cris_mmu_result *res,
- CPUCRISState *env, uint32_t vaddr,
- MMUAccessType access_type,
- int usermode, int debug)
-{
- unsigned int vpage;
- unsigned int idx;
- uint32_t pid, lo, hi;
- uint32_t tlb_vpn, tlb_pfn = 0;
- int tlb_pid, tlb_g, tlb_v, tlb_k, tlb_w, tlb_x;
- int cfg_v, cfg_k, cfg_w, cfg_x;
- int set, match = 0;
- uint32_t r_cause;
- uint32_t r_cfg;
- int rwcause;
- int mmu = 1; /* Data mmu is default. */
- int vect_base;
-
- r_cause = env->sregs[SFR_R_MM_CAUSE];
- r_cfg = env->sregs[SFR_RW_MM_CFG];
- pid = env->pregs[PR_PID] & 0xff;
-
- switch (access_type) {
- case MMU_INST_FETCH:
- rwcause = CRIS_MMU_ERR_EXEC;
- mmu = 0;
- break;
- case MMU_DATA_STORE:
- rwcause = CRIS_MMU_ERR_WRITE;
- break;
- default:
- case MMU_DATA_LOAD:
- rwcause = CRIS_MMU_ERR_READ;
- break;
- }
-
- /* I exception vectors 4 - 7, D 8 - 11. */
- vect_base = (mmu + 1) * 4;
-
- vpage = vaddr >> 13;
-
- /*
- * We know the index which to check on each set.
- * Scan both I and D.
- */
- idx = vpage & 15;
- for (set = 0; set < 4; set++) {
- lo = env->tlbsets[mmu][set][idx].lo;
- hi = env->tlbsets[mmu][set][idx].hi;
-
- tlb_vpn = hi >> 13;
- tlb_pid = EXTRACT_FIELD(hi, 0, 7);
- tlb_g = EXTRACT_FIELD(lo, 4, 4);
-
- D_LOG("TLB[%d][%d][%d] v=%x vpage=%x lo=%x hi=%x\n",
- mmu, set, idx, tlb_vpn, vpage, lo, hi);
- if ((tlb_g || (tlb_pid == pid)) && tlb_vpn == vpage) {
- match = 1;
- break;
- }
- }
-
- res->bf_vec = vect_base;
- if (match) {
- cfg_w = EXTRACT_FIELD(r_cfg, 19, 19);
- cfg_k = EXTRACT_FIELD(r_cfg, 18, 18);
- cfg_x = EXTRACT_FIELD(r_cfg, 17, 17);
- cfg_v = EXTRACT_FIELD(r_cfg, 16, 16);
-
- tlb_pfn = EXTRACT_FIELD(lo, 13, 31);
- tlb_v = EXTRACT_FIELD(lo, 3, 3);
- tlb_k = EXTRACT_FIELD(lo, 2, 2);
- tlb_w = EXTRACT_FIELD(lo, 1, 1);
- tlb_x = EXTRACT_FIELD(lo, 0, 0);
-
- /*
- * set_exception_vector(0x04, i_mmu_refill);
- * set_exception_vector(0x05, i_mmu_invalid);
- * set_exception_vector(0x06, i_mmu_access);
- * set_exception_vector(0x07, i_mmu_execute);
- * set_exception_vector(0x08, d_mmu_refill);
- * set_exception_vector(0x09, d_mmu_invalid);
- * set_exception_vector(0x0a, d_mmu_access);
- * set_exception_vector(0x0b, d_mmu_write);
- */
- if (cfg_k && tlb_k && usermode) {
- D(printf("tlb: kernel protected %x lo=%x pc=%x\n",
- vaddr, lo, env->pc));
- match = 0;
- res->bf_vec = vect_base + 2;
- } else if (access_type == MMU_DATA_STORE && cfg_w && !tlb_w) {
- D(printf("tlb: write protected %x lo=%x pc=%x\n",
- vaddr, lo, env->pc));
- match = 0;
- /* write accesses never go through the I mmu. */
- res->bf_vec = vect_base + 3;
- } else if (access_type == MMU_INST_FETCH && cfg_x && !tlb_x) {
- D(printf("tlb: exec protected %x lo=%x pc=%x\n",
- vaddr, lo, env->pc));
- match = 0;
- res->bf_vec = vect_base + 3;
- } else if (cfg_v && !tlb_v) {
- D(printf("tlb: invalid %x\n", vaddr));
- match = 0;
- res->bf_vec = vect_base + 1;
- }
-
- res->prot = 0;
- if (match) {
- res->prot |= PAGE_READ;
- if (tlb_w) {
- res->prot |= PAGE_WRITE;
- }
- if (mmu == 0 && (cfg_x || tlb_x)) {
- res->prot |= PAGE_EXEC;
- }
- } else {
- D(dump_tlb(env, mmu));
- }
- } else {
- /* If refill, provide a randomized set. */
- set = env->mmu_rand_lfsr & 3;
- }
-
- if (!match && !debug) {
- cris_mmu_update_rand_lfsr(env);
-
- /* Compute index. */
- idx = vpage & 15;
-
- /* Update RW_MM_TLB_SEL. */
- env->sregs[SFR_RW_MM_TLB_SEL] = 0;
- set_field(&env->sregs[SFR_RW_MM_TLB_SEL], idx, 0, 4);
- set_field(&env->sregs[SFR_RW_MM_TLB_SEL], set, 4, 2);
-
- /* Update RW_MM_CAUSE. */
- set_field(&r_cause, rwcause, 8, 2);
- set_field(&r_cause, vpage, 13, 19);
- set_field(&r_cause, pid, 0, 8);
- env->sregs[SFR_R_MM_CAUSE] = r_cause;
- D(printf("refill vaddr=%x pc=%x\n", vaddr, env->pc));
- }
-
- D(printf("%s access=%u mtch=%d pc=%x va=%x vpn=%x tlbvpn=%x pfn=%x pid=%x"
- " %x cause=%x sel=%x sp=%x %x %x\n",
- __func__, access_type, match, env->pc,
- vaddr, vpage,
- tlb_vpn, tlb_pfn, tlb_pid,
- pid,
- r_cause,
- env->sregs[SFR_RW_MM_TLB_SEL],
- env->regs[R_SP], env->pregs[PR_USP], env->ksp));
-
- res->phy = tlb_pfn << TARGET_PAGE_BITS;
- return !match;
-}
-
-void cris_mmu_flush_pid(CPUCRISState *env, uint32_t pid)
-{
- target_ulong vaddr;
- unsigned int idx;
- uint32_t lo, hi;
- uint32_t tlb_vpn;
- int tlb_pid, tlb_g, tlb_v;
- unsigned int set;
- unsigned int mmu;
-
- pid &= 0xff;
- for (mmu = 0; mmu < 2; mmu++) {
- for (set = 0; set < 4; set++) {
- for (idx = 0; idx < 16; idx++) {
- lo = env->tlbsets[mmu][set][idx].lo;
- hi = env->tlbsets[mmu][set][idx].hi;
-
- tlb_vpn = EXTRACT_FIELD(hi, 13, 31);
- tlb_pid = EXTRACT_FIELD(hi, 0, 7);
- tlb_g = EXTRACT_FIELD(lo, 4, 4);
- tlb_v = EXTRACT_FIELD(lo, 3, 3);
-
- if (tlb_v && !tlb_g && (tlb_pid == pid)) {
- vaddr = tlb_vpn << TARGET_PAGE_BITS;
- D_LOG("flush pid=%x vaddr=%x\n", pid, vaddr);
- tlb_flush_page(env_cpu(env), vaddr);
- }
- }
- }
- }
-}
-
-int cris_mmu_translate(struct cris_mmu_result *res,
- CPUCRISState *env, uint32_t vaddr,
- MMUAccessType access_type, int mmu_idx, int debug)
-{
- int seg;
- int miss = 0;
- int is_user = mmu_idx == MMU_USER_IDX;
- uint32_t old_srs;
-
- old_srs = env->pregs[PR_SRS];
-
- env->pregs[PR_SRS] = access_type == MMU_INST_FETCH ? 1 : 2;
-
- if (!cris_mmu_enabled(env->sregs[SFR_RW_GC_CFG])) {
- res->phy = vaddr;
- res->prot = PAGE_RWX;
- goto done;
- }
-
- seg = vaddr >> 28;
- if (!is_user && cris_mmu_segmented_addr(seg, env->sregs[SFR_RW_MM_CFG])) {
- uint32_t base;
-
- miss = 0;
- base = cris_mmu_translate_seg(env, seg);
- res->phy = base | (0x0fffffff & vaddr);
- res->prot = PAGE_RWX;
- } else {
- miss = cris_mmu_translate_page(res, env, vaddr, access_type,
- is_user, debug);
- }
- done:
- env->pregs[PR_SRS] = old_srs;
- return miss;
-}
diff --git a/target/cris/mmu.h b/target/cris/mmu.h
deleted file mode 100644
index d57386e..0000000
--- a/target/cris/mmu.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef TARGET_CRIS_MMU_H
-#define TARGET_CRIS_MMU_H
-
-#define CRIS_MMU_ERR_EXEC 0
-#define CRIS_MMU_ERR_READ 1
-#define CRIS_MMU_ERR_WRITE 2
-#define CRIS_MMU_ERR_FLUSH 3
-
-struct cris_mmu_result
-{
- uint32_t phy;
- int prot;
- int bf_vec;
-};
-
-void cris_mmu_init(CPUCRISState *env);
-void cris_mmu_flush_pid(CPUCRISState *env, uint32_t pid);
-int cris_mmu_translate(struct cris_mmu_result *res,
- CPUCRISState *env, uint32_t vaddr,
- MMUAccessType access_type, int mmu_idx, int debug);
-
-#endif
diff --git a/target/cris/op_helper.c b/target/cris/op_helper.c
deleted file mode 100644
index 98a9aaf..0000000
--- a/target/cris/op_helper.c
+++ /dev/null
@@ -1,580 +0,0 @@
-/*
- * CRIS helper routines
- *
- * Copyright (c) 2007 AXIS Communications
- * Written by Edgar E. Iglesias
- *
- * 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 "mmu.h"
-#include "exec/helper-proto.h"
-#include "qemu/host-utils.h"
-#include "exec/exec-all.h"
-
-//#define CRIS_OP_HELPER_DEBUG
-
-
-#ifdef CRIS_OP_HELPER_DEBUG
-#define D(x) x
-#define D_LOG(...) qemu_log(__VA_ARGS__)
-#else
-#define D(x)
-#define D_LOG(...) do { } while (0)
-#endif
-
-void helper_raise_exception(CPUCRISState *env, uint32_t index)
-{
- CPUState *cs = env_cpu(env);
-
- cs->exception_index = index;
- cpu_loop_exit(cs);
-}
-
-void helper_tlb_flush_pid(CPUCRISState *env, uint32_t pid)
-{
-#if !defined(CONFIG_USER_ONLY)
- pid &= 0xff;
- if (pid != (env->pregs[PR_PID] & 0xff)) {
- cris_mmu_flush_pid(env, env->pregs[PR_PID]);
- }
-#endif
-}
-
-void helper_spc_write(CPUCRISState *env, uint32_t new_spc)
-{
-#if !defined(CONFIG_USER_ONLY)
- CPUState *cs = env_cpu(env);
-
- tlb_flush_page(cs, env->pregs[PR_SPC]);
- tlb_flush_page(cs, new_spc);
-#endif
-}
-
-/* Used by the tlb decoder. */
-#define EXTRACT_FIELD(src, start, end) \
- (((src) >> start) & ((1 << (end - start + 1)) - 1))
-
-void helper_movl_sreg_reg(CPUCRISState *env, uint32_t sreg, uint32_t reg)
-{
- uint32_t srs;
- srs = env->pregs[PR_SRS];
- srs &= 3;
- env->sregs[srs][sreg] = env->regs[reg];
-
-#if !defined(CONFIG_USER_ONLY)
- if (srs == 1 || srs == 2) {
- if (sreg == 6) {
- /* Writes to tlb-hi write to mm_cause as a side effect. */
- env->sregs[SFR_RW_MM_TLB_HI] = env->regs[reg];
- env->sregs[SFR_R_MM_CAUSE] = env->regs[reg];
- } else if (sreg == 5) {
- uint32_t set;
- uint32_t idx;
- uint32_t lo, hi;
- uint32_t vaddr;
- int tlb_v;
-
- idx = set = env->sregs[SFR_RW_MM_TLB_SEL];
- set >>= 4;
- set &= 3;
-
- idx &= 15;
- /* We've just made a write to tlb_lo. */
- lo = env->sregs[SFR_RW_MM_TLB_LO];
- /* Writes are done via r_mm_cause. */
- hi = env->sregs[SFR_R_MM_CAUSE];
-
- vaddr = EXTRACT_FIELD(env->tlbsets[srs - 1][set][idx].hi, 13, 31);
- vaddr <<= TARGET_PAGE_BITS;
- tlb_v = EXTRACT_FIELD(env->tlbsets[srs - 1][set][idx].lo, 3, 3);
- env->tlbsets[srs - 1][set][idx].lo = lo;
- env->tlbsets[srs - 1][set][idx].hi = hi;
-
- D_LOG("tlb flush vaddr=%x v=%d pc=%x\n",
- vaddr, tlb_v, env->pc);
- if (tlb_v) {
- tlb_flush_page(env_cpu(env), vaddr);
- }
- }
- }
-#endif
-}
-
-void helper_movl_reg_sreg(CPUCRISState *env, uint32_t reg, uint32_t sreg)
-{
- uint32_t srs;
- env->pregs[PR_SRS] &= 3;
- srs = env->pregs[PR_SRS];
-
-#if !defined(CONFIG_USER_ONLY)
- if (srs == 1 || srs == 2) {
- uint32_t set;
- uint32_t idx;
- uint32_t lo, hi;
-
- idx = set = env->sregs[SFR_RW_MM_TLB_SEL];
- set >>= 4;
- set &= 3;
- idx &= 15;
-
- /* Update the mirror regs. */
- hi = env->tlbsets[srs - 1][set][idx].hi;
- lo = env->tlbsets[srs - 1][set][idx].lo;
- env->sregs[SFR_RW_MM_TLB_HI] = hi;
- env->sregs[SFR_RW_MM_TLB_LO] = lo;
- }
-#endif
- env->regs[reg] = env->sregs[srs][sreg];
-}
-
-static void cris_ccs_rshift(CPUCRISState *env)
-{
- uint32_t ccs;
-
- /* Apply the ccs shift. */
- ccs = env->pregs[PR_CCS];
- ccs = (ccs & 0xc0000000) | ((ccs & 0x0fffffff) >> 10);
- if (ccs & U_FLAG) {
- /* Enter user mode. */
- env->ksp = env->regs[R_SP];
- env->regs[R_SP] = env->pregs[PR_USP];
- }
-
- env->pregs[PR_CCS] = ccs;
-}
-
-void helper_rfe(CPUCRISState *env)
-{
- int rflag = env->pregs[PR_CCS] & R_FLAG;
-
- D_LOG("rfe: erp=%x pid=%x ccs=%x btarget=%x\n",
- env->pregs[PR_ERP], env->pregs[PR_PID],
- env->pregs[PR_CCS],
- env->btarget);
-
- cris_ccs_rshift(env);
-
- /* RFE sets the P_FLAG only if the R_FLAG is not set. */
- if (!rflag) {
- env->pregs[PR_CCS] |= P_FLAG;
- }
-}
-
-void helper_rfn(CPUCRISState *env)
-{
- int rflag = env->pregs[PR_CCS] & R_FLAG;
-
- D_LOG("rfn: erp=%x pid=%x ccs=%x btarget=%x\n",
- env->pregs[PR_ERP], env->pregs[PR_PID],
- env->pregs[PR_CCS],
- env->btarget);
-
- cris_ccs_rshift(env);
-
- /* Set the P_FLAG only if the R_FLAG is not set. */
- if (!rflag) {
- env->pregs[PR_CCS] |= P_FLAG;
- }
-
- /* Always set the M flag. */
- env->pregs[PR_CCS] |= M_FLAG_V32;
-}
-
-uint32_t helper_btst(CPUCRISState *env, uint32_t t0, uint32_t t1, uint32_t ccs)
-{
- /* FIXME: clean this up. */
-
- /*
- * des ref:
- * The N flag is set according to the selected bit in the dest reg.
- * The Z flag is set if the selected bit and all bits to the right are
- * zero.
- * The X flag is cleared.
- * Other flags are left untouched.
- * The destination reg is not affected.
- */
- unsigned int fz, sbit, bset, mask, masked_t0;
-
- sbit = t1 & 31;
- bset = !!(t0 & (1 << sbit));
- mask = sbit == 31 ? -1 : (1 << (sbit + 1)) - 1;
- masked_t0 = t0 & mask;
- fz = !(masked_t0 | bset);
-
- /* Clear the X, N and Z flags. */
- ccs = ccs & ~(X_FLAG | N_FLAG | Z_FLAG);
- if (env->pregs[PR_VR] < 32) {
- ccs &= ~(V_FLAG | C_FLAG);
- }
- /* Set the N and Z flags accordingly. */
- ccs |= (bset << 3) | (fz << 2);
- return ccs;
-}
-
-static inline uint32_t evaluate_flags_writeback(CPUCRISState *env,
- uint32_t flags, uint32_t ccs)
-{
- unsigned int x, z, mask;
-
- /* Extended arithmetic, leave the z flag alone. */
- x = env->cc_x;
- mask = env->cc_mask | X_FLAG;
- if (x) {
- z = flags & Z_FLAG;
- mask = mask & ~z;
- }
- flags &= mask;
-
- /* all insn clear the x-flag except setf or clrf. */
- ccs &= ~mask;
- ccs |= flags;
- return ccs;
-}
-
-uint32_t helper_evaluate_flags_muls(CPUCRISState *env,
- uint32_t ccs, uint32_t res, uint32_t mof)
-{
- uint32_t flags = 0;
- int64_t tmp;
- int dneg;
-
- dneg = ((int32_t)res) < 0;
-
- tmp = mof;
- tmp <<= 32;
- tmp |= res;
- if (tmp == 0) {
- flags |= Z_FLAG;
- } else if (tmp < 0) {
- flags |= N_FLAG;
- }
- if ((dneg && mof != -1) || (!dneg && mof != 0)) {
- flags |= V_FLAG;
- }
- return evaluate_flags_writeback(env, flags, ccs);
-}
-
-uint32_t helper_evaluate_flags_mulu(CPUCRISState *env,
- uint32_t ccs, uint32_t res, uint32_t mof)
-{
- uint32_t flags = 0;
- uint64_t tmp;
-
- tmp = mof;
- tmp <<= 32;
- tmp |= res;
- if (tmp == 0) {
- flags |= Z_FLAG;
- } else if (tmp >> 63) {
- flags |= N_FLAG;
- }
- if (mof) {
- flags |= V_FLAG;
- }
-
- return evaluate_flags_writeback(env, flags, ccs);
-}
-
-uint32_t helper_evaluate_flags_mcp(CPUCRISState *env, uint32_t ccs,
- uint32_t src, uint32_t dst, uint32_t res)
-{
- uint32_t flags = 0;
-
- src = src & 0x80000000;
- dst = dst & 0x80000000;
-
- if ((res & 0x80000000L) != 0L) {
- flags |= N_FLAG;
- if (!src && !dst) {
- flags |= V_FLAG;
- } else if (src & dst) {
- flags |= R_FLAG;
- }
- } else {
- if (res == 0L) {
- flags |= Z_FLAG;
- }
- if (src & dst) {
- flags |= V_FLAG;
- }
- if (dst | src) {
- flags |= R_FLAG;
- }
- }
-
- return evaluate_flags_writeback(env, flags, ccs);
-}
-
-uint32_t helper_evaluate_flags_alu_4(CPUCRISState *env, uint32_t ccs,
- uint32_t src, uint32_t dst, uint32_t res)
-{
- uint32_t flags = 0;
-
- src = src & 0x80000000;
- dst = dst & 0x80000000;
-
- if ((res & 0x80000000L) != 0L) {
- flags |= N_FLAG;
- if (!src && !dst) {
- flags |= V_FLAG;
- } else if (src & dst) {
- flags |= C_FLAG;
- }
- } else {
- if (res == 0L) {
- flags |= Z_FLAG;
- }
- if (src & dst) {
- flags |= V_FLAG;
- }
- if (dst | src) {
- flags |= C_FLAG;
- }
- }
-
- return evaluate_flags_writeback(env, flags, ccs);
-}
-
-uint32_t helper_evaluate_flags_sub_4(CPUCRISState *env, uint32_t ccs,
- uint32_t src, uint32_t dst, uint32_t res)
-{
- uint32_t flags = 0;
-
- src = (~src) & 0x80000000;
- dst = dst & 0x80000000;
-
- if ((res & 0x80000000L) != 0L) {
- flags |= N_FLAG;
- if (!src && !dst) {
- flags |= V_FLAG;
- } else if (src & dst) {
- flags |= C_FLAG;
- }
- } else {
- if (res == 0L) {
- flags |= Z_FLAG;
- }
- if (src & dst) {
- flags |= V_FLAG;
- }
- if (dst | src) {
- flags |= C_FLAG;
- }
- }
-
- flags ^= C_FLAG;
- return evaluate_flags_writeback(env, flags, ccs);
-}
-
-uint32_t helper_evaluate_flags_move_4(CPUCRISState *env,
- uint32_t ccs, uint32_t res)
-{
- uint32_t flags = 0;
-
- if ((int32_t)res < 0) {
- flags |= N_FLAG;
- } else if (res == 0L) {
- flags |= Z_FLAG;
- }
-
- return evaluate_flags_writeback(env, flags, ccs);
-}
-
-uint32_t helper_evaluate_flags_move_2(CPUCRISState *env,
- uint32_t ccs, uint32_t res)
-{
- uint32_t flags = 0;
-
- if ((int16_t)res < 0L) {
- flags |= N_FLAG;
- } else if (res == 0) {
- flags |= Z_FLAG;
- }
-
- return evaluate_flags_writeback(env, flags, ccs);
-}
-
-/*
- * TODO: This is expensive. We could split things up and only evaluate part of
- * CCR on a need to know basis. For now, we simply re-evaluate everything.
- */
-void helper_evaluate_flags(CPUCRISState *env)
-{
- uint32_t src, dst, res;
- uint32_t flags = 0;
-
- src = env->cc_src;
- dst = env->cc_dest;
- res = env->cc_result;
-
- if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP) {
- src = ~src;
- }
-
- /*
- * Now, evaluate the flags. This stuff is based on
- * Per Zander's CRISv10 simulator.
- */
- switch (env->cc_size) {
- case 1:
- if ((res & 0x80L) != 0L) {
- flags |= N_FLAG;
- if (((src & 0x80L) == 0L) && ((dst & 0x80L) == 0L)) {
- flags |= V_FLAG;
- } else if (((src & 0x80L) != 0L) && ((dst & 0x80L) != 0L)) {
- flags |= C_FLAG;
- }
- } else {
- if ((res & 0xFFL) == 0L) {
- flags |= Z_FLAG;
- }
- if (((src & 0x80L) != 0L) && ((dst & 0x80L) != 0L)) {
- flags |= V_FLAG;
- }
- if ((dst & 0x80L) != 0L || (src & 0x80L) != 0L) {
- flags |= C_FLAG;
- }
- }
- break;
- case 2:
- if ((res & 0x8000L) != 0L) {
- flags |= N_FLAG;
- if (((src & 0x8000L) == 0L) && ((dst & 0x8000L) == 0L)) {
- flags |= V_FLAG;
- } else if (((src & 0x8000L) != 0L) && ((dst & 0x8000L) != 0L)) {
- flags |= C_FLAG;
- }
- } else {
- if ((res & 0xFFFFL) == 0L) {
- flags |= Z_FLAG;
- }
- if (((src & 0x8000L) != 0L) && ((dst & 0x8000L) != 0L)) {
- flags |= V_FLAG;
- }
- if ((dst & 0x8000L) != 0L || (src & 0x8000L) != 0L) {
- flags |= C_FLAG;
- }
- }
- break;
- case 4:
- if ((res & 0x80000000L) != 0L) {
- flags |= N_FLAG;
- if (((src & 0x80000000L) == 0L) && ((dst & 0x80000000L) == 0L)) {
- flags |= V_FLAG;
- } else if (((src & 0x80000000L) != 0L) &&
- ((dst & 0x80000000L) != 0L)) {
- flags |= C_FLAG;
- }
- } else {
- if (res == 0L) {
- flags |= Z_FLAG;
- }
- if (((src & 0x80000000L) != 0L) && ((dst & 0x80000000L) != 0L)) {
- flags |= V_FLAG;
- }
- if ((dst & 0x80000000L) != 0L || (src & 0x80000000L) != 0L) {
- flags |= C_FLAG;
- }
- }
- break;
- default:
- break;
- }
-
- if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP) {
- flags ^= C_FLAG;
- }
-
- env->pregs[PR_CCS] = evaluate_flags_writeback(env, flags,
- env->pregs[PR_CCS]);
-}
-
-void helper_top_evaluate_flags(CPUCRISState *env)
-{
- switch (env->cc_op) {
- case CC_OP_MCP:
- env->pregs[PR_CCS]
- = helper_evaluate_flags_mcp(env, env->pregs[PR_CCS],
- env->cc_src, env->cc_dest,
- env->cc_result);
- break;
- case CC_OP_MULS:
- env->pregs[PR_CCS]
- = helper_evaluate_flags_muls(env, env->pregs[PR_CCS],
- env->cc_result, env->pregs[PR_MOF]);
- break;
- case CC_OP_MULU:
- env->pregs[PR_CCS]
- = helper_evaluate_flags_mulu(env, env->pregs[PR_CCS],
- env->cc_result, env->pregs[PR_MOF]);
- break;
- case CC_OP_MOVE:
- case CC_OP_AND:
- case CC_OP_OR:
- case CC_OP_XOR:
- case CC_OP_ASR:
- case CC_OP_LSR:
- case CC_OP_LSL:
- switch (env->cc_size) {
- case 4:
- env->pregs[PR_CCS] =
- helper_evaluate_flags_move_4(env,
- env->pregs[PR_CCS],
- env->cc_result);
- break;
- case 2:
- env->pregs[PR_CCS] =
- helper_evaluate_flags_move_2(env,
- env->pregs[PR_CCS],
- env->cc_result);
- break;
- default:
- helper_evaluate_flags(env);
- break;
- }
- break;
- case CC_OP_FLAGS:
- /* live. */
- break;
- case CC_OP_SUB:
- case CC_OP_CMP:
- if (env->cc_size == 4) {
- env->pregs[PR_CCS] =
- helper_evaluate_flags_sub_4(env,
- env->pregs[PR_CCS],
- env->cc_src, env->cc_dest,
- env->cc_result);
- } else {
- helper_evaluate_flags(env);
- }
- break;
- default:
- switch (env->cc_size) {
- case 4:
- env->pregs[PR_CCS] =
- helper_evaluate_flags_alu_4(env,
- env->pregs[PR_CCS],
- env->cc_src, env->cc_dest,
- env->cc_result);
- break;
- default:
- helper_evaluate_flags(env);
- break;
- }
- break;
- }
-}
diff --git a/target/cris/opcode-cris.h b/target/cris/opcode-cris.h
deleted file mode 100644
index 40509c8..0000000
--- a/target/cris/opcode-cris.h
+++ /dev/null
@@ -1,355 +0,0 @@
-/* cris.h -- Header file for CRIS opcode and register tables.
- Copyright (C) 2000, 2001, 2004 Free Software Foundation, Inc.
- Contributed by Axis Communications AB, Lund, Sweden.
- Originally written for GAS 1.38.1 by Mikael Asker.
- Updated, BFDized and GNUified by Hans-Peter Nilsson.
-
-This file is part of GAS, GDB and the GNU binutils.
-
-GAS, GDB, and GNU binutils is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2, or (at your
-option) any later version.
-
-GAS, GDB, and GNU binutils are distributed in the hope that they 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 TARGET_CRIS_OPCODE_CRIS_H
-#define TARGET_CRIS_OPCODE_CRIS_H
-
-#if !defined(__STDC__) && !defined(const)
-#define const
-#endif
-
-
-/* Registers. */
-#define MAX_REG (15)
-#define CRIS_REG_SP (14)
-#define CRIS_REG_PC (15)
-
-/* CPU version control of disassembly and assembly of instructions.
- May affect how the instruction is assembled, at least the size of
- immediate operands. */
-enum cris_insn_version_usage
-{
- /* Any version. */
- cris_ver_version_all=0,
-
- /* Indeterminate (intended for disassembly only, or obsolete). */
- cris_ver_warning,
-
- /* Only for v0..3 (Etrax 1..4). */
- cris_ver_v0_3,
-
- /* Only for v3 or higher (ETRAX 4 and beyond). */
- cris_ver_v3p,
-
- /* Only for v8 (Etrax 100). */
- cris_ver_v8,
-
- /* Only for v8 or higher (ETRAX 100, ETRAX 100 LX). */
- cris_ver_v8p,
-
- /* Only for v0..10. FIXME: Not sure what to do with this. */
- cris_ver_sim_v0_10,
-
- /* Only for v0..10. */
- cris_ver_v0_10,
-
- /* Only for v3..10. (ETRAX 4, ETRAX 100 and ETRAX 100 LX). */
- cris_ver_v3_10,
-
- /* Only for v8..10 (ETRAX 100 and ETRAX 100 LX). */
- cris_ver_v8_10,
-
- /* Only for v10 (ETRAX 100 LX) and same series. */
- cris_ver_v10,
-
- /* Only for v10 (ETRAX 100 LX) and same series. */
- cris_ver_v10p,
-
- /* Only for v32 or higher (codename GUINNESS).
- Of course some or all these of may change to cris_ver_v32p if/when
- there's a new revision. */
- cris_ver_v32p
-};
-
-
-/* Special registers. */
-struct cris_spec_reg
-{
- const char *const name;
- unsigned int number;
-
- /* The size of the register. */
- unsigned int reg_size;
-
- /* What CPU version the special register of that name is implemented
- in. If cris_ver_warning, emit an unimplemented-warning. */
- enum cris_insn_version_usage applicable_version;
-
- /* There might be a specific warning for using a special register
- here. */
- const char *const warning;
-};
-extern const struct cris_spec_reg cris_spec_regs[];
-
-
-/* Support registers (kind of special too, but not named as such). */
-struct cris_support_reg
-{
- const char *const name;
- unsigned int number;
-};
-extern const struct cris_support_reg cris_support_regs[];
-
-/* Opcode-dependent constants. */
-#define AUTOINCR_BIT (0x04)
-
-/* Prefixes. */
-#define BDAP_QUICK_OPCODE (0x0100)
-#define BDAP_QUICK_Z_BITS (0x0e00)
-
-#define BIAP_OPCODE (0x0540)
-#define BIAP_Z_BITS (0x0a80)
-
-#define DIP_OPCODE (0x0970)
-#define DIP_Z_BITS (0xf280)
-
-#define BDAP_INDIR_LOW (0x40)
-#define BDAP_INDIR_LOW_Z (0x80)
-#define BDAP_INDIR_HIGH (0x09)
-#define BDAP_INDIR_HIGH_Z (0x02)
-
-#define BDAP_INDIR_OPCODE (BDAP_INDIR_HIGH * 0x0100 + BDAP_INDIR_LOW)
-#define BDAP_INDIR_Z_BITS (BDAP_INDIR_HIGH_Z * 0x100 + BDAP_INDIR_LOW_Z)
-#define BDAP_PC_LOW (BDAP_INDIR_LOW + CRIS_REG_PC)
-#define BDAP_INCR_HIGH (BDAP_INDIR_HIGH + AUTOINCR_BIT)
-
-/* No prefix must have this code for its "match" bits in the
- opcode-table. "BCC .+2" will do nicely. */
-#define NO_CRIS_PREFIX 0
-
-/* Definitions for condition codes. */
-#define CC_CC 0x0
-#define CC_HS 0x0
-#define CC_CS 0x1
-#define CC_LO 0x1
-#define CC_NE 0x2
-#define CC_EQ 0x3
-#define CC_VC 0x4
-#define CC_VS 0x5
-#define CC_PL 0x6
-#define CC_MI 0x7
-#define CC_LS 0x8
-#define CC_HI 0x9
-#define CC_GE 0xA
-#define CC_LT 0xB
-#define CC_GT 0xC
-#define CC_LE 0xD
-#define CC_A 0xE
-#define CC_EXT 0xF
-
-/* A table of strings "cc", "cs"... indexed with condition code
- values as above. */
-extern const char *const cris_cc_strings[];
-
-/* Bcc quick. */
-#define BRANCH_QUICK_LOW (0)
-#define BRANCH_QUICK_HIGH (0)
-#define BRANCH_QUICK_OPCODE (BRANCH_QUICK_HIGH * 0x0100 + BRANCH_QUICK_LOW)
-#define BRANCH_QUICK_Z_BITS (0x0F00)
-
-/* BA quick. */
-#define BA_QUICK_HIGH (BRANCH_QUICK_HIGH + CC_A * 0x10)
-#define BA_QUICK_OPCODE (BA_QUICK_HIGH * 0x100 + BRANCH_QUICK_LOW)
-
-/* Bcc [PC+]. */
-#define BRANCH_PC_LOW (0xFF)
-#define BRANCH_INCR_HIGH (0x0D)
-#define BA_PC_INCR_OPCODE \
- ((BRANCH_INCR_HIGH + CC_A * 0x10) * 0x0100 + BRANCH_PC_LOW)
-
-/* Jump. */
-/* Note that old versions generated special register 8 (in high bits)
- and not-that-old versions recognized it as a jump-instruction.
- That opcode now belongs to JUMPU. */
-#define JUMP_INDIR_OPCODE (0x0930)
-#define JUMP_INDIR_Z_BITS (0xf2c0)
-#define JUMP_PC_INCR_OPCODE \
- (JUMP_INDIR_OPCODE + AUTOINCR_BIT * 0x0100 + CRIS_REG_PC)
-
-#define MOVE_M_TO_PREG_OPCODE 0x0a30
-#define MOVE_M_TO_PREG_ZBITS 0x01c0
-
-/* BDAP.D N,PC. */
-#define MOVE_PC_INCR_OPCODE_PREFIX \
- (((BDAP_INCR_HIGH | (CRIS_REG_PC << 4)) << 8) | BDAP_PC_LOW | (2 << 4))
-#define MOVE_PC_INCR_OPCODE_SUFFIX \
- (MOVE_M_TO_PREG_OPCODE | CRIS_REG_PC | (AUTOINCR_BIT << 8))
-
-#define JUMP_PC_INCR_OPCODE_V32 (0x0DBF)
-
-/* BA DWORD (V32). */
-#define BA_DWORD_OPCODE (0x0EBF)
-
-/* Nop. */
-#define NOP_OPCODE (0x050F)
-#define NOP_Z_BITS (0xFFFF ^ NOP_OPCODE)
-
-#define NOP_OPCODE_V32 (0x05B0)
-#define NOP_Z_BITS_V32 (0xFFFF ^ NOP_OPCODE_V32)
-
-/* For the compatibility mode, let's use "MOVE R0,P0". Doesn't affect
- registers or flags. Unfortunately shuts off interrupts for one cycle
- for < v32, but there doesn't seem to be any alternative without that
- effect. */
-#define NOP_OPCODE_COMMON (0x630)
-#define NOP_OPCODE_ZBITS_COMMON (0xffff & ~NOP_OPCODE_COMMON)
-
-/* LAPC.D */
-#define LAPC_DWORD_OPCODE (0x0D7F)
-#define LAPC_DWORD_Z_BITS (0x0fff & ~LAPC_DWORD_OPCODE)
-
-/* Structure of an opcode table entry. */
-enum cris_imm_oprnd_size_type
-{
- /* No size is applicable. */
- SIZE_NONE,
-
- /* Always 32 bits. */
- SIZE_FIX_32,
-
- /* Indicated by size of special register. */
- SIZE_SPEC_REG,
-
- /* Indicated by size field, signed. */
- SIZE_FIELD_SIGNED,
-
- /* Indicated by size field, unsigned. */
- SIZE_FIELD_UNSIGNED,
-
- /* Indicated by size field, no sign implied. */
- SIZE_FIELD
-};
-
-/* For GDB. FIXME: Is this the best way to handle opcode
- interpretation? */
-enum cris_op_type
-{
- cris_not_implemented_op = 0,
- cris_abs_op,
- cris_addi_op,
- cris_asr_op,
- cris_asrq_op,
- cris_ax_ei_setf_op,
- cris_bdap_prefix,
- cris_biap_prefix,
- cris_break_op,
- cris_btst_nop_op,
- cris_clearf_di_op,
- cris_dip_prefix,
- cris_dstep_logshift_mstep_neg_not_op,
- cris_eight_bit_offset_branch_op,
- cris_move_mem_to_reg_movem_op,
- cris_move_reg_to_mem_movem_op,
- cris_move_to_preg_op,
- cris_muls_op,
- cris_mulu_op,
- cris_none_reg_mode_add_sub_cmp_and_or_move_op,
- cris_none_reg_mode_clear_test_op,
- cris_none_reg_mode_jump_op,
- cris_none_reg_mode_move_from_preg_op,
- cris_quick_mode_add_sub_op,
- cris_quick_mode_and_cmp_move_or_op,
- cris_quick_mode_bdap_prefix,
- cris_reg_mode_add_sub_cmp_and_or_move_op,
- cris_reg_mode_clear_op,
- cris_reg_mode_jump_op,
- cris_reg_mode_move_from_preg_op,
- cris_reg_mode_test_op,
- cris_scc_op,
- cris_sixteen_bit_offset_branch_op,
- cris_three_operand_add_sub_cmp_and_or_op,
- cris_three_operand_bound_op,
- cris_two_operand_bound_op,
- cris_xor_op
-};
-
-struct cris_opcode
-{
- /* The name of the insn. */
- const char *name;
-
- /* Bits that must be 1 for a match. */
- unsigned int match;
-
- /* Bits that must be 0 for a match. */
- unsigned int lose;
-
- /* See the table in "opcodes/cris-opc.c". */
- const char *args;
-
- /* Nonzero if this is a delayed branch instruction. */
- char delayed;
-
- /* Size of immediate operands. */
- enum cris_imm_oprnd_size_type imm_oprnd_size;
-
- /* Indicates which version this insn was first implemented in. */
- enum cris_insn_version_usage applicable_version;
-
- /* What kind of operation this is. */
- enum cris_op_type op;
-};
-extern const struct cris_opcode cris_opcodes[];
-
-
-/* These macros are for the target-specific flags in disassemble_info
- used at disassembly. */
-
-/* This insn accesses memory. This flag is more trustworthy than
- checking insn_type for "dis_dref" which does not work for
- e.g. "JSR [foo]". */
-#define CRIS_DIS_FLAG_MEMREF (1 << 0)
-
-/* The "target" field holds a register number. */
-#define CRIS_DIS_FLAG_MEM_TARGET_IS_REG (1 << 1)
-
-/* The "target2" field holds a register number; add it to "target". */
-#define CRIS_DIS_FLAG_MEM_TARGET2_IS_REG (1 << 2)
-
-/* Yet another add-on: the register in "target2" must be multiplied
- by 2 before adding to "target". */
-#define CRIS_DIS_FLAG_MEM_TARGET2_MULT2 (1 << 3)
-
-/* Yet another add-on: the register in "target2" must be multiplied
- by 4 (mutually exclusive with .._MULT2). */
-#define CRIS_DIS_FLAG_MEM_TARGET2_MULT4 (1 << 4)
-
-/* The register in "target2" is an indirect memory reference (of the
- register there), add to "target". Assumed size is dword (mutually
- exclusive with .._MULT[24]). */
-#define CRIS_DIS_FLAG_MEM_TARGET2_MEM (1 << 5)
-
-/* Add-on to CRIS_DIS_FLAG_MEM_TARGET2_MEM; the memory access is "byte";
- sign-extended before adding to "target". */
-#define CRIS_DIS_FLAG_MEM_TARGET2_MEM_BYTE (1 << 6)
-
-/* Add-on to CRIS_DIS_FLAG_MEM_TARGET2_MEM; the memory access is "word";
- sign-extended before adding to "target". */
-#define CRIS_DIS_FLAG_MEM_TARGET2_MEM_WORD (1 << 7)
-
-#endif /* TARGET_CRIS_OPCODE_CRIS_H */
-
-/*
- * Local variables:
- * eval: (c-set-style "gnu")
- * indent-tabs-mode: t
- * End:
- */
diff --git a/target/cris/translate.c b/target/cris/translate.c
deleted file mode 100644
index a30c67e..0000000
--- a/target/cris/translate.c
+++ /dev/null
@@ -1,3252 +0,0 @@
-/*
- * CRIS emulation for qemu: main translation routines.
- *
- * Copyright (c) 2008 AXIS Communications AB
- * Written by Edgar E. Iglesias.
- *
- * 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/>.
- */
-
-/*
- * FIXME:
- * The condition code translation is in need of attention.
- */
-
-#include "qemu/osdep.h"
-#include "cpu.h"
-#include "exec/exec-all.h"
-#include "tcg/tcg-op.h"
-#include "exec/helper-proto.h"
-#include "mmu.h"
-#include "exec/translator.h"
-#include "crisv32-decode.h"
-#include "qemu/qemu-print.h"
-#include "exec/helper-gen.h"
-#include "exec/log.h"
-
-#define HELPER_H "helper.h"
-#include "exec/helper-info.c.inc"
-#undef HELPER_H
-
-
-#define DISAS_CRIS 0
-#if DISAS_CRIS
-# define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
-#else
-# define LOG_DIS(...) do { } while (0)
-#endif
-
-#define D(x)
-#define BUG() (gen_BUG(dc, __FILE__, __LINE__))
-#define BUG_ON(x) ({if (x) BUG();})
-
-/*
- * Target-specific is_jmp field values
- */
-/* Only pc was modified dynamically */
-#define DISAS_JUMP DISAS_TARGET_0
-/* Cpu state was modified dynamically, including pc */
-#define DISAS_UPDATE DISAS_TARGET_1
-/* Cpu state was modified dynamically, excluding pc -- use npc */
-#define DISAS_UPDATE_NEXT DISAS_TARGET_2
-/* PC update for delayed branch, see cpustate_changed otherwise */
-#define DISAS_DBRANCH DISAS_TARGET_3
-
-/* Used by the decoder. */
-#define EXTRACT_FIELD(src, start, end) \
- (((src) >> start) & ((1 << (end - start + 1)) - 1))
-
-#define CC_MASK_NZ 0xc
-#define CC_MASK_NZV 0xe
-#define CC_MASK_NZVC 0xf
-#define CC_MASK_RNZV 0x10e
-
-static TCGv cpu_R[16];
-static TCGv cpu_PR[16];
-static TCGv cc_x;
-static TCGv cc_src;
-static TCGv cc_dest;
-static TCGv cc_result;
-static TCGv cc_op;
-static TCGv cc_size;
-static TCGv cc_mask;
-
-static TCGv env_btaken;
-static TCGv env_btarget;
-static TCGv env_pc;
-
-/* This is the state at translation time. */
-typedef struct DisasContext {
- DisasContextBase base;
-
- CRISCPU *cpu;
- target_ulong pc, ppc;
- int mem_index;
-
- /* Decoder. */
- unsigned int (*decoder)(CPUCRISState *env, struct DisasContext *dc);
- uint32_t ir;
- uint32_t opcode;
- unsigned int op1;
- unsigned int op2;
- unsigned int zsize, zzsize;
- unsigned int mode;
- unsigned int postinc;
-
- unsigned int size;
- unsigned int src;
- unsigned int dst;
- unsigned int cond;
-
- int update_cc;
- int cc_op;
- int cc_size;
- uint32_t cc_mask;
-
- int cc_size_uptodate; /* -1 invalid or last written value. */
-
- int cc_x_uptodate; /* 1 - ccs, 2 - known | X_FLAG. 0 not up-to-date. */
- int flags_uptodate; /* Whether or not $ccs is up-to-date. */
- int flags_x;
-
- int clear_x; /* Clear x after this insn? */
- int clear_prefix; /* Clear prefix after this insn? */
- int clear_locked_irq; /* Clear the irq lockout. */
- int cpustate_changed;
- unsigned int tb_flags; /* tb dependent flags. */
-
-#define JMP_NOJMP 0
-#define JMP_DIRECT 1
-#define JMP_DIRECT_CC 2
-#define JMP_INDIRECT 3
- int jmp; /* 0=nojmp, 1=direct, 2=indirect. */
- uint32_t jmp_pc;
-
- int delayed_branch;
-} DisasContext;
-
-static void gen_BUG(DisasContext *dc, const char *file, int line)
-{
- cpu_abort(CPU(dc->cpu), "%s:%d pc=%x\n", file, line, dc->pc);
-}
-
-static const char * const regnames_v32[] =
-{
- "$r0", "$r1", "$r2", "$r3",
- "$r4", "$r5", "$r6", "$r7",
- "$r8", "$r9", "$r10", "$r11",
- "$r12", "$r13", "$sp", "$acr",
-};
-
-static const char * const pregnames_v32[] =
-{
- "$bz", "$vr", "$pid", "$srs",
- "$wz", "$exs", "$eda", "$mof",
- "$dz", "$ebp", "$erp", "$srp",
- "$nrp", "$ccs", "$usp", "$spc",
-};
-
-/* We need this table to handle preg-moves with implicit width. */
-static const int preg_sizes[] = {
- 1, /* bz. */
- 1, /* vr. */
- 4, /* pid. */
- 1, /* srs. */
- 2, /* wz. */
- 4, 4, 4,
- 4, 4, 4, 4,
- 4, 4, 4, 4,
-};
-
-#define t_gen_mov_TN_env(tn, member) \
- tcg_gen_ld_tl(tn, tcg_env, offsetof(CPUCRISState, member))
-#define t_gen_mov_env_TN(member, tn) \
- tcg_gen_st_tl(tn, tcg_env, offsetof(CPUCRISState, member))
-#define t_gen_movi_env_TN(member, c) \
- t_gen_mov_env_TN(member, tcg_constant_tl(c))
-
-static inline void t_gen_mov_TN_preg(TCGv tn, int r)
-{
- assert(r >= 0 && r <= 15);
- if (r == PR_BZ || r == PR_WZ || r == PR_DZ) {
- tcg_gen_movi_tl(tn, 0);
- } else if (r == PR_VR) {
- tcg_gen_movi_tl(tn, 32);
- } else {
- tcg_gen_mov_tl(tn, cpu_PR[r]);
- }
-}
-static inline void t_gen_mov_preg_TN(DisasContext *dc, int r, TCGv tn)
-{
- assert(r >= 0 && r <= 15);
- if (r == PR_BZ || r == PR_WZ || r == PR_DZ) {
- return;
- } else if (r == PR_SRS) {
- tcg_gen_andi_tl(cpu_PR[r], tn, 3);
- } else {
- if (r == PR_PID) {
- gen_helper_tlb_flush_pid(tcg_env, tn);
- }
- if (dc->tb_flags & S_FLAG && r == PR_SPC) {
- gen_helper_spc_write(tcg_env, tn);
- } else if (r == PR_CCS) {
- dc->cpustate_changed = 1;
- }
- tcg_gen_mov_tl(cpu_PR[r], tn);
- }
-}
-
-/* Sign extend at translation time. */
-static int sign_extend(unsigned int val, unsigned int width)
-{
- int sval;
-
- /* LSL. */
- val <<= 31 - width;
- sval = val;
- /* ASR. */
- sval >>= 31 - width;
- return sval;
-}
-
-static int cris_fetch(CPUCRISState *env, DisasContext *dc, uint32_t addr,
- unsigned int size, bool sign)
-{
- int r;
-
- switch (size) {
- case 4:
- r = translator_ldl(env, &dc->base, addr);
- break;
- case 2:
- r = translator_lduw(env, &dc->base, addr);
- if (sign) {
- r = (int16_t)r;
- }
- break;
- case 1:
- r = translator_ldub(env, &dc->base, addr);
- if (sign) {
- r = (int8_t)r;
- }
- break;
- default:
- g_assert_not_reached();
- }
- return r;
-}
-
-static void cris_lock_irq(DisasContext *dc)
-{
- dc->clear_locked_irq = 0;
- t_gen_movi_env_TN(locked_irq, 1);
-}
-
-static inline void t_gen_raise_exception(uint32_t index)
-{
- gen_helper_raise_exception(tcg_env, tcg_constant_i32(index));
-}
-
-static void t_gen_lsl(TCGv d, TCGv a, TCGv b)
-{
- TCGv t0, t_31;
-
- t0 = tcg_temp_new();
- t_31 = tcg_constant_tl(31);
- tcg_gen_shl_tl(d, a, b);
-
- tcg_gen_sub_tl(t0, t_31, b);
- tcg_gen_sar_tl(t0, t0, t_31);
- tcg_gen_and_tl(t0, t0, d);
- tcg_gen_xor_tl(d, d, t0);
-}
-
-static void t_gen_lsr(TCGv d, TCGv a, TCGv b)
-{
- TCGv t0, t_31;
-
- t0 = tcg_temp_new();
- t_31 = tcg_temp_new();
- tcg_gen_shr_tl(d, a, b);
-
- tcg_gen_movi_tl(t_31, 31);
- tcg_gen_sub_tl(t0, t_31, b);
- tcg_gen_sar_tl(t0, t0, t_31);
- tcg_gen_and_tl(t0, t0, d);
- tcg_gen_xor_tl(d, d, t0);
-}
-
-static void t_gen_asr(TCGv d, TCGv a, TCGv b)
-{
- TCGv t0, t_31;
-
- t0 = tcg_temp_new();
- t_31 = tcg_temp_new();
- tcg_gen_sar_tl(d, a, b);
-
- tcg_gen_movi_tl(t_31, 31);
- tcg_gen_sub_tl(t0, t_31, b);
- tcg_gen_sar_tl(t0, t0, t_31);
- tcg_gen_or_tl(d, d, t0);
-}
-
-static void t_gen_cris_dstep(TCGv d, TCGv a, TCGv b)
-{
- TCGv t = tcg_temp_new();
-
- /*
- * d <<= 1
- * if (d >= s)
- * d -= s;
- */
- tcg_gen_shli_tl(d, a, 1);
- tcg_gen_sub_tl(t, d, b);
- tcg_gen_movcond_tl(TCG_COND_GEU, d, d, b, t, d);
-}
-
-static void t_gen_cris_mstep(TCGv d, TCGv a, TCGv b, TCGv ccs)
-{
- TCGv t;
-
- /*
- * d <<= 1
- * if (n)
- * d += s;
- */
- t = tcg_temp_new();
- tcg_gen_shli_tl(d, a, 1);
- tcg_gen_shli_tl(t, ccs, 31 - 3);
- tcg_gen_sari_tl(t, t, 31);
- tcg_gen_and_tl(t, t, b);
- tcg_gen_add_tl(d, d, t);
-}
-
-/* Extended arithmetic on CRIS. */
-static inline void t_gen_add_flag(TCGv d, int flag)
-{
- TCGv c;
-
- c = tcg_temp_new();
- t_gen_mov_TN_preg(c, PR_CCS);
- /* Propagate carry into d. */
- tcg_gen_andi_tl(c, c, 1 << flag);
- if (flag) {
- tcg_gen_shri_tl(c, c, flag);
- }
- tcg_gen_add_tl(d, d, c);
-}
-
-static inline void t_gen_addx_carry(DisasContext *dc, TCGv d)
-{
- if (dc->flags_x) {
- TCGv c = tcg_temp_new();
-
- t_gen_mov_TN_preg(c, PR_CCS);
- /* C flag is already at bit 0. */
- tcg_gen_andi_tl(c, c, C_FLAG);
- tcg_gen_add_tl(d, d, c);
- }
-}
-
-static inline void t_gen_subx_carry(DisasContext *dc, TCGv d)
-{
- if (dc->flags_x) {
- TCGv c = tcg_temp_new();
-
- t_gen_mov_TN_preg(c, PR_CCS);
- /* C flag is already at bit 0. */
- tcg_gen_andi_tl(c, c, C_FLAG);
- tcg_gen_sub_tl(d, d, c);
- }
-}
-
-/* Swap the two bytes within each half word of the s operand.
- T0 = ((T0 << 8) & 0xff00ff00) | ((T0 >> 8) & 0x00ff00ff) */
-static inline void t_gen_swapb(TCGv d, TCGv s)
-{
- TCGv t, org_s;
-
- t = tcg_temp_new();
- org_s = tcg_temp_new();
-
- /* d and s may refer to the same object. */
- tcg_gen_mov_tl(org_s, s);
- tcg_gen_shli_tl(t, org_s, 8);
- tcg_gen_andi_tl(d, t, 0xff00ff00);
- tcg_gen_shri_tl(t, org_s, 8);
- tcg_gen_andi_tl(t, t, 0x00ff00ff);
- tcg_gen_or_tl(d, d, t);
-}
-
-/* Swap the halfwords of the s operand. */
-static inline void t_gen_swapw(TCGv d, TCGv s)
-{
- TCGv t;
- /* d and s refer the same object. */
- t = tcg_temp_new();
- tcg_gen_mov_tl(t, s);
- tcg_gen_shli_tl(d, t, 16);
- tcg_gen_shri_tl(t, t, 16);
- tcg_gen_or_tl(d, d, t);
-}
-
-/*
- * Reverse the bits within each byte.
- *
- * T0 = ((T0 << 7) & 0x80808080)
- * | ((T0 << 5) & 0x40404040)
- * | ((T0 << 3) & 0x20202020)
- * | ((T0 << 1) & 0x10101010)
- * | ((T0 >> 1) & 0x08080808)
- * | ((T0 >> 3) & 0x04040404)
- * | ((T0 >> 5) & 0x02020202)
- * | ((T0 >> 7) & 0x01010101);
- */
-static void t_gen_swapr(TCGv d, TCGv s)
-{
- static const struct {
- int shift; /* LSL when positive, LSR when negative. */
- uint32_t mask;
- } bitrev[] = {
- {7, 0x80808080},
- {5, 0x40404040},
- {3, 0x20202020},
- {1, 0x10101010},
- {-1, 0x08080808},
- {-3, 0x04040404},
- {-5, 0x02020202},
- {-7, 0x01010101}
- };
- int i;
- TCGv t, org_s;
-
- /* d and s refer the same object. */
- t = tcg_temp_new();
- org_s = tcg_temp_new();
- tcg_gen_mov_tl(org_s, s);
-
- tcg_gen_shli_tl(t, org_s, bitrev[0].shift);
- tcg_gen_andi_tl(d, t, bitrev[0].mask);
- for (i = 1; i < ARRAY_SIZE(bitrev); i++) {
- if (bitrev[i].shift >= 0) {
- tcg_gen_shli_tl(t, org_s, bitrev[i].shift);
- } else {
- tcg_gen_shri_tl(t, org_s, -bitrev[i].shift);
- }
- tcg_gen_andi_tl(t, t, bitrev[i].mask);
- tcg_gen_or_tl(d, d, t);
- }
-}
-
-static bool use_goto_tb(DisasContext *dc, target_ulong dest)
-{
- return translator_use_goto_tb(&dc->base, dest);
-}
-
-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(env_pc, dest);
- tcg_gen_exit_tb(dc->base.tb, n);
- } else {
- tcg_gen_movi_tl(env_pc, dest);
- tcg_gen_lookup_and_goto_ptr();
- }
-}
-
-static inline void cris_clear_x_flag(DisasContext *dc)
-{
- if (dc->flags_x) {
- dc->flags_uptodate = 0;
- }
- dc->flags_x = 0;
-}
-
-static void cris_flush_cc_state(DisasContext *dc)
-{
- if (dc->cc_size_uptodate != dc->cc_size) {
- tcg_gen_movi_tl(cc_size, dc->cc_size);
- dc->cc_size_uptodate = dc->cc_size;
- }
- tcg_gen_movi_tl(cc_op, dc->cc_op);
- tcg_gen_movi_tl(cc_mask, dc->cc_mask);
-}
-
-static void cris_evaluate_flags(DisasContext *dc)
-{
- if (dc->flags_uptodate) {
- return;
- }
-
- cris_flush_cc_state(dc);
-
- switch (dc->cc_op) {
- case CC_OP_MCP:
- gen_helper_evaluate_flags_mcp(cpu_PR[PR_CCS], tcg_env,
- cpu_PR[PR_CCS], cc_src,
- cc_dest, cc_result);
- break;
- case CC_OP_MULS:
- gen_helper_evaluate_flags_muls(cpu_PR[PR_CCS], tcg_env,
- cpu_PR[PR_CCS], cc_result,
- cpu_PR[PR_MOF]);
- break;
- case CC_OP_MULU:
- gen_helper_evaluate_flags_mulu(cpu_PR[PR_CCS], tcg_env,
- cpu_PR[PR_CCS], cc_result,
- cpu_PR[PR_MOF]);
- break;
- case CC_OP_MOVE:
- case CC_OP_AND:
- case CC_OP_OR:
- case CC_OP_XOR:
- case CC_OP_ASR:
- case CC_OP_LSR:
- case CC_OP_LSL:
- switch (dc->cc_size) {
- case 4:
- gen_helper_evaluate_flags_move_4(cpu_PR[PR_CCS],
- tcg_env, cpu_PR[PR_CCS], cc_result);
- break;
- case 2:
- gen_helper_evaluate_flags_move_2(cpu_PR[PR_CCS],
- tcg_env, cpu_PR[PR_CCS], cc_result);
- break;
- default:
- gen_helper_evaluate_flags(tcg_env);
- break;
- }
- break;
- case CC_OP_FLAGS:
- /* live. */
- break;
- case CC_OP_SUB:
- case CC_OP_CMP:
- if (dc->cc_size == 4) {
- gen_helper_evaluate_flags_sub_4(cpu_PR[PR_CCS], tcg_env,
- cpu_PR[PR_CCS], cc_src, cc_dest, cc_result);
- } else {
- gen_helper_evaluate_flags(tcg_env);
- }
-
- break;
- default:
- switch (dc->cc_size) {
- case 4:
- gen_helper_evaluate_flags_alu_4(cpu_PR[PR_CCS], tcg_env,
- cpu_PR[PR_CCS], cc_src, cc_dest, cc_result);
- break;
- default:
- gen_helper_evaluate_flags(tcg_env);
- break;
- }
- break;
- }
-
- if (dc->flags_x) {
- tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], X_FLAG);
- } else if (dc->cc_op == CC_OP_FLAGS) {
- tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~X_FLAG);
- }
- dc->flags_uptodate = 1;
-}
-
-static void cris_cc_mask(DisasContext *dc, unsigned int mask)
-{
- uint32_t ovl;
-
- if (!mask) {
- dc->update_cc = 0;
- return;
- }
-
- /* Check if we need to evaluate the condition codes due to
- CC overlaying. */
- ovl = (dc->cc_mask ^ mask) & ~mask;
- if (ovl) {
- /* TODO: optimize this case. It trigs all the time. */
- cris_evaluate_flags(dc);
- }
- dc->cc_mask = mask;
- dc->update_cc = 1;
-}
-
-static void cris_update_cc_op(DisasContext *dc, int op, int size)
-{
- dc->cc_op = op;
- dc->cc_size = size;
- dc->flags_uptodate = 0;
-}
-
-static inline void cris_update_cc_x(DisasContext *dc)
-{
- /* Save the x flag state at the time of the cc snapshot. */
- if (dc->cc_x_uptodate == (2 | dc->flags_x)) {
- return;
- }
- tcg_gen_movi_tl(cc_x, dc->flags_x);
- dc->cc_x_uptodate = 2 | dc->flags_x;
-}
-
-/* Update cc prior to executing ALU op. Needs source operands untouched. */
-static void cris_pre_alu_update_cc(DisasContext *dc, int op,
- TCGv dst, TCGv src, int size)
-{
- if (dc->update_cc) {
- cris_update_cc_op(dc, op, size);
- tcg_gen_mov_tl(cc_src, src);
-
- if (op != CC_OP_MOVE
- && op != CC_OP_AND
- && op != CC_OP_OR
- && op != CC_OP_XOR
- && op != CC_OP_ASR
- && op != CC_OP_LSR
- && op != CC_OP_LSL) {
- tcg_gen_mov_tl(cc_dest, dst);
- }
-
- cris_update_cc_x(dc);
- }
-}
-
-/* Update cc after executing ALU op. needs the result. */
-static inline void cris_update_result(DisasContext *dc, TCGv res)
-{
- if (dc->update_cc) {
- tcg_gen_mov_tl(cc_result, res);
- }
-}
-
-/* Returns one if the write back stage should execute. */
-static void cris_alu_op_exec(DisasContext *dc, int op,
- TCGv dst, TCGv a, TCGv b, int size)
-{
- /* Emit the ALU insns. */
- switch (op) {
- case CC_OP_ADD:
- tcg_gen_add_tl(dst, a, b);
- /* Extended arithmetic. */
- t_gen_addx_carry(dc, dst);
- break;
- case CC_OP_ADDC:
- tcg_gen_add_tl(dst, a, b);
- t_gen_add_flag(dst, 0); /* C_FLAG. */
- break;
- case CC_OP_MCP:
- tcg_gen_add_tl(dst, a, b);
- t_gen_add_flag(dst, 8); /* R_FLAG. */
- break;
- case CC_OP_SUB:
- tcg_gen_sub_tl(dst, a, b);
- /* Extended arithmetic. */
- t_gen_subx_carry(dc, dst);
- break;
- case CC_OP_MOVE:
- tcg_gen_mov_tl(dst, b);
- break;
- case CC_OP_OR:
- tcg_gen_or_tl(dst, a, b);
- break;
- case CC_OP_AND:
- tcg_gen_and_tl(dst, a, b);
- break;
- case CC_OP_XOR:
- tcg_gen_xor_tl(dst, a, b);
- break;
- case CC_OP_LSL:
- t_gen_lsl(dst, a, b);
- break;
- case CC_OP_LSR:
- t_gen_lsr(dst, a, b);
- break;
- case CC_OP_ASR:
- t_gen_asr(dst, a, b);
- break;
- case CC_OP_NEG:
- tcg_gen_neg_tl(dst, b);
- /* Extended arithmetic. */
- t_gen_subx_carry(dc, dst);
- break;
- case CC_OP_LZ:
- tcg_gen_clzi_tl(dst, b, TARGET_LONG_BITS);
- break;
- case CC_OP_MULS:
- tcg_gen_muls2_tl(dst, cpu_PR[PR_MOF], a, b);
- break;
- case CC_OP_MULU:
- tcg_gen_mulu2_tl(dst, cpu_PR[PR_MOF], a, b);
- break;
- case CC_OP_DSTEP:
- t_gen_cris_dstep(dst, a, b);
- break;
- case CC_OP_MSTEP:
- t_gen_cris_mstep(dst, a, b, cpu_PR[PR_CCS]);
- break;
- case CC_OP_BOUND:
- tcg_gen_movcond_tl(TCG_COND_LEU, dst, a, b, a, b);
- break;
- case CC_OP_CMP:
- tcg_gen_sub_tl(dst, a, b);
- /* Extended arithmetic. */
- t_gen_subx_carry(dc, dst);
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "illegal ALU op.\n");
- BUG();
- break;
- }
-
- if (size == 1) {
- tcg_gen_andi_tl(dst, dst, 0xff);
- } else if (size == 2) {
- tcg_gen_andi_tl(dst, dst, 0xffff);
- }
-}
-
-static void cris_alu(DisasContext *dc, int op,
- TCGv d, TCGv op_a, TCGv op_b, int size)
-{
- TCGv tmp;
- int writeback;
-
- writeback = 1;
-
- if (op == CC_OP_CMP) {
- tmp = tcg_temp_new();
- writeback = 0;
- } else if (size == 4) {
- tmp = d;
- writeback = 0;
- } else {
- tmp = tcg_temp_new();
- }
-
-
- cris_pre_alu_update_cc(dc, op, op_a, op_b, size);
- cris_alu_op_exec(dc, op, tmp, op_a, op_b, size);
- cris_update_result(dc, tmp);
-
- /* Writeback. */
- if (writeback) {
- if (size == 1) {
- tcg_gen_andi_tl(d, d, ~0xff);
- } else {
- tcg_gen_andi_tl(d, d, ~0xffff);
- }
- tcg_gen_or_tl(d, d, tmp);
- }
-}
-
-static int arith_cc(DisasContext *dc)
-{
- if (dc->update_cc) {
- switch (dc->cc_op) {
- case CC_OP_ADDC: return 1;
- case CC_OP_ADD: return 1;
- case CC_OP_SUB: return 1;
- case CC_OP_DSTEP: return 1;
- case CC_OP_LSL: return 1;
- case CC_OP_LSR: return 1;
- case CC_OP_ASR: return 1;
- case CC_OP_CMP: return 1;
- case CC_OP_NEG: return 1;
- case CC_OP_OR: return 1;
- case CC_OP_AND: return 1;
- case CC_OP_XOR: return 1;
- case CC_OP_MULU: return 1;
- case CC_OP_MULS: return 1;
- default:
- return 0;
- }
- }
- return 0;
-}
-
-static void gen_tst_cc (DisasContext *dc, TCGv cc, int cond)
-{
- int arith_opt, move_opt;
-
- /* TODO: optimize more condition codes. */
-
- /*
- * If the flags are live, we've gotta look into the bits of CCS.
- * Otherwise, if we just did an arithmetic operation we try to
- * evaluate the condition code faster.
- *
- * When this function is done, T0 should be non-zero if the condition
- * code is true.
- */
- arith_opt = arith_cc(dc) && !dc->flags_uptodate;
- move_opt = (dc->cc_op == CC_OP_MOVE);
- switch (cond) {
- case CC_EQ:
- if ((arith_opt || move_opt)
- && dc->cc_x_uptodate != (2 | X_FLAG)) {
- tcg_gen_setcondi_tl(TCG_COND_EQ, cc, cc_result, 0);
- } else {
- cris_evaluate_flags(dc);
- tcg_gen_andi_tl(cc,
- cpu_PR[PR_CCS], Z_FLAG);
- }
- break;
- case CC_NE:
- if ((arith_opt || move_opt)
- && dc->cc_x_uptodate != (2 | X_FLAG)) {
- tcg_gen_mov_tl(cc, cc_result);
- } else {
- cris_evaluate_flags(dc);
- tcg_gen_xori_tl(cc, cpu_PR[PR_CCS],
- Z_FLAG);
- tcg_gen_andi_tl(cc, cc, Z_FLAG);
- }
- break;
- case CC_CS:
- cris_evaluate_flags(dc);
- tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], C_FLAG);
- break;
- case CC_CC:
- cris_evaluate_flags(dc);
- tcg_gen_xori_tl(cc, cpu_PR[PR_CCS], C_FLAG);
- tcg_gen_andi_tl(cc, cc, C_FLAG);
- break;
- case CC_VS:
- cris_evaluate_flags(dc);
- tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], V_FLAG);
- break;
- case CC_VC:
- cris_evaluate_flags(dc);
- tcg_gen_xori_tl(cc, cpu_PR[PR_CCS],
- V_FLAG);
- tcg_gen_andi_tl(cc, cc, V_FLAG);
- break;
- case CC_PL:
- if (arith_opt || move_opt) {
- int bits = 31;
-
- if (dc->cc_size == 1) {
- bits = 7;
- } else if (dc->cc_size == 2) {
- bits = 15;
- }
-
- tcg_gen_shri_tl(cc, cc_result, bits);
- tcg_gen_xori_tl(cc, cc, 1);
- } else {
- cris_evaluate_flags(dc);
- tcg_gen_xori_tl(cc, cpu_PR[PR_CCS],
- N_FLAG);
- tcg_gen_andi_tl(cc, cc, N_FLAG);
- }
- break;
- case CC_MI:
- if (arith_opt || move_opt) {
- int bits = 31;
-
- if (dc->cc_size == 1) {
- bits = 7;
- } else if (dc->cc_size == 2) {
- bits = 15;
- }
-
- tcg_gen_shri_tl(cc, cc_result, bits);
- tcg_gen_andi_tl(cc, cc, 1);
- } else {
- cris_evaluate_flags(dc);
- tcg_gen_andi_tl(cc, cpu_PR[PR_CCS],
- N_FLAG);
- }
- break;
- case CC_LS:
- cris_evaluate_flags(dc);
- tcg_gen_andi_tl(cc, cpu_PR[PR_CCS],
- C_FLAG | Z_FLAG);
- break;
- case CC_HI:
- cris_evaluate_flags(dc);
- {
- TCGv tmp;
-
- tmp = tcg_temp_new();
- tcg_gen_xori_tl(tmp, cpu_PR[PR_CCS],
- C_FLAG | Z_FLAG);
- /* Overlay the C flag on top of the Z. */
- tcg_gen_shli_tl(cc, tmp, 2);
- tcg_gen_and_tl(cc, tmp, cc);
- tcg_gen_andi_tl(cc, cc, Z_FLAG);
- }
- break;
- case CC_GE:
- cris_evaluate_flags(dc);
- /* Overlay the V flag on top of the N. */
- tcg_gen_shli_tl(cc, cpu_PR[PR_CCS], 2);
- tcg_gen_xor_tl(cc,
- cpu_PR[PR_CCS], cc);
- tcg_gen_andi_tl(cc, cc, N_FLAG);
- tcg_gen_xori_tl(cc, cc, N_FLAG);
- break;
- case CC_LT:
- cris_evaluate_flags(dc);
- /* Overlay the V flag on top of the N. */
- tcg_gen_shli_tl(cc, cpu_PR[PR_CCS], 2);
- tcg_gen_xor_tl(cc,
- cpu_PR[PR_CCS], cc);
- tcg_gen_andi_tl(cc, cc, N_FLAG);
- break;
- case CC_GT:
- cris_evaluate_flags(dc);
- {
- TCGv n, z;
-
- n = tcg_temp_new();
- z = tcg_temp_new();
-
- /* To avoid a shift we overlay everything on
- the V flag. */
- tcg_gen_shri_tl(n, cpu_PR[PR_CCS], 2);
- tcg_gen_shri_tl(z, cpu_PR[PR_CCS], 1);
- /* invert Z. */
- tcg_gen_xori_tl(z, z, 2);
-
- tcg_gen_xor_tl(n, n, cpu_PR[PR_CCS]);
- tcg_gen_xori_tl(n, n, 2);
- tcg_gen_and_tl(cc, z, n);
- tcg_gen_andi_tl(cc, cc, 2);
- }
- break;
- case CC_LE:
- cris_evaluate_flags(dc);
- {
- TCGv n, z;
-
- n = tcg_temp_new();
- z = tcg_temp_new();
-
- /* To avoid a shift we overlay everything on
- the V flag. */
- tcg_gen_shri_tl(n, cpu_PR[PR_CCS], 2);
- tcg_gen_shri_tl(z, cpu_PR[PR_CCS], 1);
-
- tcg_gen_xor_tl(n, n, cpu_PR[PR_CCS]);
- tcg_gen_or_tl(cc, z, n);
- tcg_gen_andi_tl(cc, cc, 2);
- }
- break;
- case CC_P:
- cris_evaluate_flags(dc);
- tcg_gen_andi_tl(cc, cpu_PR[PR_CCS], P_FLAG);
- break;
- case CC_A:
- tcg_gen_movi_tl(cc, 1);
- break;
- default:
- BUG();
- break;
- };
-}
-
-static void cris_store_direct_jmp(DisasContext *dc)
-{
- /* Store the direct jmp state into the cpu-state. */
- if (dc->jmp == JMP_DIRECT || dc->jmp == JMP_DIRECT_CC) {
- if (dc->jmp == JMP_DIRECT) {
- tcg_gen_movi_tl(env_btaken, 1);
- }
- tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
- dc->jmp = JMP_INDIRECT;
- }
-}
-
-static void cris_prepare_cc_branch (DisasContext *dc,
- int offset, int cond)
-{
- /* This helps us re-schedule the micro-code to insns in delay-slots
- before the actual jump. */
- dc->delayed_branch = 2;
- dc->jmp = JMP_DIRECT_CC;
- dc->jmp_pc = dc->pc + offset;
-
- gen_tst_cc(dc, env_btaken, cond);
- tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
-}
-
-
-/* jumps, when the dest is in a live reg for example. Direct should be set
- when the dest addr is constant to allow tb chaining. */
-static inline void cris_prepare_jmp (DisasContext *dc, unsigned int type)
-{
- /* This helps us re-schedule the micro-code to insns in delay-slots
- before the actual jump. */
- dc->delayed_branch = 2;
- dc->jmp = type;
- if (type == JMP_INDIRECT) {
- tcg_gen_movi_tl(env_btaken, 1);
- }
-}
-
-static void gen_load64(DisasContext *dc, TCGv_i64 dst, TCGv addr)
-{
- /* If we get a fault on a delayslot we must keep the jmp state in
- the cpu-state to be able to re-execute the jmp. */
- if (dc->delayed_branch == 1) {
- cris_store_direct_jmp(dc);
- }
-
- tcg_gen_qemu_ld_i64(dst, addr, dc->mem_index, MO_TEUQ);
-}
-
-static void gen_load(DisasContext *dc, TCGv dst, TCGv addr,
- unsigned int size, int sign)
-{
- /* If we get a fault on a delayslot we must keep the jmp state in
- the cpu-state to be able to re-execute the jmp. */
- if (dc->delayed_branch == 1) {
- cris_store_direct_jmp(dc);
- }
-
- tcg_gen_qemu_ld_tl(dst, addr, dc->mem_index,
- MO_TE + ctz32(size) + (sign ? MO_SIGN : 0));
-}
-
-static void gen_store (DisasContext *dc, TCGv addr, TCGv val,
- unsigned int size)
-{
- /* If we get a fault on a delayslot we must keep the jmp state in
- the cpu-state to be able to re-execute the jmp. */
- if (dc->delayed_branch == 1) {
- cris_store_direct_jmp(dc);
- }
-
-
- /* Conditional writes. We only support the kind were X and P are known
- at translation time. */
- if (dc->flags_x && (dc->tb_flags & P_FLAG)) {
- dc->postinc = 0;
- cris_evaluate_flags(dc);
- tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], C_FLAG);
- return;
- }
-
- tcg_gen_qemu_st_tl(val, addr, dc->mem_index, MO_TE + ctz32(size));
-
- if (dc->flags_x) {
- cris_evaluate_flags(dc);
- tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~C_FLAG);
- }
-}
-
-static inline void t_gen_sext(TCGv d, TCGv s, int size)
-{
- if (size == 1) {
- tcg_gen_ext8s_i32(d, s);
- } else if (size == 2) {
- tcg_gen_ext16s_i32(d, s);
- } else {
- tcg_gen_mov_tl(d, s);
- }
-}
-
-static inline void t_gen_zext(TCGv d, TCGv s, int size)
-{
- if (size == 1) {
- tcg_gen_ext8u_i32(d, s);
- } else if (size == 2) {
- tcg_gen_ext16u_i32(d, s);
- } else {
- tcg_gen_mov_tl(d, s);
- }
-}
-
-#if DISAS_CRIS
-static char memsize_char(int size)
-{
- switch (size) {
- case 1: return 'b';
- case 2: return 'w';
- case 4: return 'd';
- default:
- return 'x';
- }
-}
-#endif
-
-static inline unsigned int memsize_z(DisasContext *dc)
-{
- return dc->zsize + 1;
-}
-
-static inline unsigned int memsize_zz(DisasContext *dc)
-{
- switch (dc->zzsize) {
- case 0: return 1;
- case 1: return 2;
- default:
- return 4;
- }
-}
-
-static inline void do_postinc (DisasContext *dc, int size)
-{
- if (dc->postinc) {
- tcg_gen_addi_tl(cpu_R[dc->op1], cpu_R[dc->op1], size);
- }
-}
-
-static inline void dec_prep_move_r(DisasContext *dc, int rs, int rd,
- int size, int s_ext, TCGv dst)
-{
- if (s_ext) {
- t_gen_sext(dst, cpu_R[rs], size);
- } else {
- t_gen_zext(dst, cpu_R[rs], size);
- }
-}
-
-/* Prepare T0 and T1 for a register alu operation.
- s_ext decides if the operand1 should be sign-extended or zero-extended when
- needed. */
-static void dec_prep_alu_r(DisasContext *dc, int rs, int rd,
- int size, int s_ext, TCGv dst, TCGv src)
-{
- dec_prep_move_r(dc, rs, rd, size, s_ext, src);
-
- if (s_ext) {
- t_gen_sext(dst, cpu_R[rd], size);
- } else {
- t_gen_zext(dst, cpu_R[rd], size);
- }
-}
-
-static int dec_prep_move_m(CPUCRISState *env, DisasContext *dc,
- int s_ext, int memsize, TCGv dst)
-{
- unsigned int rs;
- uint32_t imm;
- int is_imm;
- int insn_len = 2;
-
- rs = dc->op1;
- is_imm = rs == 15 && dc->postinc;
-
- /* Load [$rs] onto T1. */
- if (is_imm) {
- insn_len = 2 + memsize;
- if (memsize == 1) {
- insn_len++;
- }
-
- imm = cris_fetch(env, dc, dc->pc + 2, memsize, s_ext);
- tcg_gen_movi_tl(dst, imm);
- dc->postinc = 0;
- } else {
- cris_flush_cc_state(dc);
- gen_load(dc, dst, cpu_R[rs], memsize, 0);
- if (s_ext) {
- t_gen_sext(dst, dst, memsize);
- } else {
- t_gen_zext(dst, dst, memsize);
- }
- }
- return insn_len;
-}
-
-/* Prepare T0 and T1 for a memory + alu operation.
- s_ext decides if the operand1 should be sign-extended or zero-extended when
- needed. */
-static int dec_prep_alu_m(CPUCRISState *env, DisasContext *dc,
- int s_ext, int memsize, TCGv dst, TCGv src)
-{
- int insn_len;
-
- insn_len = dec_prep_move_m(env, dc, s_ext, memsize, src);
- tcg_gen_mov_tl(dst, cpu_R[dc->op2]);
- return insn_len;
-}
-
-#if DISAS_CRIS
-static const char *cc_name(int cc)
-{
- static const char * const cc_names[16] = {
- "cc", "cs", "ne", "eq", "vc", "vs", "pl", "mi",
- "ls", "hi", "ge", "lt", "gt", "le", "a", "p"
- };
- assert(cc < 16);
- return cc_names[cc];
-}
-#endif
-
-/* Start of insn decoders. */
-
-static int dec_bccq(CPUCRISState *env, DisasContext *dc)
-{
- int32_t offset;
- int sign;
- uint32_t cond = dc->op2;
-
- offset = EXTRACT_FIELD(dc->ir, 1, 7);
- sign = EXTRACT_FIELD(dc->ir, 0, 0);
-
- offset *= 2;
- offset |= sign << 8;
- offset = sign_extend(offset, 8);
-
- LOG_DIS("b%s %x\n", cc_name(cond), dc->pc + offset);
-
- /* op2 holds the condition-code. */
- cris_cc_mask(dc, 0);
- cris_prepare_cc_branch(dc, offset, cond);
- return 2;
-}
-static int dec_addoq(CPUCRISState *env, DisasContext *dc)
-{
- int32_t imm;
-
- dc->op1 = EXTRACT_FIELD(dc->ir, 0, 7);
- imm = sign_extend(dc->op1, 7);
-
- LOG_DIS("addoq %d, $r%u\n", imm, dc->op2);
- cris_cc_mask(dc, 0);
- /* Fetch register operand, */
- tcg_gen_addi_tl(cpu_R[R_ACR], cpu_R[dc->op2], imm);
-
- return 2;
-}
-static int dec_addq(CPUCRISState *env, DisasContext *dc)
-{
- TCGv c;
- LOG_DIS("addq %u, $r%u\n", dc->op1, dc->op2);
-
- dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5);
-
- cris_cc_mask(dc, CC_MASK_NZVC);
-
- c = tcg_constant_tl(dc->op1);
- cris_alu(dc, CC_OP_ADD,
- cpu_R[dc->op2], cpu_R[dc->op2], c, 4);
- return 2;
-}
-static int dec_moveq(CPUCRISState *env, DisasContext *dc)
-{
- uint32_t imm;
-
- dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5);
- imm = sign_extend(dc->op1, 5);
- LOG_DIS("moveq %d, $r%u\n", imm, dc->op2);
-
- tcg_gen_movi_tl(cpu_R[dc->op2], imm);
- return 2;
-}
-static int dec_subq(CPUCRISState *env, DisasContext *dc)
-{
- TCGv c;
- dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5);
-
- LOG_DIS("subq %u, $r%u\n", dc->op1, dc->op2);
-
- cris_cc_mask(dc, CC_MASK_NZVC);
- c = tcg_constant_tl(dc->op1);
- cris_alu(dc, CC_OP_SUB,
- cpu_R[dc->op2], cpu_R[dc->op2], c, 4);
- return 2;
-}
-static int dec_cmpq(CPUCRISState *env, DisasContext *dc)
-{
- uint32_t imm;
- TCGv c;
- dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5);
- imm = sign_extend(dc->op1, 5);
-
- LOG_DIS("cmpq %d, $r%d\n", imm, dc->op2);
- cris_cc_mask(dc, CC_MASK_NZVC);
-
- c = tcg_constant_tl(imm);
- cris_alu(dc, CC_OP_CMP,
- cpu_R[dc->op2], cpu_R[dc->op2], c, 4);
- return 2;
-}
-static int dec_andq(CPUCRISState *env, DisasContext *dc)
-{
- uint32_t imm;
- TCGv c;
- dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5);
- imm = sign_extend(dc->op1, 5);
-
- LOG_DIS("andq %d, $r%d\n", imm, dc->op2);
- cris_cc_mask(dc, CC_MASK_NZ);
-
- c = tcg_constant_tl(imm);
- cris_alu(dc, CC_OP_AND,
- cpu_R[dc->op2], cpu_R[dc->op2], c, 4);
- return 2;
-}
-static int dec_orq(CPUCRISState *env, DisasContext *dc)
-{
- uint32_t imm;
- TCGv c;
- dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5);
- imm = sign_extend(dc->op1, 5);
- LOG_DIS("orq %d, $r%d\n", imm, dc->op2);
- cris_cc_mask(dc, CC_MASK_NZ);
-
- c = tcg_constant_tl(imm);
- cris_alu(dc, CC_OP_OR,
- cpu_R[dc->op2], cpu_R[dc->op2], c, 4);
- return 2;
-}
-static int dec_btstq(CPUCRISState *env, DisasContext *dc)
-{
- TCGv c;
- dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4);
- LOG_DIS("btstq %u, $r%d\n", dc->op1, dc->op2);
-
- cris_cc_mask(dc, CC_MASK_NZ);
- c = tcg_constant_tl(dc->op1);
- cris_evaluate_flags(dc);
- gen_helper_btst(cpu_PR[PR_CCS], tcg_env, cpu_R[dc->op2],
- c, cpu_PR[PR_CCS]);
- cris_alu(dc, CC_OP_MOVE,
- cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op2], 4);
- cris_update_cc_op(dc, CC_OP_FLAGS, 4);
- dc->flags_uptodate = 1;
- return 2;
-}
-static int dec_asrq(CPUCRISState *env, DisasContext *dc)
-{
- dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4);
- LOG_DIS("asrq %u, $r%d\n", dc->op1, dc->op2);
- cris_cc_mask(dc, CC_MASK_NZ);
-
- tcg_gen_sari_tl(cpu_R[dc->op2], cpu_R[dc->op2], dc->op1);
- cris_alu(dc, CC_OP_MOVE,
- cpu_R[dc->op2],
- cpu_R[dc->op2], cpu_R[dc->op2], 4);
- return 2;
-}
-static int dec_lslq(CPUCRISState *env, DisasContext *dc)
-{
- dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4);
- LOG_DIS("lslq %u, $r%d\n", dc->op1, dc->op2);
-
- cris_cc_mask(dc, CC_MASK_NZ);
-
- tcg_gen_shli_tl(cpu_R[dc->op2], cpu_R[dc->op2], dc->op1);
-
- cris_alu(dc, CC_OP_MOVE,
- cpu_R[dc->op2],
- cpu_R[dc->op2], cpu_R[dc->op2], 4);
- return 2;
-}
-static int dec_lsrq(CPUCRISState *env, DisasContext *dc)
-{
- dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4);
- LOG_DIS("lsrq %u, $r%d\n", dc->op1, dc->op2);
-
- cris_cc_mask(dc, CC_MASK_NZ);
-
- tcg_gen_shri_tl(cpu_R[dc->op2], cpu_R[dc->op2], dc->op1);
- cris_alu(dc, CC_OP_MOVE,
- cpu_R[dc->op2],
- cpu_R[dc->op2], cpu_R[dc->op2], 4);
- return 2;
-}
-
-static int dec_move_r(CPUCRISState *env, DisasContext *dc)
-{
- int size = memsize_zz(dc);
-
- LOG_DIS("move.%c $r%u, $r%u\n",
- memsize_char(size), dc->op1, dc->op2);
-
- cris_cc_mask(dc, CC_MASK_NZ);
- if (size == 4) {
- dec_prep_move_r(dc, dc->op1, dc->op2, size, 0, cpu_R[dc->op2]);
- cris_cc_mask(dc, CC_MASK_NZ);
- cris_update_cc_op(dc, CC_OP_MOVE, 4);
- cris_update_cc_x(dc);
- cris_update_result(dc, cpu_R[dc->op2]);
- } else {
- TCGv t0;
-
- t0 = tcg_temp_new();
- dec_prep_move_r(dc, dc->op1, dc->op2, size, 0, t0);
- cris_alu(dc, CC_OP_MOVE,
- cpu_R[dc->op2],
- cpu_R[dc->op2], t0, size);
- }
- return 2;
-}
-
-static int dec_scc_r(CPUCRISState *env, DisasContext *dc)
-{
- int cond = dc->op2;
-
- LOG_DIS("s%s $r%u\n",
- cc_name(cond), dc->op1);
-
- gen_tst_cc(dc, cpu_R[dc->op1], cond);
- tcg_gen_setcondi_tl(TCG_COND_NE, cpu_R[dc->op1], cpu_R[dc->op1], 0);
-
- cris_cc_mask(dc, 0);
- return 2;
-}
-
-static inline void cris_alu_alloc_temps(DisasContext *dc, int size, TCGv *t)
-{
- if (size == 4) {
- t[0] = cpu_R[dc->op2];
- t[1] = cpu_R[dc->op1];
- } else {
- t[0] = tcg_temp_new();
- t[1] = tcg_temp_new();
- }
-}
-
-static int dec_and_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int size = memsize_zz(dc);
-
- LOG_DIS("and.%c $r%u, $r%u\n",
- memsize_char(size), dc->op1, dc->op2);
-
- cris_cc_mask(dc, CC_MASK_NZ);
-
- cris_alu_alloc_temps(dc, size, t);
- dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]);
- cris_alu(dc, CC_OP_AND, cpu_R[dc->op2], t[0], t[1], size);
- return 2;
-}
-
-static int dec_lz_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t0;
- LOG_DIS("lz $r%u, $r%u\n",
- dc->op1, dc->op2);
- cris_cc_mask(dc, CC_MASK_NZ);
- t0 = tcg_temp_new();
- dec_prep_alu_r(dc, dc->op1, dc->op2, 4, 0, cpu_R[dc->op2], t0);
- cris_alu(dc, CC_OP_LZ, cpu_R[dc->op2], cpu_R[dc->op2], t0, 4);
- return 2;
-}
-
-static int dec_lsl_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int size = memsize_zz(dc);
-
- LOG_DIS("lsl.%c $r%u, $r%u\n",
- memsize_char(size), dc->op1, dc->op2);
-
- cris_cc_mask(dc, CC_MASK_NZ);
- cris_alu_alloc_temps(dc, size, t);
- dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]);
- tcg_gen_andi_tl(t[1], t[1], 63);
- cris_alu(dc, CC_OP_LSL, cpu_R[dc->op2], t[0], t[1], size);
- return 2;
-}
-
-static int dec_lsr_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int size = memsize_zz(dc);
-
- LOG_DIS("lsr.%c $r%u, $r%u\n",
- memsize_char(size), dc->op1, dc->op2);
-
- cris_cc_mask(dc, CC_MASK_NZ);
- cris_alu_alloc_temps(dc, size, t);
- dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]);
- tcg_gen_andi_tl(t[1], t[1], 63);
- cris_alu(dc, CC_OP_LSR, cpu_R[dc->op2], t[0], t[1], size);
- return 2;
-}
-
-static int dec_asr_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int size = memsize_zz(dc);
-
- LOG_DIS("asr.%c $r%u, $r%u\n",
- memsize_char(size), dc->op1, dc->op2);
-
- cris_cc_mask(dc, CC_MASK_NZ);
- cris_alu_alloc_temps(dc, size, t);
- dec_prep_alu_r(dc, dc->op1, dc->op2, size, 1, t[0], t[1]);
- tcg_gen_andi_tl(t[1], t[1], 63);
- cris_alu(dc, CC_OP_ASR, cpu_R[dc->op2], t[0], t[1], size);
- return 2;
-}
-
-static int dec_muls_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int size = memsize_zz(dc);
-
- LOG_DIS("muls.%c $r%u, $r%u\n",
- memsize_char(size), dc->op1, dc->op2);
- cris_cc_mask(dc, CC_MASK_NZV);
- cris_alu_alloc_temps(dc, size, t);
- dec_prep_alu_r(dc, dc->op1, dc->op2, size, 1, t[0], t[1]);
-
- cris_alu(dc, CC_OP_MULS, cpu_R[dc->op2], t[0], t[1], 4);
- return 2;
-}
-
-static int dec_mulu_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int size = memsize_zz(dc);
-
- LOG_DIS("mulu.%c $r%u, $r%u\n",
- memsize_char(size), dc->op1, dc->op2);
- cris_cc_mask(dc, CC_MASK_NZV);
- cris_alu_alloc_temps(dc, size, t);
- dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]);
-
- cris_alu(dc, CC_OP_MULU, cpu_R[dc->op2], t[0], t[1], 4);
- return 2;
-}
-
-
-static int dec_dstep_r(CPUCRISState *env, DisasContext *dc)
-{
- LOG_DIS("dstep $r%u, $r%u\n", dc->op1, dc->op2);
- cris_cc_mask(dc, CC_MASK_NZ);
- cris_alu(dc, CC_OP_DSTEP,
- cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op1], 4);
- return 2;
-}
-
-static int dec_xor_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int size = memsize_zz(dc);
- LOG_DIS("xor.%c $r%u, $r%u\n",
- memsize_char(size), dc->op1, dc->op2);
- BUG_ON(size != 4); /* xor is dword. */
- cris_cc_mask(dc, CC_MASK_NZ);
- cris_alu_alloc_temps(dc, size, t);
- dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]);
-
- cris_alu(dc, CC_OP_XOR, cpu_R[dc->op2], t[0], t[1], 4);
- return 2;
-}
-
-static int dec_bound_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv l0;
- int size = memsize_zz(dc);
- LOG_DIS("bound.%c $r%u, $r%u\n",
- memsize_char(size), dc->op1, dc->op2);
- cris_cc_mask(dc, CC_MASK_NZ);
- l0 = tcg_temp_new();
- dec_prep_move_r(dc, dc->op1, dc->op2, size, 0, l0);
- cris_alu(dc, CC_OP_BOUND, cpu_R[dc->op2], cpu_R[dc->op2], l0, 4);
- return 2;
-}
-
-static int dec_cmp_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int size = memsize_zz(dc);
- LOG_DIS("cmp.%c $r%u, $r%u\n",
- memsize_char(size), dc->op1, dc->op2);
- cris_cc_mask(dc, CC_MASK_NZVC);
- cris_alu_alloc_temps(dc, size, t);
- dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]);
-
- cris_alu(dc, CC_OP_CMP, cpu_R[dc->op2], t[0], t[1], size);
- return 2;
-}
-
-static int dec_abs_r(CPUCRISState *env, DisasContext *dc)
-{
- LOG_DIS("abs $r%u, $r%u\n",
- dc->op1, dc->op2);
- cris_cc_mask(dc, CC_MASK_NZ);
-
- tcg_gen_abs_tl(cpu_R[dc->op2], cpu_R[dc->op1]);
- cris_alu(dc, CC_OP_MOVE,
- cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op2], 4);
- return 2;
-}
-
-static int dec_add_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int size = memsize_zz(dc);
- LOG_DIS("add.%c $r%u, $r%u\n",
- memsize_char(size), dc->op1, dc->op2);
- cris_cc_mask(dc, CC_MASK_NZVC);
- cris_alu_alloc_temps(dc, size, t);
- dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]);
-
- cris_alu(dc, CC_OP_ADD, cpu_R[dc->op2], t[0], t[1], size);
- return 2;
-}
-
-static int dec_addc_r(CPUCRISState *env, DisasContext *dc)
-{
- LOG_DIS("addc $r%u, $r%u\n",
- dc->op1, dc->op2);
- cris_evaluate_flags(dc);
-
- /* Set for this insn. */
- dc->flags_x = X_FLAG;
-
- cris_cc_mask(dc, CC_MASK_NZVC);
- cris_alu(dc, CC_OP_ADDC,
- cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op1], 4);
- return 2;
-}
-
-static int dec_mcp_r(CPUCRISState *env, DisasContext *dc)
-{
- LOG_DIS("mcp $p%u, $r%u\n",
- dc->op2, dc->op1);
- cris_evaluate_flags(dc);
- cris_cc_mask(dc, CC_MASK_RNZV);
- cris_alu(dc, CC_OP_MCP,
- cpu_R[dc->op1], cpu_R[dc->op1], cpu_PR[dc->op2], 4);
- return 2;
-}
-
-#if DISAS_CRIS
-static char * swapmode_name(int mode, char *modename) {
- int i = 0;
- if (mode & 8) {
- modename[i++] = 'n';
- }
- if (mode & 4) {
- modename[i++] = 'w';
- }
- if (mode & 2) {
- modename[i++] = 'b';
- }
- if (mode & 1) {
- modename[i++] = 'r';
- }
- modename[i++] = 0;
- return modename;
-}
-#endif
-
-static int dec_swap_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t0;
-#if DISAS_CRIS
- char modename[4];
-#endif
- LOG_DIS("swap%s $r%u\n",
- swapmode_name(dc->op2, modename), dc->op1);
-
- cris_cc_mask(dc, CC_MASK_NZ);
- t0 = tcg_temp_new();
- tcg_gen_mov_tl(t0, cpu_R[dc->op1]);
- if (dc->op2 & 8) {
- tcg_gen_not_tl(t0, t0);
- }
- if (dc->op2 & 4) {
- t_gen_swapw(t0, t0);
- }
- if (dc->op2 & 2) {
- t_gen_swapb(t0, t0);
- }
- if (dc->op2 & 1) {
- t_gen_swapr(t0, t0);
- }
- cris_alu(dc, CC_OP_MOVE, cpu_R[dc->op1], cpu_R[dc->op1], t0, 4);
- return 2;
-}
-
-static int dec_or_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int size = memsize_zz(dc);
- LOG_DIS("or.%c $r%u, $r%u\n",
- memsize_char(size), dc->op1, dc->op2);
- cris_cc_mask(dc, CC_MASK_NZ);
- cris_alu_alloc_temps(dc, size, t);
- dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]);
- cris_alu(dc, CC_OP_OR, cpu_R[dc->op2], t[0], t[1], size);
- return 2;
-}
-
-static int dec_addi_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t0;
- LOG_DIS("addi.%c $r%u, $r%u\n",
- memsize_char(memsize_zz(dc)), dc->op2, dc->op1);
- cris_cc_mask(dc, 0);
- t0 = tcg_temp_new();
- tcg_gen_shli_tl(t0, cpu_R[dc->op2], dc->zzsize);
- tcg_gen_add_tl(cpu_R[dc->op1], cpu_R[dc->op1], t0);
- return 2;
-}
-
-static int dec_addi_acr(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t0;
- LOG_DIS("addi.%c $r%u, $r%u, $acr\n",
- memsize_char(memsize_zz(dc)), dc->op2, dc->op1);
- cris_cc_mask(dc, 0);
- t0 = tcg_temp_new();
- tcg_gen_shli_tl(t0, cpu_R[dc->op2], dc->zzsize);
- tcg_gen_add_tl(cpu_R[R_ACR], cpu_R[dc->op1], t0);
- return 2;
-}
-
-static int dec_neg_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int size = memsize_zz(dc);
- LOG_DIS("neg.%c $r%u, $r%u\n",
- memsize_char(size), dc->op1, dc->op2);
- cris_cc_mask(dc, CC_MASK_NZVC);
- cris_alu_alloc_temps(dc, size, t);
- dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]);
-
- cris_alu(dc, CC_OP_NEG, cpu_R[dc->op2], t[0], t[1], size);
- return 2;
-}
-
-static int dec_btst_r(CPUCRISState *env, DisasContext *dc)
-{
- LOG_DIS("btst $r%u, $r%u\n",
- dc->op1, dc->op2);
- cris_cc_mask(dc, CC_MASK_NZ);
- cris_evaluate_flags(dc);
- gen_helper_btst(cpu_PR[PR_CCS], tcg_env, cpu_R[dc->op2],
- cpu_R[dc->op1], cpu_PR[PR_CCS]);
- cris_alu(dc, CC_OP_MOVE, cpu_R[dc->op2],
- cpu_R[dc->op2], cpu_R[dc->op2], 4);
- cris_update_cc_op(dc, CC_OP_FLAGS, 4);
- dc->flags_uptodate = 1;
- return 2;
-}
-
-static int dec_sub_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int size = memsize_zz(dc);
- LOG_DIS("sub.%c $r%u, $r%u\n",
- memsize_char(size), dc->op1, dc->op2);
- cris_cc_mask(dc, CC_MASK_NZVC);
- cris_alu_alloc_temps(dc, size, t);
- dec_prep_alu_r(dc, dc->op1, dc->op2, size, 0, t[0], t[1]);
- cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], t[0], t[1], size);
- return 2;
-}
-
-/* Zero extension. From size to dword. */
-static int dec_movu_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t0;
- int size = memsize_z(dc);
- LOG_DIS("movu.%c $r%u, $r%u\n",
- memsize_char(size),
- dc->op1, dc->op2);
-
- cris_cc_mask(dc, CC_MASK_NZ);
- t0 = tcg_temp_new();
- dec_prep_move_r(dc, dc->op1, dc->op2, size, 0, t0);
- cris_alu(dc, CC_OP_MOVE, cpu_R[dc->op2], cpu_R[dc->op2], t0, 4);
- return 2;
-}
-
-/* Sign extension. From size to dword. */
-static int dec_movs_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t0;
- int size = memsize_z(dc);
- LOG_DIS("movs.%c $r%u, $r%u\n",
- memsize_char(size),
- dc->op1, dc->op2);
-
- cris_cc_mask(dc, CC_MASK_NZ);
- t0 = tcg_temp_new();
- /* Size can only be qi or hi. */
- t_gen_sext(t0, cpu_R[dc->op1], size);
- cris_alu(dc, CC_OP_MOVE,
- cpu_R[dc->op2], cpu_R[dc->op1], t0, 4);
- return 2;
-}
-
-/* zero extension. From size to dword. */
-static int dec_addu_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t0;
- int size = memsize_z(dc);
- LOG_DIS("addu.%c $r%u, $r%u\n",
- memsize_char(size),
- dc->op1, dc->op2);
-
- cris_cc_mask(dc, CC_MASK_NZVC);
- t0 = tcg_temp_new();
- /* Size can only be qi or hi. */
- t_gen_zext(t0, cpu_R[dc->op1], size);
- cris_alu(dc, CC_OP_ADD, cpu_R[dc->op2], cpu_R[dc->op2], t0, 4);
- return 2;
-}
-
-/* Sign extension. From size to dword. */
-static int dec_adds_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t0;
- int size = memsize_z(dc);
- LOG_DIS("adds.%c $r%u, $r%u\n",
- memsize_char(size),
- dc->op1, dc->op2);
-
- cris_cc_mask(dc, CC_MASK_NZVC);
- t0 = tcg_temp_new();
- /* Size can only be qi or hi. */
- t_gen_sext(t0, cpu_R[dc->op1], size);
- cris_alu(dc, CC_OP_ADD,
- cpu_R[dc->op2], cpu_R[dc->op2], t0, 4);
- return 2;
-}
-
-/* Zero extension. From size to dword. */
-static int dec_subu_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t0;
- int size = memsize_z(dc);
- LOG_DIS("subu.%c $r%u, $r%u\n",
- memsize_char(size),
- dc->op1, dc->op2);
-
- cris_cc_mask(dc, CC_MASK_NZVC);
- t0 = tcg_temp_new();
- /* Size can only be qi or hi. */
- t_gen_zext(t0, cpu_R[dc->op1], size);
- cris_alu(dc, CC_OP_SUB,
- cpu_R[dc->op2], cpu_R[dc->op2], t0, 4);
- return 2;
-}
-
-/* Sign extension. From size to dword. */
-static int dec_subs_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t0;
- int size = memsize_z(dc);
- LOG_DIS("subs.%c $r%u, $r%u\n",
- memsize_char(size),
- dc->op1, dc->op2);
-
- cris_cc_mask(dc, CC_MASK_NZVC);
- t0 = tcg_temp_new();
- /* Size can only be qi or hi. */
- t_gen_sext(t0, cpu_R[dc->op1], size);
- cris_alu(dc, CC_OP_SUB,
- cpu_R[dc->op2], cpu_R[dc->op2], t0, 4);
- return 2;
-}
-
-static int dec_setclrf(CPUCRISState *env, DisasContext *dc)
-{
- uint32_t flags;
- int set = (~dc->opcode >> 2) & 1;
-
-
- flags = (EXTRACT_FIELD(dc->ir, 12, 15) << 4)
- | EXTRACT_FIELD(dc->ir, 0, 3);
- if (set && flags == 0) {
- LOG_DIS("nop\n");
- return 2;
- } else if (!set && (flags & 0x20)) {
- LOG_DIS("di\n");
- } else {
- LOG_DIS("%sf %x\n", set ? "set" : "clr", flags);
- }
-
- /* User space is not allowed to touch these. Silently ignore. */
- if (dc->tb_flags & U_FLAG) {
- flags &= ~(S_FLAG | I_FLAG | U_FLAG);
- }
-
- if (flags & X_FLAG) {
- if (set) {
- dc->flags_x = X_FLAG;
- } else {
- dc->flags_x = 0;
- }
- }
-
- /* Break the TB if any of the SPI flag changes. */
- if (flags & (P_FLAG | S_FLAG)) {
- tcg_gen_movi_tl(env_pc, dc->pc + 2);
- dc->base.is_jmp = DISAS_UPDATE;
- dc->cpustate_changed = 1;
- }
-
- /* For the I flag, only act on posedge. */
- if ((flags & I_FLAG)) {
- tcg_gen_movi_tl(env_pc, dc->pc + 2);
- dc->base.is_jmp = DISAS_UPDATE;
- dc->cpustate_changed = 1;
- }
-
-
- /* Simply decode the flags. */
- cris_evaluate_flags(dc);
- cris_update_cc_op(dc, CC_OP_FLAGS, 4);
- cris_update_cc_x(dc);
- tcg_gen_movi_tl(cc_op, dc->cc_op);
-
- if (set) {
- if (!(dc->tb_flags & U_FLAG) && (flags & U_FLAG)) {
- /* Enter user mode. */
- t_gen_mov_env_TN(ksp, cpu_R[R_SP]);
- tcg_gen_mov_tl(cpu_R[R_SP], cpu_PR[PR_USP]);
- dc->cpustate_changed = 1;
- }
- tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], flags);
- } else {
- tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~flags);
- }
-
- dc->flags_uptodate = 1;
- dc->clear_x = 0;
- return 2;
-}
-
-static int dec_move_rs(CPUCRISState *env, DisasContext *dc)
-{
- TCGv c2, c1;
- LOG_DIS("move $r%u, $s%u\n", dc->op1, dc->op2);
- c1 = tcg_constant_tl(dc->op1);
- c2 = tcg_constant_tl(dc->op2);
- cris_cc_mask(dc, 0);
- gen_helper_movl_sreg_reg(tcg_env, c2, c1);
- return 2;
-}
-static int dec_move_sr(CPUCRISState *env, DisasContext *dc)
-{
- TCGv c2, c1;
- LOG_DIS("move $s%u, $r%u\n", dc->op2, dc->op1);
- c1 = tcg_constant_tl(dc->op1);
- c2 = tcg_constant_tl(dc->op2);
- cris_cc_mask(dc, 0);
- gen_helper_movl_reg_sreg(tcg_env, c1, c2);
- return 2;
-}
-
-static int dec_move_rp(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- LOG_DIS("move $r%u, $p%u\n", dc->op1, dc->op2);
- cris_cc_mask(dc, 0);
-
- t[0] = tcg_temp_new();
- if (dc->op2 == PR_CCS) {
- cris_evaluate_flags(dc);
- tcg_gen_mov_tl(t[0], cpu_R[dc->op1]);
- if (dc->tb_flags & U_FLAG) {
- t[1] = tcg_temp_new();
- /* User space is not allowed to touch all flags. */
- tcg_gen_andi_tl(t[0], t[0], 0x39f);
- tcg_gen_andi_tl(t[1], cpu_PR[PR_CCS], ~0x39f);
- tcg_gen_or_tl(t[0], t[1], t[0]);
- }
- } else {
- tcg_gen_mov_tl(t[0], cpu_R[dc->op1]);
- }
-
- t_gen_mov_preg_TN(dc, dc->op2, t[0]);
- if (dc->op2 == PR_CCS) {
- cris_update_cc_op(dc, CC_OP_FLAGS, 4);
- dc->flags_uptodate = 1;
- }
- return 2;
-}
-static int dec_move_pr(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t0;
- LOG_DIS("move $p%u, $r%u\n", dc->op2, dc->op1);
- cris_cc_mask(dc, 0);
-
- if (dc->op2 == PR_CCS) {
- cris_evaluate_flags(dc);
- }
-
- if (dc->op2 == PR_DZ) {
- tcg_gen_movi_tl(cpu_R[dc->op1], 0);
- } else {
- t0 = tcg_temp_new();
- t_gen_mov_TN_preg(t0, dc->op2);
- cris_alu(dc, CC_OP_MOVE,
- cpu_R[dc->op1], cpu_R[dc->op1], t0,
- preg_sizes[dc->op2]);
- }
- return 2;
-}
-
-static int dec_move_mr(CPUCRISState *env, DisasContext *dc)
-{
- int memsize = memsize_zz(dc);
- int insn_len;
- LOG_DIS("move.%c [$r%u%s, $r%u\n",
- memsize_char(memsize),
- dc->op1, dc->postinc ? "+]" : "]",
- dc->op2);
-
- if (memsize == 4) {
- insn_len = dec_prep_move_m(env, dc, 0, 4, cpu_R[dc->op2]);
- cris_cc_mask(dc, CC_MASK_NZ);
- cris_update_cc_op(dc, CC_OP_MOVE, 4);
- cris_update_cc_x(dc);
- cris_update_result(dc, cpu_R[dc->op2]);
- } else {
- TCGv t0;
-
- t0 = tcg_temp_new();
- insn_len = dec_prep_move_m(env, dc, 0, memsize, t0);
- cris_cc_mask(dc, CC_MASK_NZ);
- cris_alu(dc, CC_OP_MOVE,
- cpu_R[dc->op2], cpu_R[dc->op2], t0, memsize);
- }
- do_postinc(dc, memsize);
- return insn_len;
-}
-
-static inline void cris_alu_m_alloc_temps(TCGv *t)
-{
- t[0] = tcg_temp_new();
- t[1] = tcg_temp_new();
-}
-
-static int dec_movs_m(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int memsize = memsize_z(dc);
- int insn_len;
- LOG_DIS("movs.%c [$r%u%s, $r%u\n",
- memsize_char(memsize),
- dc->op1, dc->postinc ? "+]" : "]",
- dc->op2);
-
- cris_alu_m_alloc_temps(t);
- /* sign extend. */
- insn_len = dec_prep_alu_m(env, dc, 1, memsize, t[0], t[1]);
- cris_cc_mask(dc, CC_MASK_NZ);
- cris_alu(dc, CC_OP_MOVE,
- cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4);
- do_postinc(dc, memsize);
- return insn_len;
-}
-
-static int dec_addu_m(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int memsize = memsize_z(dc);
- int insn_len;
- LOG_DIS("addu.%c [$r%u%s, $r%u\n",
- memsize_char(memsize),
- dc->op1, dc->postinc ? "+]" : "]",
- dc->op2);
-
- cris_alu_m_alloc_temps(t);
- /* sign extend. */
- insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]);
- cris_cc_mask(dc, CC_MASK_NZVC);
- cris_alu(dc, CC_OP_ADD,
- cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4);
- do_postinc(dc, memsize);
- return insn_len;
-}
-
-static int dec_adds_m(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int memsize = memsize_z(dc);
- int insn_len;
- LOG_DIS("adds.%c [$r%u%s, $r%u\n",
- memsize_char(memsize),
- dc->op1, dc->postinc ? "+]" : "]",
- dc->op2);
-
- cris_alu_m_alloc_temps(t);
- /* sign extend. */
- insn_len = dec_prep_alu_m(env, dc, 1, memsize, t[0], t[1]);
- cris_cc_mask(dc, CC_MASK_NZVC);
- cris_alu(dc, CC_OP_ADD, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4);
- do_postinc(dc, memsize);
- return insn_len;
-}
-
-static int dec_subu_m(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int memsize = memsize_z(dc);
- int insn_len;
- LOG_DIS("subu.%c [$r%u%s, $r%u\n",
- memsize_char(memsize),
- dc->op1, dc->postinc ? "+]" : "]",
- dc->op2);
-
- cris_alu_m_alloc_temps(t);
- /* sign extend. */
- insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]);
- cris_cc_mask(dc, CC_MASK_NZVC);
- cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4);
- do_postinc(dc, memsize);
- return insn_len;
-}
-
-static int dec_subs_m(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int memsize = memsize_z(dc);
- int insn_len;
- LOG_DIS("subs.%c [$r%u%s, $r%u\n",
- memsize_char(memsize),
- dc->op1, dc->postinc ? "+]" : "]",
- dc->op2);
-
- cris_alu_m_alloc_temps(t);
- /* sign extend. */
- insn_len = dec_prep_alu_m(env, dc, 1, memsize, t[0], t[1]);
- cris_cc_mask(dc, CC_MASK_NZVC);
- cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4);
- do_postinc(dc, memsize);
- return insn_len;
-}
-
-static int dec_movu_m(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int memsize = memsize_z(dc);
- int insn_len;
-
- LOG_DIS("movu.%c [$r%u%s, $r%u\n",
- memsize_char(memsize),
- dc->op1, dc->postinc ? "+]" : "]",
- dc->op2);
-
- cris_alu_m_alloc_temps(t);
- insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]);
- cris_cc_mask(dc, CC_MASK_NZ);
- cris_alu(dc, CC_OP_MOVE, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4);
- do_postinc(dc, memsize);
- return insn_len;
-}
-
-static int dec_cmpu_m(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int memsize = memsize_z(dc);
- int insn_len;
- LOG_DIS("cmpu.%c [$r%u%s, $r%u\n",
- memsize_char(memsize),
- dc->op1, dc->postinc ? "+]" : "]",
- dc->op2);
-
- cris_alu_m_alloc_temps(t);
- insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]);
- cris_cc_mask(dc, CC_MASK_NZVC);
- cris_alu(dc, CC_OP_CMP, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4);
- do_postinc(dc, memsize);
- return insn_len;
-}
-
-static int dec_cmps_m(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int memsize = memsize_z(dc);
- int insn_len;
- LOG_DIS("cmps.%c [$r%u%s, $r%u\n",
- memsize_char(memsize),
- dc->op1, dc->postinc ? "+]" : "]",
- dc->op2);
-
- cris_alu_m_alloc_temps(t);
- insn_len = dec_prep_alu_m(env, dc, 1, memsize, t[0], t[1]);
- cris_cc_mask(dc, CC_MASK_NZVC);
- cris_alu(dc, CC_OP_CMP,
- cpu_R[dc->op2], cpu_R[dc->op2], t[1],
- memsize_zz(dc));
- do_postinc(dc, memsize);
- return insn_len;
-}
-
-static int dec_cmp_m(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int memsize = memsize_zz(dc);
- int insn_len;
- LOG_DIS("cmp.%c [$r%u%s, $r%u\n",
- memsize_char(memsize),
- dc->op1, dc->postinc ? "+]" : "]",
- dc->op2);
-
- cris_alu_m_alloc_temps(t);
- insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]);
- cris_cc_mask(dc, CC_MASK_NZVC);
- cris_alu(dc, CC_OP_CMP,
- cpu_R[dc->op2], cpu_R[dc->op2], t[1],
- memsize_zz(dc));
- do_postinc(dc, memsize);
- return insn_len;
-}
-
-static int dec_test_m(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2], c;
- int memsize = memsize_zz(dc);
- int insn_len;
- LOG_DIS("test.%c [$r%u%s] op2=%x\n",
- memsize_char(memsize),
- dc->op1, dc->postinc ? "+]" : "]",
- dc->op2);
-
- cris_evaluate_flags(dc);
-
- cris_alu_m_alloc_temps(t);
- insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]);
- cris_cc_mask(dc, CC_MASK_NZ);
- tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~3);
-
- c = tcg_constant_tl(0);
- cris_alu(dc, CC_OP_CMP,
- cpu_R[dc->op2], t[1], c, memsize_zz(dc));
- do_postinc(dc, memsize);
- return insn_len;
-}
-
-static int dec_and_m(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int memsize = memsize_zz(dc);
- int insn_len;
- LOG_DIS("and.%c [$r%u%s, $r%u\n",
- memsize_char(memsize),
- dc->op1, dc->postinc ? "+]" : "]",
- dc->op2);
-
- cris_alu_m_alloc_temps(t);
- insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]);
- cris_cc_mask(dc, CC_MASK_NZ);
- cris_alu(dc, CC_OP_AND, cpu_R[dc->op2], t[0], t[1], memsize_zz(dc));
- do_postinc(dc, memsize);
- return insn_len;
-}
-
-static int dec_add_m(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int memsize = memsize_zz(dc);
- int insn_len;
- LOG_DIS("add.%c [$r%u%s, $r%u\n",
- memsize_char(memsize),
- dc->op1, dc->postinc ? "+]" : "]",
- dc->op2);
-
- cris_alu_m_alloc_temps(t);
- insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]);
- cris_cc_mask(dc, CC_MASK_NZVC);
- cris_alu(dc, CC_OP_ADD,
- cpu_R[dc->op2], t[0], t[1], memsize_zz(dc));
- do_postinc(dc, memsize);
- return insn_len;
-}
-
-static int dec_addo_m(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int memsize = memsize_zz(dc);
- int insn_len;
- LOG_DIS("add.%c [$r%u%s, $r%u\n",
- memsize_char(memsize),
- dc->op1, dc->postinc ? "+]" : "]",
- dc->op2);
-
- cris_alu_m_alloc_temps(t);
- insn_len = dec_prep_alu_m(env, dc, 1, memsize, t[0], t[1]);
- cris_cc_mask(dc, 0);
- cris_alu(dc, CC_OP_ADD, cpu_R[R_ACR], t[0], t[1], 4);
- do_postinc(dc, memsize);
- return insn_len;
-}
-
-static int dec_bound_m(CPUCRISState *env, DisasContext *dc)
-{
- TCGv l[2];
- int memsize = memsize_zz(dc);
- int insn_len;
- LOG_DIS("bound.%c [$r%u%s, $r%u\n",
- memsize_char(memsize),
- dc->op1, dc->postinc ? "+]" : "]",
- dc->op2);
-
- l[0] = tcg_temp_new();
- l[1] = tcg_temp_new();
- insn_len = dec_prep_alu_m(env, dc, 0, memsize, l[0], l[1]);
- cris_cc_mask(dc, CC_MASK_NZ);
- cris_alu(dc, CC_OP_BOUND, cpu_R[dc->op2], l[0], l[1], 4);
- do_postinc(dc, memsize);
- return insn_len;
-}
-
-static int dec_addc_mr(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int insn_len = 2;
- LOG_DIS("addc [$r%u%s, $r%u\n",
- dc->op1, dc->postinc ? "+]" : "]",
- dc->op2);
-
- cris_evaluate_flags(dc);
-
- /* Set for this insn. */
- dc->flags_x = X_FLAG;
-
- cris_alu_m_alloc_temps(t);
- insn_len = dec_prep_alu_m(env, dc, 0, 4, t[0], t[1]);
- cris_cc_mask(dc, CC_MASK_NZVC);
- cris_alu(dc, CC_OP_ADDC, cpu_R[dc->op2], t[0], t[1], 4);
- do_postinc(dc, 4);
- return insn_len;
-}
-
-static int dec_sub_m(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int memsize = memsize_zz(dc);
- int insn_len;
- LOG_DIS("sub.%c [$r%u%s, $r%u ir=%x zz=%x\n",
- memsize_char(memsize),
- dc->op1, dc->postinc ? "+]" : "]",
- dc->op2, dc->ir, dc->zzsize);
-
- cris_alu_m_alloc_temps(t);
- insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]);
- cris_cc_mask(dc, CC_MASK_NZVC);
- cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], t[0], t[1], memsize);
- do_postinc(dc, memsize);
- return insn_len;
-}
-
-static int dec_or_m(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int memsize = memsize_zz(dc);
- int insn_len;
- LOG_DIS("or.%c [$r%u%s, $r%u pc=%x\n",
- memsize_char(memsize),
- dc->op1, dc->postinc ? "+]" : "]",
- dc->op2, dc->pc);
-
- cris_alu_m_alloc_temps(t);
- insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]);
- cris_cc_mask(dc, CC_MASK_NZ);
- cris_alu(dc, CC_OP_OR,
- cpu_R[dc->op2], t[0], t[1], memsize_zz(dc));
- do_postinc(dc, memsize);
- return insn_len;
-}
-
-static int dec_move_mp(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t[2];
- int memsize = memsize_zz(dc);
- int insn_len = 2;
-
- LOG_DIS("move.%c [$r%u%s, $p%u\n",
- memsize_char(memsize),
- dc->op1,
- dc->postinc ? "+]" : "]",
- dc->op2);
-
- cris_alu_m_alloc_temps(t);
- insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]);
- cris_cc_mask(dc, 0);
- if (dc->op2 == PR_CCS) {
- cris_evaluate_flags(dc);
- if (dc->tb_flags & U_FLAG) {
- /* User space is not allowed to touch all flags. */
- tcg_gen_andi_tl(t[1], t[1], 0x39f);
- tcg_gen_andi_tl(t[0], cpu_PR[PR_CCS], ~0x39f);
- tcg_gen_or_tl(t[1], t[0], t[1]);
- }
- }
-
- t_gen_mov_preg_TN(dc, dc->op2, t[1]);
-
- do_postinc(dc, memsize);
- return insn_len;
-}
-
-static int dec_move_pm(CPUCRISState *env, DisasContext *dc)
-{
- TCGv t0;
- int memsize;
-
- memsize = preg_sizes[dc->op2];
-
- LOG_DIS("move.%c $p%u, [$r%u%s\n",
- memsize_char(memsize),
- dc->op2, dc->op1, dc->postinc ? "+]" : "]");
-
- /* prepare store. Address in T0, value in T1. */
- if (dc->op2 == PR_CCS) {
- cris_evaluate_flags(dc);
- }
- t0 = tcg_temp_new();
- t_gen_mov_TN_preg(t0, dc->op2);
- cris_flush_cc_state(dc);
- gen_store(dc, cpu_R[dc->op1], t0, memsize);
-
- cris_cc_mask(dc, 0);
- if (dc->postinc) {
- tcg_gen_addi_tl(cpu_R[dc->op1], cpu_R[dc->op1], memsize);
- }
- return 2;
-}
-
-static int dec_movem_mr(CPUCRISState *env, DisasContext *dc)
-{
- TCGv_i64 tmp[16];
- TCGv tmp32;
- TCGv addr;
- int i;
- int nr = dc->op2 + 1;
-
- LOG_DIS("movem [$r%u%s, $r%u\n", dc->op1,
- dc->postinc ? "+]" : "]", dc->op2);
-
- addr = tcg_temp_new();
- /* There are probably better ways of doing this. */
- cris_flush_cc_state(dc);
- for (i = 0; i < (nr >> 1); i++) {
- tmp[i] = tcg_temp_new_i64();
- tcg_gen_addi_tl(addr, cpu_R[dc->op1], i * 8);
- gen_load64(dc, tmp[i], addr);
- }
- if (nr & 1) {
- tmp32 = tcg_temp_new_i32();
- tcg_gen_addi_tl(addr, cpu_R[dc->op1], i * 8);
- gen_load(dc, tmp32, addr, 4, 0);
- } else {
- tmp32 = NULL;
- }
-
- for (i = 0; i < (nr >> 1); i++) {
- tcg_gen_extrl_i64_i32(cpu_R[i * 2], tmp[i]);
- tcg_gen_shri_i64(tmp[i], tmp[i], 32);
- tcg_gen_extrl_i64_i32(cpu_R[i * 2 + 1], tmp[i]);
- }
- if (nr & 1) {
- tcg_gen_mov_tl(cpu_R[dc->op2], tmp32);
- }
-
- /* writeback the updated pointer value. */
- if (dc->postinc) {
- tcg_gen_addi_tl(cpu_R[dc->op1], cpu_R[dc->op1], nr * 4);
- }
-
- /* gen_load might want to evaluate the previous insns flags. */
- cris_cc_mask(dc, 0);
- return 2;
-}
-
-static int dec_movem_rm(CPUCRISState *env, DisasContext *dc)
-{
- TCGv tmp;
- TCGv addr;
- int i;
-
- LOG_DIS("movem $r%u, [$r%u%s\n", dc->op2, dc->op1,
- dc->postinc ? "+]" : "]");
-
- cris_flush_cc_state(dc);
-
- tmp = tcg_temp_new();
- addr = tcg_temp_new();
- tcg_gen_movi_tl(tmp, 4);
- tcg_gen_mov_tl(addr, cpu_R[dc->op1]);
- for (i = 0; i <= dc->op2; i++) {
- /* Displace addr. */
- /* Perform the store. */
- gen_store(dc, addr, cpu_R[i], 4);
- tcg_gen_add_tl(addr, addr, tmp);
- }
- if (dc->postinc) {
- tcg_gen_mov_tl(cpu_R[dc->op1], addr);
- }
- cris_cc_mask(dc, 0);
- return 2;
-}
-
-static int dec_move_rm(CPUCRISState *env, DisasContext *dc)
-{
- int memsize;
-
- memsize = memsize_zz(dc);
-
- LOG_DIS("move.%c $r%u, [$r%u]\n",
- memsize_char(memsize), dc->op2, dc->op1);
-
- /* prepare store. */
- cris_flush_cc_state(dc);
- gen_store(dc, cpu_R[dc->op1], cpu_R[dc->op2], memsize);
-
- if (dc->postinc) {
- tcg_gen_addi_tl(cpu_R[dc->op1], cpu_R[dc->op1], memsize);
- }
- cris_cc_mask(dc, 0);
- return 2;
-}
-
-static int dec_lapcq(CPUCRISState *env, DisasContext *dc)
-{
- LOG_DIS("lapcq %x, $r%u\n",
- dc->pc + dc->op1*2, dc->op2);
- cris_cc_mask(dc, 0);
- tcg_gen_movi_tl(cpu_R[dc->op2], dc->pc + dc->op1 * 2);
- return 2;
-}
-
-static int dec_lapc_im(CPUCRISState *env, DisasContext *dc)
-{
- unsigned int rd;
- int32_t imm;
- int32_t pc;
-
- rd = dc->op2;
-
- cris_cc_mask(dc, 0);
- imm = cris_fetch(env, dc, dc->pc + 2, 4, 0);
- LOG_DIS("lapc 0x%x, $r%u\n", imm + dc->pc, dc->op2);
-
- pc = dc->pc;
- pc += imm;
- tcg_gen_movi_tl(cpu_R[rd], pc);
- return 6;
-}
-
-/* Jump to special reg. */
-static int dec_jump_p(CPUCRISState *env, DisasContext *dc)
-{
- LOG_DIS("jump $p%u\n", dc->op2);
-
- if (dc->op2 == PR_CCS) {
- cris_evaluate_flags(dc);
- }
- t_gen_mov_TN_preg(env_btarget, dc->op2);
- /* rete will often have low bit set to indicate delayslot. */
- tcg_gen_andi_tl(env_btarget, env_btarget, ~1);
- cris_cc_mask(dc, 0);
- cris_prepare_jmp(dc, JMP_INDIRECT);
- return 2;
-}
-
-/* Jump and save. */
-static int dec_jas_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv c;
- LOG_DIS("jas $r%u, $p%u\n", dc->op1, dc->op2);
- cris_cc_mask(dc, 0);
- /* Store the return address in Pd. */
- tcg_gen_mov_tl(env_btarget, cpu_R[dc->op1]);
- if (dc->op2 > 15) {
- abort();
- }
- c = tcg_constant_tl(dc->pc + 4);
- t_gen_mov_preg_TN(dc, dc->op2, c);
-
- cris_prepare_jmp(dc, JMP_INDIRECT);
- return 2;
-}
-
-static int dec_jas_im(CPUCRISState *env, DisasContext *dc)
-{
- uint32_t imm;
- TCGv c;
-
- imm = cris_fetch(env, dc, dc->pc + 2, 4, 0);
-
- LOG_DIS("jas 0x%x\n", imm);
- cris_cc_mask(dc, 0);
- c = tcg_constant_tl(dc->pc + 8);
- /* Store the return address in Pd. */
- t_gen_mov_preg_TN(dc, dc->op2, c);
-
- dc->jmp_pc = imm;
- cris_prepare_jmp(dc, JMP_DIRECT);
- return 6;
-}
-
-static int dec_jasc_im(CPUCRISState *env, DisasContext *dc)
-{
- uint32_t imm;
- TCGv c;
-
- imm = cris_fetch(env, dc, dc->pc + 2, 4, 0);
-
- LOG_DIS("jasc 0x%x\n", imm);
- cris_cc_mask(dc, 0);
- c = tcg_constant_tl(dc->pc + 8 + 4);
- /* Store the return address in Pd. */
- t_gen_mov_preg_TN(dc, dc->op2, c);
-
- dc->jmp_pc = imm;
- cris_prepare_jmp(dc, JMP_DIRECT);
- return 6;
-}
-
-static int dec_jasc_r(CPUCRISState *env, DisasContext *dc)
-{
- TCGv c;
- LOG_DIS("jasc_r $r%u, $p%u\n", dc->op1, dc->op2);
- cris_cc_mask(dc, 0);
- /* Store the return address in Pd. */
- tcg_gen_mov_tl(env_btarget, cpu_R[dc->op1]);
- c = tcg_constant_tl(dc->pc + 4 + 4);
- t_gen_mov_preg_TN(dc, dc->op2, c);
- cris_prepare_jmp(dc, JMP_INDIRECT);
- return 2;
-}
-
-static int dec_bcc_im(CPUCRISState *env, DisasContext *dc)
-{
- int32_t offset;
- uint32_t cond = dc->op2;
-
- offset = cris_fetch(env, dc, dc->pc + 2, 2, 1);
-
- LOG_DIS("b%s %d pc=%x dst=%x\n",
- cc_name(cond), offset,
- dc->pc, dc->pc + offset);
-
- cris_cc_mask(dc, 0);
- /* op2 holds the condition-code. */
- cris_prepare_cc_branch(dc, offset, cond);
- return 4;
-}
-
-static int dec_bas_im(CPUCRISState *env, DisasContext *dc)
-{
- int32_t simm;
- TCGv c;
-
- simm = cris_fetch(env, dc, dc->pc + 2, 4, 0);
-
- LOG_DIS("bas 0x%x, $p%u\n", dc->pc + simm, dc->op2);
- cris_cc_mask(dc, 0);
- c = tcg_constant_tl(dc->pc + 8);
- /* Store the return address in Pd. */
- t_gen_mov_preg_TN(dc, dc->op2, c);
-
- dc->jmp_pc = dc->pc + simm;
- cris_prepare_jmp(dc, JMP_DIRECT);
- return 6;
-}
-
-static int dec_basc_im(CPUCRISState *env, DisasContext *dc)
-{
- int32_t simm;
- TCGv c;
- simm = cris_fetch(env, dc, dc->pc + 2, 4, 0);
-
- LOG_DIS("basc 0x%x, $p%u\n", dc->pc + simm, dc->op2);
- cris_cc_mask(dc, 0);
- c = tcg_constant_tl(dc->pc + 12);
- /* Store the return address in Pd. */
- t_gen_mov_preg_TN(dc, dc->op2, c);
-
- dc->jmp_pc = dc->pc + simm;
- cris_prepare_jmp(dc, JMP_DIRECT);
- return 6;
-}
-
-static int dec_rfe_etc(CPUCRISState *env, DisasContext *dc)
-{
- cris_cc_mask(dc, 0);
-
- if (dc->op2 == 15) {
- tcg_gen_st_i32(tcg_constant_i32(1), tcg_env,
- -offsetof(CRISCPU, env) + offsetof(CPUState, halted));
- tcg_gen_movi_tl(env_pc, dc->pc + 2);
- t_gen_raise_exception(EXCP_HLT);
- dc->base.is_jmp = DISAS_NORETURN;
- return 2;
- }
-
- switch (dc->op2 & 7) {
- case 2:
- /* rfe. */
- LOG_DIS("rfe\n");
- cris_evaluate_flags(dc);
- gen_helper_rfe(tcg_env);
- dc->base.is_jmp = DISAS_UPDATE;
- dc->cpustate_changed = true;
- break;
- case 5:
- /* rfn. */
- LOG_DIS("rfn\n");
- cris_evaluate_flags(dc);
- gen_helper_rfn(tcg_env);
- dc->base.is_jmp = DISAS_UPDATE;
- dc->cpustate_changed = true;
- break;
- case 6:
- LOG_DIS("break %d\n", dc->op1);
- cris_evaluate_flags(dc);
- /* break. */
- tcg_gen_movi_tl(env_pc, dc->pc + 2);
-
- /* Breaks start at 16 in the exception vector. */
- t_gen_movi_env_TN(trap_vector, dc->op1 + 16);
- t_gen_raise_exception(EXCP_BREAK);
- dc->base.is_jmp = DISAS_NORETURN;
- break;
- default:
- printf("op2=%x\n", dc->op2);
- BUG();
- break;
-
- }
- return 2;
-}
-
-static int dec_ftag_fidx_d_m(CPUCRISState *env, DisasContext *dc)
-{
- return 2;
-}
-
-static int dec_ftag_fidx_i_m(CPUCRISState *env, DisasContext *dc)
-{
- return 2;
-}
-
-static int dec_null(CPUCRISState *env, DisasContext *dc)
-{
- printf("unknown insn pc=%x opc=%x op1=%x op2=%x\n",
- dc->pc, dc->opcode, dc->op1, dc->op2);
- fflush(NULL);
- BUG();
- return 2;
-}
-
-static const struct decoder_info {
- struct {
- uint32_t bits;
- uint32_t mask;
- };
- int (*dec)(CPUCRISState *env, DisasContext *dc);
-} decinfo[] = {
- /* Order matters here. */
- {DEC_MOVEQ, dec_moveq},
- {DEC_BTSTQ, dec_btstq},
- {DEC_CMPQ, dec_cmpq},
- {DEC_ADDOQ, dec_addoq},
- {DEC_ADDQ, dec_addq},
- {DEC_SUBQ, dec_subq},
- {DEC_ANDQ, dec_andq},
- {DEC_ORQ, dec_orq},
- {DEC_ASRQ, dec_asrq},
- {DEC_LSLQ, dec_lslq},
- {DEC_LSRQ, dec_lsrq},
- {DEC_BCCQ, dec_bccq},
-
- {DEC_BCC_IM, dec_bcc_im},
- {DEC_JAS_IM, dec_jas_im},
- {DEC_JAS_R, dec_jas_r},
- {DEC_JASC_IM, dec_jasc_im},
- {DEC_JASC_R, dec_jasc_r},
- {DEC_BAS_IM, dec_bas_im},
- {DEC_BASC_IM, dec_basc_im},
- {DEC_JUMP_P, dec_jump_p},
- {DEC_LAPC_IM, dec_lapc_im},
- {DEC_LAPCQ, dec_lapcq},
-
- {DEC_RFE_ETC, dec_rfe_etc},
- {DEC_ADDC_MR, dec_addc_mr},
-
- {DEC_MOVE_MP, dec_move_mp},
- {DEC_MOVE_PM, dec_move_pm},
- {DEC_MOVEM_MR, dec_movem_mr},
- {DEC_MOVEM_RM, dec_movem_rm},
- {DEC_MOVE_PR, dec_move_pr},
- {DEC_SCC_R, dec_scc_r},
- {DEC_SETF, dec_setclrf},
- {DEC_CLEARF, dec_setclrf},
-
- {DEC_MOVE_SR, dec_move_sr},
- {DEC_MOVE_RP, dec_move_rp},
- {DEC_SWAP_R, dec_swap_r},
- {DEC_ABS_R, dec_abs_r},
- {DEC_LZ_R, dec_lz_r},
- {DEC_MOVE_RS, dec_move_rs},
- {DEC_BTST_R, dec_btst_r},
- {DEC_ADDC_R, dec_addc_r},
-
- {DEC_DSTEP_R, dec_dstep_r},
- {DEC_XOR_R, dec_xor_r},
- {DEC_MCP_R, dec_mcp_r},
- {DEC_CMP_R, dec_cmp_r},
-
- {DEC_ADDI_R, dec_addi_r},
- {DEC_ADDI_ACR, dec_addi_acr},
-
- {DEC_ADD_R, dec_add_r},
- {DEC_SUB_R, dec_sub_r},
-
- {DEC_ADDU_R, dec_addu_r},
- {DEC_ADDS_R, dec_adds_r},
- {DEC_SUBU_R, dec_subu_r},
- {DEC_SUBS_R, dec_subs_r},
- {DEC_LSL_R, dec_lsl_r},
-
- {DEC_AND_R, dec_and_r},
- {DEC_OR_R, dec_or_r},
- {DEC_BOUND_R, dec_bound_r},
- {DEC_ASR_R, dec_asr_r},
- {DEC_LSR_R, dec_lsr_r},
-
- {DEC_MOVU_R, dec_movu_r},
- {DEC_MOVS_R, dec_movs_r},
- {DEC_NEG_R, dec_neg_r},
- {DEC_MOVE_R, dec_move_r},
-
- {DEC_FTAG_FIDX_I_M, dec_ftag_fidx_i_m},
- {DEC_FTAG_FIDX_D_M, dec_ftag_fidx_d_m},
-
- {DEC_MULS_R, dec_muls_r},
- {DEC_MULU_R, dec_mulu_r},
-
- {DEC_ADDU_M, dec_addu_m},
- {DEC_ADDS_M, dec_adds_m},
- {DEC_SUBU_M, dec_subu_m},
- {DEC_SUBS_M, dec_subs_m},
-
- {DEC_CMPU_M, dec_cmpu_m},
- {DEC_CMPS_M, dec_cmps_m},
- {DEC_MOVU_M, dec_movu_m},
- {DEC_MOVS_M, dec_movs_m},
-
- {DEC_CMP_M, dec_cmp_m},
- {DEC_ADDO_M, dec_addo_m},
- {DEC_BOUND_M, dec_bound_m},
- {DEC_ADD_M, dec_add_m},
- {DEC_SUB_M, dec_sub_m},
- {DEC_AND_M, dec_and_m},
- {DEC_OR_M, dec_or_m},
- {DEC_MOVE_RM, dec_move_rm},
- {DEC_TEST_M, dec_test_m},
- {DEC_MOVE_MR, dec_move_mr},
-
- {{0, 0}, dec_null}
-};
-
-static unsigned int crisv32_decoder(CPUCRISState *env, DisasContext *dc)
-{
- int insn_len = 2;
- int i;
-
- /* Load a halfword onto the instruction register. */
- dc->ir = cris_fetch(env, dc, dc->pc, 2, 0);
-
- /* Now decode it. */
- dc->opcode = EXTRACT_FIELD(dc->ir, 4, 11);
- dc->op1 = EXTRACT_FIELD(dc->ir, 0, 3);
- dc->op2 = EXTRACT_FIELD(dc->ir, 12, 15);
- dc->zsize = EXTRACT_FIELD(dc->ir, 4, 4);
- dc->zzsize = EXTRACT_FIELD(dc->ir, 4, 5);
- dc->postinc = EXTRACT_FIELD(dc->ir, 10, 10);
-
- /* Large switch for all insns. */
- for (i = 0; i < ARRAY_SIZE(decinfo); i++) {
- if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) {
- insn_len = decinfo[i].dec(env, dc);
- break;
- }
- }
-
-#if !defined(CONFIG_USER_ONLY)
- /* Single-stepping ? */
- if (dc->tb_flags & S_FLAG) {
- TCGLabel *l1 = gen_new_label();
- tcg_gen_brcondi_tl(TCG_COND_NE, cpu_PR[PR_SPC], dc->pc, l1);
- /* We treat SPC as a break with an odd trap vector. */
- cris_evaluate_flags(dc);
- t_gen_movi_env_TN(trap_vector, 3);
- tcg_gen_movi_tl(env_pc, dc->pc + insn_len);
- tcg_gen_movi_tl(cpu_PR[PR_SPC], dc->pc + insn_len);
- t_gen_raise_exception(EXCP_BREAK);
- gen_set_label(l1);
- }
-#endif
- return insn_len;
-}
-
-#include "translate_v10.c.inc"
-
-/*
- * Delay slots on QEMU/CRIS.
- *
- * If an exception hits on a delayslot, the core will let ERP (the Exception
- * Return Pointer) point to the branch (the previous) insn and set the lsb to
- * to give SW a hint that the exception actually hit on the dslot.
- *
- * CRIS expects all PC addresses to be 16-bit aligned. The lsb is ignored by
- * the core and any jmp to an odd addresses will mask off that lsb. It is
- * simply there to let sw know there was an exception on a dslot.
- *
- * When the software returns from an exception, the branch will re-execute.
- * On QEMU care needs to be taken when a branch+delayslot sequence is broken
- * and the branch and delayslot don't share pages.
- *
- * The TB containing the branch insn will set up env->btarget and evaluate
- * env->btaken. When the translation loop exits we will note that the branch
- * sequence is broken and let env->dslot be the size of the branch insn (those
- * vary in length).
- *
- * The TB containing the delayslot will have the PC of its real insn (i.e no lsb
- * set). It will also expect to have env->dslot setup with the size of the
- * delay slot so that env->pc - env->dslot point to the branch insn. This TB
- * will execute the dslot and take the branch, either to btarget or just one
- * insn ahead.
- *
- * When exceptions occur, we check for env->dslot in do_interrupt to detect
- * broken branch sequences and setup $erp accordingly (i.e let it point to the
- * branch and set lsb). Then env->dslot gets cleared so that the exception
- * handler can enter. When returning from exceptions (jump $erp) the lsb gets
- * masked off and we will reexecute the branch insn.
- *
- */
-
-static void cris_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
-{
- DisasContext *dc = container_of(dcbase, DisasContext, base);
- CPUCRISState *env = cpu_env(cs);
- uint32_t tb_flags = dc->base.tb->flags;
- uint32_t pc_start;
-
- if (env->pregs[PR_VR] == 32) {
- dc->decoder = crisv32_decoder;
- dc->clear_locked_irq = 0;
- } else {
- dc->decoder = crisv10_decoder;
- dc->clear_locked_irq = 1;
- }
-
- /*
- * Odd PC indicates that branch is rexecuting due to exception in the
- * delayslot, like in real hw.
- */
- pc_start = dc->base.pc_first & ~1;
- dc->base.pc_first = pc_start;
- dc->base.pc_next = pc_start;
-
- dc->cpu = env_archcpu(env);
- dc->ppc = pc_start;
- dc->pc = pc_start;
- dc->mem_index = cpu_mmu_index(cs, false);
- dc->flags_uptodate = 1;
- dc->flags_x = tb_flags & X_FLAG;
- dc->cc_x_uptodate = 0;
- dc->cc_mask = 0;
- dc->update_cc = 0;
- dc->clear_prefix = 0;
- dc->cpustate_changed = 0;
-
- cris_update_cc_op(dc, CC_OP_FLAGS, 4);
- dc->cc_size_uptodate = -1;
-
- /* Decode TB flags. */
- dc->tb_flags = tb_flags & (S_FLAG | P_FLAG | U_FLAG | X_FLAG | PFIX_FLAG);
- dc->delayed_branch = !!(tb_flags & 7);
- if (dc->delayed_branch) {
- dc->jmp = JMP_INDIRECT;
- } else {
- dc->jmp = JMP_NOJMP;
- }
-}
-
-static void cris_tr_tb_start(DisasContextBase *db, CPUState *cpu)
-{
-}
-
-static void cris_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
-{
- DisasContext *dc = container_of(dcbase, DisasContext, base);
-
- tcg_gen_insn_start(dc->delayed_branch == 1 ? dc->ppc | 1 : dc->pc);
-}
-
-static void cris_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
-{
- DisasContext *dc = container_of(dcbase, DisasContext, base);
- unsigned int insn_len;
-
- /* Pretty disas. */
- LOG_DIS("%8.8x:\t", dc->pc);
-
- dc->clear_x = 1;
-
- insn_len = dc->decoder(cpu_env(cs), dc);
- dc->ppc = dc->pc;
- dc->pc += insn_len;
- dc->base.pc_next += insn_len;
-
- if (dc->base.is_jmp == DISAS_NORETURN) {
- return;
- }
-
- if (dc->clear_x) {
- cris_clear_x_flag(dc);
- }
-
- /*
- * All branches are delayed branches, handled immediately below.
- * We don't expect to see odd combinations of exit conditions.
- */
- assert(dc->base.is_jmp == DISAS_NEXT || dc->cpustate_changed);
-
- if (dc->delayed_branch && --dc->delayed_branch == 0) {
- dc->base.is_jmp = DISAS_DBRANCH;
- return;
- }
-
- if (dc->base.is_jmp != DISAS_NEXT) {
- return;
- }
-
- /* Force an update if the per-tb cpu state has changed. */
- if (dc->cpustate_changed) {
- dc->base.is_jmp = DISAS_UPDATE_NEXT;
- return;
- }
-
- /*
- * FIXME: Only the first insn in the TB should cross a page boundary.
- * If we can detect the length of the next insn easily, we should.
- * In the meantime, simply stop when we do cross.
- */
- if ((dc->pc ^ dc->base.pc_first) & TARGET_PAGE_MASK) {
- dc->base.is_jmp = DISAS_TOO_MANY;
- }
-}
-
-static void cris_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
-{
- DisasContext *dc = container_of(dcbase, DisasContext, base);
- DisasJumpType is_jmp = dc->base.is_jmp;
- target_ulong npc = dc->pc;
-
- if (is_jmp == DISAS_NORETURN) {
- /* If we have a broken branch+delayslot sequence, it's too late. */
- assert(dc->delayed_branch != 1);
- return;
- }
-
- if (dc->clear_locked_irq) {
- t_gen_movi_env_TN(locked_irq, 0);
- }
-
- /* Broken branch+delayslot sequence. */
- if (dc->delayed_branch == 1) {
- /* Set env->dslot to the size of the branch insn. */
- t_gen_movi_env_TN(dslot, dc->pc - dc->ppc);
- cris_store_direct_jmp(dc);
- }
-
- cris_evaluate_flags(dc);
-
- /* Evaluate delayed branch destination and fold to another is_jmp case. */
- if (is_jmp == DISAS_DBRANCH) {
- if (dc->base.tb->flags & 7) {
- t_gen_movi_env_TN(dslot, 0);
- }
-
- switch (dc->jmp) {
- case JMP_DIRECT:
- npc = dc->jmp_pc;
- is_jmp = dc->cpustate_changed ? DISAS_UPDATE_NEXT : DISAS_TOO_MANY;
- break;
-
- case JMP_DIRECT_CC:
- /*
- * Use a conditional branch if either taken or not-taken path
- * can use goto_tb. If neither can, then treat it as indirect.
- */
- if (likely(!dc->cpustate_changed)
- && (use_goto_tb(dc, dc->jmp_pc) || use_goto_tb(dc, npc))) {
- TCGLabel *not_taken = gen_new_label();
-
- tcg_gen_brcondi_tl(TCG_COND_EQ, env_btaken, 0, not_taken);
- gen_goto_tb(dc, 1, dc->jmp_pc);
- gen_set_label(not_taken);
-
- /* not-taken case handled below. */
- is_jmp = DISAS_TOO_MANY;
- break;
- }
- tcg_gen_movi_tl(env_btarget, dc->jmp_pc);
- /* fall through */
-
- case JMP_INDIRECT:
- tcg_gen_movcond_tl(TCG_COND_NE, env_pc,
- env_btaken, tcg_constant_tl(0),
- env_btarget, tcg_constant_tl(npc));
- is_jmp = dc->cpustate_changed ? DISAS_UPDATE : DISAS_JUMP;
-
- /*
- * We have now consumed btaken and btarget. Hint to the
- * tcg compiler that the writeback to env may be dropped.
- */
- tcg_gen_discard_tl(env_btaken);
- tcg_gen_discard_tl(env_btarget);
- break;
-
- default:
- g_assert_not_reached();
- }
- }
-
- switch (is_jmp) {
- case DISAS_TOO_MANY:
- gen_goto_tb(dc, 0, npc);
- break;
- case DISAS_UPDATE_NEXT:
- tcg_gen_movi_tl(env_pc, npc);
- /* fall through */
- case DISAS_JUMP:
- tcg_gen_lookup_and_goto_ptr();
- break;
- case DISAS_UPDATE:
- /* Indicate that interrupts must be re-evaluated before the next TB. */
- tcg_gen_exit_tb(NULL, 0);
- break;
- default:
- g_assert_not_reached();
- }
-}
-
-static const TranslatorOps cris_tr_ops = {
- .init_disas_context = cris_tr_init_disas_context,
- .tb_start = cris_tr_tb_start,
- .insn_start = cris_tr_insn_start,
- .translate_insn = cris_tr_translate_insn,
- .tb_stop = cris_tr_tb_stop,
-};
-
-void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
- vaddr pc, void *host_pc)
-{
- DisasContext dc;
- translator_loop(cs, tb, max_insns, pc, host_pc, &cris_tr_ops, &dc.base);
-}
-
-void cris_cpu_dump_state(CPUState *cs, FILE *f, int flags)
-{
- CPUCRISState *env = cpu_env(cs);
- const char * const *regnames;
- const char * const *pregnames;
- int i;
-
- if (!env) {
- return;
- }
- if (env->pregs[PR_VR] < 32) {
- pregnames = pregnames_v10;
- regnames = regnames_v10;
- } else {
- pregnames = pregnames_v32;
- regnames = regnames_v32;
- }
-
- qemu_fprintf(f, "PC=%x CCS=%x btaken=%d btarget=%x\n"
- "cc_op=%d cc_src=%d cc_dest=%d cc_result=%x cc_mask=%x\n",
- env->pc, env->pregs[PR_CCS], env->btaken, env->btarget,
- env->cc_op,
- env->cc_src, env->cc_dest, env->cc_result, env->cc_mask);
-
-
- for (i = 0; i < 16; i++) {
- qemu_fprintf(f, "%s=%8.8x ", regnames[i], env->regs[i]);
- if ((i + 1) % 4 == 0) {
- qemu_fprintf(f, "\n");
- }
- }
- qemu_fprintf(f, "\nspecial regs:\n");
- for (i = 0; i < 16; i++) {
- qemu_fprintf(f, "%s=%8.8x ", pregnames[i], env->pregs[i]);
- if ((i + 1) % 4 == 0) {
- qemu_fprintf(f, "\n");
- }
- }
- if (env->pregs[PR_VR] >= 32) {
- uint32_t srs = env->pregs[PR_SRS];
- qemu_fprintf(f, "\nsupport function regs bank %x:\n", srs);
- if (srs < ARRAY_SIZE(env->sregs)) {
- for (i = 0; i < 16; i++) {
- qemu_fprintf(f, "s%2.2d=%8.8x ",
- i, env->sregs[srs][i]);
- if ((i + 1) % 4 == 0) {
- qemu_fprintf(f, "\n");
- }
- }
- }
- }
- qemu_fprintf(f, "\n\n");
-
-}
-
-void cris_initialize_tcg(void)
-{
- int i;
-
- cc_x = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, cc_x), "cc_x");
- cc_src = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, cc_src), "cc_src");
- cc_dest = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, cc_dest),
- "cc_dest");
- cc_result = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, cc_result),
- "cc_result");
- cc_op = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, cc_op), "cc_op");
- cc_size = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, cc_size),
- "cc_size");
- cc_mask = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, cc_mask),
- "cc_mask");
-
- env_pc = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, pc),
- "pc");
- env_btarget = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, btarget),
- "btarget");
- env_btaken = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, btaken),
- "btaken");
- for (i = 0; i < 16; i++) {
- cpu_R[i] = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, regs[i]),
- regnames_v32[i]);
- }
- for (i = 0; i < 16; i++) {
- cpu_PR[i] = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, pregs[i]),
- pregnames_v32[i]);
- }
-}
diff --git a/target/cris/translate_v10.c.inc b/target/cris/translate_v10.c.inc
deleted file mode 100644
index c15ff47..0000000
--- a/target/cris/translate_v10.c.inc
+++ /dev/null
@@ -1,1262 +0,0 @@
-/*
- * CRISv10 emulation for qemu: main translation routines.
- *
- * Copyright (c) 2010 AXIS Communications AB
- * Written by Edgar E. Iglesias.
- *
- * 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 "crisv10-decode.h"
-
-static const char * const regnames_v10[] =
-{
- "$r0", "$r1", "$r2", "$r3",
- "$r4", "$r5", "$r6", "$r7",
- "$r8", "$r9", "$r10", "$r11",
- "$r12", "$r13", "$sp", "$pc",
-};
-
-static const char * const pregnames_v10[] =
-{
- "$bz", "$vr", "$p2", "$p3",
- "$wz", "$ccr", "$p6-prefix", "$mof",
- "$dz", "$ibr", "$irp", "$srp",
- "$bar", "$dccr", "$brp", "$usp",
-};
-
-/* We need this table to handle preg-moves with implicit width. */
-static const int preg_sizes_v10[] = {
- 1, /* bz. */
- 1, /* vr. */
- 1, /* pid. */
- 1, /* srs. */
- 2, /* wz. */
- 2, 2, 4,
- 4, 4, 4, 4,
- 4, 4, 4, 4,
-};
-
-static inline int dec10_size(unsigned int size)
-{
- size++;
- if (size == 3)
- size++;
- return size;
-}
-
-static inline void cris_illegal_insn(DisasContext *dc)
-{
- qemu_log_mask(LOG_GUEST_ERROR, "illegal insn at pc=%x\n", dc->pc);
- t_gen_raise_exception(EXCP_BREAK);
- dc->base.is_jmp = DISAS_NORETURN;
-}
-
-static void gen_store_v10_conditional(DisasContext *dc, TCGv addr, TCGv val,
- unsigned int size, int mem_index)
-{
- TCGLabel *l1 = gen_new_label();
- TCGv taddr = tcg_temp_new();
- TCGv tval = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- dc->postinc = 0;
- cris_evaluate_flags(dc);
-
- tcg_gen_mov_tl(taddr, addr);
- tcg_gen_mov_tl(tval, val);
-
- /* Store only if F flag isn't set */
- tcg_gen_andi_tl(t1, cpu_PR[PR_CCS], F_FLAG_V10);
- tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
-
- tcg_gen_qemu_st_tl(tval, taddr, mem_index, ctz32(size) | MO_TE);
-
- gen_set_label(l1);
- tcg_gen_shri_tl(t1, t1, 1); /* shift F to P position */
- tcg_gen_or_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], t1); /*P=F*/
-}
-
-static void gen_store_v10(DisasContext *dc, TCGv addr, TCGv val,
- unsigned int size)
-{
- /* If we get a fault on a delayslot we must keep the jmp state in
- the cpu-state to be able to re-execute the jmp. */
- if (dc->delayed_branch == 1) {
- cris_store_direct_jmp(dc);
- }
-
- /* Conditional writes. */
- if (dc->flags_x) {
- gen_store_v10_conditional(dc, addr, val, size, dc->mem_index);
- return;
- }
-
- tcg_gen_qemu_st_tl(val, addr, dc->mem_index, ctz32(size) | MO_TE);
-}
-
-
-/* Prefix flag and register are used to handle the more complex
- addressing modes. */
-static void cris_set_prefix(DisasContext *dc)
-{
- dc->clear_prefix = 0;
- dc->tb_flags |= PFIX_FLAG;
- tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], PFIX_FLAG);
-
- /* prefix insns don't clear the x flag. */
- dc->clear_x = 0;
- cris_lock_irq(dc);
-}
-
-static void crisv10_prepare_memaddr(DisasContext *dc,
- TCGv addr, unsigned int size)
-{
- if (dc->tb_flags & PFIX_FLAG) {
- tcg_gen_mov_tl(addr, cpu_PR[PR_PREFIX]);
- } else {
- tcg_gen_mov_tl(addr, cpu_R[dc->src]);
- }
-}
-
-static unsigned int crisv10_post_memaddr(DisasContext *dc, unsigned int size)
-{
- unsigned int insn_len = 0;
-
- if (dc->tb_flags & PFIX_FLAG) {
- if (dc->mode == CRISV10_MODE_AUTOINC) {
- tcg_gen_mov_tl(cpu_R[dc->src], cpu_PR[PR_PREFIX]);
- }
- } else {
- if (dc->mode == CRISV10_MODE_AUTOINC) {
- if (dc->src == 15) {
- insn_len += size & ~1;
- } else {
- tcg_gen_addi_tl(cpu_R[dc->src], cpu_R[dc->src], size);
- }
- }
- }
- return insn_len;
-}
-
-static int dec10_prep_move_m(CPUCRISState *env, DisasContext *dc,
- int s_ext, int memsize, TCGv dst)
-{
- unsigned int rs;
- uint32_t imm;
- int is_imm;
- int insn_len = 0;
-
- rs = dc->src;
- is_imm = rs == 15 && !(dc->tb_flags & PFIX_FLAG);
- LOG_DIS("rs=%d rd=%d is_imm=%d mode=%d pfix=%d\n",
- rs, dc->dst, is_imm, dc->mode, dc->tb_flags & PFIX_FLAG);
-
- /* Load [$rs] onto T1. */
- if (is_imm) {
- imm = cris_fetch(env, dc, dc->pc + 2, memsize, s_ext);
-
- tcg_gen_movi_tl(dst, imm);
-
- if (dc->mode == CRISV10_MODE_AUTOINC) {
- insn_len += memsize;
- if (memsize == 1)
- insn_len++;
- tcg_gen_addi_tl(cpu_R[15], cpu_R[15], insn_len);
- }
- } else {
- TCGv addr;
-
- addr = tcg_temp_new();
- cris_flush_cc_state(dc);
- crisv10_prepare_memaddr(dc, addr, memsize);
- gen_load(dc, dst, addr, memsize, 0);
- if (s_ext)
- t_gen_sext(dst, dst, memsize);
- else
- t_gen_zext(dst, dst, memsize);
- insn_len += crisv10_post_memaddr(dc, memsize);
- }
-
- if (dc->mode == CRISV10_MODE_INDIRECT && (dc->tb_flags & PFIX_FLAG)) {
- dc->dst = dc->src;
- }
- return insn_len;
-}
-
-static unsigned int dec10_quick_imm(DisasContext *dc)
-{
- int32_t imm, simm;
- int op;
- TCGv c;
-
- /* sign extend. */
- imm = dc->ir & ((1 << 6) - 1);
- simm = (int8_t) (imm << 2);
- simm >>= 2;
- switch (dc->opcode) {
- case CRISV10_QIMM_BDAP_R0:
- case CRISV10_QIMM_BDAP_R1:
- case CRISV10_QIMM_BDAP_R2:
- case CRISV10_QIMM_BDAP_R3:
- simm = (int8_t)dc->ir;
- LOG_DIS("bdap %d $r%d\n", simm, dc->dst);
- LOG_DIS("pc=%x mode=%x quickimm %d r%d r%d\n",
- dc->pc, dc->mode, dc->opcode, dc->src, dc->dst);
- cris_set_prefix(dc);
- if (dc->dst == 15) {
- tcg_gen_movi_tl(cpu_PR[PR_PREFIX], dc->pc + 2 + simm);
- } else {
- tcg_gen_addi_tl(cpu_PR[PR_PREFIX], cpu_R[dc->dst], simm);
- }
- break;
-
- case CRISV10_QIMM_MOVEQ:
- LOG_DIS("moveq %d, $r%d\n", simm, dc->dst);
-
- cris_cc_mask(dc, CC_MASK_NZVC);
- c = tcg_constant_tl(simm);
- cris_alu(dc, CC_OP_MOVE, cpu_R[dc->dst],
- cpu_R[dc->dst], c, 4);
- break;
- case CRISV10_QIMM_CMPQ:
- LOG_DIS("cmpq %d, $r%d\n", simm, dc->dst);
-
- cris_cc_mask(dc, CC_MASK_NZVC);
- c = tcg_constant_tl(simm);
- cris_alu(dc, CC_OP_CMP, cpu_R[dc->dst],
- cpu_R[dc->dst], c, 4);
- break;
- case CRISV10_QIMM_ADDQ:
- LOG_DIS("addq %d, $r%d\n", imm, dc->dst);
-
- cris_cc_mask(dc, CC_MASK_NZVC);
- c = tcg_constant_tl(imm);
- cris_alu(dc, CC_OP_ADD, cpu_R[dc->dst],
- cpu_R[dc->dst], c, 4);
- break;
- case CRISV10_QIMM_ANDQ:
- LOG_DIS("andq %d, $r%d\n", simm, dc->dst);
-
- cris_cc_mask(dc, CC_MASK_NZVC);
- c = tcg_constant_tl(simm);
- cris_alu(dc, CC_OP_AND, cpu_R[dc->dst],
- cpu_R[dc->dst], c, 4);
- break;
- case CRISV10_QIMM_ASHQ:
- LOG_DIS("ashq %d, $r%d\n", simm, dc->dst);
-
- cris_cc_mask(dc, CC_MASK_NZVC);
- op = imm & (1 << 5);
- imm &= 0x1f;
- c = tcg_constant_tl(imm);
- if (op) {
- cris_alu(dc, CC_OP_ASR, cpu_R[dc->dst],
- cpu_R[dc->dst], c, 4);
- } else {
- /* BTST */
- cris_update_cc_op(dc, CC_OP_FLAGS, 4);
- gen_helper_btst(cpu_PR[PR_CCS], tcg_env, cpu_R[dc->dst],
- c, cpu_PR[PR_CCS]);
- }
- break;
- case CRISV10_QIMM_LSHQ:
- LOG_DIS("lshq %d, $r%d\n", simm, dc->dst);
-
- op = CC_OP_LSL;
- if (imm & (1 << 5)) {
- op = CC_OP_LSR;
- }
- imm &= 0x1f;
- cris_cc_mask(dc, CC_MASK_NZVC);
- c = tcg_constant_tl(imm);
- cris_alu(dc, op, cpu_R[dc->dst],
- cpu_R[dc->dst], c, 4);
- break;
- case CRISV10_QIMM_SUBQ:
- LOG_DIS("subq %d, $r%d\n", imm, dc->dst);
-
- cris_cc_mask(dc, CC_MASK_NZVC);
- c = tcg_constant_tl(imm);
- cris_alu(dc, CC_OP_SUB, cpu_R[dc->dst],
- cpu_R[dc->dst], c, 4);
- break;
- case CRISV10_QIMM_ORQ:
- LOG_DIS("andq %d, $r%d\n", simm, dc->dst);
-
- cris_cc_mask(dc, CC_MASK_NZVC);
- c = tcg_constant_tl(simm);
- cris_alu(dc, CC_OP_OR, cpu_R[dc->dst],
- cpu_R[dc->dst], c, 4);
- break;
-
- case CRISV10_QIMM_BCC_R0:
- case CRISV10_QIMM_BCC_R1:
- case CRISV10_QIMM_BCC_R2:
- case CRISV10_QIMM_BCC_R3:
- imm = dc->ir & 0xff;
- /* bit 0 is a sign bit. */
- if (imm & 1) {
- imm |= 0xffffff00; /* sign extend. */
- imm &= ~1; /* get rid of the sign bit. */
- }
- imm += 2;
- LOG_DIS("b%s %d\n", cc_name(dc->cond), imm);
-
- cris_cc_mask(dc, 0);
- cris_prepare_cc_branch(dc, imm, dc->cond);
- break;
-
- default:
- LOG_DIS("pc=%x mode=%x quickimm %d r%d r%d\n",
- dc->pc, dc->mode, dc->opcode, dc->src, dc->dst);
- cpu_abort(CPU(dc->cpu), "Unhandled quickimm\n");
- break;
- }
- return 2;
-}
-
-static unsigned int dec10_setclrf(DisasContext *dc)
-{
- uint32_t flags;
- unsigned int set = ~dc->opcode & 1;
-
- flags = EXTRACT_FIELD(dc->ir, 0, 3)
- | (EXTRACT_FIELD(dc->ir, 12, 15) << 4);
- LOG_DIS("%s set=%d flags=%x\n", __func__, set, flags);
-
-
- if (flags & X_FLAG) {
- if (set)
- dc->flags_x = X_FLAG;
- else
- dc->flags_x = 0;
- }
-
- cris_evaluate_flags (dc);
- cris_update_cc_op(dc, CC_OP_FLAGS, 4);
- cris_update_cc_x(dc);
- tcg_gen_movi_tl(cc_op, dc->cc_op);
-
- if (set) {
- tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], flags);
- } else {
- tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS],
- ~(flags|F_FLAG_V10|P_FLAG_V10));
- }
-
- dc->flags_uptodate = 1;
- dc->clear_x = 0;
- cris_lock_irq(dc);
- return 2;
-}
-
-static inline void dec10_reg_prep_sext(DisasContext *dc, int size, int sext,
- TCGv dd, TCGv ds, TCGv sd, TCGv ss)
-{
- if (sext) {
- t_gen_sext(dd, sd, size);
- t_gen_sext(ds, ss, size);
- } else {
- t_gen_zext(dd, sd, size);
- t_gen_zext(ds, ss, size);
- }
-}
-
-static void dec10_reg_alu(DisasContext *dc, int op, int size, int sext)
-{
- TCGv t[2];
-
- t[0] = tcg_temp_new();
- t[1] = tcg_temp_new();
- dec10_reg_prep_sext(dc, size, sext,
- t[0], t[1], cpu_R[dc->dst], cpu_R[dc->src]);
-
- if (op == CC_OP_LSL || op == CC_OP_LSR || op == CC_OP_ASR) {
- tcg_gen_andi_tl(t[1], t[1], 63);
- }
-
- assert(dc->dst != 15);
- cris_alu(dc, op, cpu_R[dc->dst], t[0], t[1], size);
-}
-
-static void dec10_reg_bound(DisasContext *dc, int size)
-{
- TCGv t;
-
- t = tcg_temp_new();
- t_gen_zext(t, cpu_R[dc->src], size);
- cris_alu(dc, CC_OP_BOUND, cpu_R[dc->dst], cpu_R[dc->dst], t, 4);
-}
-
-static void dec10_reg_mul(DisasContext *dc, int size, int sext)
-{
- int op = sext ? CC_OP_MULS : CC_OP_MULU;
- TCGv t[2];
-
- t[0] = tcg_temp_new();
- t[1] = tcg_temp_new();
- dec10_reg_prep_sext(dc, size, sext,
- t[0], t[1], cpu_R[dc->dst], cpu_R[dc->src]);
-
- cris_alu(dc, op, cpu_R[dc->dst], t[0], t[1], 4);
-}
-
-
-static void dec10_reg_movs(DisasContext *dc)
-{
- int size = (dc->size & 1) + 1;
- TCGv t;
-
- LOG_DIS("movx.%d $r%d, $r%d\n", size, dc->src, dc->dst);
- cris_cc_mask(dc, CC_MASK_NZVC);
-
- t = tcg_temp_new();
- if (dc->ir & 32)
- t_gen_sext(t, cpu_R[dc->src], size);
- else
- t_gen_zext(t, cpu_R[dc->src], size);
-
- cris_alu(dc, CC_OP_MOVE, cpu_R[dc->dst], cpu_R[dc->dst], t, 4);
-}
-
-static void dec10_reg_alux(DisasContext *dc, int op)
-{
- int size = (dc->size & 1) + 1;
- TCGv t;
-
- LOG_DIS("movx.%d $r%d, $r%d\n", size, dc->src, dc->dst);
- cris_cc_mask(dc, CC_MASK_NZVC);
-
- t = tcg_temp_new();
- if (dc->ir & 32)
- t_gen_sext(t, cpu_R[dc->src], size);
- else
- t_gen_zext(t, cpu_R[dc->src], size);
-
- cris_alu(dc, op, cpu_R[dc->dst], cpu_R[dc->dst], t, 4);
-}
-
-static void dec10_reg_mov_pr(DisasContext *dc)
-{
- LOG_DIS("move p%d r%d sz=%d\n", dc->dst, dc->src, preg_sizes_v10[dc->dst]);
- cris_lock_irq(dc);
- if (dc->src == 15) {
- tcg_gen_mov_tl(env_btarget, cpu_PR[dc->dst]);
- cris_prepare_jmp(dc, JMP_INDIRECT);
- return;
- }
- if (dc->dst == PR_CCS) {
- cris_evaluate_flags(dc);
- }
- cris_alu(dc, CC_OP_MOVE, cpu_R[dc->src],
- cpu_R[dc->src], cpu_PR[dc->dst], preg_sizes_v10[dc->dst]);
-}
-
-static void dec10_reg_abs(DisasContext *dc)
-{
- TCGv t0;
-
- LOG_DIS("abs $r%u, $r%u\n", dc->src, dc->dst);
-
- assert(dc->dst != 15);
- t0 = tcg_temp_new();
- tcg_gen_sari_tl(t0, cpu_R[dc->src], 31);
- tcg_gen_xor_tl(cpu_R[dc->dst], cpu_R[dc->src], t0);
- tcg_gen_sub_tl(t0, cpu_R[dc->dst], t0);
-
- cris_alu(dc, CC_OP_MOVE, cpu_R[dc->dst], cpu_R[dc->dst], t0, 4);
-}
-
-static void dec10_reg_swap(DisasContext *dc)
-{
- TCGv t0;
-
- LOG_DIS("not $r%d, $r%d\n", dc->src, dc->dst);
-
- cris_cc_mask(dc, CC_MASK_NZVC);
- t0 = tcg_temp_new();
- tcg_gen_mov_tl(t0, cpu_R[dc->src]);
- if (dc->dst & 8)
- tcg_gen_not_tl(t0, t0);
- if (dc->dst & 4)
- t_gen_swapw(t0, t0);
- if (dc->dst & 2)
- t_gen_swapb(t0, t0);
- if (dc->dst & 1)
- t_gen_swapr(t0, t0);
- cris_alu(dc, CC_OP_MOVE, cpu_R[dc->src], cpu_R[dc->src], t0, 4);
-}
-
-static void dec10_reg_scc(DisasContext *dc)
-{
- int cond = dc->dst;
-
- LOG_DIS("s%s $r%u\n", cc_name(cond), dc->src);
-
- gen_tst_cc(dc, cpu_R[dc->src], cond);
- tcg_gen_setcondi_tl(TCG_COND_NE, cpu_R[dc->src], cpu_R[dc->src], 0);
-
- cris_cc_mask(dc, 0);
-}
-
-static unsigned int dec10_reg(DisasContext *dc)
-{
- TCGv t;
- unsigned int insn_len = 2;
- unsigned int size = dec10_size(dc->size);
- unsigned int tmp;
-
- if (dc->size != 3) {
- switch (dc->opcode) {
- case CRISV10_REG_MOVE_R:
- LOG_DIS("move.%d $r%d, $r%d\n", dc->size, dc->src, dc->dst);
- cris_cc_mask(dc, CC_MASK_NZVC);
- dec10_reg_alu(dc, CC_OP_MOVE, size, 0);
- if (dc->dst == 15) {
- tcg_gen_mov_tl(env_btarget, cpu_R[dc->dst]);
- cris_prepare_jmp(dc, JMP_INDIRECT);
- dc->delayed_branch = 1;
- }
- break;
- case CRISV10_REG_MOVX:
- cris_cc_mask(dc, CC_MASK_NZVC);
- dec10_reg_movs(dc);
- break;
- case CRISV10_REG_ADDX:
- cris_cc_mask(dc, CC_MASK_NZVC);
- dec10_reg_alux(dc, CC_OP_ADD);
- break;
- case CRISV10_REG_SUBX:
- cris_cc_mask(dc, CC_MASK_NZVC);
- dec10_reg_alux(dc, CC_OP_SUB);
- break;
- case CRISV10_REG_ADD:
- LOG_DIS("add $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
- cris_cc_mask(dc, CC_MASK_NZVC);
- dec10_reg_alu(dc, CC_OP_ADD, size, 0);
- break;
- case CRISV10_REG_SUB:
- LOG_DIS("sub $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
- cris_cc_mask(dc, CC_MASK_NZVC);
- dec10_reg_alu(dc, CC_OP_SUB, size, 0);
- break;
- case CRISV10_REG_CMP:
- LOG_DIS("cmp $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
- cris_cc_mask(dc, CC_MASK_NZVC);
- dec10_reg_alu(dc, CC_OP_CMP, size, 0);
- break;
- case CRISV10_REG_BOUND:
- LOG_DIS("bound $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
- cris_cc_mask(dc, CC_MASK_NZVC);
- dec10_reg_bound(dc, size);
- break;
- case CRISV10_REG_AND:
- LOG_DIS("and $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
- cris_cc_mask(dc, CC_MASK_NZVC);
- dec10_reg_alu(dc, CC_OP_AND, size, 0);
- break;
- case CRISV10_REG_ADDI:
- if (dc->src == 15) {
- /* nop. */
- return 2;
- }
- t = tcg_temp_new();
- LOG_DIS("addi r%d r%d size=%d\n", dc->src, dc->dst, dc->size);
- tcg_gen_shli_tl(t, cpu_R[dc->dst], dc->size & 3);
- tcg_gen_add_tl(cpu_R[dc->src], cpu_R[dc->src], t);
- break;
- case CRISV10_REG_LSL:
- LOG_DIS("lsl $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
- cris_cc_mask(dc, CC_MASK_NZVC);
- dec10_reg_alu(dc, CC_OP_LSL, size, 0);
- break;
- case CRISV10_REG_LSR:
- LOG_DIS("lsr $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
- cris_cc_mask(dc, CC_MASK_NZVC);
- dec10_reg_alu(dc, CC_OP_LSR, size, 0);
- break;
- case CRISV10_REG_ASR:
- LOG_DIS("asr $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
- cris_cc_mask(dc, CC_MASK_NZVC);
- dec10_reg_alu(dc, CC_OP_ASR, size, 1);
- break;
- case CRISV10_REG_OR:
- LOG_DIS("or $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
- cris_cc_mask(dc, CC_MASK_NZVC);
- dec10_reg_alu(dc, CC_OP_OR, size, 0);
- break;
- case CRISV10_REG_NEG:
- LOG_DIS("neg $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
- cris_cc_mask(dc, CC_MASK_NZVC);
- dec10_reg_alu(dc, CC_OP_NEG, size, 0);
- break;
- case CRISV10_REG_BIAP:
- LOG_DIS("BIAP pc=%x reg %d r%d r%d size=%d\n", dc->pc,
- dc->opcode, dc->src, dc->dst, size);
- switch (size) {
- case 4: tmp = 2; break;
- case 2: tmp = 1; break;
- case 1: tmp = 0; break;
- default:
- cpu_abort(CPU(dc->cpu), "Unhandled BIAP");
- break;
- }
-
- t = tcg_temp_new();
- tcg_gen_shli_tl(t, cpu_R[dc->dst], tmp);
- if (dc->src == 15) {
- tcg_gen_addi_tl(cpu_PR[PR_PREFIX], t, ((dc->pc +2)| 1) + 1);
- } else {
- tcg_gen_add_tl(cpu_PR[PR_PREFIX], cpu_R[dc->src], t);
- }
- cris_set_prefix(dc);
- break;
-
- default:
- LOG_DIS("pc=%x reg %d r%d r%d\n", dc->pc,
- dc->opcode, dc->src, dc->dst);
- cpu_abort(CPU(dc->cpu), "Unhandled opcode");
- break;
- }
- } else {
- switch (dc->opcode) {
- case CRISV10_REG_MOVX:
- cris_cc_mask(dc, CC_MASK_NZVC);
- dec10_reg_movs(dc);
- break;
- case CRISV10_REG_ADDX:
- cris_cc_mask(dc, CC_MASK_NZVC);
- dec10_reg_alux(dc, CC_OP_ADD);
- break;
- case CRISV10_REG_SUBX:
- cris_cc_mask(dc, CC_MASK_NZVC);
- dec10_reg_alux(dc, CC_OP_SUB);
- break;
- case CRISV10_REG_MOVE_SPR_R:
- cris_evaluate_flags(dc);
- cris_cc_mask(dc, 0);
- dec10_reg_mov_pr(dc);
- break;
- case CRISV10_REG_MOVE_R_SPR:
- LOG_DIS("move r%d p%d\n", dc->src, dc->dst);
- cris_evaluate_flags(dc);
- if (dc->src != 11) /* fast for srp. */
- dc->cpustate_changed = 1;
- t_gen_mov_preg_TN(dc, dc->dst, cpu_R[dc->src]);
- break;
- case CRISV10_REG_SETF:
- case CRISV10_REG_CLEARF:
- dec10_setclrf(dc);
- break;
- case CRISV10_REG_SWAP:
- dec10_reg_swap(dc);
- break;
- case CRISV10_REG_ABS:
- cris_cc_mask(dc, CC_MASK_NZVC);
- dec10_reg_abs(dc);
- break;
- case CRISV10_REG_LZ:
- LOG_DIS("lz $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
- cris_cc_mask(dc, CC_MASK_NZVC);
- dec10_reg_alu(dc, CC_OP_LZ, 4, 0);
- break;
- case CRISV10_REG_XOR:
- LOG_DIS("xor $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
- cris_cc_mask(dc, CC_MASK_NZVC);
- dec10_reg_alu(dc, CC_OP_XOR, 4, 0);
- break;
- case CRISV10_REG_BTST:
- LOG_DIS("btst $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
- cris_cc_mask(dc, CC_MASK_NZVC);
- cris_update_cc_op(dc, CC_OP_FLAGS, 4);
- gen_helper_btst(cpu_PR[PR_CCS], tcg_env, cpu_R[dc->dst],
- cpu_R[dc->src], cpu_PR[PR_CCS]);
- break;
- case CRISV10_REG_DSTEP:
- LOG_DIS("dstep $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
- cris_cc_mask(dc, CC_MASK_NZVC);
- cris_alu(dc, CC_OP_DSTEP, cpu_R[dc->dst],
- cpu_R[dc->dst], cpu_R[dc->src], 4);
- break;
- case CRISV10_REG_MSTEP:
- LOG_DIS("mstep $r%d, $r%d sz=%d\n", dc->src, dc->dst, size);
- cris_evaluate_flags(dc);
- cris_cc_mask(dc, CC_MASK_NZVC);
- cris_alu(dc, CC_OP_MSTEP, cpu_R[dc->dst],
- cpu_R[dc->dst], cpu_R[dc->src], 4);
- break;
- case CRISV10_REG_SCC:
- dec10_reg_scc(dc);
- break;
- default:
- LOG_DIS("pc=%x reg %d r%d r%d\n", dc->pc,
- dc->opcode, dc->src, dc->dst);
- cpu_abort(CPU(dc->cpu), "Unhandled opcode");
- break;
- }
- }
- return insn_len;
-}
-
-static unsigned int dec10_ind_move_m_r(CPUCRISState *env, DisasContext *dc,
- unsigned int size)
-{
- unsigned int insn_len = 2;
- TCGv t;
-
- LOG_DIS("%s: move.%d [$r%d], $r%d\n", __func__,
- size, dc->src, dc->dst);
-
- cris_cc_mask(dc, CC_MASK_NZVC);
- t = tcg_temp_new();
- insn_len += dec10_prep_move_m(env, dc, 0, size, t);
- cris_alu(dc, CC_OP_MOVE, cpu_R[dc->dst], cpu_R[dc->dst], t, size);
- if (dc->dst == 15) {
- tcg_gen_mov_tl(env_btarget, cpu_R[dc->dst]);
- cris_prepare_jmp(dc, JMP_INDIRECT);
- dc->delayed_branch = 1;
- }
-
- return insn_len;
-}
-
-static unsigned int dec10_ind_move_r_m(DisasContext *dc, unsigned int size)
-{
- unsigned int insn_len = 2;
- TCGv addr;
-
- LOG_DIS("move.%d $r%d, [$r%d]\n", dc->size, dc->src, dc->dst);
- addr = tcg_temp_new();
- crisv10_prepare_memaddr(dc, addr, size);
- gen_store_v10(dc, addr, cpu_R[dc->dst], size);
- insn_len += crisv10_post_memaddr(dc, size);
-
- return insn_len;
-}
-
-static unsigned int dec10_ind_move_m_pr(CPUCRISState *env, DisasContext *dc)
-{
- unsigned int insn_len = 2, rd = dc->dst;
- TCGv t;
-
- LOG_DIS("move.%d $p%d, [$r%d]\n", dc->size, dc->dst, dc->src);
- cris_lock_irq(dc);
-
- t = tcg_temp_new();
- insn_len += dec10_prep_move_m(env, dc, 0, 4, t);
- if (rd == 15) {
- tcg_gen_mov_tl(env_btarget, t);
- cris_prepare_jmp(dc, JMP_INDIRECT);
- dc->delayed_branch = 1;
- } else {
- tcg_gen_mov_tl(cpu_PR[rd], t);
- dc->cpustate_changed = 1;
- }
- return insn_len;
-}
-
-static unsigned int dec10_ind_move_pr_m(DisasContext *dc)
-{
- unsigned int insn_len = 2, size = preg_sizes_v10[dc->dst];
- TCGv addr, t0;
-
- LOG_DIS("move.%d $p%d, [$r%d]\n", dc->size, dc->dst, dc->src);
-
- addr = tcg_temp_new();
- crisv10_prepare_memaddr(dc, addr, size);
- if (dc->dst == PR_CCS) {
- t0 = tcg_temp_new();
- cris_evaluate_flags(dc);
- tcg_gen_andi_tl(t0, cpu_PR[PR_CCS], ~PFIX_FLAG);
- gen_store_v10(dc, addr, t0, size);
- } else {
- gen_store_v10(dc, addr, cpu_PR[dc->dst], size);
- }
- insn_len += crisv10_post_memaddr(dc, size);
- cris_lock_irq(dc);
-
- return insn_len;
-}
-
-static void dec10_movem_r_m(DisasContext *dc)
-{
- int i, pfix = dc->tb_flags & PFIX_FLAG;
- TCGv addr, t0;
-
- LOG_DIS("%s r%d, [r%d] pi=%d ir=%x\n", __func__,
- dc->dst, dc->src, dc->postinc, dc->ir);
-
- addr = tcg_temp_new();
- t0 = tcg_temp_new();
- crisv10_prepare_memaddr(dc, addr, 4);
- tcg_gen_mov_tl(t0, addr);
- for (i = dc->dst; i >= 0; i--) {
- if ((pfix && dc->mode == CRISV10_MODE_AUTOINC) && dc->src == i) {
- gen_store_v10(dc, addr, t0, 4);
- } else {
- gen_store_v10(dc, addr, cpu_R[i], 4);
- }
- tcg_gen_addi_tl(addr, addr, 4);
- }
-
- if (pfix && dc->mode == CRISV10_MODE_AUTOINC) {
- tcg_gen_mov_tl(cpu_R[dc->src], t0);
- }
-
- if (!pfix && dc->mode == CRISV10_MODE_AUTOINC) {
- tcg_gen_mov_tl(cpu_R[dc->src], addr);
- }
-}
-
-static void dec10_movem_m_r(DisasContext *dc)
-{
- int i, pfix = dc->tb_flags & PFIX_FLAG;
- TCGv addr, t0;
-
- LOG_DIS("%s [r%d], r%d pi=%d ir=%x\n", __func__,
- dc->src, dc->dst, dc->postinc, dc->ir);
-
- addr = tcg_temp_new();
- t0 = tcg_temp_new();
- crisv10_prepare_memaddr(dc, addr, 4);
- tcg_gen_mov_tl(t0, addr);
- for (i = dc->dst; i >= 0; i--) {
- gen_load(dc, cpu_R[i], addr, 4, 0);
- tcg_gen_addi_tl(addr, addr, 4);
- }
-
- if (pfix && dc->mode == CRISV10_MODE_AUTOINC) {
- tcg_gen_mov_tl(cpu_R[dc->src], t0);
- }
-
- if (!pfix && dc->mode == CRISV10_MODE_AUTOINC) {
- tcg_gen_mov_tl(cpu_R[dc->src], addr);
- }
-}
-
-static int dec10_ind_alu(CPUCRISState *env, DisasContext *dc,
- int op, unsigned int size)
-{
- int insn_len = 0;
- int rd = dc->dst;
- TCGv t[2];
-
- cris_alu_m_alloc_temps(t);
- insn_len += dec10_prep_move_m(env, dc, 0, size, t[0]);
- cris_alu(dc, op, cpu_R[dc->dst], cpu_R[rd], t[0], size);
- if (dc->dst == 15) {
- tcg_gen_mov_tl(env_btarget, cpu_R[dc->dst]);
- cris_prepare_jmp(dc, JMP_INDIRECT);
- dc->delayed_branch = 1;
- return insn_len;
- }
- return insn_len;
-}
-
-static int dec10_ind_bound(CPUCRISState *env, DisasContext *dc,
- unsigned int size)
-{
- int insn_len = 0;
- int rd = dc->dst;
- TCGv t;
-
- t = tcg_temp_new();
- insn_len += dec10_prep_move_m(env, dc, 0, size, t);
- cris_alu(dc, CC_OP_BOUND, cpu_R[dc->dst], cpu_R[rd], t, 4);
- if (dc->dst == 15) {
- tcg_gen_mov_tl(env_btarget, cpu_R[dc->dst]);
- cris_prepare_jmp(dc, JMP_INDIRECT);
- dc->delayed_branch = 1;
- }
-
- return insn_len;
-}
-
-static int dec10_alux_m(CPUCRISState *env, DisasContext *dc, int op)
-{
- unsigned int size = (dc->size & 1) ? 2 : 1;
- unsigned int sx = !!(dc->size & 2);
- int insn_len = 2;
- int rd = dc->dst;
- TCGv t;
-
- LOG_DIS("addx size=%d sx=%d op=%d %d\n", size, sx, dc->src, dc->dst);
-
- t = tcg_temp_new();
-
- cris_cc_mask(dc, CC_MASK_NZVC);
- insn_len += dec10_prep_move_m(env, dc, sx, size, t);
- cris_alu(dc, op, cpu_R[dc->dst], cpu_R[rd], t, 4);
- if (dc->dst == 15) {
- tcg_gen_mov_tl(env_btarget, cpu_R[dc->dst]);
- cris_prepare_jmp(dc, JMP_INDIRECT);
- dc->delayed_branch = 1;
- }
-
- return insn_len;
-}
-
-static int dec10_dip(CPUCRISState *env, DisasContext *dc)
-{
- int insn_len = 2;
- uint32_t imm;
-
- LOG_DIS("dip pc=%x opcode=%d r%d r%d\n",
- dc->pc, dc->opcode, dc->src, dc->dst);
- if (dc->src == 15) {
- imm = cris_fetch(env, dc, dc->pc + 2, 4, 0);
- tcg_gen_movi_tl(cpu_PR[PR_PREFIX], imm);
- if (dc->postinc) {
- insn_len += 4;
- }
- tcg_gen_addi_tl(cpu_R[15], cpu_R[15], insn_len - 2);
- } else {
- gen_load(dc, cpu_PR[PR_PREFIX], cpu_R[dc->src], 4, 0);
- if (dc->postinc)
- tcg_gen_addi_tl(cpu_R[dc->src], cpu_R[dc->src], 4);
- }
-
- cris_set_prefix(dc);
- return insn_len;
-}
-
-static int dec10_bdap_m(CPUCRISState *env, DisasContext *dc, int size)
-{
- int insn_len = 2;
- int rd = dc->dst;
-
- LOG_DIS("bdap_m pc=%x opcode=%d r%d r%d sz=%d\n",
- dc->pc, dc->opcode, dc->src, dc->dst, size);
-
- assert(dc->dst != 15);
-#if 0
- /* 8bit embedded offset? */
- if (!dc->postinc && (dc->ir & (1 << 11))) {
- int simm = dc->ir & 0xff;
-
- /* cpu_abort(CPU(dc->cpu), "Unhandled opcode"); */
- /* sign extended. */
- simm = (int8_t)simm;
-
- tcg_gen_addi_tl(cpu_PR[PR_PREFIX], cpu_R[dc->dst], simm);
-
- cris_set_prefix(dc);
- return insn_len;
- }
-#endif
- /* Now the rest of the modes are truly indirect. */
- insn_len += dec10_prep_move_m(env, dc, 1, size, cpu_PR[PR_PREFIX]);
- tcg_gen_add_tl(cpu_PR[PR_PREFIX], cpu_PR[PR_PREFIX], cpu_R[rd]);
- cris_set_prefix(dc);
- return insn_len;
-}
-
-static unsigned int dec10_ind(CPUCRISState *env, DisasContext *dc)
-{
- unsigned int insn_len = 2;
- unsigned int size = dec10_size(dc->size);
- uint32_t imm;
- int32_t simm;
- TCGv t[2], c;
-
- if (dc->size != 3) {
- switch (dc->opcode) {
- case CRISV10_IND_MOVE_M_R:
- return dec10_ind_move_m_r(env, dc, size);
- case CRISV10_IND_MOVE_R_M:
- return dec10_ind_move_r_m(dc, size);
- case CRISV10_IND_CMP:
- LOG_DIS("cmp size=%d op=%d %d\n", size, dc->src, dc->dst);
- cris_cc_mask(dc, CC_MASK_NZVC);
- insn_len += dec10_ind_alu(env, dc, CC_OP_CMP, size);
- break;
- case CRISV10_IND_TEST:
- LOG_DIS("test size=%d op=%d %d\n", size, dc->src, dc->dst);
-
- cris_evaluate_flags(dc);
- cris_cc_mask(dc, CC_MASK_NZVC);
- cris_alu_m_alloc_temps(t);
- insn_len += dec10_prep_move_m(env, dc, 0, size, t[0]);
- tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~3);
- c = tcg_constant_tl(0);
- cris_alu(dc, CC_OP_CMP, cpu_R[dc->dst],
- t[0], c, size);
- break;
- case CRISV10_IND_ADD:
- LOG_DIS("add size=%d op=%d %d\n", size, dc->src, dc->dst);
- cris_cc_mask(dc, CC_MASK_NZVC);
- insn_len += dec10_ind_alu(env, dc, CC_OP_ADD, size);
- break;
- case CRISV10_IND_SUB:
- LOG_DIS("sub size=%d op=%d %d\n", size, dc->src, dc->dst);
- cris_cc_mask(dc, CC_MASK_NZVC);
- insn_len += dec10_ind_alu(env, dc, CC_OP_SUB, size);
- break;
- case CRISV10_IND_BOUND:
- LOG_DIS("bound size=%d op=%d %d\n", size, dc->src, dc->dst);
- cris_cc_mask(dc, CC_MASK_NZVC);
- insn_len += dec10_ind_bound(env, dc, size);
- break;
- case CRISV10_IND_AND:
- LOG_DIS("and size=%d op=%d %d\n", size, dc->src, dc->dst);
- cris_cc_mask(dc, CC_MASK_NZVC);
- insn_len += dec10_ind_alu(env, dc, CC_OP_AND, size);
- break;
- case CRISV10_IND_OR:
- LOG_DIS("or size=%d op=%d %d\n", size, dc->src, dc->dst);
- cris_cc_mask(dc, CC_MASK_NZVC);
- insn_len += dec10_ind_alu(env, dc, CC_OP_OR, size);
- break;
- case CRISV10_IND_MOVX:
- insn_len = dec10_alux_m(env, dc, CC_OP_MOVE);
- break;
- case CRISV10_IND_ADDX:
- insn_len = dec10_alux_m(env, dc, CC_OP_ADD);
- break;
- case CRISV10_IND_SUBX:
- insn_len = dec10_alux_m(env, dc, CC_OP_SUB);
- break;
- case CRISV10_IND_CMPX:
- insn_len = dec10_alux_m(env, dc, CC_OP_CMP);
- break;
- case CRISV10_IND_MUL:
- /* This is a reg insn coded in the mem indir space. */
- LOG_DIS("mul pc=%x opcode=%d\n", dc->pc, dc->opcode);
- cris_cc_mask(dc, CC_MASK_NZVC);
- dec10_reg_mul(dc, size, dc->ir & (1 << 10));
- break;
- case CRISV10_IND_BDAP_M:
- insn_len = dec10_bdap_m(env, dc, size);
- break;
- default:
- /*
- * ADDC for v17:
- *
- * Instruction format: ADDC [Rs],Rd
- *
- * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+-+
- * |Destination(Rd)| 1 0 0 1 1 0 1 0 | Source(Rs)|
- * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+--+--+
- *
- * Instruction format: ADDC [Rs+],Rd
- *
- * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+-+
- * |Destination(Rd)| 1 1 0 1 1 0 1 0 | Source(Rs)|
- * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+-+
- */
- if (dc->opcode == CRISV17_IND_ADDC && dc->size == 2 &&
- env->pregs[PR_VR] == 17) {
- LOG_DIS("addc op=%d %d\n", dc->src, dc->dst);
- cris_cc_mask(dc, CC_MASK_NZVC);
- insn_len += dec10_ind_alu(env, dc, CC_OP_ADDC, size);
- break;
- }
-
- LOG_DIS("pc=%x var-ind.%d %d r%d r%d\n",
- dc->pc, size, dc->opcode, dc->src, dc->dst);
- cpu_abort(CPU(dc->cpu), "Unhandled opcode");
- break;
- }
- return insn_len;
- }
-
- switch (dc->opcode) {
- case CRISV10_IND_MOVE_M_SPR:
- insn_len = dec10_ind_move_m_pr(env, dc);
- break;
- case CRISV10_IND_MOVE_SPR_M:
- insn_len = dec10_ind_move_pr_m(dc);
- break;
- case CRISV10_IND_JUMP_M:
- if (dc->src == 15) {
- LOG_DIS("jump.%d %d r%d r%d direct\n", size,
- dc->opcode, dc->src, dc->dst);
- imm = cris_fetch(env, dc, dc->pc + 2, size, 0);
- if (dc->mode == CRISV10_MODE_AUTOINC) {
- insn_len += size;
- }
- c = tcg_constant_tl(dc->pc + insn_len);
- t_gen_mov_preg_TN(dc, dc->dst, c);
- dc->jmp_pc = imm;
- cris_prepare_jmp(dc, JMP_DIRECT);
- dc->delayed_branch--; /* v10 has no dslot here. */
- } else {
- if (dc->dst == 14) {
- LOG_DIS("break %d\n", dc->src);
- cris_evaluate_flags(dc);
- tcg_gen_movi_tl(env_pc, dc->pc + 2);
- c = tcg_constant_tl(dc->src + 2);
- t_gen_mov_env_TN(trap_vector, c);
- t_gen_raise_exception(EXCP_BREAK);
- dc->base.is_jmp = DISAS_NORETURN;
- return insn_len;
- }
- LOG_DIS("%d: jump.%d %d r%d r%d\n", __LINE__, size,
- dc->opcode, dc->src, dc->dst);
- t[0] = tcg_temp_new();
- c = tcg_constant_tl(dc->pc + insn_len);
- t_gen_mov_preg_TN(dc, dc->dst, c);
- crisv10_prepare_memaddr(dc, t[0], size);
- gen_load(dc, env_btarget, t[0], 4, 0);
- insn_len += crisv10_post_memaddr(dc, size);
- cris_prepare_jmp(dc, JMP_INDIRECT);
- dc->delayed_branch--; /* v10 has no dslot here. */
- }
- break;
-
- case CRISV10_IND_MOVEM_R_M:
- LOG_DIS("movem_r_m pc=%x opcode=%d r%d r%d\n",
- dc->pc, dc->opcode, dc->dst, dc->src);
- dec10_movem_r_m(dc);
- break;
- case CRISV10_IND_MOVEM_M_R:
- LOG_DIS("movem_m_r pc=%x opcode=%d\n", dc->pc, dc->opcode);
- dec10_movem_m_r(dc);
- break;
- case CRISV10_IND_JUMP_R:
- LOG_DIS("jmp pc=%x opcode=%d r%d r%d\n",
- dc->pc, dc->opcode, dc->dst, dc->src);
- tcg_gen_mov_tl(env_btarget, cpu_R[dc->src]);
- c = tcg_constant_tl(dc->pc + insn_len);
- t_gen_mov_preg_TN(dc, dc->dst, c);
- cris_prepare_jmp(dc, JMP_INDIRECT);
- dc->delayed_branch--; /* v10 has no dslot here. */
- break;
- case CRISV10_IND_MOVX:
- insn_len = dec10_alux_m(env, dc, CC_OP_MOVE);
- break;
- case CRISV10_IND_ADDX:
- insn_len = dec10_alux_m(env, dc, CC_OP_ADD);
- break;
- case CRISV10_IND_SUBX:
- insn_len = dec10_alux_m(env, dc, CC_OP_SUB);
- break;
- case CRISV10_IND_CMPX:
- insn_len = dec10_alux_m(env, dc, CC_OP_CMP);
- break;
- case CRISV10_IND_DIP:
- insn_len = dec10_dip(env, dc);
- break;
- case CRISV10_IND_BCC_M:
-
- cris_cc_mask(dc, 0);
- simm = cris_fetch(env, dc, dc->pc + 2, 2, 1);
- simm += 4;
-
- LOG_DIS("bcc_m: b%s %x\n", cc_name(dc->cond), dc->pc + simm);
- cris_prepare_cc_branch(dc, simm, dc->cond);
- insn_len = 4;
- break;
- default:
- LOG_DIS("ERROR pc=%x opcode=%d\n", dc->pc, dc->opcode);
- cpu_abort(CPU(dc->cpu), "Unhandled opcode");
- break;
- }
-
- return insn_len;
-}
-
-static unsigned int crisv10_decoder(CPUCRISState *env, DisasContext *dc)
-{
- unsigned int insn_len = 2;
-
- /* Load a halfword onto the instruction register. */
- dc->ir = cris_fetch(env, dc, dc->pc, 2, 0);
-
- /* Now decode it. */
- dc->opcode = EXTRACT_FIELD(dc->ir, 6, 9);
- dc->mode = EXTRACT_FIELD(dc->ir, 10, 11);
- dc->src = EXTRACT_FIELD(dc->ir, 0, 3);
- dc->size = EXTRACT_FIELD(dc->ir, 4, 5);
- dc->cond = dc->dst = EXTRACT_FIELD(dc->ir, 12, 15);
- dc->postinc = EXTRACT_FIELD(dc->ir, 10, 10);
-
- dc->clear_prefix = 1;
-
- /* FIXME: What if this insn insn't 2 in length?? */
- if (dc->src == 15 || dc->dst == 15)
- tcg_gen_movi_tl(cpu_R[15], dc->pc + 2);
-
- switch (dc->mode) {
- case CRISV10_MODE_QIMMEDIATE:
- insn_len = dec10_quick_imm(dc);
- break;
- case CRISV10_MODE_REG:
- insn_len = dec10_reg(dc);
- break;
- case CRISV10_MODE_AUTOINC:
- case CRISV10_MODE_INDIRECT:
- insn_len = dec10_ind(env, dc);
- break;
- }
-
- if (dc->clear_prefix && dc->tb_flags & PFIX_FLAG) {
- dc->tb_flags &= ~PFIX_FLAG;
- tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~PFIX_FLAG);
- if (dc->tb_flags != dc->base.tb->flags) {
- dc->cpustate_changed = 1;
- }
- }
-
- /* CRISv10 locks out interrupts on dslots. */
- if (dc->delayed_branch == 2) {
- cris_lock_irq(dc);
- }
- return insn_len;
-}
-
-void cris_initialize_crisv10_tcg(void)
-{
- int i;
-
- cc_x = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, cc_x), "cc_x");
- cc_src = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, cc_src), "cc_src");
- cc_dest = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, cc_dest),
- "cc_dest");
- cc_result = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, cc_result),
- "cc_result");
- cc_op = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, cc_op), "cc_op");
- cc_size = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, cc_size),
- "cc_size");
- cc_mask = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, cc_mask),
- "cc_mask");
-
- env_pc = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, pc),
- "pc");
- env_btarget = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, btarget),
- "btarget");
- env_btaken = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, btaken),
- "btaken");
- for (i = 0; i < 16; i++) {
- cpu_R[i] = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, regs[i]),
- regnames_v10[i]);
- }
- for (i = 0; i < 16; i++) {
- cpu_PR[i] = tcg_global_mem_new(tcg_env,
- offsetof(CPUCRISState, pregs[i]),
- pregnames_v10[i]);
- }
-}
diff --git a/target/hexagon/cpu-qom.h b/target/hexagon/cpu-qom.h
index da92fe7..0b149bd 100644
--- a/target/hexagon/cpu-qom.h
+++ b/target/hexagon/cpu-qom.h
@@ -16,6 +16,7 @@
#define HEXAGON_CPU_TYPE_SUFFIX "-" TYPE_HEXAGON_CPU
#define HEXAGON_CPU_TYPE_NAME(name) (name HEXAGON_CPU_TYPE_SUFFIX)
+#define TYPE_HEXAGON_CPU_V66 HEXAGON_CPU_TYPE_NAME("v66")
#define TYPE_HEXAGON_CPU_V67 HEXAGON_CPU_TYPE_NAME("v67")
#define TYPE_HEXAGON_CPU_V68 HEXAGON_CPU_TYPE_NAME("v68")
#define TYPE_HEXAGON_CPU_V69 HEXAGON_CPU_TYPE_NAME("v69")
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 64cc05c..020038f 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -26,6 +26,7 @@
#include "tcg/tcg.h"
#include "exec/gdbstub.h"
+static void hexagon_v66_cpu_init(Object *obj) { }
static void hexagon_v67_cpu_init(Object *obj) { }
static void hexagon_v68_cpu_init(Object *obj) { }
static void hexagon_v69_cpu_init(Object *obj) { }
@@ -47,13 +48,13 @@ static ObjectClass *hexagon_cpu_class_by_name(const char *cpu_model)
return oc;
}
-static Property hexagon_lldb_compat_property =
- DEFINE_PROP_BOOL("lldb-compat", HexagonCPU, lldb_compat, false);
-static Property hexagon_lldb_stack_adjust_property =
- DEFINE_PROP_UNSIGNED("lldb-stack-adjust", HexagonCPU, lldb_stack_adjust,
- 0, qdev_prop_uint32, target_ulong);
-static Property hexagon_short_circuit_property =
- DEFINE_PROP_BOOL("short-circuit", HexagonCPU, short_circuit, true);
+static Property hexagon_cpu_properties[] = {
+ DEFINE_PROP_BOOL("lldb-compat", HexagonCPU, lldb_compat, false),
+ DEFINE_PROP_UNSIGNED("lldb-stack-adjust", HexagonCPU, lldb_stack_adjust, 0,
+ qdev_prop_uint32, target_ulong),
+ DEFINE_PROP_BOOL("short-circuit", HexagonCPU, short_circuit, true),
+ DEFINE_PROP_END_OF_LIST()
+};
const char * const hexagon_regnames[TOTAL_PER_THREAD_REGS] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
@@ -316,9 +317,6 @@ static void hexagon_cpu_realize(DeviceState *dev, Error **errp)
static void hexagon_cpu_init(Object *obj)
{
- qdev_property_add_static(DEVICE(obj), &hexagon_lldb_compat_property);
- qdev_property_add_static(DEVICE(obj), &hexagon_lldb_stack_adjust_property);
- qdev_property_add_static(DEVICE(obj), &hexagon_short_circuit_property);
}
#include "hw/core/tcg-cpu-ops.h"
@@ -339,6 +337,7 @@ static void hexagon_cpu_class_init(ObjectClass *c, void *data)
device_class_set_parent_realize(dc, hexagon_cpu_realize,
&mcc->parent_realize);
+ device_class_set_props(dc, hexagon_cpu_properties);
resettable_class_set_parent_phases(rc, NULL, hexagon_cpu_reset_hold, NULL,
&mcc->parent_phases);
@@ -373,6 +372,7 @@ static const TypeInfo hexagon_cpu_type_infos[] = {
.class_size = sizeof(HexagonCPUClass),
.class_init = hexagon_cpu_class_init,
},
+ DEFINE_CPU(TYPE_HEXAGON_CPU_V66, hexagon_v66_cpu_init),
DEFINE_CPU(TYPE_HEXAGON_CPU_V67, hexagon_v67_cpu_init),
DEFINE_CPU(TYPE_HEXAGON_CPU_V68, hexagon_v68_cpu_init),
DEFINE_CPU(TYPE_HEXAGON_CPU_V69, hexagon_v69_cpu_init),
diff --git a/target/hexagon/gdbstub.c b/target/hexagon/gdbstub.c
index 502c698..12d6b3b 100644
--- a/target/hexagon/gdbstub.c
+++ b/target/hexagon/gdbstub.c
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ * Copyright(c) 2019-2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
*
* 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
@@ -36,6 +36,14 @@ int hexagon_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
return gdb_get_regl(mem_buf, env->gpr[n]);
}
+ n -= TOTAL_PER_THREAD_REGS;
+
+ if (n < NUM_PREGS) {
+ return gdb_get_reg8(mem_buf, env->pred[n]);
+ }
+
+ n -= NUM_PREGS;
+
g_assert_not_reached();
}
@@ -44,7 +52,7 @@ int hexagon_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
CPUHexagonState *env = cpu_env(cs);
if (n == HEX_REG_P3_0_ALIASED) {
- uint32_t p3_0 = ldtul_p(mem_buf);
+ uint32_t p3_0 = ldl_le_p(mem_buf);
for (int i = 0; i < NUM_PREGS; i++) {
env->pred[i] = extract32(p3_0, i * 8, 8);
}
@@ -52,10 +60,19 @@ int hexagon_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
}
if (n < TOTAL_PER_THREAD_REGS) {
- env->gpr[n] = ldtul_p(mem_buf);
+ env->gpr[n] = ldl_le_p(mem_buf);
return sizeof(target_ulong);
}
+ n -= TOTAL_PER_THREAD_REGS;
+
+ if (n < NUM_PREGS) {
+ env->pred[n] = ldl_le_p(mem_buf) & 0xff;
+ return sizeof(uint8_t);
+ }
+
+ n -= NUM_PREGS;
+
g_assert_not_reached();
}
@@ -100,7 +117,7 @@ static int gdb_put_vreg(CPUHexagonState *env, uint8_t *mem_buf, int n)
{
int i;
for (i = 0; i < ARRAY_SIZE(env->VRegs[n].uw); i++) {
- env->VRegs[n].uw[i] = ldtul_p(mem_buf);
+ env->VRegs[n].uw[i] = ldl_le_p(mem_buf);
mem_buf += 4;
}
return MAX_VEC_SIZE_BYTES;
@@ -110,7 +127,7 @@ static int gdb_put_qreg(CPUHexagonState *env, uint8_t *mem_buf, int n)
{
int i;
for (i = 0; i < ARRAY_SIZE(env->QRegs[n].uw); i++) {
- env->QRegs[n].uw[i] = ldtul_p(mem_buf);
+ env->QRegs[n].uw[i] = ldl_le_p(mem_buf);
mem_buf += 4;
}
return MAX_VEC_SIZE_BYTES / 8;
diff --git a/target/hexagon/gen_idef_parser_funcs.py b/target/hexagon/gen_idef_parser_funcs.py
index eb494ab..72f11c6 100644
--- a/target/hexagon/gen_idef_parser_funcs.py
+++ b/target/hexagon/gen_idef_parser_funcs.py
@@ -50,7 +50,7 @@ def main():
tagimms = hex_common.get_tagimms()
with open(sys.argv[-1], "w") as f:
- f.write('#include "macros.inc"\n\n')
+ f.write('#include "macros.h.inc"\n\n')
for tag in hex_common.tags:
## Skip the priv instructions
diff --git a/target/hexagon/idef-parser/README.rst b/target/hexagon/idef-parser/README.rst
index d0aa343..7199177 100644
--- a/target/hexagon/idef-parser/README.rst
+++ b/target/hexagon/idef-parser/README.rst
@@ -138,7 +138,7 @@ we obtain the pseudo code
with macros such as ``fJUMPR`` intact.
The second step is to expand macros into a form suitable for our parser.
-These macros are defined in ``idef-parser/macros.inc`` and the step is
+These macros are defined in ``idef-parser/macros.h.inc`` and the step is
carried out by the ``prepare`` script which runs the C preprocessor on
``idef_parser_input.h.inc`` to produce
``idef_parser_input.preprocessed.h.inc``.
@@ -266,7 +266,7 @@ in plain C is defined as
#define fABS(A) (((A) < 0) ? (-(A)) : (A))
and returns the absolute value of the argument ``A``. This macro is not included
-in ``idef-parser/macros.inc`` and as such is not expanded and kept as a "call"
+in ``idef-parser/macros.h.inc`` and as such is not expanded and kept as a "call"
``fABS(...)``. Reason being, that ``fABS`` is easier to match and map to
``tcg_gen_abs_<width>``, compared to the full ternary expression above. Loads of
macros in ``macros.h`` are kept unexpanded to aid in parsing, as seen in the
diff --git a/target/hexagon/idef-parser/idef-parser.y b/target/hexagon/idef-parser/idef-parser.y
index 9ffb9f9..c6f17c6 100644
--- a/target/hexagon/idef-parser/idef-parser.y
+++ b/target/hexagon/idef-parser/idef-parser.y
@@ -800,7 +800,6 @@ rvalue : FAIL
lvalue : FAIL
{
- @1.last_column = @1.last_column;
yyassert(c, &@1, false, "Encountered a FAIL token as lvalue.\n");
}
| REG
diff --git a/target/hexagon/idef-parser/macros.inc b/target/hexagon/idef-parser/macros.h.inc
index 94975d9..94975d9 100644
--- a/target/hexagon/idef-parser/macros.inc
+++ b/target/hexagon/idef-parser/macros.h.inc
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index b0b253a..f172377 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -284,7 +284,7 @@ if idef_parser_enabled and 'hexagon-linux-user' in target_dirs
'idef_parser_input.preprocessed.h.inc',
output: 'idef_parser_input.preprocessed.h.inc',
input: idef_parser_input_generated,
- depend_files: [idef_parser_dir / 'macros.inc'],
+ depend_files: [idef_parser_dir / 'macros.h.inc'],
command: [idef_parser_dir / 'prepare', '@INPUT@', '-I' + idef_parser_dir, '-o', '@OUTPUT@'],
)
@@ -300,7 +300,7 @@ if idef_parser_enabled and 'hexagon-linux-user' in target_dirs
arguments: ['@INPUT@', '--defines=@OUTPUT1@', '--output=@OUTPUT0@']
)
- glib_dep = dependency('glib-2.0', native: true)
+ glib_dep = dependency('glib-2.0', native: true, static: false)
idef_parser = executable(
'idef-parser',
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index ae5a605..90e7aaa 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2019-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ * Copyright(c) 2019-2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
*
* 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
@@ -683,7 +683,7 @@ uint32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV)
uint32_t RdV;
arch_fpop_start(env);
/* Hexagon checks the sign before rounding */
- if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
+ if (float32_is_neg(RsV) && !float32_is_any_nan(RsV) && !float32_is_zero(RsV)) {
float_raise(float_flag_invalid, &env->fp_status);
RdV = 0;
} else {
@@ -713,7 +713,7 @@ uint64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV)
uint64_t RddV;
arch_fpop_start(env);
/* Hexagon checks the sign before rounding */
- if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
+ if (float32_is_neg(RsV) && !float32_is_any_nan(RsV) && !float32_is_zero(RsV)) {
float_raise(float_flag_invalid, &env->fp_status);
RddV = 0;
} else {
@@ -743,7 +743,7 @@ uint32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV)
uint32_t RdV;
arch_fpop_start(env);
/* Hexagon checks the sign before rounding */
- if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
+ if (float64_is_neg(RssV) && !float64_is_any_nan(RssV) && !float64_is_zero(RssV)) {
float_raise(float_flag_invalid, &env->fp_status);
RdV = 0;
} else {
@@ -773,7 +773,7 @@ uint64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV)
uint64_t RddV;
arch_fpop_start(env);
/* Hexagon checks the sign before rounding */
- if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
+ if (float64_is_neg(RssV) && !float64_is_any_nan(RssV) && !float64_is_zero(RssV)) {
float_raise(float_flag_invalid, &env->fp_status);
RddV = 0;
} else {
@@ -803,7 +803,7 @@ uint32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV)
uint32_t RdV;
arch_fpop_start(env);
/* Hexagon checks the sign before rounding */
- if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
+ if (float32_is_neg(RsV) && !float32_is_any_nan(RsV) && !float32_is_zero(RsV)) {
float_raise(float_flag_invalid, &env->fp_status);
RdV = 0;
} else {
@@ -833,7 +833,7 @@ uint64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV)
uint64_t RddV;
arch_fpop_start(env);
/* Hexagon checks the sign before rounding */
- if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
+ if (float32_is_neg(RsV) && !float32_is_any_nan(RsV) && !float32_is_zero(RsV)) {
float_raise(float_flag_invalid, &env->fp_status);
RddV = 0;
} else {
@@ -863,7 +863,7 @@ uint32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV)
uint32_t RdV;
arch_fpop_start(env);
/* Hexagon checks the sign before rounding */
- if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
+ if (float64_is_neg(RssV) && !float64_is_any_nan(RssV) && !float64_is_zero(RssV)) {
float_raise(float_flag_invalid, &env->fp_status);
RdV = 0;
} else {
@@ -893,7 +893,7 @@ uint64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV)
uint64_t RddV;
arch_fpop_start(env);
/* Hexagon checks the sign before rounding */
- if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
+ if (float64_is_neg(RssV) && !float64_is_any_nan(RssV) && !float64_is_zero(RssV)) {
float_raise(float_flag_invalid, &env->fp_status);
RddV = 0;
} else {
diff --git a/target/hppa/cpu-param.h b/target/hppa/cpu-param.h
index 473d489..ef3200f 100644
--- a/target/hppa/cpu-param.h
+++ b/target/hppa/cpu-param.h
@@ -2,7 +2,7 @@
* PA-RISC cpu parameters for qemu.
*
* Copyright (c) 2016 Richard Henderson <rth@twiddle.net>
- * SPDX-License-Identifier: LGPL-2.0+
+ * SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef HPPA_CPU_PARAM_H
diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c
index 7cf2e2f..c38439c 100644
--- a/target/hppa/cpu.c
+++ b/target/hppa/cpu.c
@@ -226,7 +226,7 @@ static const TCGCPUOps hppa_tcg_ops = {
.restore_state_to_opc = hppa_restore_state_to_opc,
#ifndef CONFIG_USER_ONLY
- .tlb_fill = hppa_cpu_tlb_fill,
+ .tlb_fill_align = hppa_cpu_tlb_fill_align,
.cpu_exec_interrupt = hppa_cpu_exec_interrupt,
.cpu_exec_halt = hppa_cpu_has_work,
.do_interrupt = hppa_cpu_do_interrupt,
diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h
index 2bcb3b6..e45ba50 100644
--- a/target/hppa/cpu.h
+++ b/target/hppa/cpu.h
@@ -211,7 +211,7 @@ typedef struct CPUArchState {
uint32_t psw; /* All psw bits except the following: */
uint32_t psw_xb; /* X and B, in their normal positions */
target_ulong psw_n; /* boolean */
- target_long psw_v; /* in most significant bit */
+ target_long psw_v; /* in bit 31 */
/* Splitting the carry-borrow field into the MSB and "the rest", allows
* for "the rest" to be deleted when it is unused, but the MSB is in use.
@@ -281,7 +281,6 @@ struct ArchCPU {
/**
* HPPACPUClass:
* @parent_realize: The parent class' realize handler.
- * @parent_reset: The parent class' reset handler.
*
* An HPPA CPU model.
*/
@@ -289,7 +288,6 @@ struct HPPACPUClass {
CPUClass parent_class;
DeviceRealize parent_realize;
- DeviceReset parent_reset;
};
#include "exec/cpu-all.h"
@@ -319,7 +317,7 @@ static inline target_ulong hppa_form_gva_psw(target_ulong psw, uint64_t spc,
target_ulong off)
{
#ifdef CONFIG_USER_ONLY
- return off;
+ return off & gva_offset_mask(psw);
#else
return spc | (off & gva_offset_mask(psw));
#endif
@@ -365,13 +363,13 @@ void hppa_cpu_dump_state(CPUState *cs, FILE *f, int);
void hppa_ptlbe(CPUHPPAState *env);
hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr);
void hppa_set_ior_and_isr(CPUHPPAState *env, vaddr addr, bool mmu_disabled);
-bool hppa_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
- MMUAccessType access_type, int mmu_idx,
- bool probe, uintptr_t retaddr);
+bool hppa_cpu_tlb_fill_align(CPUState *cs, CPUTLBEntryFull *out, vaddr addr,
+ MMUAccessType access_type, int mmu_idx,
+ MemOp memop, int size, bool probe, uintptr_t ra);
void hppa_cpu_do_interrupt(CPUState *cpu);
bool hppa_cpu_exec_interrupt(CPUState *cpu, int int_req);
int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
- int type, hwaddr *pphys, int *pprot);
+ int type, MemOp mop, hwaddr *pphys, int *pprot);
void hppa_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
vaddr addr, unsigned size,
MMUAccessType access_type,
diff --git a/target/hppa/helper.c b/target/hppa/helper.c
index b79ddd8..d4b1a3c 100644
--- a/target/hppa/helper.c
+++ b/target/hppa/helper.c
@@ -53,7 +53,7 @@ target_ulong cpu_hppa_get_psw(CPUHPPAState *env)
}
psw |= env->psw_n * PSW_N;
- psw |= (env->psw_v < 0) * PSW_V;
+ psw |= ((env->psw_v >> 31) & 1) * PSW_V;
psw |= env->psw | env->psw_xb;
return psw;
diff --git a/target/hppa/int_helper.c b/target/hppa/int_helper.c
index 391f32f..58695de 100644
--- a/target/hppa/int_helper.c
+++ b/target/hppa/int_helper.c
@@ -167,7 +167,7 @@ void hppa_cpu_do_interrupt(CPUState *cs)
vaddr = hppa_form_gva_psw(old_psw, env->iasq_f, vaddr);
t = hppa_get_physical_address(env, vaddr, MMU_KERNEL_IDX,
- 0, &paddr, &prot);
+ 0, 0, &paddr, &prot);
if (t >= 0) {
/* We can't re-load the instruction. */
env->cr[CR_IIR] = 0;
diff --git a/target/hppa/mem_helper.c b/target/hppa/mem_helper.c
index b984f73..b8c3e55 100644
--- a/target/hppa/mem_helper.c
+++ b/target/hppa/mem_helper.c
@@ -197,7 +197,7 @@ static int match_prot_id64(CPUHPPAState *env, uint32_t access_id)
}
int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
- int type, hwaddr *pphys, int *pprot)
+ int type, MemOp mop, hwaddr *pphys, int *pprot)
{
hwaddr phys;
int prot, r_prot, w_prot, x_prot, priv;
@@ -221,7 +221,7 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
g_assert_not_reached();
}
prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
- goto egress;
+ goto egress_align;
}
/* Find a valid tlb entry that matches the virtual address. */
@@ -267,6 +267,12 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
goto egress;
}
+ if (unlikely(!(prot & type))) {
+ /* Not allowed -- Inst/Data Memory Access Rights Fault. */
+ ret = (type & PAGE_EXEC) ? EXCP_IMP : EXCP_DMAR;
+ goto egress;
+ }
+
/* access_id == 0 means public page and no check is performed */
if (ent->access_id && MMU_IDX_TO_P(mmu_idx)) {
int access_prot = (hppa_is_pa20(env)
@@ -281,14 +287,8 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
prot &= access_prot;
}
- if (unlikely(!(prot & type))) {
- /* Not allowed -- Inst/Data Memory Access Rights Fault. */
- ret = (type & PAGE_EXEC) ? EXCP_IMP : EXCP_DMAR;
- goto egress;
- }
-
/*
- * In priority order, check for conditions which raise faults.
+ * In reverse priority order, check for conditions which raise faults.
* Remove PROT bits that cover the condition we want to check,
* so that the resulting PROT will force a re-check of the
* architectural TLB entry for the next access.
@@ -299,13 +299,15 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
/* The T bit is set -- Page Reference Fault. */
ret = EXCP_PAGE_REF;
}
- } else if (!ent->d) {
+ }
+ if (unlikely(!ent->d)) {
prot &= PAGE_READ | PAGE_EXEC;
if (type & PAGE_WRITE) {
/* The D bit is not set -- TLB Dirty Bit Fault. */
ret = EXCP_TLB_DIRTY;
}
- } else if (unlikely(ent->b)) {
+ }
+ if (unlikely(ent->b)) {
prot &= PAGE_READ | PAGE_EXEC;
if (type & PAGE_WRITE) {
/*
@@ -321,6 +323,11 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
}
}
+ egress_align:
+ if (addr & ((1u << memop_alignment_bits(mop)) - 1)) {
+ ret = EXCP_UNALIGN;
+ }
+
egress:
*pphys = phys;
*pprot = prot;
@@ -340,7 +347,7 @@ hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
mmu_idx = (cpu->env.psw & PSW_D ? MMU_KERNEL_IDX :
cpu->env.psw & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX);
- excp = hppa_get_physical_address(&cpu->env, addr, mmu_idx, 0,
+ excp = hppa_get_physical_address(&cpu->env, addr, mmu_idx, 0, 0,
&phys, &prot);
/* Since we're translating for debugging, the only error that is a
@@ -417,12 +424,11 @@ void hppa_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
}
}
-bool hppa_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
- MMUAccessType type, int mmu_idx,
- bool probe, uintptr_t retaddr)
+bool hppa_cpu_tlb_fill_align(CPUState *cs, CPUTLBEntryFull *out, vaddr addr,
+ MMUAccessType type, int mmu_idx,
+ MemOp memop, int size, bool probe, uintptr_t ra)
{
- HPPACPU *cpu = HPPA_CPU(cs);
- CPUHPPAState *env = &cpu->env;
+ CPUHPPAState *env = cpu_env(cs);
int prot, excp, a_prot;
hwaddr phys;
@@ -438,7 +444,8 @@ bool hppa_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
break;
}
- excp = hppa_get_physical_address(env, addr, mmu_idx, a_prot, &phys, &prot);
+ excp = hppa_get_physical_address(env, addr, mmu_idx, a_prot, memop,
+ &phys, &prot);
if (unlikely(excp >= 0)) {
if (probe) {
return false;
@@ -446,7 +453,7 @@ bool hppa_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
trace_hppa_tlb_fill_excp(env, addr, size, type, mmu_idx);
/* Failure. Raise the indicated exception. */
- raise_exception_with_ior(env, excp, retaddr, addr,
+ raise_exception_with_ior(env, excp, ra, addr,
MMU_IDX_MMU_DISABLED(mmu_idx));
}
@@ -460,8 +467,12 @@ bool hppa_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
* the large page protection mask. We do not require this,
* because we record the large page here in the hppa tlb.
*/
- tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
- prot, mmu_idx, TARGET_PAGE_SIZE);
+ memset(out, 0, sizeof(*out));
+ out->phys_addr = phys;
+ out->prot = prot;
+ out->attrs = MEMTXATTRS_UNSPECIFIED;
+ out->lg_page_size = TARGET_PAGE_BITS;
+
return true;
}
@@ -678,7 +689,7 @@ target_ulong HELPER(lpa)(CPUHPPAState *env, target_ulong addr)
hwaddr phys;
int prot, excp;
- excp = hppa_get_physical_address(env, addr, MMU_KERNEL_IDX, 0,
+ excp = hppa_get_physical_address(env, addr, MMU_KERNEL_IDX, 0, 0,
&phys, &prot);
if (excp >= 0) {
if (excp == EXCP_DTLB_MISS) {
diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c
index 7f79196..7443259 100644
--- a/target/hppa/op_helper.c
+++ b/target/hppa/op_helper.c
@@ -334,7 +334,7 @@ target_ulong HELPER(probe)(CPUHPPAState *env, target_ulong addr,
}
mmu_idx = PRIV_P_TO_MMU_IDX(level, env->psw & PSW_P);
- excp = hppa_get_physical_address(env, addr, mmu_idx, 0, &phys, &prot);
+ excp = hppa_get_physical_address(env, addr, mmu_idx, 0, 0, &phys, &prot);
if (excp >= 0) {
cpu_restore_state(env_cpu(env), GETPC());
hppa_set_ior_and_isr(env, addr, MMU_IDX_MMU_DISABLED(mmu_idx));
diff --git a/target/i386/cpu-param.h b/target/i386/cpu-param.h
index 5e15335..8c75abe 100644
--- a/target/i386/cpu-param.h
+++ b/target/i386/cpu-param.h
@@ -2,7 +2,7 @@
* i386 cpu parameters for qemu.
*
* Copyright (c) 2003 Fabrice Bellard
- * SPDX-License-Identifier: LGPL-2.0+
+ * SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef I386_CPU_PARAM_H
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 4688d14..1ff1af0 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -31,7 +31,6 @@
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "qapi/qapi-visit-machine.h"
-#include "qapi/qmp/qerror.h"
#include "standard-headers/asm-x86/kvm_para.h"
#include "hw/qdev-properties.h"
#include "hw/i386/topology.h"
@@ -1054,9 +1053,9 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
.type = CPUID_FEATURE_WORD,
.feat_names = {
"fsgsbase", "tsc-adjust", "sgx", "bmi1",
- "hle", "avx2", NULL, "smep",
+ "hle", "avx2", "fdp-excptn-only", "smep",
"bmi2", "erms", "invpcid", "rtm",
- NULL, NULL, "mpx", NULL,
+ NULL, "zero-fcs-fds", "mpx", NULL,
"avx512f", "avx512dq", "rdseed", "adx",
"smap", "avx512ifma", "pcommit", "clflushopt",
"clwb", "intel-pt", "avx512pf", "avx512er",
@@ -1148,8 +1147,8 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
[FEAT_7_2_EDX] = {
.type = CPUID_FEATURE_WORD,
.feat_names = {
- NULL, NULL, NULL, NULL,
- NULL, "mcdt-no", NULL, NULL,
+ "intel-psfd", "ipred-ctrl", "rrsba-ctrl", "ddpd-u",
+ "bhi-ctrl", "mcdt-no", NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
@@ -1221,8 +1220,8 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, "sbpb",
+ "ibpb-brtype", NULL, NULL, NULL,
},
.cpuid = { .eax = 0x80000021, .reg = R_EAX, },
.tcg_features = 0,
@@ -1435,7 +1434,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
"vmx-exit-save-efer", "vmx-exit-load-efer",
"vmx-exit-save-preemption-timer", "vmx-exit-clear-bndcfgs",
NULL, "vmx-exit-clear-rtit-ctl", NULL, NULL,
- NULL, "vmx-exit-load-pkrs", NULL, NULL,
+ NULL, "vmx-exit-load-pkrs", NULL, "vmx-exit-secondary-ctls",
},
.msr = {
.index = MSR_IA32_VMX_TRUE_EXIT_CTLS,
@@ -1450,7 +1449,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
NULL, "vmx-entry-ia32e-mode", NULL, NULL,
NULL, "vmx-entry-load-perf-global-ctrl", "vmx-entry-load-pat", "vmx-entry-load-efer",
"vmx-entry-load-bndcfgs", NULL, "vmx-entry-load-rtit-ctl", NULL,
- NULL, NULL, "vmx-entry-load-pkrs", NULL,
+ NULL, NULL, "vmx-entry-load-pkrs", "vmx-entry-load-fred",
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
},
@@ -1730,6 +1729,22 @@ static FeatureDep feature_dependencies[] = {
.from = { FEAT_7_1_EAX, CPUID_7_1_EAX_WRMSRNS },
.to = { FEAT_7_1_EAX, CPUID_7_1_EAX_FRED },
},
+ {
+ .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_SGX },
+ .to = { FEAT_7_0_ECX, CPUID_7_0_ECX_SGX_LC },
+ },
+ {
+ .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_SGX },
+ .to = { FEAT_SGX_12_0_EAX, ~0ull },
+ },
+ {
+ .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_SGX },
+ .to = { FEAT_SGX_12_0_EBX, ~0ull },
+ },
+ {
+ .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_SGX },
+ .to = { FEAT_SGX_12_1_EAX, ~0ull },
+ },
};
typedef struct X86RegisterInfo32 {
@@ -1849,9 +1864,10 @@ static inline uint64_t x86_cpu_xsave_xss_components(X86CPU *cpu)
* Returns the set of feature flags that are supported and migratable by
* QEMU, for a given FeatureWord.
*/
-static uint64_t x86_cpu_get_migratable_flags(FeatureWord w)
+static uint64_t x86_cpu_get_migratable_flags(X86CPU *cpu, FeatureWord w)
{
FeatureWordInfo *wi = &feature_word_info[w];
+ CPUX86State *env = &cpu->env;
uint64_t r = 0;
int i;
@@ -1865,6 +1881,12 @@ static uint64_t x86_cpu_get_migratable_flags(FeatureWord w)
r |= f;
}
}
+
+ /* when tsc-khz is set explicitly, invtsc is migratable */
+ if ((w == FEAT_8000_0007_EDX) && env->user_tsc_khz) {
+ r |= CPUID_APM_INVTSC;
+ }
+
return r;
}
@@ -5417,13 +5439,13 @@ static void x86_cpuid_version_get_family(Object *obj, Visitor *v,
{
X86CPU *cpu = X86_CPU(obj);
CPUX86State *env = &cpu->env;
- int64_t value;
+ uint64_t value;
value = (env->cpuid_version >> 8) & 0xf;
if (value == 0xf) {
value += (env->cpuid_version >> 20) & 0xff;
}
- visit_type_int(v, name, &value, errp);
+ visit_type_uint64(v, name, &value, errp);
}
static void x86_cpuid_version_set_family(Object *obj, Visitor *v,
@@ -5432,16 +5454,15 @@ static void x86_cpuid_version_set_family(Object *obj, Visitor *v,
{
X86CPU *cpu = X86_CPU(obj);
CPUX86State *env = &cpu->env;
- const int64_t min = 0;
- const int64_t max = 0xff + 0xf;
- int64_t value;
+ const uint64_t max = 0xff + 0xf;
+ uint64_t value;
- if (!visit_type_int(v, name, &value, errp)) {
+ if (!visit_type_uint64(v, name, &value, errp)) {
return;
}
- if (value < min || value > max) {
- error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
- name ? name : "null", value, min, max);
+ if (value > max) {
+ error_setg(errp, "parameter '%s' can be at most %" PRIu64,
+ name ? name : "null", max);
return;
}
@@ -5459,11 +5480,11 @@ static void x86_cpuid_version_get_model(Object *obj, Visitor *v,
{
X86CPU *cpu = X86_CPU(obj);
CPUX86State *env = &cpu->env;
- int64_t value;
+ uint64_t value;
value = (env->cpuid_version >> 4) & 0xf;
value |= ((env->cpuid_version >> 16) & 0xf) << 4;
- visit_type_int(v, name, &value, errp);
+ visit_type_uint64(v, name, &value, errp);
}
static void x86_cpuid_version_set_model(Object *obj, Visitor *v,
@@ -5472,16 +5493,15 @@ static void x86_cpuid_version_set_model(Object *obj, Visitor *v,
{
X86CPU *cpu = X86_CPU(obj);
CPUX86State *env = &cpu->env;
- const int64_t min = 0;
- const int64_t max = 0xff;
- int64_t value;
+ const uint64_t max = 0xff;
+ uint64_t value;
- if (!visit_type_int(v, name, &value, errp)) {
+ if (!visit_type_uint64(v, name, &value, errp)) {
return;
}
- if (value < min || value > max) {
- error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
- name ? name : "null", value, min, max);
+ if (value > max) {
+ error_setg(errp, "parameter '%s' can be at most %" PRIu64,
+ name ? name : "null", max);
return;
}
@@ -5495,10 +5515,10 @@ static void x86_cpuid_version_get_stepping(Object *obj, Visitor *v,
{
X86CPU *cpu = X86_CPU(obj);
CPUX86State *env = &cpu->env;
- int64_t value;
+ uint64_t value;
value = env->cpuid_version & 0xf;
- visit_type_int(v, name, &value, errp);
+ visit_type_uint64(v, name, &value, errp);
}
static void x86_cpuid_version_set_stepping(Object *obj, Visitor *v,
@@ -5507,16 +5527,15 @@ static void x86_cpuid_version_set_stepping(Object *obj, Visitor *v,
{
X86CPU *cpu = X86_CPU(obj);
CPUX86State *env = &cpu->env;
- const int64_t min = 0;
- const int64_t max = 0xf;
- int64_t value;
+ const uint64_t max = 0xf;
+ uint64_t value;
- if (!visit_type_int(v, name, &value, errp)) {
+ if (!visit_type_uint64(v, name, &value, errp)) {
return;
}
- if (value < min || value > max) {
- error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
- name ? name : "null", value, min, max);
+ if (value > max) {
+ error_setg(errp, "parameter '%s' can be at most %" PRIu64,
+ name ? name : "null", max);
return;
}
@@ -5610,16 +5629,15 @@ static void x86_cpuid_set_tsc_freq(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
X86CPU *cpu = X86_CPU(obj);
- const int64_t min = 0;
const int64_t max = INT64_MAX;
int64_t value;
if (!visit_type_int(v, name, &value, errp)) {
return;
}
- if (value < min || value > max) {
- error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
- name ? name : "null", value, min, max);
+ if (value < 0 || value > max) {
+ error_setg(errp, "parameter '%s' can be at most %" PRId64,
+ name ? name : "null", max);
return;
}
@@ -6039,7 +6057,7 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w)
{
FeatureWordInfo *wi = &feature_word_info[w];
uint64_t r = 0;
- uint32_t unavail = 0;
+ uint64_t unavail = 0;
if (kvm_enabled()) {
switch (wi->type) {
@@ -6087,13 +6105,28 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w)
}
break;
+ case FEAT_7_0_EBX:
+#ifndef CONFIG_USER_ONLY
+ if (!check_sgx_support()) {
+ unavail = CPUID_7_0_EBX_SGX;
+ }
+#endif
+ break;
+ case FEAT_7_0_ECX:
+#ifndef CONFIG_USER_ONLY
+ if (!check_sgx_support()) {
+ unavail = CPUID_7_0_ECX_SGX_LC;
+ }
+#endif
+ break;
+
default:
break;
}
r &= ~unavail;
if (cpu && cpu->migratable) {
- r &= x86_cpu_get_migratable_flags(w);
+ r &= x86_cpu_get_migratable_flags(cpu, w);
}
return r;
}
@@ -6537,8 +6570,6 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
case 7:
/* Structured Extended Feature Flags Enumeration Leaf */
if (count == 0) {
- uint32_t eax_0_unused, ebx_0, ecx_0, edx_0_unused;
-
/* Maximum ECX value for sub-leaves */
*eax = env->cpuid_level_func7;
*ebx = env->features[FEAT_7_0_EBX]; /* Feature flags */
@@ -6547,23 +6578,6 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*ecx |= CPUID_7_0_ECX_OSPKE;
}
*edx = env->features[FEAT_7_0_EDX]; /* Feature flags */
-
- /*
- * SGX cannot be emulated in software. If hardware does not
- * support enabling SGX and/or SGX flexible launch control,
- * then we need to update the VM's CPUID values accordingly.
- */
- x86_cpu_get_supported_cpuid(0x7, 0,
- &eax_0_unused, &ebx_0,
- &ecx_0, &edx_0_unused);
- if ((*ebx & CPUID_7_0_EBX_SGX) && !(ebx_0 & CPUID_7_0_EBX_SGX)) {
- *ebx &= ~CPUID_7_0_EBX_SGX;
- }
-
- if ((*ecx & CPUID_7_0_ECX_SGX_LC)
- && (!(*ebx & CPUID_7_0_EBX_SGX) || !(ecx_0 & CPUID_7_0_ECX_SGX_LC))) {
- *ecx &= ~CPUID_7_0_ECX_SGX_LC;
- }
} else if (count == 1) {
*eax = env->features[FEAT_7_1_EAX];
*edx = env->features[FEAT_7_1_EDX];
@@ -7819,6 +7833,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
mce_init(cpu);
+ x86_cpu_gdb_init(cs);
qemu_init_vcpu(cs);
/*
@@ -8279,8 +8294,10 @@ static Property x86_cpu_properties[] = {
HYPERV_FEAT_TLBFLUSH_DIRECT, 0),
DEFINE_PROP_ON_OFF_AUTO("hv-no-nonarch-coresharing", X86CPU,
hyperv_no_nonarch_cs, ON_OFF_AUTO_OFF),
+#ifdef CONFIG_SYNDBG
DEFINE_PROP_BIT64("hv-syndbg", X86CPU, hyperv_features,
HYPERV_FEAT_SYNDBG, 0),
+#endif
DEFINE_PROP_BOOL("hv-passthrough", X86CPU, hyperv_passthrough, false),
DEFINE_PROP_BOOL("hv-enforce-cpuid", X86CPU, hyperv_enforce_cpuid, false),
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 1e121ac..74886d1 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -267,12 +267,6 @@ typedef enum X86Seg {
#define CR4_FRED_MASK 0
#endif
-#ifdef TARGET_X86_64
-#define CR4_FRED_MASK (1ULL << 32)
-#else
-#define CR4_FRED_MASK 0
-#endif
-
#define CR4_RESERVED_MASK \
(~(target_ulong)(CR4_VME_MASK | CR4_PVI_MASK | CR4_TSD_MASK \
| CR4_DE_MASK | CR4_PSE_MASK | CR4_PAE_MASK \
@@ -414,6 +408,10 @@ typedef enum X86Seg {
#define MSR_IA32_TSX_CTRL 0x122
#define MSR_IA32_TSCDEADLINE 0x6e0
#define MSR_IA32_PKRS 0x6e1
+#define MSR_RAPL_POWER_UNIT 0x00000606
+#define MSR_PKG_POWER_LIMIT 0x00000610
+#define MSR_PKG_ENERGY_STATUS 0x00000611
+#define MSR_PKG_POWER_INFO 0x00000614
#define MSR_ARCH_LBR_CTL 0x000014ce
#define MSR_ARCH_LBR_DEPTH 0x000014cf
#define MSR_ARCH_LBR_FROM_0 0x00001500
@@ -535,6 +533,8 @@ typedef enum X86Seg {
#define MSR_AMD64_TSC_RATIO_DEFAULT 0x100000000ULL
+#define MSR_K7_HWCR 0xc0010015
+
#define MSR_VM_HSAVE_PA 0xc0010117
#define MSR_IA32_XFD 0x000001c4
@@ -822,6 +822,8 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w);
#define CPUID_7_0_EBX_HLE (1U << 4)
/* Intel Advanced Vector Extensions 2 */
#define CPUID_7_0_EBX_AVX2 (1U << 5)
+/* FPU data pointer updated only on x87 exceptions */
+#define CPUID_7_0_EBX_FDP_EXCPTN_ONLY (1u << 6)
/* Supervisor-mode Execution Prevention */
#define CPUID_7_0_EBX_SMEP (1U << 7)
/* 2nd Group of Advanced Bit Manipulation Extensions */
@@ -832,6 +834,8 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w);
#define CPUID_7_0_EBX_INVPCID (1U << 10)
/* Restricted Transactional Memory */
#define CPUID_7_0_EBX_RTM (1U << 11)
+/* Zero out FPU CS and FPU DS */
+#define CPUID_7_0_EBX_ZERO_FCS_FDS (1U << 13)
/* Memory Protection Extension */
#define CPUID_7_0_EBX_MPX (1U << 14)
/* AVX-512 Foundation */
@@ -1188,6 +1192,7 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w);
#define VMX_VM_EXIT_PT_CONCEAL_PIP 0x01000000
#define VMX_VM_EXIT_CLEAR_IA32_RTIT_CTL 0x02000000
#define VMX_VM_EXIT_LOAD_IA32_PKRS 0x20000000
+#define VMX_VM_EXIT_ACTIVATE_SECONDARY_CONTROLS 0x80000000
#define VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS 0x00000004
#define VMX_VM_ENTRY_IA32E_MODE 0x00000200
@@ -1335,6 +1340,11 @@ typedef enum {
CC_OP_BMILGL,
CC_OP_BMILGQ,
+ CC_OP_BLSIB, /* Z,S via CC_DST, C = SRC!=0; O=0; P,A undefined */
+ CC_OP_BLSIW,
+ CC_OP_BLSIL,
+ CC_OP_BLSIQ,
+
/*
* Note that only CC_OP_POPCNT (i.e. the one with MO_TL size)
* is used or implemented, because the translation needs
@@ -1850,6 +1860,9 @@ typedef struct CPUArchState {
uint64_t msr_lbr_depth;
LBREntry lbr_records[ARCH_LBR_NR_ENTRIES];
+ /* AMD MSRC001_0015 Hardware Configuration */
+ uint64_t msr_hwcr;
+
/* exception/interrupt handling */
int error_code;
int exception_is_int;
@@ -1880,6 +1893,10 @@ typedef struct CPUArchState {
uintptr_t retaddr;
+ /* RAPL MSR */
+ uint64_t msr_rapl_power_unit;
+ uint64_t msr_pkg_energy_status;
+
/* Fields up to this point are cleared by a CPU reset */
struct {} end_reset_fields;
@@ -2218,6 +2235,7 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, int flags);
int x86_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int x86_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
+void x86_cpu_gdb_init(CPUState *cs);
void x86_cpu_list(void);
int cpu_x86_support_mca_broadcast(CPUX86State *env);
diff --git a/target/i386/gdbstub.c b/target/i386/gdbstub.c
index 4acf485..04c49e8 100644
--- a/target/i386/gdbstub.c
+++ b/target/i386/gdbstub.c
@@ -18,8 +18,13 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
+#include "accel/tcg/vcpu-state.h"
#include "cpu.h"
+#include "exec/gdbstub.h"
#include "gdbstub/helpers.h"
+#ifdef CONFIG_LINUX_USER
+#include "linux-user/qemu.h"
+#endif
#ifdef TARGET_X86_64
static const int gpr_map[16] = {
@@ -96,6 +101,19 @@ static int gdb_write_reg_cs64(uint32_t hflags, uint8_t *buf, target_ulong *val)
return 4;
}
+static int gdb_get_reg(CPUX86State *env, GByteArray *mem_buf, target_ulong val)
+{
+ if (TARGET_LONG_BITS == 64) {
+ if (env->hflags & HF_CS64_MASK) {
+ return gdb_get_reg64(mem_buf, val);
+ } else {
+ return gdb_get_reg64(mem_buf, val & 0xffffffffUL);
+ }
+ } else {
+ return gdb_get_reg32(mem_buf, val);
+ }
+}
+
int x86_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
X86CPU *cpu = X86_CPU(cs);
@@ -137,15 +155,7 @@ int x86_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
} else {
switch (n) {
case IDX_IP_REG:
- if (TARGET_LONG_BITS == 64) {
- if (env->hflags & HF_CS64_MASK) {
- return gdb_get_reg64(mem_buf, env->eip);
- } else {
- return gdb_get_reg64(mem_buf, env->eip & 0xffffffffUL);
- }
- } else {
- return gdb_get_reg32(mem_buf, env->eip);
- }
+ return gdb_get_reg(env, mem_buf, env->eip);
case IDX_FLAGS_REG:
return gdb_get_reg32(mem_buf, env->eflags);
@@ -248,6 +258,21 @@ static int x86_cpu_gdb_load_seg(X86CPU *cpu, X86Seg sreg, uint8_t *mem_buf)
return 4;
}
+static int gdb_write_reg(CPUX86State *env, uint8_t *mem_buf, target_ulong *val)
+{
+ if (TARGET_LONG_BITS == 64) {
+ if (env->hflags & HF_CS64_MASK) {
+ *val = ldq_p(mem_buf);
+ } else {
+ *val = ldq_p(mem_buf) & 0xffffffffUL;
+ }
+ return 8;
+ } else {
+ *val = (uint32_t)ldl_p(mem_buf);
+ return 4;
+ }
+}
+
int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
X86CPU *cpu = X86_CPU(cs);
@@ -288,18 +313,7 @@ int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
} else {
switch (n) {
case IDX_IP_REG:
- if (TARGET_LONG_BITS == 64) {
- if (env->hflags & HF_CS64_MASK) {
- env->eip = ldq_p(mem_buf);
- } else {
- env->eip = ldq_p(mem_buf) & 0xffffffffUL;
- }
- return 8;
- } else {
- env->eip &= ~0xffffffffUL;
- env->eip |= (uint32_t)ldl_p(mem_buf);
- return 4;
- }
+ return gdb_write_reg(env, mem_buf, &env->eip);
case IDX_FLAGS_REG:
env->eflags = ldl_p(mem_buf);
return 4;
@@ -397,3 +411,49 @@ int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
/* Unrecognised register. */
return 0;
}
+
+#ifdef CONFIG_LINUX_USER
+
+#define IDX_ORIG_AX 0
+
+static int x86_cpu_gdb_read_linux_register(CPUState *cs, GByteArray *mem_buf,
+ int n)
+{
+ X86CPU *cpu = X86_CPU(cs);
+ CPUX86State *env = &cpu->env;
+
+ switch (n) {
+ case IDX_ORIG_AX:
+ return gdb_get_reg(env, mem_buf, get_task_state(cs)->orig_ax);
+ }
+ return 0;
+}
+
+static int x86_cpu_gdb_write_linux_register(CPUState *cs, uint8_t *mem_buf,
+ int n)
+{
+ X86CPU *cpu = X86_CPU(cs);
+ CPUX86State *env = &cpu->env;
+
+ switch (n) {
+ case IDX_ORIG_AX:
+ return gdb_write_reg(env, mem_buf, &get_task_state(cs)->orig_ax);
+ }
+ return 0;
+}
+
+#endif
+
+void x86_cpu_gdb_init(CPUState *cs)
+{
+#ifdef CONFIG_LINUX_USER
+ gdb_register_coprocessor(cs, x86_cpu_gdb_read_linux_register,
+ x86_cpu_gdb_write_linux_register,
+#ifdef TARGET_X86_64
+ gdb_find_static_feature("i386-64bit-linux.xml"),
+#else
+ gdb_find_static_feature("i386-32bit-linux.xml"),
+#endif
+ 0);
+#endif
+}
diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c
index c9c64e2..68dc5d9 100644
--- a/target/i386/hvf/hvf.c
+++ b/target/i386/hvf/hvf.c
@@ -223,6 +223,11 @@ int hvf_arch_init(void)
return 0;
}
+hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range)
+{
+ return hv_vm_create(HV_VM_DEFAULT);
+}
+
int hvf_arch_init_vcpu(CPUState *cpu)
{
X86CPU *x86cpu = X86_CPU(cpu);
diff --git a/target/i386/kvm/hyperv.c b/target/i386/kvm/hyperv.c
index b94f12a..70b89ca 100644
--- a/target/i386/kvm/hyperv.c
+++ b/target/i386/kvm/hyperv.c
@@ -80,6 +80,7 @@ int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
* necessary because memory hierarchy is being changed
*/
async_safe_run_on_cpu(CPU(cpu), async_synic_update, RUN_ON_CPU_NULL);
+ cpu_exit(CPU(cpu));
return EXCP_INTERRUPT;
case KVM_EXIT_HYPERV_HCALL: {
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index becca2e..fd9f198 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -16,9 +16,12 @@
#include "qapi/qapi-events-run-state.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
+#include <math.h>
#include <sys/ioctl.h>
#include <sys/utsname.h>
#include <sys/syscall.h>
+#include <sys/resource.h>
+#include <sys/time.h>
#include <linux/kvm.h>
#include <linux/kvm_para.h>
@@ -27,6 +30,7 @@
#include "cpu.h"
#include "host-cpu.h"
+#include "vmsr_energy.h"
#include "sysemu/sysemu.h"
#include "sysemu/hw_accel.h"
#include "sysemu/kvm_int.h"
@@ -77,6 +81,16 @@
do { } while (0)
#endif
+/*
+ * On older Intel CPUs, KVM uses vm86 mode to emulate 16-bit code directly.
+ * In order to use vm86 mode, an EPT identity map and a TSS are needed.
+ * Since these must be part of guest physical memory, we need to allocate
+ * them, both by setting their start addresses in the kernel and by
+ * creating a corresponding e820 entry. We need 4 pages before the BIOS,
+ * so this value allows up to 16M BIOSes.
+ */
+#define KVM_IDENTITY_BASE 0xfeffc000
+
/* From arch/x86/kvm/lapic.h */
#define KVM_APIC_BUS_CYCLE_NS 1
#define KVM_APIC_BUS_FREQUENCY (1000000000ULL / KVM_APIC_BUS_CYCLE_NS)
@@ -88,7 +102,17 @@
* 255 kvm_msr_entry structs */
#define MSR_BUF_SIZE 4096
+typedef bool QEMURDMSRHandler(X86CPU *cpu, uint32_t msr, uint64_t *val);
+typedef bool QEMUWRMSRHandler(X86CPU *cpu, uint32_t msr, uint64_t val);
+typedef struct {
+ uint32_t msr;
+ QEMURDMSRHandler *rdmsr;
+ QEMUWRMSRHandler *wrmsr;
+} KVMMSRHandlers;
+
static void kvm_init_msrs(X86CPU *cpu);
+static bool kvm_filter_msr(KVMState *s, uint32_t msr, QEMURDMSRHandler *rdmsr,
+ QEMUWRMSRHandler *wrmsr);
const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
KVM_CAP_INFO(SET_TSS_ADDR),
@@ -141,6 +165,7 @@ static bool has_msr_ucode_rev;
static bool has_msr_vmx_procbased_ctls2;
static bool has_msr_perf_capabs;
static bool has_msr_pkrs;
+static bool has_msr_hwcr;
static uint32_t has_architectural_pmu_version;
static uint32_t num_architectural_pmu_gp_counters;
@@ -909,6 +934,7 @@ static struct {
uint32_t bits;
} flags[2];
uint64_t dependencies;
+ bool skip_passthrough;
} kvm_hyperv_properties[] = {
[HYPERV_FEAT_RELAXED] = {
.desc = "relaxed timing (hv-relaxed)",
@@ -1031,16 +1057,15 @@ static struct {
.bits = HV_DEPRECATING_AEOI_RECOMMENDED}
}
},
-#ifdef CONFIG_SYNDBG
[HYPERV_FEAT_SYNDBG] = {
.desc = "Enable synthetic kernel debugger channel (hv-syndbg)",
.flags = {
{.func = HV_CPUID_FEATURES, .reg = R_EDX,
.bits = HV_FEATURE_DEBUG_MSRS_AVAILABLE}
},
- .dependencies = BIT(HYPERV_FEAT_SYNIC) | BIT(HYPERV_FEAT_RELAXED)
+ .dependencies = BIT(HYPERV_FEAT_SYNIC) | BIT(HYPERV_FEAT_RELAXED),
+ .skip_passthrough = true,
},
-#endif
[HYPERV_FEAT_MSR_BITMAP] = {
.desc = "enlightened MSR-Bitmap (hv-emsr-bitmap)",
.flags = {
@@ -1292,6 +1317,13 @@ static bool hyperv_feature_supported(CPUState *cs, int feature)
uint32_t func, bits;
int i, reg;
+ /*
+ * kvm_hyperv_properties needs to define at least one CPUID flag which
+ * must be used to detect the feature, it's hard to say whether it is
+ * supported or not otherwise.
+ */
+ assert(kvm_hyperv_properties[feature].flags[0].func);
+
for (i = 0; i < ARRAY_SIZE(kvm_hyperv_properties[feature].flags); i++) {
func = kvm_hyperv_properties[feature].flags[i].func;
@@ -1441,7 +1473,8 @@ bool kvm_hyperv_expand_features(X86CPU *cpu, Error **errp)
* hv_build_cpuid_leaf() uses this info to build guest CPUIDs.
*/
for (feat = 0; feat < ARRAY_SIZE(kvm_hyperv_properties); feat++) {
- if (hyperv_feature_supported(cs, feat)) {
+ if (hyperv_feature_supported(cs, feat) &&
+ !kvm_hyperv_properties[feat].skip_passthrough) {
cpu->hyperv_features |= BIT(feat);
}
}
@@ -1814,10 +1847,12 @@ static uint32_t kvm_x86_build_cpuid(CPUX86State *env,
int times;
c->function = i;
- c->flags = KVM_CPUID_FLAG_STATEFUL_FUNC |
- KVM_CPUID_FLAG_STATE_READ_NEXT;
cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
times = c->eax & 0xff;
+ if (times > 1) {
+ c->flags = KVM_CPUID_FLAG_STATEFUL_FUNC |
+ KVM_CPUID_FLAG_STATE_READ_NEXT;
+ }
for (j = 1; j < times; ++j) {
if (cpuid_i == KVM_MAX_CPUID_ENTRIES) {
@@ -1840,10 +1875,6 @@ static uint32_t kvm_x86_build_cpuid(CPUX86State *env,
case 0xb:
case 0xd:
for (j = 0; ; j++) {
- if (i == 0xd && j == 64) {
- break;
- }
-
c->function = i;
c->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
c->index = j;
@@ -1859,7 +1890,12 @@ static uint32_t kvm_x86_build_cpuid(CPUX86State *env,
break;
}
if (i == 0xd && c->eax == 0) {
- continue;
+ if (j < 63) {
+ continue;
+ } else {
+ cpuid_i--;
+ break;
+ }
}
if (cpuid_i == KVM_MAX_CPUID_ENTRIES) {
goto full;
@@ -2550,6 +2586,8 @@ static int kvm_get_supported_msrs(KVMState *s)
case MSR_IA32_PKRS:
has_msr_pkrs = true;
break;
+ case MSR_K7_HWCR:
+ has_msr_hwcr = true;
}
}
}
@@ -2559,7 +2597,8 @@ static int kvm_get_supported_msrs(KVMState *s)
return ret;
}
-static bool kvm_rdmsr_core_thread_count(X86CPU *cpu, uint32_t msr,
+static bool kvm_rdmsr_core_thread_count(X86CPU *cpu,
+ uint32_t msr,
uint64_t *val)
{
CPUState *cs = CPU(cpu);
@@ -2570,6 +2609,53 @@ static bool kvm_rdmsr_core_thread_count(X86CPU *cpu, uint32_t msr,
return true;
}
+static bool kvm_rdmsr_rapl_power_unit(X86CPU *cpu,
+ uint32_t msr,
+ uint64_t *val)
+{
+
+ CPUState *cs = CPU(cpu);
+
+ *val = cs->kvm_state->msr_energy.msr_unit;
+
+ return true;
+}
+
+static bool kvm_rdmsr_pkg_power_limit(X86CPU *cpu,
+ uint32_t msr,
+ uint64_t *val)
+{
+
+ CPUState *cs = CPU(cpu);
+
+ *val = cs->kvm_state->msr_energy.msr_limit;
+
+ return true;
+}
+
+static bool kvm_rdmsr_pkg_power_info(X86CPU *cpu,
+ uint32_t msr,
+ uint64_t *val)
+{
+
+ CPUState *cs = CPU(cpu);
+
+ *val = cs->kvm_state->msr_energy.msr_info;
+
+ return true;
+}
+
+static bool kvm_rdmsr_pkg_energy_status(X86CPU *cpu,
+ uint32_t msr,
+ uint64_t *val)
+{
+
+ CPUState *cs = CPU(cpu);
+ *val = cs->kvm_state->msr_energy.msr_value[cs->cpu_index];
+
+ return true;
+}
+
static Notifier smram_machine_done;
static KVMMemoryListener smram_listener;
static AddressSpace smram_address_space;
@@ -2604,15 +2690,513 @@ static void register_smram_listener(Notifier *n, void *unused)
&smram_address_space, 1, "kvm-smram");
}
+static void *kvm_msr_energy_thread(void *data)
+{
+ KVMState *s = data;
+ struct KVMMsrEnergy *vmsr = &s->msr_energy;
+
+ g_autofree vmsr_package_energy_stat *pkg_stat = NULL;
+ g_autofree vmsr_thread_stat *thd_stat = NULL;
+ g_autofree CPUState *cpu = NULL;
+ g_autofree unsigned int *vpkgs_energy_stat = NULL;
+ unsigned int num_threads = 0;
+
+ X86CPUTopoIDs topo_ids;
+
+ rcu_register_thread();
+
+ /* Allocate memory for each package energy status */
+ pkg_stat = g_new0(vmsr_package_energy_stat, vmsr->host_topo.maxpkgs);
+
+ /* Allocate memory for thread stats */
+ thd_stat = g_new0(vmsr_thread_stat, 1);
+
+ /* Allocate memory for holding virtual package energy counter */
+ vpkgs_energy_stat = g_new0(unsigned int, vmsr->guest_vsockets);
+
+ /* Populate the max tick of each packages */
+ for (int i = 0; i < vmsr->host_topo.maxpkgs; i++) {
+ /*
+ * Max numbers of ticks per package
+ * Time in second * Number of ticks/second * Number of cores/package
+ * ex: 100 ticks/second/CPU, 12 CPUs per Package gives 1200 ticks max
+ */
+ vmsr->host_topo.maxticks[i] = (MSR_ENERGY_THREAD_SLEEP_US / 1000000)
+ * sysconf(_SC_CLK_TCK)
+ * vmsr->host_topo.pkg_cpu_count[i];
+ }
+
+ while (true) {
+ /* Get all qemu threads id */
+ g_autofree pid_t *thread_ids
+ = vmsr_get_thread_ids(vmsr->pid, &num_threads);
+
+ if (thread_ids == NULL) {
+ goto clean;
+ }
+
+ thd_stat = g_renew(vmsr_thread_stat, thd_stat, num_threads);
+ /* Unlike g_new0, g_renew0 function doesn't exist yet... */
+ memset(thd_stat, 0, num_threads * sizeof(vmsr_thread_stat));
+
+ /* Populate all the thread stats */
+ for (int i = 0; i < num_threads; i++) {
+ thd_stat[i].utime = g_new0(unsigned long long, 2);
+ thd_stat[i].stime = g_new0(unsigned long long, 2);
+ thd_stat[i].thread_id = thread_ids[i];
+ vmsr_read_thread_stat(vmsr->pid,
+ thd_stat[i].thread_id,
+ &thd_stat[i].utime[0],
+ &thd_stat[i].stime[0],
+ &thd_stat[i].cpu_id);
+ thd_stat[i].pkg_id =
+ vmsr_get_physical_package_id(thd_stat[i].cpu_id);
+ }
+
+ /* Retrieve all packages power plane energy counter */
+ for (int i = 0; i < vmsr->host_topo.maxpkgs; i++) {
+ for (int j = 0; j < num_threads; j++) {
+ /*
+ * Use the first thread we found that ran on the CPU
+ * of the package to read the packages energy counter
+ */
+ if (thd_stat[j].pkg_id == i) {
+ pkg_stat[i].e_start =
+ vmsr_read_msr(MSR_PKG_ENERGY_STATUS,
+ thd_stat[j].cpu_id,
+ thd_stat[j].thread_id,
+ s->msr_energy.sioc);
+ break;
+ }
+ }
+ }
+
+ /* Sleep a short period while the other threads are working */
+ usleep(MSR_ENERGY_THREAD_SLEEP_US);
+
+ /*
+ * Retrieve all packages power plane energy counter
+ * Calculate the delta of all packages
+ */
+ for (int i = 0; i < vmsr->host_topo.maxpkgs; i++) {
+ for (int j = 0; j < num_threads; j++) {
+ /*
+ * Use the first thread we found that ran on the CPU
+ * of the package to read the packages energy counter
+ */
+ if (thd_stat[j].pkg_id == i) {
+ pkg_stat[i].e_end =
+ vmsr_read_msr(MSR_PKG_ENERGY_STATUS,
+ thd_stat[j].cpu_id,
+ thd_stat[j].thread_id,
+ s->msr_energy.sioc);
+ /*
+ * Prevent the case we have migrate the VM
+ * during the sleep period or any other cases
+ * were energy counter might be lower after
+ * the sleep period.
+ */
+ if (pkg_stat[i].e_end > pkg_stat[i].e_start) {
+ pkg_stat[i].e_delta =
+ pkg_stat[i].e_end - pkg_stat[i].e_start;
+ } else {
+ pkg_stat[i].e_delta = 0;
+ }
+ break;
+ }
+ }
+ }
+
+ /* Delta of ticks spend by each thread between the sample */
+ for (int i = 0; i < num_threads; i++) {
+ vmsr_read_thread_stat(vmsr->pid,
+ thd_stat[i].thread_id,
+ &thd_stat[i].utime[1],
+ &thd_stat[i].stime[1],
+ &thd_stat[i].cpu_id);
+
+ if (vmsr->pid < 0) {
+ /*
+ * We don't count the dead thread
+ * i.e threads that existed before the sleep
+ * and not anymore
+ */
+ thd_stat[i].delta_ticks = 0;
+ } else {
+ vmsr_delta_ticks(thd_stat, i);
+ }
+ }
+
+ /*
+ * Identify the vcpu threads
+ * Calculate the number of vcpu per package
+ */
+ CPU_FOREACH(cpu) {
+ for (int i = 0; i < num_threads; i++) {
+ if (cpu->thread_id == thd_stat[i].thread_id) {
+ thd_stat[i].is_vcpu = true;
+ thd_stat[i].vcpu_id = cpu->cpu_index;
+ pkg_stat[thd_stat[i].pkg_id].nb_vcpu++;
+ thd_stat[i].acpi_id = kvm_arch_vcpu_id(cpu);
+ break;
+ }
+ }
+ }
+
+ /* Retrieve the virtual package number of each vCPU */
+ for (int i = 0; i < vmsr->guest_cpu_list->len; i++) {
+ for (int j = 0; j < num_threads; j++) {
+ if ((thd_stat[j].acpi_id ==
+ vmsr->guest_cpu_list->cpus[i].arch_id)
+ && (thd_stat[j].is_vcpu == true)) {
+ x86_topo_ids_from_apicid(thd_stat[j].acpi_id,
+ &vmsr->guest_topo_info, &topo_ids);
+ thd_stat[j].vpkg_id = topo_ids.pkg_id;
+ }
+ }
+ }
+
+ /* Calculate the total energy of all non-vCPU thread */
+ for (int i = 0; i < num_threads; i++) {
+ if ((thd_stat[i].is_vcpu != true) &&
+ (thd_stat[i].delta_ticks > 0)) {
+ double temp;
+ temp = vmsr_get_ratio(pkg_stat[thd_stat[i].pkg_id].e_delta,
+ thd_stat[i].delta_ticks,
+ vmsr->host_topo.maxticks[thd_stat[i].pkg_id]);
+ pkg_stat[thd_stat[i].pkg_id].e_ratio
+ += (uint64_t)lround(temp);
+ }
+ }
+
+ /* Calculate the ratio per non-vCPU thread of each package */
+ for (int i = 0; i < vmsr->host_topo.maxpkgs; i++) {
+ if (pkg_stat[i].nb_vcpu > 0) {
+ pkg_stat[i].e_ratio = pkg_stat[i].e_ratio / pkg_stat[i].nb_vcpu;
+ }
+ }
+
+ /*
+ * Calculate the energy for each Package:
+ * Energy Package = sum of each vCPU energy that belongs to the package
+ */
+ for (int i = 0; i < num_threads; i++) {
+ if ((thd_stat[i].is_vcpu == true) && \
+ (thd_stat[i].delta_ticks > 0)) {
+ double temp;
+ temp = vmsr_get_ratio(pkg_stat[thd_stat[i].pkg_id].e_delta,
+ thd_stat[i].delta_ticks,
+ vmsr->host_topo.maxticks[thd_stat[i].pkg_id]);
+ vpkgs_energy_stat[thd_stat[i].vpkg_id] +=
+ (uint64_t)lround(temp);
+ vpkgs_energy_stat[thd_stat[i].vpkg_id] +=
+ pkg_stat[thd_stat[i].pkg_id].e_ratio;
+ }
+ }
+
+ /*
+ * Finally populate the vmsr register of each vCPU with the total
+ * package value to emulate the real hardware where each CPU return the
+ * value of the package it belongs.
+ */
+ for (int i = 0; i < num_threads; i++) {
+ if ((thd_stat[i].is_vcpu == true) && \
+ (thd_stat[i].delta_ticks > 0)) {
+ vmsr->msr_value[thd_stat[i].vcpu_id] = \
+ vpkgs_energy_stat[thd_stat[i].vpkg_id];
+ }
+ }
+
+ /* Freeing memory before zeroing the pointer */
+ for (int i = 0; i < num_threads; i++) {
+ g_free(thd_stat[i].utime);
+ g_free(thd_stat[i].stime);
+ }
+ }
+
+clean:
+ rcu_unregister_thread();
+ return NULL;
+}
+
+static int kvm_msr_energy_thread_init(KVMState *s, MachineState *ms)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ struct KVMMsrEnergy *r = &s->msr_energy;
+ int ret = 0;
+
+ /*
+ * Sanity check
+ * 1. Host cpu must be Intel cpu
+ * 2. RAPL must be enabled on the Host
+ */
+ if (!is_host_cpu_intel()) {
+ error_report("The RAPL feature can only be enabled on hosts "
+ "with Intel CPU models");
+ ret = 1;
+ goto out;
+ }
+
+ if (!is_rapl_enabled()) {
+ ret = 1;
+ goto out;
+ }
+
+ /* Retrieve the virtual topology */
+ vmsr_init_topo_info(&r->guest_topo_info, ms);
+
+ /* Retrieve the number of vcpu */
+ r->guest_vcpus = ms->smp.cpus;
+
+ /* Retrieve the number of virtual sockets */
+ r->guest_vsockets = ms->smp.sockets;
+
+ /* Allocate register memory (MSR_PKG_STATUS) for each vcpu */
+ r->msr_value = g_new0(uint64_t, r->guest_vcpus);
+
+ /* Retrieve the CPUArchIDlist */
+ r->guest_cpu_list = mc->possible_cpu_arch_ids(ms);
+
+ /* Max number of cpus on the Host */
+ r->host_topo.maxcpus = vmsr_get_maxcpus();
+ if (r->host_topo.maxcpus == 0) {
+ error_report("host max cpus = 0");
+ ret = 1;
+ goto out;
+ }
+
+ /* Max number of packages on the host */
+ r->host_topo.maxpkgs = vmsr_get_max_physical_package(r->host_topo.maxcpus);
+ if (r->host_topo.maxpkgs == 0) {
+ error_report("host max pkgs = 0");
+ ret = 1;
+ goto out;
+ }
+
+ /* Allocate memory for each package on the host */
+ r->host_topo.pkg_cpu_count = g_new0(unsigned int, r->host_topo.maxpkgs);
+ r->host_topo.maxticks = g_new0(unsigned int, r->host_topo.maxpkgs);
+
+ vmsr_count_cpus_per_package(r->host_topo.pkg_cpu_count,
+ r->host_topo.maxpkgs);
+ for (int i = 0; i < r->host_topo.maxpkgs; i++) {
+ if (r->host_topo.pkg_cpu_count[i] == 0) {
+ error_report("cpu per packages = 0 on package_%d", i);
+ ret = 1;
+ goto out;
+ }
+ }
+
+ /* Get QEMU PID*/
+ r->pid = getpid();
+
+ /* Compute the socket path if necessary */
+ if (s->msr_energy.socket_path == NULL) {
+ s->msr_energy.socket_path = vmsr_compute_default_paths();
+ }
+
+ /* Open socket with vmsr helper */
+ s->msr_energy.sioc = vmsr_open_socket(s->msr_energy.socket_path);
+
+ if (s->msr_energy.sioc == NULL) {
+ error_report("vmsr socket opening failed");
+ ret = 1;
+ goto out;
+ }
+
+ /* Those MSR values should not change */
+ r->msr_unit = vmsr_read_msr(MSR_RAPL_POWER_UNIT, 0, r->pid,
+ s->msr_energy.sioc);
+ r->msr_limit = vmsr_read_msr(MSR_PKG_POWER_LIMIT, 0, r->pid,
+ s->msr_energy.sioc);
+ r->msr_info = vmsr_read_msr(MSR_PKG_POWER_INFO, 0, r->pid,
+ s->msr_energy.sioc);
+ if (r->msr_unit == 0 || r->msr_limit == 0 || r->msr_info == 0) {
+ error_report("can't read any virtual msr");
+ ret = 1;
+ goto out;
+ }
+
+ qemu_thread_create(&r->msr_thr, "kvm-msr",
+ kvm_msr_energy_thread,
+ s, QEMU_THREAD_JOINABLE);
+out:
+ return ret;
+}
+
int kvm_arch_get_default_type(MachineState *ms)
{
return 0;
}
-int kvm_arch_init(MachineState *ms, KVMState *s)
+static int kvm_vm_enable_exception_payload(KVMState *s)
+{
+ int ret = 0;
+ has_exception_payload = kvm_check_extension(s, KVM_CAP_EXCEPTION_PAYLOAD);
+ if (has_exception_payload) {
+ ret = kvm_vm_enable_cap(s, KVM_CAP_EXCEPTION_PAYLOAD, 0, true);
+ if (ret < 0) {
+ error_report("kvm: Failed to enable exception payload cap: %s",
+ strerror(-ret));
+ }
+ }
+
+ return ret;
+}
+
+static int kvm_vm_enable_triple_fault_event(KVMState *s)
+{
+ int ret = 0;
+ has_triple_fault_event = \
+ kvm_check_extension(s,
+ KVM_CAP_X86_TRIPLE_FAULT_EVENT);
+ if (has_triple_fault_event) {
+ ret = kvm_vm_enable_cap(s, KVM_CAP_X86_TRIPLE_FAULT_EVENT, 0, true);
+ if (ret < 0) {
+ error_report("kvm: Failed to enable triple fault event cap: %s",
+ strerror(-ret));
+ }
+ }
+ return ret;
+}
+
+static int kvm_vm_set_identity_map_addr(KVMState *s, uint64_t identity_base)
+{
+ return kvm_vm_ioctl(s, KVM_SET_IDENTITY_MAP_ADDR, &identity_base);
+}
+
+static int kvm_vm_set_nr_mmu_pages(KVMState *s)
{
- uint64_t identity_base = 0xfffbc000;
uint64_t shadow_mem;
+ int ret = 0;
+ shadow_mem = object_property_get_int(OBJECT(s),
+ "kvm-shadow-mem",
+ &error_abort);
+ if (shadow_mem != -1) {
+ shadow_mem /= 4096;
+ ret = kvm_vm_ioctl(s, KVM_SET_NR_MMU_PAGES, shadow_mem);
+ }
+ return ret;
+}
+
+static int kvm_vm_set_tss_addr(KVMState *s, uint64_t tss_base)
+{
+ return kvm_vm_ioctl(s, KVM_SET_TSS_ADDR, tss_base);
+}
+
+static int kvm_vm_enable_disable_exits(KVMState *s)
+{
+ int disable_exits = kvm_check_extension(s, KVM_CAP_X86_DISABLE_EXITS);
+/* Work around for kernel header with a typo. TODO: fix header and drop. */
+#if defined(KVM_X86_DISABLE_EXITS_HTL) && !defined(KVM_X86_DISABLE_EXITS_HLT)
+#define KVM_X86_DISABLE_EXITS_HLT KVM_X86_DISABLE_EXITS_HTL
+#endif
+ if (disable_exits) {
+ disable_exits &= (KVM_X86_DISABLE_EXITS_MWAIT |
+ KVM_X86_DISABLE_EXITS_HLT |
+ KVM_X86_DISABLE_EXITS_PAUSE |
+ KVM_X86_DISABLE_EXITS_CSTATE);
+ }
+
+ return kvm_vm_enable_cap(s, KVM_CAP_X86_DISABLE_EXITS, 0,
+ disable_exits);
+}
+
+static int kvm_vm_enable_bus_lock_exit(KVMState *s)
+{
+ int ret = 0;
+ ret = kvm_check_extension(s, KVM_CAP_X86_BUS_LOCK_EXIT);
+ if (!(ret & KVM_BUS_LOCK_DETECTION_EXIT)) {
+ error_report("kvm: bus lock detection unsupported");
+ return -ENOTSUP;
+ }
+ ret = kvm_vm_enable_cap(s, KVM_CAP_X86_BUS_LOCK_EXIT, 0,
+ KVM_BUS_LOCK_DETECTION_EXIT);
+ if (ret < 0) {
+ error_report("kvm: Failed to enable bus lock detection cap: %s",
+ strerror(-ret));
+ }
+
+ return ret;
+}
+
+static int kvm_vm_enable_notify_vmexit(KVMState *s)
+{
+ int ret = 0;
+ if (s->notify_vmexit != NOTIFY_VMEXIT_OPTION_DISABLE) {
+ uint64_t notify_window_flags =
+ ((uint64_t)s->notify_window << 32) |
+ KVM_X86_NOTIFY_VMEXIT_ENABLED |
+ KVM_X86_NOTIFY_VMEXIT_USER;
+ ret = kvm_vm_enable_cap(s, KVM_CAP_X86_NOTIFY_VMEXIT, 0,
+ notify_window_flags);
+ if (ret < 0) {
+ error_report("kvm: Failed to enable notify vmexit cap: %s",
+ strerror(-ret));
+ }
+ }
+ return ret;
+}
+
+static int kvm_vm_enable_userspace_msr(KVMState *s)
+{
+ int ret = kvm_vm_enable_cap(s, KVM_CAP_X86_USER_SPACE_MSR, 0,
+ KVM_MSR_EXIT_REASON_FILTER);
+ if (ret < 0) {
+ error_report("Could not enable user space MSRs: %s",
+ strerror(-ret));
+ exit(1);
+ }
+
+ if (!kvm_filter_msr(s, MSR_CORE_THREAD_COUNT,
+ kvm_rdmsr_core_thread_count, NULL)) {
+ error_report("Could not install MSR_CORE_THREAD_COUNT handler!");
+ exit(1);
+ }
+
+ return 0;
+}
+
+static void kvm_vm_enable_energy_msrs(KVMState *s)
+{
+ bool r;
+ if (s->msr_energy.enable == true) {
+ r = kvm_filter_msr(s, MSR_RAPL_POWER_UNIT,
+ kvm_rdmsr_rapl_power_unit, NULL);
+ if (!r) {
+ error_report("Could not install MSR_RAPL_POWER_UNIT \
+ handler");
+ exit(1);
+ }
+
+ r = kvm_filter_msr(s, MSR_PKG_POWER_LIMIT,
+ kvm_rdmsr_pkg_power_limit, NULL);
+ if (!r) {
+ error_report("Could not install MSR_PKG_POWER_LIMIT \
+ handler");
+ exit(1);
+ }
+
+ r = kvm_filter_msr(s, MSR_PKG_POWER_INFO,
+ kvm_rdmsr_pkg_power_info, NULL);
+ if (!r) {
+ error_report("Could not install MSR_PKG_POWER_INFO \
+ handler");
+ exit(1);
+ }
+ r = kvm_filter_msr(s, MSR_PKG_ENERGY_STATUS,
+ kvm_rdmsr_pkg_energy_status, NULL);
+ if (!r) {
+ error_report("Could not install MSR_PKG_ENERGY_STATUS \
+ handler");
+ exit(1);
+ }
+ }
+ return;
+}
+
+int kvm_arch_init(MachineState *ms, KVMState *s)
+{
int ret;
struct utsname utsname;
Error *local_err = NULL;
@@ -2642,24 +3226,14 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
hv_vpindex_settable = kvm_check_extension(s, KVM_CAP_HYPERV_VP_INDEX);
- has_exception_payload = kvm_check_extension(s, KVM_CAP_EXCEPTION_PAYLOAD);
- if (has_exception_payload) {
- ret = kvm_vm_enable_cap(s, KVM_CAP_EXCEPTION_PAYLOAD, 0, true);
- if (ret < 0) {
- error_report("kvm: Failed to enable exception payload cap: %s",
- strerror(-ret));
- return ret;
- }
+ ret = kvm_vm_enable_exception_payload(s);
+ if (ret < 0) {
+ return ret;
}
- has_triple_fault_event = kvm_check_extension(s, KVM_CAP_X86_TRIPLE_FAULT_EVENT);
- if (has_triple_fault_event) {
- ret = kvm_vm_enable_cap(s, KVM_CAP_X86_TRIPLE_FAULT_EVENT, 0, true);
- if (ret < 0) {
- error_report("kvm: Failed to enable triple fault event cap: %s",
- strerror(-ret));
- return ret;
- }
+ ret = kvm_vm_enable_triple_fault_event(s);
+ if (ret < 0) {
+ return ret;
}
if (s->xen_version) {
@@ -2690,36 +3264,23 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
uname(&utsname);
lm_capable_kernel = strcmp(utsname.machine, "x86_64") == 0;
- /*
- * On older Intel CPUs, KVM uses vm86 mode to emulate 16-bit code directly.
- * In order to use vm86 mode, an EPT identity map and a TSS are needed.
- * Since these must be part of guest physical memory, we need to allocate
- * them, both by setting their start addresses in the kernel and by
- * creating a corresponding e820 entry. We need 4 pages before the BIOS,
- * so this value allows up to 16M BIOSes.
- */
- identity_base = 0xfeffc000;
- ret = kvm_vm_ioctl(s, KVM_SET_IDENTITY_MAP_ADDR, &identity_base);
+ ret = kvm_vm_set_identity_map_addr(s, KVM_IDENTITY_BASE);
if (ret < 0) {
return ret;
}
/* Set TSS base one page after EPT identity map. */
- ret = kvm_vm_ioctl(s, KVM_SET_TSS_ADDR, identity_base + 0x1000);
+ ret = kvm_vm_set_tss_addr(s, KVM_IDENTITY_BASE + 0x1000);
if (ret < 0) {
return ret;
}
/* Tell fw_cfg to notify the BIOS to reserve the range. */
- e820_add_entry(identity_base, 0x4000, E820_RESERVED);
+ e820_add_entry(KVM_IDENTITY_BASE, 0x4000, E820_RESERVED);
- shadow_mem = object_property_get_int(OBJECT(s), "kvm-shadow-mem", &error_abort);
- if (shadow_mem != -1) {
- shadow_mem /= 4096;
- ret = kvm_vm_ioctl(s, KVM_SET_NR_MMU_PAGES, shadow_mem);
- if (ret < 0) {
- return ret;
- }
+ ret = kvm_vm_set_nr_mmu_pages(s);
+ if (ret < 0) {
+ return ret;
}
if (kvm_check_extension(s, KVM_CAP_X86_SMM) &&
@@ -2730,20 +3291,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
}
if (enable_cpu_pm) {
- int disable_exits = kvm_check_extension(s, KVM_CAP_X86_DISABLE_EXITS);
-/* Work around for kernel header with a typo. TODO: fix header and drop. */
-#if defined(KVM_X86_DISABLE_EXITS_HTL) && !defined(KVM_X86_DISABLE_EXITS_HLT)
-#define KVM_X86_DISABLE_EXITS_HLT KVM_X86_DISABLE_EXITS_HTL
-#endif
- if (disable_exits) {
- disable_exits &= (KVM_X86_DISABLE_EXITS_MWAIT |
- KVM_X86_DISABLE_EXITS_HLT |
- KVM_X86_DISABLE_EXITS_PAUSE |
- KVM_X86_DISABLE_EXITS_CSTATE);
- }
-
- ret = kvm_vm_enable_cap(s, KVM_CAP_X86_DISABLE_EXITS, 0,
- disable_exits);
+ ret = kvm_vm_enable_disable_exits(s);
if (ret < 0) {
error_report("kvm: guest stopping CPU not supported: %s",
strerror(-ret));
@@ -2754,16 +3302,8 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
X86MachineState *x86ms = X86_MACHINE(ms);
if (x86ms->bus_lock_ratelimit > 0) {
- ret = kvm_check_extension(s, KVM_CAP_X86_BUS_LOCK_EXIT);
- if (!(ret & KVM_BUS_LOCK_DETECTION_EXIT)) {
- error_report("kvm: bus lock detection unsupported");
- return -ENOTSUP;
- }
- ret = kvm_vm_enable_cap(s, KVM_CAP_X86_BUS_LOCK_EXIT, 0,
- KVM_BUS_LOCK_DETECTION_EXIT);
+ ret = kvm_vm_enable_bus_lock_exit(s);
if (ret < 0) {
- error_report("kvm: Failed to enable bus lock detection cap: %s",
- strerror(-ret));
return ret;
}
ratelimit_init(&bus_lock_ratelimit_ctrl);
@@ -2772,37 +3312,25 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
}
}
- if (s->notify_vmexit != NOTIFY_VMEXIT_OPTION_DISABLE &&
- kvm_check_extension(s, KVM_CAP_X86_NOTIFY_VMEXIT)) {
- uint64_t notify_window_flags =
- ((uint64_t)s->notify_window << 32) |
- KVM_X86_NOTIFY_VMEXIT_ENABLED |
- KVM_X86_NOTIFY_VMEXIT_USER;
- ret = kvm_vm_enable_cap(s, KVM_CAP_X86_NOTIFY_VMEXIT, 0,
- notify_window_flags);
- if (ret < 0) {
- error_report("kvm: Failed to enable notify vmexit cap: %s",
- strerror(-ret));
- return ret;
- }
+ if (kvm_check_extension(s, KVM_CAP_X86_NOTIFY_VMEXIT)) {
+ ret = kvm_vm_enable_notify_vmexit(s);
+ if (ret < 0) {
+ return ret;
+ }
}
- if (kvm_vm_check_extension(s, KVM_CAP_X86_USER_SPACE_MSR)) {
- bool r;
- ret = kvm_vm_enable_cap(s, KVM_CAP_X86_USER_SPACE_MSR, 0,
- KVM_MSR_EXIT_REASON_FILTER);
- if (ret) {
- error_report("Could not enable user space MSRs: %s",
- strerror(-ret));
- exit(1);
+ if (kvm_vm_check_extension(s, KVM_CAP_X86_USER_SPACE_MSR)) {
+ ret = kvm_vm_enable_userspace_msr(s);
+ if (ret < 0) {
+ return ret;
}
- r = kvm_filter_msr(s, MSR_CORE_THREAD_COUNT,
- kvm_rdmsr_core_thread_count, NULL);
- if (!r) {
- error_report("Could not install MSR_CORE_THREAD_COUNT handler: %s",
- strerror(-ret));
- exit(1);
+ if (s->msr_energy.enable == true) {
+ kvm_vm_enable_energy_msrs(s);
+ if (kvm_msr_energy_thread_init(s, ms)) {
+ error_report("kvm : error RAPL feature requirement not met");
+ exit(1);
+ }
}
}
@@ -3265,7 +3793,14 @@ static void kvm_msr_entry_add_vmx(X86CPU *cpu, FeatureWordArray f)
kvm_msr_entry_add(cpu, MSR_IA32_VMX_CR4_FIXED0,
CR4_VMXE_MASK);
- if (f[FEAT_VMX_SECONDARY_CTLS] & VMX_SECONDARY_EXEC_TSC_SCALING) {
+ if (f[FEAT_7_1_EAX] & CPUID_7_1_EAX_FRED) {
+ /* FRED injected-event data (0x2052). */
+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_VMCS_ENUM, 0x52);
+ } else if (f[FEAT_VMX_EXIT_CTLS] &
+ VMX_VM_EXIT_ACTIVATE_SECONDARY_CONTROLS) {
+ /* Secondary VM-exit controls (0x2044). */
+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_VMCS_ENUM, 0x44);
+ } else if (f[FEAT_VMX_SECONDARY_CTLS] & VMX_SECONDARY_EXEC_TSC_SCALING) {
/* TSC multiplier (0x2032). */
kvm_msr_entry_add(cpu, MSR_IA32_VMX_VMCS_ENUM, 0x32);
} else {
@@ -3395,6 +3930,9 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
if (has_msr_virt_ssbd) {
kvm_msr_entry_add(cpu, MSR_VIRT_SSBD, env->virt_ssbd);
}
+ if (has_msr_hwcr) {
+ kvm_msr_entry_add(cpu, MSR_K7_HWCR, env->msr_hwcr);
+ }
#ifdef TARGET_X86_64
if (lm_capable_kernel) {
@@ -3495,13 +4033,11 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
kvm_msr_entry_add(cpu, HV_X64_MSR_TSC_EMULATION_STATUS,
env->msr_hv_tsc_emulation_status);
}
-#ifdef CONFIG_SYNDBG
if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNDBG) &&
has_msr_hv_syndbg_options) {
kvm_msr_entry_add(cpu, HV_X64_MSR_SYNDBG_OPTIONS,
hyperv_syndbg_query_options());
}
-#endif
}
if (hyperv_feat_enabled(cpu, HYPERV_FEAT_VAPIC)) {
kvm_msr_entry_add(cpu, HV_X64_MSR_APIC_ASSIST_PAGE,
@@ -3673,7 +4209,8 @@ static int kvm_get_xsave(X86CPU *cpu)
{
CPUX86State *env = &cpu->env;
void *xsave = env->xsave_buf;
- int type, ret;
+ unsigned long type;
+ int ret;
type = has_xsave2 ? KVM_GET_XSAVE2 : KVM_GET_XSAVE;
ret = kvm_vcpu_ioctl(CPU(cpu), type, xsave);
@@ -3878,6 +4415,9 @@ static int kvm_get_msrs(X86CPU *cpu)
kvm_msr_entry_add(cpu, MSR_IA32_TSC, 0);
env->tsc_valid = !runstate_is_running();
}
+ if (has_msr_hwcr) {
+ kvm_msr_entry_add(cpu, MSR_K7_HWCR, 0);
+ }
#ifdef TARGET_X86_64
if (lm_capable_kernel) {
@@ -4397,6 +4937,9 @@ static int kvm_get_msrs(X86CPU *cpu)
case MSR_ARCH_LBR_INFO_0 ... MSR_ARCH_LBR_INFO_0 + 31:
env->lbr_records[index - MSR_ARCH_LBR_INFO_0].info = msrs[i].data;
break;
+ case MSR_K7_HWCR:
+ env->msr_hwcr = msrs[i].data;
+ break;
}
}
@@ -4688,7 +5231,7 @@ static int kvm_get_nested_state(X86CPU *cpu)
return ret;
}
-int kvm_arch_put_registers(CPUState *cpu, int level)
+int kvm_arch_put_registers(CPUState *cpu, int level, Error **errp)
{
X86CPU *x86_cpu = X86_CPU(cpu);
int ret;
@@ -4703,6 +5246,7 @@ int kvm_arch_put_registers(CPUState *cpu, int level)
if (level >= KVM_PUT_RESET_STATE) {
ret = kvm_put_msr_feature_control(x86_cpu);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to set feature control MSR");
return ret;
}
}
@@ -4710,12 +5254,14 @@ int kvm_arch_put_registers(CPUState *cpu, int level)
/* must be before kvm_put_nested_state so that EFER.SVME is set */
ret = has_sregs2 ? kvm_put_sregs2(x86_cpu) : kvm_put_sregs(x86_cpu);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to set special registers");
return ret;
}
if (level >= KVM_PUT_RESET_STATE) {
ret = kvm_put_nested_state(x86_cpu);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to set nested state");
return ret;
}
}
@@ -4733,6 +5279,7 @@ int kvm_arch_put_registers(CPUState *cpu, int level)
if (xen_mode == XEN_EMULATE && level == KVM_PUT_FULL_STATE) {
ret = kvm_put_xen_state(cpu);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to set Xen state");
return ret;
}
}
@@ -4740,43 +5287,51 @@ int kvm_arch_put_registers(CPUState *cpu, int level)
ret = kvm_getput_regs(x86_cpu, 1);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to set general purpose registers");
return ret;
}
ret = kvm_put_xsave(x86_cpu);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to set XSAVE");
return ret;
}
ret = kvm_put_xcrs(x86_cpu);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to set XCRs");
return ret;
}
ret = kvm_put_msrs(x86_cpu, level);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to set MSRs");
return ret;
}
ret = kvm_put_vcpu_events(x86_cpu, level);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to set vCPU events");
return ret;
}
if (level >= KVM_PUT_RESET_STATE) {
ret = kvm_put_mp_state(x86_cpu);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to set MP state");
return ret;
}
}
ret = kvm_put_tscdeadline_msr(x86_cpu);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to set TSC deadline MSR");
return ret;
}
ret = kvm_put_debugregs(x86_cpu);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to set debug registers");
return ret;
}
return 0;
}
-int kvm_arch_get_registers(CPUState *cs)
+int kvm_arch_get_registers(CPUState *cs, Error **errp)
{
X86CPU *cpu = X86_CPU(cs);
int ret;
@@ -4785,6 +5340,7 @@ int kvm_arch_get_registers(CPUState *cs)
ret = kvm_get_vcpu_events(cpu);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to get vCPU events");
goto out;
}
/*
@@ -4793,44 +5349,54 @@ int kvm_arch_get_registers(CPUState *cs)
*/
ret = kvm_get_mp_state(cpu);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to get MP state");
goto out;
}
ret = kvm_getput_regs(cpu, 0);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to get general purpose registers");
goto out;
}
ret = kvm_get_xsave(cpu);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to get XSAVE");
goto out;
}
ret = kvm_get_xcrs(cpu);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to get XCRs");
goto out;
}
ret = has_sregs2 ? kvm_get_sregs2(cpu) : kvm_get_sregs(cpu);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to get special registers");
goto out;
}
ret = kvm_get_msrs(cpu);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to get MSRs");
goto out;
}
ret = kvm_get_apic(cpu);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to get APIC");
goto out;
}
ret = kvm_get_debugregs(cpu);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to get debug registers");
goto out;
}
ret = kvm_get_nested_state(cpu);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to get nested state");
goto out;
}
#ifdef CONFIG_XEN_EMU
if (xen_mode == XEN_EMULATE) {
ret = kvm_get_xen_state(cs);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to get Xen state");
goto out;
}
}
@@ -5299,7 +5865,7 @@ static bool kvm_install_msr_filters(KVMState *s)
return true;
}
-bool kvm_filter_msr(KVMState *s, uint32_t msr, QEMURDMSRHandler *rdmsr,
+static bool kvm_filter_msr(KVMState *s, uint32_t msr, QEMURDMSRHandler *rdmsr,
QEMUWRMSRHandler *wrmsr)
{
int i;
@@ -5341,7 +5907,7 @@ static int kvm_handle_rdmsr(X86CPU *cpu, struct kvm_run *run)
}
}
- assert(false);
+ g_assert_not_reached();
}
static int kvm_handle_wrmsr(X86CPU *cpu, struct kvm_run *run)
@@ -5360,7 +5926,7 @@ static int kvm_handle_wrmsr(X86CPU *cpu, struct kvm_run *run)
}
}
- assert(false);
+ g_assert_not_reached();
}
static bool has_sgx_provisioning;
diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h
index 34fc607..9de9c0d 100644
--- a/target/i386/kvm/kvm_i386.h
+++ b/target/i386/kvm/kvm_i386.h
@@ -66,17 +66,6 @@ uint64_t kvm_swizzle_msi_ext_dest_id(uint64_t address);
void kvm_update_msi_routes_all(void *private, bool global,
uint32_t index, uint32_t mask);
-typedef bool QEMURDMSRHandler(X86CPU *cpu, uint32_t msr, uint64_t *val);
-typedef bool QEMUWRMSRHandler(X86CPU *cpu, uint32_t msr, uint64_t val);
-typedef struct kvm_msr_handlers {
- uint32_t msr;
- QEMURDMSRHandler *rdmsr;
- QEMUWRMSRHandler *wrmsr;
-} KVMMSRHandlers;
-
-bool kvm_filter_msr(KVMState *s, uint32_t msr, QEMURDMSRHandler *rdmsr,
- QEMUWRMSRHandler *wrmsr);
-
#endif /* CONFIG_KVM */
void kvm_pc_setup_irq_routing(bool pci_enabled);
diff --git a/target/i386/kvm/meson.build b/target/i386/kvm/meson.build
index e785098..3996caf 100644
--- a/target/i386/kvm/meson.build
+++ b/target/i386/kvm/meson.build
@@ -3,6 +3,7 @@ i386_kvm_ss = ss.source_set()
i386_kvm_ss.add(files(
'kvm.c',
'kvm-cpu.c',
+ 'vmsr_energy.c',
))
i386_kvm_ss.add(when: 'CONFIG_XEN_EMU', if_true: files('xen-emu.c'))
diff --git a/target/i386/kvm/vmsr_energy.c b/target/i386/kvm/vmsr_energy.c
new file mode 100644
index 0000000..31508d4
--- /dev/null
+++ b/target/i386/kvm/vmsr_energy.c
@@ -0,0 +1,346 @@
+/*
+ * QEMU KVM support -- x86 virtual RAPL msr
+ *
+ * Copyright 2024 Red Hat, Inc. 2024
+ *
+ * Author:
+ * Anthony Harivel <aharivel@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/error-report.h"
+#include "vmsr_energy.h"
+#include "io/channel.h"
+#include "io/channel-socket.h"
+#include "hw/boards.h"
+#include "cpu.h"
+#include "host-cpu.h"
+
+char *vmsr_compute_default_paths(void)
+{
+ g_autofree char *state = qemu_get_local_state_dir();
+
+ return g_build_filename(state, "run", "qemu-vmsr-helper.sock", NULL);
+}
+
+bool is_host_cpu_intel(void)
+{
+ int family, model, stepping;
+ char vendor[CPUID_VENDOR_SZ + 1];
+
+ host_cpu_vendor_fms(vendor, &family, &model, &stepping);
+
+ return g_str_equal(vendor, CPUID_VENDOR_INTEL);
+}
+
+int is_rapl_enabled(void)
+{
+ const char *path = "/sys/class/powercap/intel-rapl/enabled";
+ FILE *file = fopen(path, "r");
+ int value = 0;
+
+ if (file != NULL) {
+ if (fscanf(file, "%d", &value) != 1) {
+ error_report("INTEL RAPL not enabled");
+ }
+ fclose(file);
+ } else {
+ error_report("Error opening %s", path);
+ }
+
+ return value;
+}
+
+QIOChannelSocket *vmsr_open_socket(const char *path)
+{
+ g_autofree char *socket_path = NULL;
+
+ socket_path = g_strdup(path);
+
+ SocketAddress saddr = {
+ .type = SOCKET_ADDRESS_TYPE_UNIX,
+ .u.q_unix.path = socket_path
+ };
+
+ QIOChannelSocket *sioc = qio_channel_socket_new();
+ Error *local_err = NULL;
+
+ qio_channel_set_name(QIO_CHANNEL(sioc), "vmsr-helper");
+ qio_channel_socket_connect_sync(sioc,
+ &saddr,
+ &local_err);
+ if (local_err) {
+ /* Close socket. */
+ qio_channel_close(QIO_CHANNEL(sioc), NULL);
+ object_unref(OBJECT(sioc));
+ sioc = NULL;
+ goto out;
+ }
+
+ qio_channel_set_delay(QIO_CHANNEL(sioc), false);
+out:
+ return sioc;
+}
+
+uint64_t vmsr_read_msr(uint32_t reg, uint32_t cpu_id, uint32_t tid,
+ QIOChannelSocket *sioc)
+{
+ uint64_t data = 0;
+ int r = 0;
+ Error *local_err = NULL;
+ uint32_t buffer[3];
+ /*
+ * Send the required arguments:
+ * 1. RAPL MSR register to read
+ * 2. On which CPU ID
+ * 3. From which vCPU (Thread ID)
+ */
+ buffer[0] = reg;
+ buffer[1] = cpu_id;
+ buffer[2] = tid;
+
+ r = qio_channel_write_all(QIO_CHANNEL(sioc),
+ (char *)buffer, sizeof(buffer),
+ &local_err);
+ if (r < 0) {
+ goto out_close;
+ }
+
+ r = qio_channel_read(QIO_CHANNEL(sioc),
+ (char *)&data, sizeof(data),
+ &local_err);
+ if (r < 0) {
+ data = 0;
+ goto out_close;
+ }
+
+out_close:
+ return data;
+}
+
+/* Retrieve the max number of physical package */
+unsigned int vmsr_get_max_physical_package(unsigned int max_cpus)
+{
+ const char *dir = "/sys/devices/system/cpu/";
+ const char *topo_path = "topology/physical_package_id";
+ g_autofree int *uniquePackages = g_new0(int, max_cpus);
+ unsigned int packageCount = 0;
+ FILE *file = NULL;
+
+ for (int i = 0; i < max_cpus; i++) {
+ g_autofree char *filePath = NULL;
+ g_autofree char *cpuid = g_strdup_printf("cpu%d", i);
+
+ filePath = g_build_filename(dir, cpuid, topo_path, NULL);
+
+ file = fopen(filePath, "r");
+
+ if (file == NULL) {
+ error_report("Error opening physical_package_id file");
+ return 0;
+ }
+
+ char packageId[10];
+ if (fgets(packageId, sizeof(packageId), file) == NULL) {
+ packageCount = 0;
+ }
+
+ fclose(file);
+
+ int currentPackageId = atoi(packageId);
+
+ bool isUnique = true;
+ for (int j = 0; j < packageCount; j++) {
+ if (uniquePackages[j] == currentPackageId) {
+ isUnique = false;
+ break;
+ }
+ }
+
+ if (isUnique) {
+ uniquePackages[packageCount] = currentPackageId;
+ packageCount++;
+
+ if (packageCount >= max_cpus) {
+ break;
+ }
+ }
+ }
+
+ return (packageCount == 0) ? 1 : packageCount;
+}
+
+/* Retrieve the max number of physical cpu on the host */
+unsigned int vmsr_get_maxcpus(void)
+{
+ GDir *dir;
+ const gchar *entry_name;
+ unsigned int cpu_count = 0;
+ const char *path = "/sys/devices/system/cpu/";
+
+ dir = g_dir_open(path, 0, NULL);
+ if (dir == NULL) {
+ error_report("Unable to open cpu directory");
+ return -1;
+ }
+
+ while ((entry_name = g_dir_read_name(dir)) != NULL) {
+ if (g_ascii_strncasecmp(entry_name, "cpu", 3) == 0 &&
+ isdigit(entry_name[3])) {
+ cpu_count++;
+ }
+ }
+
+ g_dir_close(dir);
+
+ return cpu_count;
+}
+
+/* Count the number of physical cpu on each packages */
+unsigned int vmsr_count_cpus_per_package(unsigned int *package_count,
+ unsigned int max_pkgs)
+{
+ g_autofree char *file_contents = NULL;
+ g_autofree char *path = NULL;
+ g_autofree char *path_name = NULL;
+ gsize length;
+
+ /* Iterate over cpus and count cpus in each package */
+ for (int cpu_id = 0; ; cpu_id++) {
+ path_name = g_strdup_printf("/sys/devices/system/cpu/cpu%d/"
+ "topology/physical_package_id", cpu_id);
+
+ path = g_build_filename(path_name, NULL);
+
+ if (!g_file_get_contents(path, &file_contents, &length, NULL)) {
+ break; /* No more cpus */
+ }
+
+ /* Get the physical package ID for this CPU */
+ int package_id = atoi(file_contents);
+
+ /* Check if the package ID is within the known number of packages */
+ if (package_id >= 0 && package_id < max_pkgs) {
+ /* If yes, count the cpu for this package*/
+ package_count[package_id]++;
+ }
+ }
+
+ return 0;
+}
+
+/* Get the physical package id from a given cpu id */
+int vmsr_get_physical_package_id(int cpu_id)
+{
+ g_autofree char *file_contents = NULL;
+ g_autofree char *file_path = NULL;
+ int package_id = -1;
+ gsize length;
+
+ file_path = g_strdup_printf("/sys/devices/system/cpu/cpu%d"
+ "/topology/physical_package_id", cpu_id);
+
+ if (!g_file_get_contents(file_path, &file_contents, &length, NULL)) {
+ goto out;
+ }
+
+ package_id = atoi(file_contents);
+
+out:
+ return package_id;
+}
+
+/* Read the scheduled time for a given thread of a give pid */
+void vmsr_read_thread_stat(pid_t pid,
+ unsigned int thread_id,
+ unsigned long long *utime,
+ unsigned long long *stime,
+ unsigned int *cpu_id)
+{
+ g_autofree char *path = NULL;
+ g_autofree char *path_name = NULL;
+
+ path_name = g_strdup_printf("/proc/%u/task/%d/stat", pid, thread_id);
+
+ path = g_build_filename(path_name, NULL);
+
+ FILE *file = fopen(path, "r");
+ if (file == NULL) {
+ error_report("Error opening %s", path_name);
+ return;
+ }
+
+ if (fscanf(file, "%*d (%*[^)]) %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u"
+ " %llu %llu %*d %*d %*d %*d %*d %*d %*u %*u %*d %*u %*u"
+ " %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %*u %*u %u",
+ utime, stime, cpu_id) != 3)
+ {
+ fclose(file);
+ error_report("Error fscanf did not report the right amount of items");
+ return;
+ }
+
+ fclose(file);
+ return;
+}
+
+/* Read QEMU stat task folder to retrieve all QEMU threads ID */
+pid_t *vmsr_get_thread_ids(pid_t pid, unsigned int *num_threads)
+{
+ g_autofree char *task_path = g_strdup_printf("%d/task", pid);
+ g_autofree char *path = g_build_filename("/proc", task_path, NULL);
+
+ DIR *dir = opendir(path);
+ if (dir == NULL) {
+ error_report("Error opening /proc/qemu/task");
+ return NULL;
+ }
+
+ pid_t *thread_ids = NULL;
+ unsigned int thread_count = 0;
+
+ g_autofree struct dirent *ent = NULL;
+ while ((ent = readdir(dir)) != NULL) {
+ if (ent->d_name[0] == '.') {
+ continue;
+ }
+ pid_t tid = atoi(ent->d_name);
+ if (pid != tid) {
+ thread_ids = g_renew(pid_t, thread_ids, (thread_count + 1));
+ thread_ids[thread_count] = tid;
+ thread_count++;
+ }
+ }
+
+ closedir(dir);
+
+ *num_threads = thread_count;
+ return thread_ids;
+}
+
+void vmsr_delta_ticks(vmsr_thread_stat *thd_stat, int i)
+{
+ thd_stat[i].delta_ticks = (thd_stat[i].utime[1] + thd_stat[i].stime[1])
+ - (thd_stat[i].utime[0] + thd_stat[i].stime[0]);
+}
+
+double vmsr_get_ratio(uint64_t e_delta,
+ unsigned long long delta_ticks,
+ unsigned int maxticks)
+{
+ return (e_delta / 100.0) * ((100.0 / maxticks) * delta_ticks);
+}
+
+void vmsr_init_topo_info(X86CPUTopoInfo *topo_info,
+ const MachineState *ms)
+{
+ topo_info->dies_per_pkg = ms->smp.dies;
+ topo_info->modules_per_die = ms->smp.modules;
+ topo_info->cores_per_module = ms->smp.cores;
+ topo_info->threads_per_core = ms->smp.threads;
+}
+
diff --git a/target/i386/kvm/vmsr_energy.h b/target/i386/kvm/vmsr_energy.h
new file mode 100644
index 0000000..16cc1f4
--- /dev/null
+++ b/target/i386/kvm/vmsr_energy.h
@@ -0,0 +1,99 @@
+/*
+ * QEMU KVM support -- x86 virtual energy-related MSR.
+ *
+ * Copyright 2024 Red Hat, Inc. 2024
+ *
+ * Author:
+ * Anthony Harivel <aharivel@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef VMSR_ENERGY_H
+#define VMSR_ENERGY_H
+
+#include <stdint.h>
+#include "qemu/osdep.h"
+#include "io/channel-socket.h"
+#include "hw/i386/topology.h"
+
+/*
+ * Define the interval time in micro seconds between 2 samples of
+ * energy related MSRs
+ */
+#define MSR_ENERGY_THREAD_SLEEP_US 1000000.0
+
+/*
+ * Thread statistic
+ * @ thread_id: TID (thread ID)
+ * @ is_vcpu: true if TID is vCPU thread
+ * @ cpu_id: CPU number last executed on
+ * @ pkg_id: package number of the CPU
+ * @ vcpu_id: vCPU ID
+ * @ vpkg: virtual package number
+ * @ acpi_id: APIC id of the vCPU
+ * @ utime: amount of clock ticks the thread
+ * has been scheduled in User mode
+ * @ stime: amount of clock ticks the thread
+ * has been scheduled in System mode
+ * @ delta_ticks: delta of utime+stime between
+ * the two samples (before/after sleep)
+ */
+struct vmsr_thread_stat {
+ unsigned int thread_id;
+ bool is_vcpu;
+ unsigned int cpu_id;
+ unsigned int pkg_id;
+ unsigned int vpkg_id;
+ unsigned int vcpu_id;
+ unsigned long acpi_id;
+ unsigned long long *utime;
+ unsigned long long *stime;
+ unsigned long long delta_ticks;
+};
+
+/*
+ * Package statistic
+ * @ e_start: package energy counter before the sleep
+ * @ e_end: package energy counter after the sleep
+ * @ e_delta: delta of package energy counter
+ * @ e_ratio: store the energy ratio of non-vCPU thread
+ * @ nb_vcpu: number of vCPU running on this package
+ */
+struct vmsr_package_energy_stat {
+ uint64_t e_start;
+ uint64_t e_end;
+ uint64_t e_delta;
+ uint64_t e_ratio;
+ unsigned int nb_vcpu;
+};
+
+typedef struct vmsr_thread_stat vmsr_thread_stat;
+typedef struct vmsr_package_energy_stat vmsr_package_energy_stat;
+
+char *vmsr_compute_default_paths(void);
+void vmsr_read_thread_stat(pid_t pid,
+ unsigned int thread_id,
+ unsigned long long *utime,
+ unsigned long long *stime,
+ unsigned int *cpu_id);
+
+QIOChannelSocket *vmsr_open_socket(const char *path);
+uint64_t vmsr_read_msr(uint32_t reg, uint32_t cpu_id,
+ uint32_t tid, QIOChannelSocket *sioc);
+void vmsr_delta_ticks(vmsr_thread_stat *thd_stat, int i);
+unsigned int vmsr_get_maxcpus(void);
+unsigned int vmsr_get_max_physical_package(unsigned int max_cpus);
+unsigned int vmsr_count_cpus_per_package(unsigned int *package_count,
+ unsigned int max_pkgs);
+int vmsr_get_physical_package_id(int cpu_id);
+pid_t *vmsr_get_thread_ids(pid_t pid, unsigned int *num_threads);
+double vmsr_get_ratio(uint64_t e_delta,
+ unsigned long long delta_ticks,
+ unsigned int maxticks);
+void vmsr_init_topo_info(X86CPUTopoInfo *topo_info, const MachineState *ms);
+bool is_host_cpu_intel(void);
+int is_rapl_enabled(void);
+#endif /* VMSR_ENERGY_H */
diff --git a/target/i386/machine.c b/target/i386/machine.c
index 39f8294..b461032 100644
--- a/target/i386/machine.c
+++ b/target/i386/machine.c
@@ -1543,6 +1543,25 @@ static const VMStateDescription vmstate_msr_xfd = {
}
};
+static bool msr_hwcr_needed(void *opaque)
+{
+ X86CPU *cpu = opaque;
+ CPUX86State *env = &cpu->env;
+
+ return env->msr_hwcr != 0;
+}
+
+static const VMStateDescription vmstate_msr_hwcr = {
+ .name = "cpu/msr_hwcr",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = msr_hwcr_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(env.msr_hwcr, X86CPU),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
#ifdef TARGET_X86_64
static bool intel_fred_msrs_needed(void *opaque)
{
@@ -1773,6 +1792,7 @@ const VMStateDescription vmstate_x86_cpu = {
&vmstate_msr_intel_sgx,
&vmstate_pdptrs,
&vmstate_msr_xfd,
+ &vmstate_msr_hwcr,
#ifdef TARGET_X86_64
&vmstate_msr_fred,
&vmstate_amx_xtile,
diff --git a/target/i386/sev.c b/target/i386/sev.c
index a1157c0..1a4eb1a 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -1883,7 +1883,7 @@ static bool build_kernel_loader_hashes(PaddedSevHashTable *padded_ht,
* be used.
*/
hashp = cmdline_hash;
- if (qcrypto_hash_bytes(QCRYPTO_HASH_ALG_SHA256, ctx->cmdline_data,
+ if (qcrypto_hash_bytes(QCRYPTO_HASH_ALGO_SHA256, ctx->cmdline_data,
ctx->cmdline_size, &hashp, &hash_len, errp) < 0) {
return false;
}
@@ -1894,7 +1894,7 @@ static bool build_kernel_loader_hashes(PaddedSevHashTable *padded_ht,
* -initrd, an empty buffer will be used (ctx->initrd_size == 0).
*/
hashp = initrd_hash;
- if (qcrypto_hash_bytes(QCRYPTO_HASH_ALG_SHA256, ctx->initrd_data,
+ if (qcrypto_hash_bytes(QCRYPTO_HASH_ALGO_SHA256, ctx->initrd_data,
ctx->initrd_size, &hashp, &hash_len, errp) < 0) {
return false;
}
@@ -1906,7 +1906,7 @@ static bool build_kernel_loader_hashes(PaddedSevHashTable *padded_ht,
{ .iov_base = ctx->setup_data, .iov_len = ctx->setup_size },
{ .iov_base = ctx->kernel_data, .iov_len = ctx->kernel_size }
};
- if (qcrypto_hash_bytesv(QCRYPTO_HASH_ALG_SHA256, iov, ARRAY_SIZE(iov),
+ if (qcrypto_hash_bytesv(QCRYPTO_HASH_ALGO_SHA256, iov, ARRAY_SIZE(iov),
&hashp, &hash_len, errp) < 0) {
return false;
}
@@ -2422,7 +2422,7 @@ sev_snp_guest_class_init(ObjectClass *oc, void *data)
object_class_property_add_bool(oc, "author-key-enabled",
sev_snp_guest_get_author_key_enabled,
sev_snp_guest_set_author_key_enabled);
- object_class_property_add_bool(oc, "vcek-required",
+ object_class_property_add_bool(oc, "vcek-disabled",
sev_snp_guest_get_vcek_disabled,
sev_snp_guest_set_vcek_disabled);
object_class_property_add_str(oc, "host-data",
diff --git a/target/i386/tcg/access.c b/target/i386/tcg/access.c
index 56a1181..e68b73a 100644
--- a/target/i386/tcg/access.c
+++ b/target/i386/tcg/access.c
@@ -58,6 +58,11 @@ static void *access_ptr(X86Access *ac, vaddr addr, unsigned len)
assert(addr >= ac->vaddr);
+ /* No haddr means probe_access wants to force slow path */
+ if (!ac->haddr1) {
+ return NULL;
+ }
+
#ifdef CONFIG_USER_ONLY
assert(offset <= ac->size1 - len);
return ac->haddr1 + offset;
@@ -78,17 +83,11 @@ static void *access_ptr(X86Access *ac, vaddr addr, unsigned len)
#endif
}
-#ifdef CONFIG_USER_ONLY
-# define test_ptr(p) true
-#else
-# define test_ptr(p) likely(p)
-#endif
-
uint8_t access_ldb(X86Access *ac, vaddr addr)
{
void *p = access_ptr(ac, addr, sizeof(uint8_t));
- if (test_ptr(p)) {
+ if (likely(p)) {
return ldub_p(p);
}
return cpu_ldub_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra);
@@ -98,7 +97,7 @@ uint16_t access_ldw(X86Access *ac, vaddr addr)
{
void *p = access_ptr(ac, addr, sizeof(uint16_t));
- if (test_ptr(p)) {
+ if (likely(p)) {
return lduw_le_p(p);
}
return cpu_lduw_le_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra);
@@ -108,7 +107,7 @@ uint32_t access_ldl(X86Access *ac, vaddr addr)
{
void *p = access_ptr(ac, addr, sizeof(uint32_t));
- if (test_ptr(p)) {
+ if (likely(p)) {
return ldl_le_p(p);
}
return cpu_ldl_le_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra);
@@ -118,7 +117,7 @@ uint64_t access_ldq(X86Access *ac, vaddr addr)
{
void *p = access_ptr(ac, addr, sizeof(uint64_t));
- if (test_ptr(p)) {
+ if (likely(p)) {
return ldq_le_p(p);
}
return cpu_ldq_le_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra);
@@ -128,7 +127,7 @@ void access_stb(X86Access *ac, vaddr addr, uint8_t val)
{
void *p = access_ptr(ac, addr, sizeof(uint8_t));
- if (test_ptr(p)) {
+ if (likely(p)) {
stb_p(p, val);
} else {
cpu_stb_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra);
@@ -139,7 +138,7 @@ void access_stw(X86Access *ac, vaddr addr, uint16_t val)
{
void *p = access_ptr(ac, addr, sizeof(uint16_t));
- if (test_ptr(p)) {
+ if (likely(p)) {
stw_le_p(p, val);
} else {
cpu_stw_le_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra);
@@ -150,7 +149,7 @@ void access_stl(X86Access *ac, vaddr addr, uint32_t val)
{
void *p = access_ptr(ac, addr, sizeof(uint32_t));
- if (test_ptr(p)) {
+ if (likely(p)) {
stl_le_p(p, val);
} else {
cpu_stl_le_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra);
@@ -161,7 +160,7 @@ void access_stq(X86Access *ac, vaddr addr, uint64_t val)
{
void *p = access_ptr(ac, addr, sizeof(uint64_t));
- if (test_ptr(p)) {
+ if (likely(p)) {
stq_le_p(p, val);
} else {
cpu_stq_le_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra);
diff --git a/target/i386/tcg/cc_helper.c b/target/i386/tcg/cc_helper.c
index 301ed95..dbddaa2 100644
--- a/target/i386/tcg/cc_helper.c
+++ b/target/i386/tcg/cc_helper.c
@@ -186,6 +186,13 @@ target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1,
case CC_OP_BMILGL:
return compute_all_bmilgl(dst, src1);
+ case CC_OP_BLSIB:
+ return compute_all_blsib(dst, src1);
+ case CC_OP_BLSIW:
+ return compute_all_blsiw(dst, src1);
+ case CC_OP_BLSIL:
+ return compute_all_blsil(dst, src1);
+
case CC_OP_ADCX:
return compute_all_adcx(dst, src1, src2);
case CC_OP_ADOX:
@@ -216,6 +223,8 @@ target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1,
return compute_all_sarq(dst, src1);
case CC_OP_BMILGQ:
return compute_all_bmilgq(dst, src1);
+ case CC_OP_BLSIQ:
+ return compute_all_blsiq(dst, src1);
#endif
}
}
@@ -308,6 +317,13 @@ target_ulong helper_cc_compute_c(target_ulong dst, target_ulong src1,
case CC_OP_BMILGL:
return compute_c_bmilgl(dst, src1);
+ case CC_OP_BLSIB:
+ return compute_c_blsib(dst, src1);
+ case CC_OP_BLSIW:
+ return compute_c_blsiw(dst, src1);
+ case CC_OP_BLSIL:
+ return compute_c_blsil(dst, src1);
+
#ifdef TARGET_X86_64
case CC_OP_ADDQ:
return compute_c_addq(dst, src1);
@@ -321,6 +337,8 @@ target_ulong helper_cc_compute_c(target_ulong dst, target_ulong src1,
return compute_c_shlq(dst, src1);
case CC_OP_BMILGQ:
return compute_c_bmilgq(dst, src1);
+ case CC_OP_BLSIQ:
+ return compute_c_blsiq(dst, src1);
#endif
}
}
diff --git a/target/i386/tcg/cc_helper_template.h.inc b/target/i386/tcg/cc_helper_template.h.inc
index bb611fe..c5425e5 100644
--- a/target/i386/tcg/cc_helper_template.h.inc
+++ b/target/i386/tcg/cc_helper_template.h.inc
@@ -235,6 +235,24 @@ static int glue(compute_c_bmilg, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
return src1 == 0;
}
+static int glue(compute_all_blsi, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
+{
+ int cf, pf, af, zf, sf, of;
+
+ cf = (src1 != 0);
+ pf = 0; /* undefined */
+ af = 0; /* undefined */
+ zf = (dst == 0) * CC_Z;
+ sf = lshift(dst, 8 - DATA_BITS) & CC_S;
+ of = 0;
+ return cf | pf | af | zf | sf | of;
+}
+
+static int glue(compute_c_blsi, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1)
+{
+ return src1 != 0;
+}
+
#undef DATA_BITS
#undef SIGN_MASK
#undef DATA_TYPE
diff --git a/target/i386/tcg/decode-new.c.inc b/target/i386/tcg/decode-new.c.inc
index d2da1d3..1f19371 100644
--- a/target/i386/tcg/decode-new.c.inc
+++ b/target/i386/tcg/decode-new.c.inc
@@ -129,6 +129,37 @@
*
* (^) these are the two cases in which Intel and AMD disagree on the
* primary exception class
+ *
+ * Instructions still in translate.c
+ * ---------------------------------
+ * Generation of TCG opcodes for almost all instructions is in emit.c.inc;
+ * this file interprets the prefixes and opcode bytes down to individual
+ * instruction mnemonics. There is only a handful of opcodes still using
+ * a switch statement to decode modrm bits 3-5 and prefixes after decoding
+ * is complete; these are relics of the older x86 decoder and their code
+ * generation is performed in translate.c.
+ *
+ * These unconverted opcodes also perform their own effective address
+ * generation using the gen_lea_modrm() function.
+ *
+ * There is nothing particularly complicated about them; simply, they don't
+ * need any nasty hacks in the decoder, and they shouldn't get in the way
+ * of the implementation of new x86 instructions, so they are left alone
+ * for the time being.
+ *
+ * x87:
+ * 0xD8 - 0xDF
+ *
+ * privileged/system:
+ * 0x0F 0x00 group 6 (SLDT, STR, LLDT, LTR, VERR, VERW)
+ * 0x0F 0x01 group 7 (SGDT, SIDT, LGDT, LIDT, SMSW, LMSW, INVLPG,
+ * MONITOR, MWAIT, CLAC, STAC, XGETBV, XSETBV,
+ * SWAPGS, RDTSCP)
+ * 0x0F 0xC7 (reg operand) group 9 (RDRAND, RDSEED, RDPID)
+ *
+ * MPX:
+ * 0x0F 0x1A BNDLDX, BNDMOV, BNDCL, BNDCU
+ * 0x0F 0x1B BNDSTX, BNDMOV, BNDMK, BNDCN
*/
#define X86_OP_NONE { 0 },
@@ -205,6 +236,7 @@
#define sextT0 .special = X86_SPECIAL_SExtT0,
#define zextT0 .special = X86_SPECIAL_ZExtT0,
#define op0_Mw .special = X86_SPECIAL_Op0_Mw,
+#define btEvGv .special = X86_SPECIAL_BitTest,
#define vex1 .vex_class = 1,
#define vex1_rep3 .vex_class = 1, .vex_special = X86_VEX_REPScalar,
@@ -269,6 +301,43 @@ static inline const X86OpEntry *decode_by_prefix(DisasContext *s, const X86OpEnt
}
}
+static void decode_group8(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b)
+{
+ static const X86GenFunc group8_gen[8] = {
+ NULL, NULL, NULL, NULL,
+ gen_BT, gen_BTS, gen_BTR, gen_BTC,
+ };
+ int op = (get_modrm(s, env) >> 3) & 7;
+ entry->gen = group8_gen[op];
+ if (op == 4) {
+ /* prevent writeback and LOCK for BT */
+ entry->op1 = entry->op0;
+ entry->op0 = X86_TYPE_None;
+ entry->s0 = X86_SIZE_None;
+ } else {
+ entry->special = X86_SPECIAL_HasLock;
+ }
+}
+
+static void decode_group9(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b)
+{
+ static const X86OpEntry group9_reg =
+ X86_OP_ENTRY0(multi0F); /* unconverted */
+ static const X86OpEntry cmpxchg8b =
+ X86_OP_ENTRY1(CMPXCHG8B, M,q, lock p_00 cpuid(CX8));
+ static const X86OpEntry cmpxchg16b =
+ X86_OP_ENTRY1(CMPXCHG16B, M,dq, lock p_00 cpuid(CX16));
+
+ int modrm = get_modrm(s, env);
+ int op = (modrm >> 3) & 7;
+
+ if ((modrm >> 6) == 3) {
+ *entry = group9_reg;
+ } else if (op == 1) {
+ *entry = REX_W(s) ? cmpxchg16b : cmpxchg8b;
+ }
+}
+
static void decode_group15(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b)
{
static const X86OpEntry group15_reg[8] = {
@@ -1073,6 +1142,8 @@ static void decode_MOV_CR_DR(DisasContext *s, CPUX86State *env, X86OpEntry *entr
}
static const X86OpEntry opcodes_0F[256] = {
+ [0x00] = X86_OP_ENTRY1(multi0F, nop,v, nolea), /* unconverted */
+ [0x01] = X86_OP_ENTRY1(multi0F, nop,v, nolea), /* unconverted */
[0x02] = X86_OP_ENTRYwr(LAR, G,v, E,w, chk(prot)),
[0x03] = X86_OP_ENTRYwr(LSL, G,v, E,w, chk(prot)),
[0x05] = X86_OP_ENTRY0(SYSCALL, chk(o64_intel)),
@@ -1162,12 +1233,14 @@ static const X86OpEntry opcodes_0F[256] = {
[0xa0] = X86_OP_ENTRYr(PUSH, FS, w),
[0xa1] = X86_OP_ENTRYw(POP, FS, w),
[0xa2] = X86_OP_ENTRY0(CPUID),
+ [0xa3] = X86_OP_ENTRYrr(BT, E,v, G,v, btEvGv),
[0xa4] = X86_OP_ENTRY4(SHLD, E,v, 2op,v, G,v),
[0xa5] = X86_OP_ENTRY3(SHLD, E,v, 2op,v, G,v),
[0xb0] = X86_OP_ENTRY2(CMPXCHG,E,b, G,b, lock),
[0xb1] = X86_OP_ENTRY2(CMPXCHG,E,v, G,v, lock),
[0xb2] = X86_OP_ENTRY3(LSS, G,v, EM,p, None, None),
+ [0xb3] = X86_OP_ENTRY2(BTR, E,v, G,v, btEvGv),
[0xb4] = X86_OP_ENTRY3(LFS, G,v, EM,p, None, None),
[0xb5] = X86_OP_ENTRY3(LGS, G,v, EM,p, None, None),
[0xb6] = X86_OP_ENTRY3(MOV, G,v, E,b, None, None, zextT0), /* MOVZX */
@@ -1180,6 +1253,7 @@ static const X86OpEntry opcodes_0F[256] = {
[0xc4] = X86_OP_ENTRY4(PINSRW, V,dq,H,dq,E,w, vex5 mmx p_00_66),
[0xc5] = X86_OP_ENTRY3(PEXTRW, G,d, U,dq,I,b, vex5 mmx p_00_66),
[0xc6] = X86_OP_ENTRY4(VSHUF, V,x, H,x, W,x, vex4 p_00_66),
+ [0xc7] = X86_OP_GROUP0(group9),
[0xd0] = X86_OP_ENTRY3(VADDSUB, V,x, H,x, W,x, vex2 cpuid(SSE3) p_66_f2),
[0xd1] = X86_OP_ENTRY3(PSRLW_r, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66),
@@ -1222,6 +1296,8 @@ static const X86OpEntry opcodes_0F[256] = {
[0x18] = X86_OP_ENTRY1(NOP, nop,v), /* prefetch/reserved NOP */
[0x19] = X86_OP_ENTRY1(NOP, nop,v), /* reserved NOP */
+ [0x1a] = X86_OP_ENTRY1(multi0F, nop,v, nolea), /* unconverted MPX */
+ [0x1b] = X86_OP_ENTRY1(multi0F, nop,v, nolea), /* unconverted MPX */
[0x1c] = X86_OP_ENTRY1(NOP, nop,v), /* reserved NOP */
[0x1d] = X86_OP_ENTRY1(NOP, nop,v), /* reserved NOP */
[0x1e] = X86_OP_ENTRY1(NOP, nop,v), /* reserved NOP */
@@ -1294,6 +1370,7 @@ static const X86OpEntry opcodes_0F[256] = {
[0xa8] = X86_OP_ENTRYr(PUSH, GS, w),
[0xa9] = X86_OP_ENTRYw(POP, GS, w),
[0xaa] = X86_OP_ENTRY0(RSM, chk(smm) svm(RSM)),
+ [0xab] = X86_OP_ENTRY2(BTS, E,v, G,v, btEvGv),
[0xac] = X86_OP_ENTRY4(SHRD, E,v, 2op,v, G,v),
[0xad] = X86_OP_ENTRY3(SHRD, E,v, 2op,v, G,v),
[0xae] = X86_OP_GROUP0(group15),
@@ -1306,6 +1383,8 @@ static const X86OpEntry opcodes_0F[256] = {
[0xb8] = X86_OP_GROUP0(0FB8),
/* decoded as modrm, which is visible as a difference between page fault and #UD */
[0xb9] = X86_OP_ENTRYr(UD, nop,v), /* UD1 */
+ [0xba] = X86_OP_GROUP2(group8, E,v, I,b),
+ [0xbb] = X86_OP_ENTRY2(BTC, E,v, G,v, btEvGv),
[0xbc] = X86_OP_GROUP0(0FBC),
[0xbd] = X86_OP_GROUP0(0FBD),
[0xbe] = X86_OP_ENTRY3(MOV, G,v, E,b, None, None, sextT0), /* MOVSX */
@@ -1627,9 +1706,9 @@ static const X86OpEntry opcodes_root[256] = {
[0xE2] = X86_OP_ENTRYr(LOOP, J,b), /* implicit: CX with aflag size */
[0xE3] = X86_OP_ENTRYr(JCXZ, J,b), /* implicit: CX with aflag size */
[0xE4] = X86_OP_ENTRYwr(IN, 0,b, I_unsigned,b), /* AL */
- [0xE5] = X86_OP_ENTRYwr(IN, 0,v, I_unsigned,b), /* AX/EAX */
+ [0xE5] = X86_OP_ENTRYwr(IN, 0,z, I_unsigned,b), /* AX/EAX */
[0xE6] = X86_OP_ENTRYrr(OUT, 0,b, I_unsigned,b), /* AL */
- [0xE7] = X86_OP_ENTRYrr(OUT, 0,v, I_unsigned,b), /* AX/EAX */
+ [0xE7] = X86_OP_ENTRYrr(OUT, 0,z, I_unsigned,b), /* AX/EAX */
[0xF1] = X86_OP_ENTRY0(INT1, svm(ICEBP)),
[0xF4] = X86_OP_ENTRY0(HLT, chk(cpl0) svm(HLT)),
@@ -1756,14 +1835,27 @@ static const X86OpEntry opcodes_root[256] = {
[0xCE] = X86_OP_ENTRY0(INTO),
[0xCF] = X86_OP_ENTRY0(IRET, chk(vm86_iopl) svm(IRET)),
+ /*
+ * x87 is nolea because it needs the address without segment base,
+ * in order to store it in fdp.
+ */
+ [0xD8] = X86_OP_ENTRY1(x87, nop,v, nolea),
+ [0xD9] = X86_OP_ENTRY1(x87, nop,v, nolea),
+ [0xDA] = X86_OP_ENTRY1(x87, nop,v, nolea),
+ [0xDB] = X86_OP_ENTRY1(x87, nop,v, nolea),
+ [0xDC] = X86_OP_ENTRY1(x87, nop,v, nolea),
+ [0xDD] = X86_OP_ENTRY1(x87, nop,v, nolea),
+ [0xDE] = X86_OP_ENTRY1(x87, nop,v, nolea),
+ [0xDF] = X86_OP_ENTRY1(x87, nop,v, nolea),
+
[0xE8] = X86_OP_ENTRYr(CALL, J,z_f64),
[0xE9] = X86_OP_ENTRYr(JMP, J,z_f64),
[0xEA] = X86_OP_ENTRYrr(JMPF, I_unsigned,p, I_unsigned,w, chk(i64)),
[0xEB] = X86_OP_ENTRYr(JMP, J,b),
[0xEC] = X86_OP_ENTRYwr(IN, 0,b, 2,w), /* AL, DX */
- [0xED] = X86_OP_ENTRYwr(IN, 0,v, 2,w), /* AX/EAX, DX */
+ [0xED] = X86_OP_ENTRYwr(IN, 0,z, 2,w), /* AX/EAX, DX */
[0xEE] = X86_OP_ENTRYrr(OUT, 0,b, 2,w), /* DX, AL */
- [0xEF] = X86_OP_ENTRYrr(OUT, 0,v, 2,w), /* DX, AX/EAX */
+ [0xEF] = X86_OP_ENTRYrr(OUT, 0,z, 2,w), /* DX, AX/EAX */
[0xF8] = X86_OP_ENTRY0(CLC),
[0xF9] = X86_OP_ENTRY0(STC),
@@ -1799,19 +1891,20 @@ static void decode_root(DisasContext *s, CPUX86State *env, X86OpEntry *entry, ui
}
-static int decode_modrm(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode,
- X86DecodedOp *op, X86OpType type)
+static int decode_modrm(DisasContext *s, CPUX86State *env,
+ X86DecodedInsn *decode, X86DecodedOp *op)
{
int modrm = get_modrm(s, env);
if ((modrm >> 6) == 3) {
op->n = (modrm & 7);
- if (type != X86_TYPE_Q && type != X86_TYPE_N) {
+ if (op->unit != X86_OP_MMX) {
op->n |= REX_B(s);
}
} else {
op->has_ea = true;
op->n = -1;
- decode->mem = gen_lea_modrm_0(env, s, get_modrm(s, env));
+ decode->mem = gen_lea_modrm_0(env, s, modrm,
+ decode->e.vex_class == 12);
}
return modrm;
}
@@ -1978,7 +2071,10 @@ static bool decode_op(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode,
op->unit = X86_OP_SSE;
}
get_reg:
- op->n = ((get_modrm(s, env) >> 3) & 7) | REX_R(s);
+ op->n = ((get_modrm(s, env) >> 3) & 7);
+ if (op->unit != X86_OP_MMX) {
+ op->n |= REX_R(s);
+ }
break;
case X86_TYPE_E: /* ALU modrm operand */
@@ -2036,7 +2132,7 @@ static bool decode_op(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode,
/* fall through */
case X86_TYPE_nop: /* modrm operand decoded but not fetched */
get_modrm:
- decode_modrm(s, env, decode, op, type);
+ decode_modrm(s, env, decode, op);
break;
case X86_TYPE_O: /* Absolute address encoded in the instruction */
@@ -2199,8 +2295,12 @@ static bool has_cpuid_feature(DisasContext *s, X86CPUIDFeature cpuid)
return (s->cpuid_features & CPUID_CMOV);
case X86_FEAT_CLFLUSH:
return (s->cpuid_features & CPUID_CLFLUSH);
+ case X86_FEAT_CX8:
+ return (s->cpuid_features & CPUID_CX8);
case X86_FEAT_FXSR:
return (s->cpuid_features & CPUID_FXSR);
+ case X86_FEAT_CX16:
+ return (s->cpuid_ext_features & CPUID_EXT_CX16);
case X86_FEAT_F16C:
return (s->cpuid_ext_features & CPUID_EXT_F16C);
case X86_FEAT_FMA:
@@ -2424,6 +2524,7 @@ static void disas_insn(DisasContext *s, CPUState *cpu)
CPUX86State *env = cpu_env(cpu);
X86DecodedInsn decode;
X86DecodeFunc decode_func = decode_root;
+ bool accept_lock = false;
uint8_t cc_live, b;
s->pc = s->base.pc_next;
@@ -2583,34 +2684,6 @@ static void disas_insn(DisasContext *s, CPUState *cpu)
}
}
- /* Go back to old decoder for unconverted opcodes. */
- if (!(s->prefix & PREFIX_VEX)) {
- if ((b & ~7) == 0xd8) {
- if (!disas_insn_x87(s, cpu, b)) {
- goto unknown_op;
- }
- return;
- }
-
- if (b == 0x0f) {
- b = x86_ldub_code(env, s);
- switch (b) {
- case 0x00 ... 0x01: /* mostly privileged instructions */
- case 0x1a ... 0x1b: /* MPX */
- case 0xa3: /* bt */
- case 0xab: /* bts */
- case 0xb3: /* btr */
- case 0xba ... 0xbb: /* grp8, btc */
- case 0xc7: /* grp9 */
- disas_insn_old(s, cpu, b + 0x100);
- return;
- default:
- decode_func = do_decode_0F;
- break;
- }
- }
- }
-
memset(&decode, 0, sizeof(decode));
decode.cc_op = -1;
decode.b = b;
@@ -2662,9 +2735,10 @@ static void disas_insn(DisasContext *s, CPUState *cpu)
if (decode.op[0].has_ea) {
s->prefix |= PREFIX_LOCK;
}
- decode.e.special = X86_SPECIAL_HasLock;
/* fallthrough */
case X86_SPECIAL_HasLock:
+ case X86_SPECIAL_BitTest:
+ accept_lock = decode.op[0].has_ea;
break;
case X86_SPECIAL_Op0_Rd:
@@ -2706,10 +2780,8 @@ static void disas_insn(DisasContext *s, CPUState *cpu)
break;
}
- if (s->prefix & PREFIX_LOCK) {
- if (decode.e.special != X86_SPECIAL_HasLock || !decode.op[0].has_ea) {
- goto illegal_op;
- }
+ if ((s->prefix & PREFIX_LOCK) && !accept_lock) {
+ goto illegal_op;
}
if (!validate_vex(s, &decode)) {
@@ -2755,9 +2827,10 @@ static void disas_insn(DisasContext *s, CPUState *cpu)
if (decode.e.special != X86_SPECIAL_NoLoadEA &&
(decode.op[0].has_ea || decode.op[1].has_ea || decode.op[2].has_ea)) {
- gen_load_ea(s, &decode.mem, decode.e.vex_class == 12);
+ gen_lea_modrm(s, &decode);
}
if (s->prefix & PREFIX_LOCK) {
+ assert(decode.op[0].has_ea && !decode.op[2].has_ea);
gen_load(s, &decode, 2, s->T1);
decode.e.gen(s, &decode);
} else {
diff --git a/target/i386/tcg/decode-new.h b/target/i386/tcg/decode-new.h
index f9bf9a6..7f23d37 100644
--- a/target/i386/tcg/decode-new.h
+++ b/target/i386/tcg/decode-new.h
@@ -114,6 +114,8 @@ typedef enum X86CPUIDFeature {
X86_FEAT_CLWB,
X86_FEAT_CMOV,
X86_FEAT_CMPCCXADD,
+ X86_FEAT_CX8,
+ X86_FEAT_CX16,
X86_FEAT_F16C,
X86_FEAT_FMA,
X86_FEAT_FSGSBASE,
@@ -190,6 +192,9 @@ typedef enum X86InsnSpecial {
/* Always locked if it has a memory operand (XCHG) */
X86_SPECIAL_Locked,
+ /* Like HasLock, but also operand 2 provides bit displacement into memory. */
+ X86_SPECIAL_BitTest,
+
/* Do not load effective address in s->A0 */
X86_SPECIAL_NoLoadEA,
@@ -261,12 +266,13 @@ typedef enum X86VEXSpecial {
typedef struct X86OpEntry X86OpEntry;
typedef struct X86DecodedInsn X86DecodedInsn;
+struct DisasContext;
/* Decode function for multibyte opcodes. */
-typedef void (*X86DecodeFunc)(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b);
+typedef void (*X86DecodeFunc)(struct DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b);
/* Code generation function. */
-typedef void (*X86GenFunc)(DisasContext *s, X86DecodedInsn *decode);
+typedef void (*X86GenFunc)(struct DisasContext *s, X86DecodedInsn *decode);
struct X86OpEntry {
/* Based on the is_decode flags. */
@@ -313,6 +319,14 @@ typedef struct X86DecodedOp {
};
} X86DecodedOp;
+typedef struct AddressParts {
+ int def_seg;
+ int base;
+ int index;
+ int scale;
+ target_long disp;
+} AddressParts;
+
struct X86DecodedInsn {
X86OpEntry e;
X86DecodedOp op[3];
@@ -330,3 +344,4 @@ struct X86DecodedInsn {
uint8_t b;
};
+static void gen_lea_modrm(struct DisasContext *s, X86DecodedInsn *decode);
diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc
index 016dce8..fd17a9b 100644
--- a/target/i386/tcg/emit.c.inc
+++ b/target/i386/tcg/emit.c.inc
@@ -33,8 +33,13 @@
#define TCG_TARGET_extract_tl_valid TCG_TARGET_extract_i32_valid
#endif
+#define MMX_OFFSET(reg) \
+ ({ assert((reg) >= 0 && (reg) <= 7); \
+ offsetof(CPUX86State, fpregs[reg].mmx); })
-#define ZMM_OFFSET(reg) offsetof(CPUX86State, xmm_regs[reg])
+#define ZMM_OFFSET(reg) \
+ ({ assert((reg) >= 0 && (reg) <= 15); \
+ offsetof(CPUX86State, xmm_regs[reg]); })
typedef void (*SSEFunc_i_ep)(TCGv_i32 val, TCGv_ptr env, TCGv_ptr reg);
typedef void (*SSEFunc_l_ep)(TCGv_i64 val, TCGv_ptr env, TCGv_ptr reg);
@@ -73,9 +78,26 @@ static void gen_NM_exception(DisasContext *s)
gen_exception(s, EXCP07_PREX);
}
-static void gen_load_ea(DisasContext *s, AddressParts *mem, bool is_vsib)
+static void gen_lea_modrm(DisasContext *s, X86DecodedInsn *decode)
{
- TCGv ea = gen_lea_modrm_1(s, *mem, is_vsib);
+ AddressParts *mem = &decode->mem;
+ TCGv ea;
+
+ ea = gen_lea_modrm_1(s, *mem, decode->e.vex_class == 12);
+ if (decode->e.special == X86_SPECIAL_BitTest) {
+ MemOp ot = decode->op[1].ot;
+ int poslen = 8 << ot;
+ int opn = decode->op[2].n;
+ TCGv ofs = tcg_temp_new();
+
+ /* Extract memory displacement from the second operand. */
+ assert(decode->op[2].unit == X86_OP_INT && decode->op[2].ot != MO_8);
+ tcg_gen_sextract_tl(ofs, cpu_regs[opn], 3, poslen - 3);
+ tcg_gen_andi_tl(ofs, ofs, -1 << ot);
+ tcg_gen_add_tl(s->A0, ea, ofs);
+ ea = s->A0;
+ }
+
gen_lea_v_seg(s, ea, mem->def_seg, s->override);
}
@@ -168,7 +190,7 @@ static int vector_elem_offset(X86DecodedOp *op, MemOp ot, int n)
static void compute_mmx_offset(X86DecodedOp *op)
{
if (!op->has_ea) {
- op->offset = offsetof(CPUX86State, fpregs[op->n].mmx) + mmx_offset(op->ot);
+ op->offset = MMX_OFFSET(op->n) + mmx_offset(op->ot);
} else {
op->offset = offsetof(CPUX86State, mmx_t0) + mmx_offset(op->ot);
}
@@ -407,6 +429,32 @@ static void prepare_update3_cc(X86DecodedInsn *decode, DisasContext *s, CCOp op,
decode->cc_op = op;
}
+/* Set up decode->cc_* to modify CF while keeping other flags unchanged. */
+static void prepare_update_cf(X86DecodedInsn *decode, DisasContext *s, TCGv cf)
+{
+ switch (s->cc_op) {
+ case CC_OP_ADOX:
+ case CC_OP_ADCOX:
+ decode->cc_src2 = cpu_cc_src2;
+ decode->cc_src = cpu_cc_src;
+ decode->cc_op = CC_OP_ADCOX;
+ break;
+
+ case CC_OP_EFLAGS:
+ case CC_OP_ADCX:
+ decode->cc_src = cpu_cc_src;
+ decode->cc_op = CC_OP_ADCX;
+ break;
+
+ default:
+ decode->cc_src = tcg_temp_new();
+ gen_mov_eflags(s, decode->cc_src);
+ decode->cc_op = CC_OP_ADCX;
+ break;
+ }
+ decode->cc_dst = cf;
+}
+
static void gen_store_sse(DisasContext *s, X86DecodedInsn *decode, int src_ofs)
{
MemOp ot = decode->op[0].ot;
@@ -1299,7 +1347,7 @@ static void gen_BLSI(DisasContext *s, X86DecodedInsn *decode)
/* input in T1, which is ready for prepare_update2_cc */
tcg_gen_neg_tl(s->T0, s->T1);
tcg_gen_and_tl(s->T0, s->T0, s->T1);
- prepare_update2_cc(decode, s, CC_OP_BMILGB + ot);
+ prepare_update2_cc(decode, s, CC_OP_BLSIB + ot);
}
static void gen_BLSMSK(DisasContext *s, X86DecodedInsn *decode)
@@ -1385,6 +1433,109 @@ static void gen_BSWAP(DisasContext *s, X86DecodedInsn *decode)
tcg_gen_bswap32_tl(s->T0, s->T0, TCG_BSWAP_OZ);
}
+static TCGv gen_bt_mask(DisasContext *s, X86DecodedInsn *decode)
+{
+ MemOp ot = decode->op[1].ot;
+ TCGv mask = tcg_temp_new();
+
+ tcg_gen_andi_tl(s->T1, s->T1, (8 << ot) - 1);
+ tcg_gen_shl_tl(mask, tcg_constant_tl(1), s->T1);
+ return mask;
+}
+
+/* Expects truncated bit index in s->T1, 1 << s->T1 in MASK. */
+static void gen_bt_flags(DisasContext *s, X86DecodedInsn *decode, TCGv src, TCGv mask)
+{
+ TCGv cf;
+
+ /*
+ * C is the result of the test, Z is unchanged, and the others
+ * are all undefined.
+ */
+ switch (s->cc_op) {
+ case CC_OP_DYNAMIC:
+ case CC_OP_CLR:
+ case CC_OP_EFLAGS:
+ case CC_OP_ADCX:
+ case CC_OP_ADOX:
+ case CC_OP_ADCOX:
+ /* Generate EFLAGS and replace the C bit. */
+ cf = tcg_temp_new();
+ tcg_gen_setcond_tl(TCG_COND_TSTNE, cf, src, mask);
+ prepare_update_cf(decode, s, cf);
+ break;
+ default:
+ /*
+ * Z was going to be computed from the non-zero status of CC_DST.
+ * We can get that same Z value (and the new C value) by leaving
+ * CC_DST alone, setting CC_SRC, and using a CC_OP_SAR of the
+ * same width.
+ */
+ decode->cc_src = tcg_temp_new();
+ decode->cc_dst = cpu_cc_dst;
+ decode->cc_op = ((s->cc_op - CC_OP_MULB) & 3) + CC_OP_SARB;
+ tcg_gen_shr_tl(decode->cc_src, src, s->T1);
+ break;
+ }
+}
+
+static void gen_BT(DisasContext *s, X86DecodedInsn *decode)
+{
+ TCGv mask = gen_bt_mask(s, decode);
+
+ gen_bt_flags(s, decode, s->T0, mask);
+}
+
+static void gen_BTC(DisasContext *s, X86DecodedInsn *decode)
+{
+ MemOp ot = decode->op[0].ot;
+ TCGv old = tcg_temp_new();
+ TCGv mask = gen_bt_mask(s, decode);
+
+ if (s->prefix & PREFIX_LOCK) {
+ tcg_gen_atomic_fetch_xor_tl(old, s->A0, mask, s->mem_index, ot | MO_LE);
+ } else {
+ tcg_gen_mov_tl(old, s->T0);
+ tcg_gen_xor_tl(s->T0, s->T0, mask);
+ }
+
+ gen_bt_flags(s, decode, old, mask);
+}
+
+static void gen_BTR(DisasContext *s, X86DecodedInsn *decode)
+{
+ MemOp ot = decode->op[0].ot;
+ TCGv old = tcg_temp_new();
+ TCGv mask = gen_bt_mask(s, decode);
+
+ if (s->prefix & PREFIX_LOCK) {
+ TCGv maskc = tcg_temp_new();
+ tcg_gen_not_tl(maskc, mask);
+ tcg_gen_atomic_fetch_and_tl(old, s->A0, maskc, s->mem_index, ot | MO_LE);
+ } else {
+ tcg_gen_mov_tl(old, s->T0);
+ tcg_gen_andc_tl(s->T0, s->T0, mask);
+ }
+
+ gen_bt_flags(s, decode, old, mask);
+}
+
+static void gen_BTS(DisasContext *s, X86DecodedInsn *decode)
+{
+ MemOp ot = decode->op[0].ot;
+ TCGv old = tcg_temp_new();
+ TCGv mask = gen_bt_mask(s, decode);
+
+ if (s->prefix & PREFIX_LOCK) {
+ tcg_gen_atomic_fetch_or_tl(old, s->A0, mask, s->mem_index, ot | MO_LE);
+ } else {
+ tcg_gen_mov_tl(old, s->T0);
+ tcg_gen_or_tl(s->T0, s->T0, mask);
+ }
+
+ gen_bt_flags(s, decode, old, mask);
+}
+
static void gen_BZHI(DisasContext *s, X86DecodedInsn *decode)
{
MemOp ot = decode->op[0].ot;
@@ -1637,6 +1788,102 @@ static void gen_CMPXCHG(DisasContext *s, X86DecodedInsn *decode)
decode->cc_op = CC_OP_SUBB + ot;
}
+static void gen_CMPXCHG16B(DisasContext *s, X86DecodedInsn *decode)
+{
+#ifdef TARGET_X86_64
+ MemOp mop = MO_TE | MO_128 | MO_ALIGN;
+ TCGv_i64 t0, t1;
+ TCGv_i128 cmp, val;
+
+ cmp = tcg_temp_new_i128();
+ val = tcg_temp_new_i128();
+ tcg_gen_concat_i64_i128(cmp, cpu_regs[R_EAX], cpu_regs[R_EDX]);
+ tcg_gen_concat_i64_i128(val, cpu_regs[R_EBX], cpu_regs[R_ECX]);
+
+ /* Only require atomic with LOCK; non-parallel handled in generator. */
+ if (s->prefix & PREFIX_LOCK) {
+ tcg_gen_atomic_cmpxchg_i128(val, s->A0, cmp, val, s->mem_index, mop);
+ } else {
+ tcg_gen_nonatomic_cmpxchg_i128(val, s->A0, cmp, val, s->mem_index, mop);
+ }
+
+ tcg_gen_extr_i128_i64(s->T0, s->T1, val);
+
+ /* Determine success after the fact. */
+ t0 = tcg_temp_new_i64();
+ t1 = tcg_temp_new_i64();
+ tcg_gen_xor_i64(t0, s->T0, cpu_regs[R_EAX]);
+ tcg_gen_xor_i64(t1, s->T1, cpu_regs[R_EDX]);
+ tcg_gen_or_i64(t0, t0, t1);
+
+ /* Update Z. */
+ gen_compute_eflags(s);
+ tcg_gen_setcondi_i64(TCG_COND_EQ, t0, t0, 0);
+ tcg_gen_deposit_tl(cpu_cc_src, cpu_cc_src, t0, ctz32(CC_Z), 1);
+
+ /*
+ * Extract the result values for the register pair. We may do this
+ * unconditionally, because on success (Z=1), the old value matches
+ * the previous value in RDX:RAX.
+ */
+ tcg_gen_mov_i64(cpu_regs[R_EAX], s->T0);
+ tcg_gen_mov_i64(cpu_regs[R_EDX], s->T1);
+#else
+ abort();
+#endif
+}
+
+static void gen_CMPXCHG8B(DisasContext *s, X86DecodedInsn *decode)
+{
+ TCGv_i64 cmp, val, old;
+ TCGv Z;
+
+ cmp = tcg_temp_new_i64();
+ val = tcg_temp_new_i64();
+ old = tcg_temp_new_i64();
+
+ /* Construct the comparison values from the register pair. */
+ tcg_gen_concat_tl_i64(cmp, cpu_regs[R_EAX], cpu_regs[R_EDX]);
+ tcg_gen_concat_tl_i64(val, cpu_regs[R_EBX], cpu_regs[R_ECX]);
+
+ /* Only require atomic with LOCK; non-parallel handled in generator. */
+ if (s->prefix & PREFIX_LOCK) {
+ tcg_gen_atomic_cmpxchg_i64(old, s->A0, cmp, val, s->mem_index, MO_TEUQ);
+ } else {
+ tcg_gen_nonatomic_cmpxchg_i64(old, s->A0, cmp, val,
+ s->mem_index, MO_TEUQ);
+ }
+
+ /* Set tmp0 to match the required value of Z. */
+ tcg_gen_setcond_i64(TCG_COND_EQ, cmp, old, cmp);
+ Z = tcg_temp_new();
+ tcg_gen_trunc_i64_tl(Z, cmp);
+
+ /*
+ * Extract the result values for the register pair.
+ * For 32-bit, we may do this unconditionally, because on success (Z=1),
+ * the old value matches the previous value in EDX:EAX. For x86_64,
+ * the store must be conditional, because we must leave the source
+ * registers unchanged on success, and zero-extend the writeback
+ * on failure (Z=0).
+ */
+ if (TARGET_LONG_BITS == 32) {
+ tcg_gen_extr_i64_tl(cpu_regs[R_EAX], cpu_regs[R_EDX], old);
+ } else {
+ TCGv zero = tcg_constant_tl(0);
+
+ tcg_gen_extr_i64_tl(s->T0, s->T1, old);
+ tcg_gen_movcond_tl(TCG_COND_EQ, cpu_regs[R_EAX], Z, zero,
+ s->T0, cpu_regs[R_EAX]);
+ tcg_gen_movcond_tl(TCG_COND_EQ, cpu_regs[R_EDX], Z, zero,
+ s->T1, cpu_regs[R_EDX]);
+ }
+
+ /* Update Z. */
+ gen_compute_eflags(s);
+ tcg_gen_deposit_tl(cpu_cc_src, cpu_cc_src, Z, ctz32(CC_Z), 1);
+}
+
static void gen_CPUID(DisasContext *s, X86DecodedInsn *decode)
{
gen_update_cc_op(s);
diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c
index aac092a..02ae6a0 100644
--- a/target/i386/tcg/seg_helper.c
+++ b/target/i386/tcg/seg_helper.c
@@ -378,7 +378,7 @@ static int switch_tss_ra(CPUX86State *env, int tss_selector,
/* X86Access avoids memory exceptions during the task switch */
mmu_index = cpu_mmu_index_kernel(env);
- access_prepare_mmu(&old, env, env->tr.base, old_tss_limit_max,
+ access_prepare_mmu(&old, env, env->tr.base, old_tss_limit_max + 1,
MMU_DATA_STORE, mmu_index, retaddr);
if (source == SWITCH_TSS_CALL) {
@@ -386,7 +386,8 @@ static int switch_tss_ra(CPUX86State *env, int tss_selector,
probe_access(env, tss_base, 2, MMU_DATA_STORE,
mmu_index, retaddr);
}
- access_prepare_mmu(&new, env, tss_base, tss_limit,
+ /* While true tss_limit may be larger, we don't access the iopb here. */
+ access_prepare_mmu(&new, env, tss_base, tss_limit_max + 1,
MMU_DATA_LOAD, mmu_index, retaddr);
/* save the current state in the old TSS */
@@ -694,7 +695,6 @@ static void do_interrupt_protected(CPUX86State *env, int intno, int is_int,
sa.env = env;
sa.ra = 0;
- sa.mmu_index = cpu_mmu_index_kernel(env);
if (type == 5) {
/* task gate */
@@ -704,7 +704,9 @@ static void do_interrupt_protected(CPUX86State *env, int intno, int is_int,
}
shift = switch_tss(env, intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip);
if (has_error_code) {
- /* push the error code */
+ /* push the error code on the destination stack */
+ cpl = env->hflags & HF_CPL_MASK;
+ sa.mmu_index = x86_mmu_index_pl(env, cpl);
if (env->segs[R_SS].flags & DESC_B_MASK) {
sa.sp_mask = 0xffffffff;
} else {
@@ -749,6 +751,7 @@ static void do_interrupt_protected(CPUX86State *env, int intno, int is_int,
if (e2 & DESC_C_MASK) {
dpl = cpl;
}
+ sa.mmu_index = x86_mmu_index_pl(env, dpl);
if (dpl < cpl) {
/* to inner privilege */
uint32_t esp;
@@ -926,7 +929,7 @@ static void do_interrupt64(CPUX86State *env, int intno, int is_int,
target_ulong ptr;
int type, dpl, selector, cpl, ist;
int has_error_code, new_stack;
- uint32_t e1, e2, e3, ss, eflags;
+ uint32_t e1, e2, e3, eflags;
target_ulong old_eip, offset;
bool set_rf;
StackAccess sa;
@@ -1000,14 +1003,13 @@ static void do_interrupt64(CPUX86State *env, int intno, int is_int,
sa.env = env;
sa.ra = 0;
- sa.mmu_index = cpu_mmu_index_kernel(env);
+ sa.mmu_index = x86_mmu_index_pl(env, dpl);
sa.sp_mask = -1;
sa.ss_base = 0;
if (dpl < cpl || ist != 0) {
/* to inner privilege */
new_stack = 1;
sa.sp = get_rsp_from_tss(env, ist != 0 ? ist + 3 : dpl);
- ss = 0;
} else {
/* to same privilege */
if (env->eflags & VM_MASK) {
@@ -1040,7 +1042,7 @@ static void do_interrupt64(CPUX86State *env, int intno, int is_int,
env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
if (new_stack) {
- ss = 0 | dpl;
+ uint32_t ss = 0 | dpl; /* SS = NULL selector with RPL = new CPL */
cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, dpl << DESC_DPL_SHIFT);
}
env->regs[R_ESP] = sa.sp;
@@ -1135,7 +1137,7 @@ static void do_interrupt_real(CPUX86State *env, int intno, int is_int,
sa.sp = env->regs[R_ESP];
sa.sp_mask = 0xffff;
sa.ss_base = env->segs[R_SS].base;
- sa.mmu_index = cpu_mmu_index_kernel(env);
+ sa.mmu_index = x86_mmu_index_pl(env, 0);
if (is_int) {
old_eip = next_eip;
@@ -1599,7 +1601,7 @@ void helper_lcall_real(CPUX86State *env, uint32_t new_cs, uint32_t new_eip,
sa.sp = env->regs[R_ESP];
sa.sp_mask = get_sp_mask(env->segs[R_SS].flags);
sa.ss_base = env->segs[R_SS].base;
- sa.mmu_index = cpu_mmu_index_kernel(env);
+ sa.mmu_index = x86_mmu_index_pl(env, 0);
if (shift) {
pushl(&sa, env->segs[R_CS].selector);
@@ -1639,9 +1641,9 @@ void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
sa.env = env;
sa.ra = GETPC();
- sa.mmu_index = cpu_mmu_index_kernel(env);
if (e2 & DESC_S_MASK) {
+ /* "normal" far call, no stack switch possible */
if (!(e2 & DESC_CS_MASK)) {
raise_exception_err_ra(env, EXCP0D_GPF, new_cs & 0xfffc, GETPC());
}
@@ -1665,6 +1667,7 @@ void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
raise_exception_err_ra(env, EXCP0B_NOSEG, new_cs & 0xfffc, GETPC());
}
+ sa.mmu_index = x86_mmu_index_pl(env, cpl);
#ifdef TARGET_X86_64
/* XXX: check 16/32 bit cases in long mode */
if (shift == 2) {
@@ -1792,6 +1795,7 @@ void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
if (!(e2 & DESC_C_MASK) && dpl < cpl) {
/* to inner privilege */
+ sa.mmu_index = x86_mmu_index_pl(env, dpl);
#ifdef TARGET_X86_64
if (shift == 2) {
ss = dpl; /* SS = NULL selector with RPL = new CPL */
@@ -1870,6 +1874,7 @@ void helper_lcall_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
new_stack = 1;
} else {
/* to same privilege */
+ sa.mmu_index = x86_mmu_index_pl(env, cpl);
sa.sp = env->regs[R_ESP];
sa.sp_mask = get_sp_mask(env->segs[R_SS].flags);
sa.ss_base = env->segs[R_SS].base;
diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c
index 8fb05b1..da187c8 100644
--- a/target/i386/tcg/sysemu/excp_helper.c
+++ b/target/i386/tcg/sysemu/excp_helper.c
@@ -60,14 +60,13 @@ typedef struct PTETranslate {
hwaddr gaddr;
} PTETranslate;
-static bool ptw_translate(PTETranslate *inout, hwaddr addr, uint64_t ra)
+static bool ptw_translate(PTETranslate *inout, hwaddr addr)
{
- CPUTLBEntryFull *full;
int flags;
inout->gaddr = addr;
- flags = probe_access_full(inout->env, addr, 0, MMU_DATA_STORE,
- inout->ptw_idx, true, &inout->haddr, &full, ra);
+ flags = probe_access_full_mmu(inout->env, addr, 0, MMU_DATA_STORE,
+ inout->ptw_idx, &inout->haddr, NULL);
if (unlikely(flags & TLB_INVALID_MASK)) {
TranslateFault *err = inout->err;
@@ -150,6 +149,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
uint32_t pkr;
int page_size;
int error_code;
+ int prot;
restart_all:
rsvd_mask = ~MAKE_64BIT_MASK(0, env_archcpu(env)->phys_bits);
@@ -166,7 +166,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
* Page table level 5
*/
pte_addr = (in->cr3 & ~0xfff) + (((addr >> 48) & 0x1ff) << 3);
- if (!ptw_translate(&pte_trans, pte_addr, ra)) {
+ if (!ptw_translate(&pte_trans, pte_addr)) {
return false;
}
restart_5:
@@ -190,7 +190,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
* Page table level 4
*/
pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 39) & 0x1ff) << 3);
- if (!ptw_translate(&pte_trans, pte_addr, ra)) {
+ if (!ptw_translate(&pte_trans, pte_addr)) {
return false;
}
restart_4:
@@ -210,7 +210,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
* Page table level 3
*/
pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3);
- if (!ptw_translate(&pte_trans, pte_addr, ra)) {
+ if (!ptw_translate(&pte_trans, pte_addr)) {
return false;
}
restart_3_lma:
@@ -237,7 +237,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
* Page table level 3
*/
pte_addr = (in->cr3 & 0xffffffe0ULL) + ((addr >> 27) & 0x18);
- if (!ptw_translate(&pte_trans, pte_addr, ra)) {
+ if (!ptw_translate(&pte_trans, pte_addr)) {
return false;
}
rsvd_mask |= PG_HI_USER_MASK;
@@ -259,7 +259,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
* Page table level 2
*/
pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3);
- if (!ptw_translate(&pte_trans, pte_addr, ra)) {
+ if (!ptw_translate(&pte_trans, pte_addr)) {
return false;
}
restart_2_pae:
@@ -285,7 +285,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
* Page table level 1
*/
pte_addr = (pte & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3);
- if (!ptw_translate(&pte_trans, pte_addr, ra)) {
+ if (!ptw_translate(&pte_trans, pte_addr)) {
return false;
}
pte = ptw_ldq(&pte_trans, ra);
@@ -298,12 +298,12 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
/* combine pde and pte nx, user and rw protections */
ptep &= pte ^ PG_NX_MASK;
page_size = 4096;
- } else {
+ } else if (pg_mode) {
/*
* Page table level 2
*/
pte_addr = (in->cr3 & 0xfffff000ULL) + ((addr >> 20) & 0xffc);
- if (!ptw_translate(&pte_trans, pte_addr, ra)) {
+ if (!ptw_translate(&pte_trans, pte_addr)) {
return false;
}
restart_2_nopae:
@@ -332,7 +332,7 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
* Page table level 1
*/
pte_addr = (pte & ~0xfffu) + ((addr >> 10) & 0xffc);
- if (!ptw_translate(&pte_trans, pte_addr, ra)) {
+ if (!ptw_translate(&pte_trans, pte_addr)) {
return false;
}
pte = ptw_ldl(&pte_trans, ra);
@@ -343,6 +343,15 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
ptep &= pte | PG_NX_MASK;
page_size = 4096;
rsvd_mask = 0;
+ } else {
+ /*
+ * No paging (real mode), let's tentatively resolve the address as 1:1
+ * here, but conditionally still perform an NPT walk on it later.
+ */
+ page_size = 0x40000000;
+ paddr = in->addr;
+ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ goto stage2;
}
do_check_protect:
@@ -358,7 +367,7 @@ do_check_protect_pse36:
goto do_fault_protect;
}
- int prot = 0;
+ prot = 0;
if (!is_mmu_index_smap(in->mmu_idx) || !(ptep & PG_USER_MASK)) {
prot |= PAGE_READ;
if ((ptep & PG_RW_MASK) || !(is_user || (pg_mode & PG_MODE_WP))) {
@@ -420,6 +429,7 @@ do_check_protect_pse36:
/* merge offset within page */
paddr = (pte & PG_ADDRESS_MASK & ~(page_size - 1)) | (addr & (page_size - 1));
+ stage2:
/*
* Note that NPT is walked (for both paging structures and final guest
@@ -429,9 +439,8 @@ do_check_protect_pse36:
CPUTLBEntryFull *full;
int flags, nested_page_size;
- flags = probe_access_full(env, paddr, 0, access_type,
- MMU_NESTED_IDX, true,
- &pte_trans.haddr, &full, 0);
+ flags = probe_access_full_mmu(env, paddr, 0, access_type,
+ MMU_NESTED_IDX, &pte_trans.haddr, &full);
if (unlikely(flags & TLB_INVALID_MASK)) {
*err = (TranslateFault){
.error_code = env->error_code,
@@ -562,7 +571,7 @@ static bool get_physical_address(CPUX86State *env, vaddr addr,
addr = (uint32_t)addr;
}
- if (likely(env->cr[0] & CR0_PG_MASK)) {
+ if (likely(env->cr[0] & CR0_PG_MASK || use_stage2)) {
in.cr3 = env->cr[3];
in.mmu_idx = mmu_idx;
in.ptw_idx = use_stage2 ? MMU_NESTED_IDX : MMU_PHYS_IDX;
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 95bad55..ef19041 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -29,6 +29,7 @@
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
#include "helper-tcg.h"
+#include "decode-new.h"
#include "exec/log.h"
@@ -304,6 +305,7 @@ static const uint8_t cc_op_live[CC_OP_NB] = {
[CC_OP_SHLB ... CC_OP_SHLQ] = USES_CC_DST | USES_CC_SRC,
[CC_OP_SARB ... CC_OP_SARQ] = USES_CC_DST | USES_CC_SRC,
[CC_OP_BMILGB ... CC_OP_BMILGQ] = USES_CC_DST | USES_CC_SRC,
+ [CC_OP_BLSIB ... CC_OP_BLSIQ] = USES_CC_DST | USES_CC_SRC,
[CC_OP_ADCX] = USES_CC_DST | USES_CC_SRC,
[CC_OP_ADOX] = USES_CC_SRC | USES_CC_SRC2,
[CC_OP_ADCOX] = USES_CC_DST | USES_CC_SRC | USES_CC_SRC2,
@@ -692,11 +694,6 @@ static TCGv gen_ext_tl(TCGv dst, TCGv src, MemOp size, bool sign)
return dst;
}
-static void gen_exts(MemOp ot, TCGv reg)
-{
- gen_ext_tl(reg, reg, ot, true);
-}
-
static void gen_op_j_ecx(DisasContext *s, TCGCond cond, TCGLabel *label1)
{
TCGv tmp = gen_ext_tl(NULL, cpu_regs[R_ECX], s->aflag, false);
@@ -865,6 +862,18 @@ static CCPrepare gen_prepare_sign_nz(TCGv src, MemOp size)
}
}
+static CCPrepare gen_prepare_val_nz(TCGv src, MemOp size, bool eqz)
+{
+ if (size == MO_TL) {
+ return (CCPrepare) { .cond = eqz ? TCG_COND_EQ : TCG_COND_NE,
+ .reg = src };
+ } else {
+ return (CCPrepare) { .cond = eqz ? TCG_COND_TSTEQ : TCG_COND_TSTNE,
+ .imm = MAKE_64BIT_MASK(0, 8 << size),
+ .reg = src };
+ }
+}
+
/* compute eflags.C, trying to store it in reg if not NULL */
static CCPrepare gen_prepare_eflags_c(DisasContext *s, TCGv reg)
{
@@ -908,8 +917,11 @@ static CCPrepare gen_prepare_eflags_c(DisasContext *s, TCGv reg)
case CC_OP_BMILGB ... CC_OP_BMILGQ:
size = s->cc_op - CC_OP_BMILGB;
- gen_ext_tl(cpu_cc_src, cpu_cc_src, size, false);
- return (CCPrepare) { .cond = TCG_COND_EQ, .reg = cpu_cc_src };
+ return gen_prepare_val_nz(cpu_cc_src, size, true);
+
+ case CC_OP_BLSIB ... CC_OP_BLSIQ:
+ size = s->cc_op - CC_OP_BLSIB;
+ return gen_prepare_val_nz(cpu_cc_src, size, false);
case CC_OP_ADCX:
case CC_OP_ADCOX:
@@ -1006,12 +1018,7 @@ static CCPrepare gen_prepare_eflags_z(DisasContext *s, TCGv reg)
default:
{
MemOp size = (s->cc_op - CC_OP_ADDB) & 3;
- if (size == MO_TL) {
- return (CCPrepare) { .cond = TCG_COND_EQ, .reg = cpu_cc_dst };
- } else {
- return (CCPrepare) { .cond = TCG_COND_TSTEQ, .reg = cpu_cc_dst,
- .imm = (1ull << (8 << size)) - 1 };
- }
+ return gen_prepare_val_nz(cpu_cc_dst, size, true);
}
}
}
@@ -1514,16 +1521,8 @@ static inline uint64_t x86_ldq_code(CPUX86State *env, DisasContext *s)
/* Decompose an address. */
-typedef struct AddressParts {
- int def_seg;
- int base;
- int index;
- int scale;
- target_long disp;
-} AddressParts;
-
static AddressParts gen_lea_modrm_0(CPUX86State *env, DisasContext *s,
- int modrm)
+ int modrm, bool is_vsib)
{
int def_seg, base, index, scale, mod, rm;
target_long disp;
@@ -1552,7 +1551,7 @@ static AddressParts gen_lea_modrm_0(CPUX86State *env, DisasContext *s,
int code = x86_ldub_code(env, s);
scale = (code >> 6) & 3;
index = ((code >> 3) & 7) | REX_X(s);
- if (index == 4) {
+ if (index == 4 && !is_vsib) {
index = -1; /* no index */
}
base = (code & 7) | REX_B(s);
@@ -1680,24 +1679,11 @@ static TCGv gen_lea_modrm_1(DisasContext *s, AddressParts a, bool is_vsib)
return ea;
}
-static void gen_lea_modrm(CPUX86State *env, DisasContext *s, int modrm)
-{
- AddressParts a = gen_lea_modrm_0(env, s, modrm);
- TCGv ea = gen_lea_modrm_1(s, a, false);
- gen_lea_v_seg(s, ea, a.def_seg, s->override);
-}
-
-static void gen_nop_modrm(CPUX86State *env, DisasContext *s, int modrm)
-{
- (void)gen_lea_modrm_0(env, s, modrm);
-}
-
/* Used for BNDCL, BNDCU, BNDCN. */
-static void gen_bndck(CPUX86State *env, DisasContext *s, int modrm,
+static void gen_bndck(DisasContext *s, X86DecodedInsn *decode,
TCGCond cond, TCGv_i64 bndv)
{
- AddressParts a = gen_lea_modrm_0(env, s, modrm);
- TCGv ea = gen_lea_modrm_1(s, a, false);
+ TCGv ea = gen_lea_modrm_1(s, decode->mem, false);
tcg_gen_extu_tl_i64(s->tmp1_i64, ea);
if (!CODE64(s)) {
@@ -1709,8 +1695,9 @@ static void gen_bndck(CPUX86State *env, DisasContext *s, int modrm,
}
/* generate modrm load of memory or register. */
-static void gen_ld_modrm(CPUX86State *env, DisasContext *s, int modrm, MemOp ot)
+static void gen_ld_modrm(DisasContext *s, X86DecodedInsn *decode, MemOp ot)
{
+ int modrm = s->modrm;
int mod, rm;
mod = (modrm >> 6) & 3;
@@ -1718,14 +1705,15 @@ static void gen_ld_modrm(CPUX86State *env, DisasContext *s, int modrm, MemOp ot)
if (mod == 3) {
gen_op_mov_v_reg(s, ot, s->T0, rm);
} else {
- gen_lea_modrm(env, s, modrm);
+ gen_lea_modrm(s, decode);
gen_op_ld_v(s, ot, s->T0, s->A0);
}
}
/* generate modrm store of memory or register. */
-static void gen_st_modrm(CPUX86State *env, DisasContext *s, int modrm, MemOp ot)
+static void gen_st_modrm(DisasContext *s, X86DecodedInsn *decode, MemOp ot)
{
+ int modrm = s->modrm;
int mod, rm;
mod = (modrm >> 6) & 3;
@@ -1733,7 +1721,7 @@ static void gen_st_modrm(CPUX86State *env, DisasContext *s, int modrm, MemOp ot)
if (mod == 3) {
gen_op_mov_reg_v(s, ot, rm, s->T0);
} else {
- gen_lea_modrm(env, s, modrm);
+ gen_lea_modrm(s, decode);
gen_op_st_v(s, ot, s->T0, s->A0);
}
}
@@ -2301,129 +2289,32 @@ static void gen_sty_env_A0(DisasContext *s, int offset, bool align)
tcg_gen_qemu_st_i128(t, s->tmp0, mem_index, mop);
}
-static void gen_cmpxchg8b(DisasContext *s, CPUX86State *env, int modrm)
-{
- TCGv_i64 cmp, val, old;
- TCGv Z;
-
- gen_lea_modrm(env, s, modrm);
-
- cmp = tcg_temp_new_i64();
- val = tcg_temp_new_i64();
- old = tcg_temp_new_i64();
-
- /* Construct the comparison values from the register pair. */
- tcg_gen_concat_tl_i64(cmp, cpu_regs[R_EAX], cpu_regs[R_EDX]);
- tcg_gen_concat_tl_i64(val, cpu_regs[R_EBX], cpu_regs[R_ECX]);
-
- /* Only require atomic with LOCK; non-parallel handled in generator. */
- if (s->prefix & PREFIX_LOCK) {
- tcg_gen_atomic_cmpxchg_i64(old, s->A0, cmp, val, s->mem_index, MO_TEUQ);
- } else {
- tcg_gen_nonatomic_cmpxchg_i64(old, s->A0, cmp, val,
- s->mem_index, MO_TEUQ);
- }
-
- /* Set tmp0 to match the required value of Z. */
- tcg_gen_setcond_i64(TCG_COND_EQ, cmp, old, cmp);
- Z = tcg_temp_new();
- tcg_gen_trunc_i64_tl(Z, cmp);
-
- /*
- * Extract the result values for the register pair.
- * For 32-bit, we may do this unconditionally, because on success (Z=1),
- * the old value matches the previous value in EDX:EAX. For x86_64,
- * the store must be conditional, because we must leave the source
- * registers unchanged on success, and zero-extend the writeback
- * on failure (Z=0).
- */
- if (TARGET_LONG_BITS == 32) {
- tcg_gen_extr_i64_tl(cpu_regs[R_EAX], cpu_regs[R_EDX], old);
- } else {
- TCGv zero = tcg_constant_tl(0);
-
- tcg_gen_extr_i64_tl(s->T0, s->T1, old);
- tcg_gen_movcond_tl(TCG_COND_EQ, cpu_regs[R_EAX], Z, zero,
- s->T0, cpu_regs[R_EAX]);
- tcg_gen_movcond_tl(TCG_COND_EQ, cpu_regs[R_EDX], Z, zero,
- s->T1, cpu_regs[R_EDX]);
- }
-
- /* Update Z. */
- gen_compute_eflags(s);
- tcg_gen_deposit_tl(cpu_cc_src, cpu_cc_src, Z, ctz32(CC_Z), 1);
-}
-
-#ifdef TARGET_X86_64
-static void gen_cmpxchg16b(DisasContext *s, CPUX86State *env, int modrm)
-{
- MemOp mop = MO_TE | MO_128 | MO_ALIGN;
- TCGv_i64 t0, t1;
- TCGv_i128 cmp, val;
-
- gen_lea_modrm(env, s, modrm);
-
- cmp = tcg_temp_new_i128();
- val = tcg_temp_new_i128();
- tcg_gen_concat_i64_i128(cmp, cpu_regs[R_EAX], cpu_regs[R_EDX]);
- tcg_gen_concat_i64_i128(val, cpu_regs[R_EBX], cpu_regs[R_ECX]);
-
- /* Only require atomic with LOCK; non-parallel handled in generator. */
- if (s->prefix & PREFIX_LOCK) {
- tcg_gen_atomic_cmpxchg_i128(val, s->A0, cmp, val, s->mem_index, mop);
- } else {
- tcg_gen_nonatomic_cmpxchg_i128(val, s->A0, cmp, val, s->mem_index, mop);
- }
-
- tcg_gen_extr_i128_i64(s->T0, s->T1, val);
-
- /* Determine success after the fact. */
- t0 = tcg_temp_new_i64();
- t1 = tcg_temp_new_i64();
- tcg_gen_xor_i64(t0, s->T0, cpu_regs[R_EAX]);
- tcg_gen_xor_i64(t1, s->T1, cpu_regs[R_EDX]);
- tcg_gen_or_i64(t0, t0, t1);
-
- /* Update Z. */
- gen_compute_eflags(s);
- tcg_gen_setcondi_i64(TCG_COND_EQ, t0, t0, 0);
- tcg_gen_deposit_tl(cpu_cc_src, cpu_cc_src, t0, ctz32(CC_Z), 1);
-
- /*
- * Extract the result values for the register pair. We may do this
- * unconditionally, because on success (Z=1), the old value matches
- * the previous value in RDX:RAX.
- */
- tcg_gen_mov_i64(cpu_regs[R_EAX], s->T0);
- tcg_gen_mov_i64(cpu_regs[R_EDX], s->T1);
-}
-#endif
+#include "emit.c.inc"
-static bool disas_insn_x87(DisasContext *s, CPUState *cpu, int b)
+static void gen_x87(DisasContext *s, X86DecodedInsn *decode)
{
- CPUX86State *env = cpu_env(cpu);
bool update_fip = true;
- int modrm, mod, rm, op;
+ int b = decode->b;
+ int modrm = s->modrm;
+ int mod, rm, op;
if (s->flags & (HF_EM_MASK | HF_TS_MASK)) {
/* if CR0.EM or CR0.TS are set, generate an FPU exception */
/* XXX: what to do if illegal op ? */
gen_exception(s, EXCP07_PREX);
- return true;
+ return;
}
- modrm = x86_ldub_code(env, s);
mod = (modrm >> 6) & 3;
rm = modrm & 7;
op = ((b & 7) << 3) | ((modrm >> 3) & 7);
if (mod != 3) {
/* memory op */
- AddressParts a = gen_lea_modrm_0(env, s, modrm);
- TCGv ea = gen_lea_modrm_1(s, a, false);
+ TCGv ea = gen_lea_modrm_1(s, decode->mem, false);
TCGv last_addr = tcg_temp_new();
bool update_fdp = true;
tcg_gen_mov_tl(last_addr, ea);
- gen_lea_v_seg(s, ea, a.def_seg, s->override);
+ gen_lea_v_seg(s, ea, decode->mem.def_seg, s->override);
switch (op) {
case 0x00 ... 0x07: /* fxxxs */
@@ -2613,11 +2504,11 @@ static bool disas_insn_x87(DisasContext *s, CPUState *cpu, int b)
gen_helper_fpop(tcg_env);
break;
default:
- return false;
+ goto illegal_op;
}
if (update_fdp) {
- int last_seg = s->override >= 0 ? s->override : a.def_seg;
+ int last_seg = s->override >= 0 ? s->override : decode->mem.def_seg;
tcg_gen_ld_i32(s->tmp2_i32, tcg_env,
offsetof(CPUX86State,
@@ -2654,7 +2545,7 @@ static bool disas_insn_x87(DisasContext *s, CPUState *cpu, int b)
update_fip = false;
break;
default:
- return false;
+ goto illegal_op;
}
break;
case 0x0c: /* grp d9/4 */
@@ -2673,7 +2564,7 @@ static bool disas_insn_x87(DisasContext *s, CPUState *cpu, int b)
gen_helper_fxam_ST0(tcg_env);
break;
default:
- return false;
+ goto illegal_op;
}
break;
case 0x0d: /* grp d9/5 */
@@ -2708,7 +2599,7 @@ static bool disas_insn_x87(DisasContext *s, CPUState *cpu, int b)
gen_helper_fldz_ST0(tcg_env);
break;
default:
- return false;
+ goto illegal_op;
}
}
break;
@@ -2810,7 +2701,7 @@ static bool disas_insn_x87(DisasContext *s, CPUState *cpu, int b)
gen_helper_fpop(tcg_env);
break;
default:
- return false;
+ goto illegal_op;
}
break;
case 0x1c:
@@ -2830,7 +2721,7 @@ static bool disas_insn_x87(DisasContext *s, CPUState *cpu, int b)
case 4: /* fsetpm (287 only, just do nop here) */
break;
default:
- return false;
+ goto illegal_op;
}
break;
case 0x1d: /* fucomi */
@@ -2882,7 +2773,7 @@ static bool disas_insn_x87(DisasContext *s, CPUState *cpu, int b)
gen_helper_fpop(tcg_env);
break;
default:
- return false;
+ goto illegal_op;
}
break;
case 0x38: /* ffreep sti, undocumented op */
@@ -2897,7 +2788,7 @@ static bool disas_insn_x87(DisasContext *s, CPUState *cpu, int b)
gen_op_mov_reg_v(s, MO_16, R_EAX, s->T0);
break;
default:
- return false;
+ goto illegal_op;
}
break;
case 0x3d: /* fucomip */
@@ -2944,7 +2835,7 @@ static bool disas_insn_x87(DisasContext *s, CPUState *cpu, int b)
}
break;
default:
- return false;
+ goto illegal_op;
}
}
@@ -2956,49 +2847,29 @@ static bool disas_insn_x87(DisasContext *s, CPUState *cpu, int b)
tcg_gen_st_tl(eip_cur_tl(s),
tcg_env, offsetof(CPUX86State, fpip));
}
- return true;
+ return;
illegal_op:
gen_illegal_opcode(s);
- return true;
}
-static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
+static void gen_multi0F(DisasContext *s, X86DecodedInsn *decode)
{
- CPUX86State *env = cpu_env(cpu);
int prefixes = s->prefix;
MemOp dflag = s->dflag;
+ int b = decode->b + 0x100;
+ int modrm = s->modrm;
MemOp ot;
- int modrm, reg, rm, mod, op, val;
+ int reg, rm, mod, op;
/* now check op code */
switch (b) {
- case 0x1c7: /* cmpxchg8b */
- modrm = x86_ldub_code(env, s);
+ case 0x1c7: /* RDSEED, RDPID with f3 prefix */
mod = (modrm >> 6) & 3;
switch ((modrm >> 3) & 7) {
- case 1: /* CMPXCHG8, CMPXCHG16 */
- if (mod == 3) {
- goto illegal_op;
- }
-#ifdef TARGET_X86_64
- if (dflag == MO_64) {
- if (!(s->cpuid_ext_features & CPUID_EXT_CX16)) {
- goto illegal_op;
- }
- gen_cmpxchg16b(s, env, modrm);
- break;
- }
-#endif
- if (!(s->cpuid_features & CPUID_CX8)) {
- goto illegal_op;
- }
- gen_cmpxchg8b(s, env, modrm);
- break;
-
- case 7: /* RDSEED, RDPID with f3 prefix */
+ case 7:
if (mod != 3 ||
- (s->prefix & (PREFIX_LOCK | PREFIX_REPNZ))) {
+ (s->prefix & PREFIX_REPNZ)) {
goto illegal_op;
}
if (s->prefix & PREFIX_REPZ) {
@@ -3018,7 +2889,7 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
case 6: /* RDRAND */
if (mod != 3 ||
- (s->prefix & (PREFIX_LOCK | PREFIX_REPZ | PREFIX_REPNZ)) ||
+ (s->prefix & (PREFIX_REPZ | PREFIX_REPNZ)) ||
!(s->cpuid_ext_features & CPUID_EXT_RDRAND)) {
goto illegal_op;
}
@@ -3035,148 +2906,7 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
}
break;
- /************************/
- /* bit operations */
- case 0x1ba: /* bt/bts/btr/btc Gv, im */
- ot = dflag;
- modrm = x86_ldub_code(env, s);
- op = (modrm >> 3) & 7;
- mod = (modrm >> 6) & 3;
- rm = (modrm & 7) | REX_B(s);
- if (mod != 3) {
- s->rip_offset = 1;
- gen_lea_modrm(env, s, modrm);
- if (!(s->prefix & PREFIX_LOCK)) {
- gen_op_ld_v(s, ot, s->T0, s->A0);
- }
- } else {
- gen_op_mov_v_reg(s, ot, s->T0, rm);
- }
- /* load shift */
- val = x86_ldub_code(env, s);
- tcg_gen_movi_tl(s->T1, val);
- if (op < 4)
- goto unknown_op;
- op -= 4;
- goto bt_op;
- case 0x1a3: /* bt Gv, Ev */
- op = 0;
- goto do_btx;
- case 0x1ab: /* bts */
- op = 1;
- goto do_btx;
- case 0x1b3: /* btr */
- op = 2;
- goto do_btx;
- case 0x1bb: /* btc */
- op = 3;
- do_btx:
- ot = dflag;
- modrm = x86_ldub_code(env, s);
- 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);
- if (mod != 3) {
- AddressParts a = gen_lea_modrm_0(env, s, modrm);
- /* specific case: we need to add a displacement */
- gen_exts(ot, s->T1);
- tcg_gen_sari_tl(s->tmp0, s->T1, 3 + ot);
- tcg_gen_shli_tl(s->tmp0, s->tmp0, ot);
- tcg_gen_add_tl(s->A0, gen_lea_modrm_1(s, a, false), s->tmp0);
- gen_lea_v_seg(s, s->A0, a.def_seg, s->override);
- if (!(s->prefix & PREFIX_LOCK)) {
- gen_op_ld_v(s, ot, s->T0, s->A0);
- }
- } else {
- gen_op_mov_v_reg(s, ot, s->T0, rm);
- }
- bt_op:
- tcg_gen_andi_tl(s->T1, s->T1, (1 << (3 + ot)) - 1);
- tcg_gen_movi_tl(s->tmp0, 1);
- tcg_gen_shl_tl(s->tmp0, s->tmp0, s->T1);
- if (s->prefix & PREFIX_LOCK) {
- switch (op) {
- case 0: /* bt */
- /* Needs no atomic ops; we suppressed the normal
- memory load for LOCK above so do it now. */
- gen_op_ld_v(s, ot, s->T0, s->A0);
- break;
- case 1: /* bts */
- tcg_gen_atomic_fetch_or_tl(s->T0, s->A0, s->tmp0,
- s->mem_index, ot | MO_LE);
- break;
- case 2: /* btr */
- tcg_gen_not_tl(s->tmp0, s->tmp0);
- tcg_gen_atomic_fetch_and_tl(s->T0, s->A0, s->tmp0,
- s->mem_index, ot | MO_LE);
- break;
- default:
- case 3: /* btc */
- tcg_gen_atomic_fetch_xor_tl(s->T0, s->A0, s->tmp0,
- s->mem_index, ot | MO_LE);
- break;
- }
- tcg_gen_shr_tl(s->tmp4, s->T0, s->T1);
- } else {
- tcg_gen_shr_tl(s->tmp4, s->T0, s->T1);
- switch (op) {
- case 0: /* bt */
- /* Data already loaded; nothing to do. */
- break;
- case 1: /* bts */
- tcg_gen_or_tl(s->T0, s->T0, s->tmp0);
- break;
- case 2: /* btr */
- tcg_gen_andc_tl(s->T0, s->T0, s->tmp0);
- break;
- default:
- case 3: /* btc */
- tcg_gen_xor_tl(s->T0, s->T0, s->tmp0);
- break;
- }
- if (op != 0) {
- if (mod != 3) {
- gen_op_st_v(s, ot, s->T0, s->A0);
- } else {
- gen_op_mov_reg_v(s, ot, rm, s->T0);
- }
- }
- }
-
- /* Delay all CC updates until after the store above. Note that
- C is the result of the test, Z is unchanged, and the others
- are all undefined. */
- switch (s->cc_op) {
- case CC_OP_MULB ... CC_OP_MULQ:
- case CC_OP_ADDB ... CC_OP_ADDQ:
- case CC_OP_ADCB ... CC_OP_ADCQ:
- case CC_OP_SUBB ... CC_OP_SUBQ:
- case CC_OP_SBBB ... CC_OP_SBBQ:
- case CC_OP_LOGICB ... CC_OP_LOGICQ:
- case CC_OP_INCB ... CC_OP_INCQ:
- case CC_OP_DECB ... CC_OP_DECQ:
- case CC_OP_SHLB ... CC_OP_SHLQ:
- case CC_OP_SARB ... CC_OP_SARQ:
- case CC_OP_BMILGB ... CC_OP_BMILGQ:
- case CC_OP_POPCNT:
- /* Z was going to be computed from the non-zero status of CC_DST.
- We can get that same Z value (and the new C value) by leaving
- CC_DST alone, setting CC_SRC, and using a CC_OP_SAR of the
- same width. */
- tcg_gen_mov_tl(cpu_cc_src, s->tmp4);
- set_cc_op(s, ((s->cc_op - CC_OP_MULB) & 3) + CC_OP_SARB);
- break;
- default:
- /* Otherwise, generate EFLAGS and replace the C bit. */
- gen_compute_eflags(s);
- tcg_gen_deposit_tl(cpu_cc_src, cpu_cc_src, s->tmp4,
- ctz32(CC_C), 1);
- break;
- }
- break;
case 0x100:
- modrm = x86_ldub_code(env, s);
mod = (modrm >> 6) & 3;
op = (modrm >> 3) & 7;
switch(op) {
@@ -3190,14 +2920,14 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
tcg_gen_ld32u_tl(s->T0, tcg_env,
offsetof(CPUX86State, ldt.selector));
ot = mod == 3 ? dflag : MO_16;
- gen_st_modrm(env, s, modrm, ot);
+ gen_st_modrm(s, decode, ot);
break;
case 2: /* lldt */
if (!PE(s) || VM86(s))
goto illegal_op;
if (check_cpl0(s)) {
gen_svm_check_intercept(s, SVM_EXIT_LDTR_WRITE);
- gen_ld_modrm(env, s, modrm, MO_16);
+ gen_ld_modrm(s, decode, MO_16);
tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
gen_helper_lldt(tcg_env, s->tmp2_i32);
}
@@ -3212,14 +2942,14 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
tcg_gen_ld32u_tl(s->T0, tcg_env,
offsetof(CPUX86State, tr.selector));
ot = mod == 3 ? dflag : MO_16;
- gen_st_modrm(env, s, modrm, ot);
+ gen_st_modrm(s, decode, ot);
break;
case 3: /* ltr */
if (!PE(s) || VM86(s))
goto illegal_op;
if (check_cpl0(s)) {
gen_svm_check_intercept(s, SVM_EXIT_TR_WRITE);
- gen_ld_modrm(env, s, modrm, MO_16);
+ gen_ld_modrm(s, decode, MO_16);
tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
gen_helper_ltr(tcg_env, s->tmp2_i32);
}
@@ -3228,7 +2958,7 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
case 5: /* verw */
if (!PE(s) || VM86(s))
goto illegal_op;
- gen_ld_modrm(env, s, modrm, MO_16);
+ gen_ld_modrm(s, decode, MO_16);
gen_update_cc_op(s);
if (op == 4) {
gen_helper_verr(tcg_env, s->T0);
@@ -3238,19 +2968,18 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
assume_cc_op(s, CC_OP_EFLAGS);
break;
default:
- goto unknown_op;
+ goto illegal_op;
}
break;
case 0x101:
- modrm = x86_ldub_code(env, s);
switch (modrm) {
CASE_MODRM_MEM_OP(0): /* sgdt */
if (s->flags & HF_UMIP_MASK && !check_cpl0(s)) {
break;
}
gen_svm_check_intercept(s, SVM_EXIT_GDTR_READ);
- gen_lea_modrm(env, s, modrm);
+ gen_lea_modrm(s, decode);
tcg_gen_ld32u_tl(s->T0,
tcg_env, offsetof(CPUX86State, gdt.limit));
gen_op_st_v(s, MO_16, s->T0, s->A0);
@@ -3306,7 +3035,7 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
break;
}
gen_svm_check_intercept(s, SVM_EXIT_IDTR_READ);
- gen_lea_modrm(env, s, modrm);
+ gen_lea_modrm(s, decode);
tcg_gen_ld32u_tl(s->T0, tcg_env, offsetof(CPUX86State, idt.limit));
gen_op_st_v(s, MO_16, s->T0, s->A0);
gen_add_A0_im(s, 2);
@@ -3320,8 +3049,7 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
case 0xd0: /* xgetbv */
if ((s->cpuid_ext_features & CPUID_EXT_XSAVE) == 0
- || (s->prefix & (PREFIX_LOCK | PREFIX_DATA
- | PREFIX_REPZ | PREFIX_REPNZ))) {
+ || (s->prefix & (PREFIX_DATA | PREFIX_REPZ | PREFIX_REPNZ))) {
goto illegal_op;
}
tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_ECX]);
@@ -3331,8 +3059,7 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
case 0xd1: /* xsetbv */
if ((s->cpuid_ext_features & CPUID_EXT_XSAVE) == 0
- || (s->prefix & (PREFIX_LOCK | PREFIX_DATA
- | PREFIX_REPZ | PREFIX_REPNZ))) {
+ || (s->prefix & (PREFIX_DATA | PREFIX_REPZ | PREFIX_REPNZ))) {
goto illegal_op;
}
gen_svm_check_intercept(s, SVM_EXIT_XSETBV);
@@ -3456,7 +3183,7 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
break;
}
gen_svm_check_intercept(s, SVM_EXIT_GDTR_WRITE);
- gen_lea_modrm(env, s, modrm);
+ gen_lea_modrm(s, decode);
gen_op_ld_v(s, MO_16, s->T1, s->A0);
gen_add_A0_im(s, 2);
gen_op_ld_v(s, CODE64(s) + MO_32, s->T0, s->A0);
@@ -3472,7 +3199,7 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
break;
}
gen_svm_check_intercept(s, SVM_EXIT_IDTR_WRITE);
- gen_lea_modrm(env, s, modrm);
+ gen_lea_modrm(s, decode);
gen_op_ld_v(s, MO_16, s->T1, s->A0);
gen_add_A0_im(s, 2);
gen_op_ld_v(s, CODE64(s) + MO_32, s->T0, s->A0);
@@ -3496,11 +3223,10 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
*/
mod = (modrm >> 6) & 3;
ot = (mod != 3 ? MO_16 : s->dflag);
- gen_st_modrm(env, s, modrm, ot);
+ gen_st_modrm(s, decode, ot);
break;
case 0xee: /* rdpkru */
- if (s->prefix & (PREFIX_LOCK | PREFIX_DATA
- | PREFIX_REPZ | PREFIX_REPNZ)) {
+ if (s->prefix & (PREFIX_DATA | PREFIX_REPZ | PREFIX_REPNZ)) {
goto illegal_op;
}
tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_ECX]);
@@ -3508,8 +3234,7 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
tcg_gen_extr_i64_tl(cpu_regs[R_EAX], cpu_regs[R_EDX], s->tmp1_i64);
break;
case 0xef: /* wrpkru */
- if (s->prefix & (PREFIX_LOCK | PREFIX_DATA
- | PREFIX_REPZ | PREFIX_REPNZ)) {
+ if (s->prefix & (PREFIX_DATA | PREFIX_REPZ | PREFIX_REPNZ)) {
goto illegal_op;
}
tcg_gen_concat_tl_i64(s->tmp1_i64, cpu_regs[R_EAX],
@@ -3523,7 +3248,7 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
break;
}
gen_svm_check_intercept(s, SVM_EXIT_WRITE_CR0);
- gen_ld_modrm(env, s, modrm, MO_16);
+ gen_ld_modrm(s, decode, MO_16);
/*
* Only the 4 lower bits of CR0 are modified.
* PE cannot be set to zero if already set to one.
@@ -3541,7 +3266,7 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
break;
}
gen_svm_check_intercept(s, SVM_EXIT_INVLPG);
- gen_lea_modrm(env, s, modrm);
+ gen_lea_modrm(s, decode);
gen_helper_flush_page(tcg_env, s->A0);
s->base.is_jmp = DISAS_EOB_NEXT;
break;
@@ -3574,33 +3299,30 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
break;
default:
- goto unknown_op;
+ goto illegal_op;
}
break;
case 0x11a:
- modrm = x86_ldub_code(env, s);
if (s->flags & HF_MPX_EN_MASK) {
mod = (modrm >> 6) & 3;
reg = ((modrm >> 3) & 7) | REX_R(s);
if (prefixes & PREFIX_REPZ) {
/* bndcl */
if (reg >= 4
- || (prefixes & PREFIX_LOCK)
|| s->aflag == MO_16) {
goto illegal_op;
}
- gen_bndck(env, s, modrm, TCG_COND_LTU, cpu_bndl[reg]);
+ gen_bndck(s, decode, TCG_COND_LTU, cpu_bndl[reg]);
} else if (prefixes & PREFIX_REPNZ) {
/* bndcu */
if (reg >= 4
- || (prefixes & PREFIX_LOCK)
|| s->aflag == MO_16) {
goto illegal_op;
}
TCGv_i64 notu = tcg_temp_new_i64();
tcg_gen_not_i64(notu, cpu_bndu[reg]);
- gen_bndck(env, s, modrm, TCG_COND_GTU, notu);
+ gen_bndck(s, decode, TCG_COND_GTU, notu);
} else if (prefixes & PREFIX_DATA) {
/* bndmov -- from reg/mem */
if (reg >= 4 || s->aflag == MO_16) {
@@ -3608,7 +3330,7 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
}
if (mod == 3) {
int reg2 = (modrm & 7) | REX_B(s);
- if (reg2 >= 4 || (prefixes & PREFIX_LOCK)) {
+ if (reg2 >= 4) {
goto illegal_op;
}
if (s->flags & HF_MPX_IU_MASK) {
@@ -3616,7 +3338,7 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
tcg_gen_mov_i64(cpu_bndu[reg], cpu_bndu[reg2]);
}
} else {
- gen_lea_modrm(env, s, modrm);
+ gen_lea_modrm(s, decode);
if (CODE64(s)) {
tcg_gen_qemu_ld_i64(cpu_bndl[reg], s->A0,
s->mem_index, MO_LEUQ);
@@ -3635,9 +3357,8 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
}
} else if (mod != 3) {
/* bndldx */
- AddressParts a = gen_lea_modrm_0(env, s, modrm);
+ AddressParts a = decode->mem;
if (reg >= 4
- || (prefixes & PREFIX_LOCK)
|| s->aflag == MO_16
|| a.base < -1) {
goto illegal_op;
@@ -3665,21 +3386,18 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
gen_set_hflag(s, HF_MPX_IU_MASK);
}
}
- gen_nop_modrm(env, s, modrm);
break;
case 0x11b:
- modrm = x86_ldub_code(env, s);
if (s->flags & HF_MPX_EN_MASK) {
mod = (modrm >> 6) & 3;
reg = ((modrm >> 3) & 7) | REX_R(s);
if (mod != 3 && (prefixes & PREFIX_REPZ)) {
/* bndmk */
if (reg >= 4
- || (prefixes & PREFIX_LOCK)
|| s->aflag == MO_16) {
goto illegal_op;
}
- AddressParts a = gen_lea_modrm_0(env, s, modrm);
+ AddressParts a = decode->mem;
if (a.base >= 0) {
tcg_gen_extu_tl_i64(cpu_bndl[reg], cpu_regs[a.base]);
if (!CODE64(s)) {
@@ -3692,7 +3410,7 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
/* rip-relative generates #ud */
goto illegal_op;
}
- tcg_gen_not_tl(s->A0, gen_lea_modrm_1(s, a, false));
+ tcg_gen_not_tl(s->A0, gen_lea_modrm_1(s, decode->mem, false));
if (!CODE64(s)) {
tcg_gen_ext32u_tl(s->A0, s->A0);
}
@@ -3703,11 +3421,10 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
} else if (prefixes & PREFIX_REPNZ) {
/* bndcn */
if (reg >= 4
- || (prefixes & PREFIX_LOCK)
|| s->aflag == MO_16) {
goto illegal_op;
}
- gen_bndck(env, s, modrm, TCG_COND_GTU, cpu_bndu[reg]);
+ gen_bndck(s, decode, TCG_COND_GTU, cpu_bndu[reg]);
} else if (prefixes & PREFIX_DATA) {
/* bndmov -- to reg/mem */
if (reg >= 4 || s->aflag == MO_16) {
@@ -3715,7 +3432,7 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
}
if (mod == 3) {
int reg2 = (modrm & 7) | REX_B(s);
- if (reg2 >= 4 || (prefixes & PREFIX_LOCK)) {
+ if (reg2 >= 4) {
goto illegal_op;
}
if (s->flags & HF_MPX_IU_MASK) {
@@ -3723,7 +3440,7 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
tcg_gen_mov_i64(cpu_bndu[reg2], cpu_bndu[reg]);
}
} else {
- gen_lea_modrm(env, s, modrm);
+ gen_lea_modrm(s, decode);
if (CODE64(s)) {
tcg_gen_qemu_st_i64(cpu_bndl[reg], s->A0,
s->mem_index, MO_LEUQ);
@@ -3740,9 +3457,8 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
}
} else if (mod != 3) {
/* bndstx */
- AddressParts a = gen_lea_modrm_0(env, s, modrm);
+ AddressParts a = decode->mem;
if (reg >= 4
- || (prefixes & PREFIX_LOCK)
|| s->aflag == MO_16
|| a.base < -1) {
goto illegal_op;
@@ -3767,7 +3483,6 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
}
}
}
- gen_nop_modrm(env, s, modrm);
break;
default:
g_assert_not_reached();
@@ -3776,12 +3491,8 @@ static void disas_insn_old(DisasContext *s, CPUState *cpu, int b)
illegal_op:
gen_illegal_opcode(s);
return;
- unknown_op:
- gen_unknown_opcode(env, s);
}
-#include "decode-new.h"
-#include "emit.c.inc"
#include "decode-new.c.inc"
void tcg_x86_init(void)
@@ -3989,15 +3700,9 @@ static void i386_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
case 2:
/* Restore state that may affect the next instruction. */
dc->pc = dc->base.pc_next;
- /*
- * TODO: These save/restore can be removed after the table-based
- * decoder is complete; we will be decoding the insn completely
- * before any code generation that might affect these variables.
- */
- dc->cc_op_dirty = orig_cc_op_dirty;
- dc->cc_op = orig_cc_op;
- dc->pc_save = orig_pc_save;
- /* END TODO */
+ assert(dc->cc_op_dirty == orig_cc_op_dirty);
+ assert(dc->cc_op == orig_cc_op);
+ assert(dc->pc_save == orig_pc_save);
dc->base.num_insns--;
tcg_remove_ops_after(dc->prev_insn_end);
dc->base.insn_start = dc->prev_insn_start;
diff --git a/target/loongarch/arch_dump.c b/target/loongarch/arch_dump.c
new file mode 100644
index 0000000..d9e1120
--- /dev/null
+++ b/target/loongarch/arch_dump.c
@@ -0,0 +1,163 @@
+/*
+ * Support for writing ELF notes for LoongArch architectures
+ *
+ * Copyright (c) 2023 Loongarch Technology
+ *
+ * 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 "cpu.h"
+#include "elf.h"
+#include "sysemu/dump.h"
+#include "internals.h"
+
+/* struct user_pt_regs from arch/loongarch/include/uapi/asm/ptrace.h */
+struct loongarch_user_regs {
+ uint64_t gpr[32];
+ uint64_t pad1[1];
+ /* Special CSR registers. */
+ uint64_t csr_era;
+ uint64_t csr_badv;
+ uint64_t pad2[10];
+} QEMU_PACKED;
+
+QEMU_BUILD_BUG_ON(sizeof(struct loongarch_user_regs) != 360);
+
+/* struct elf_prstatus from include/uapi/linux/elfcore.h */
+struct loongarch_elf_prstatus {
+ char pad1[32]; /* 32 == offsetof(struct elf_prstatus, pr_pid) */
+ uint32_t pr_pid;
+ /*
+ * 76 == offsetof(struct elf_prstatus, pr_reg) -
+ * offsetof(struct elf_prstatus, pr_ppid)
+ */
+ char pad2[76];
+ struct loongarch_user_regs pr_reg;
+ uint32_t pr_fpvalid;
+ char pad3[4];
+} QEMU_PACKED;
+
+QEMU_BUILD_BUG_ON(sizeof(struct loongarch_elf_prstatus) != 480);
+
+/* struct user_fp_state from arch/loongarch/include/uapi/asm/ptrace.h */
+struct loongarch_fpu_struct {
+ uint64_t fpr[32];
+ uint64_t fcc;
+ unsigned int fcsr;
+} QEMU_PACKED;
+
+QEMU_BUILD_BUG_ON(sizeof(struct loongarch_fpu_struct) != 268);
+
+struct loongarch_note {
+ Elf64_Nhdr hdr;
+ char name[8]; /* align_up(sizeof("CORE"), 4) */
+ union {
+ struct loongarch_elf_prstatus prstatus;
+ struct loongarch_fpu_struct fpu;
+ };
+} QEMU_PACKED;
+
+#define LOONGARCH_NOTE_HEADER_SIZE offsetof(struct loongarch_note, prstatus)
+#define LOONGARCH_PRSTATUS_NOTE_SIZE \
+ (LOONGARCH_NOTE_HEADER_SIZE + sizeof(struct loongarch_elf_prstatus))
+#define LOONGARCH_PRFPREG_NOTE_SIZE \
+ (LOONGARCH_NOTE_HEADER_SIZE + sizeof(struct loongarch_fpu_struct))
+
+static void loongarch_note_init(struct loongarch_note *note, DumpState *s,
+ const char *name, Elf64_Word namesz,
+ Elf64_Word type, Elf64_Word descsz)
+{
+ memset(note, 0, sizeof(*note));
+
+ note->hdr.n_namesz = cpu_to_dump32(s, namesz);
+ note->hdr.n_descsz = cpu_to_dump32(s, descsz);
+ note->hdr.n_type = cpu_to_dump32(s, type);
+
+ memcpy(note->name, name, namesz);
+}
+
+static int loongarch_write_elf64_fprpreg(WriteCoreDumpFunction f,
+ CPULoongArchState *env, int cpuid,
+ DumpState *s)
+{
+ struct loongarch_note note;
+ int ret, i;
+
+ loongarch_note_init(&note, s, "CORE", 5, NT_PRFPREG, sizeof(note.fpu));
+ note.fpu.fcsr = cpu_to_dump64(s, env->fcsr0);
+ note.fpu.fcc = cpu_to_dump64(s, read_fcc(env));
+
+ for (i = 0; i < 32; ++i) {
+ note.fpu.fpr[i] = cpu_to_dump64(s, env->fpr[i].vreg.UD[0]);
+ }
+
+ ret = f(&note, LOONGARCH_PRFPREG_NOTE_SIZE, s);
+ if (ret < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int loongarch_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
+ int cpuid, DumpState *s)
+{
+ struct loongarch_note note;
+ CPULoongArchState *env = &LOONGARCH_CPU(cs)->env;
+ int ret, i;
+
+ loongarch_note_init(&note, s, "CORE", 5, NT_PRSTATUS,
+ sizeof(note.prstatus));
+ note.prstatus.pr_pid = cpu_to_dump32(s, cpuid);
+ note.prstatus.pr_fpvalid = cpu_to_dump32(s, 1);
+
+ for (i = 0; i < 32; ++i) {
+ note.prstatus.pr_reg.gpr[i] = cpu_to_dump64(s, env->gpr[i]);
+ }
+ note.prstatus.pr_reg.csr_era = cpu_to_dump64(s, env->CSR_ERA);
+ note.prstatus.pr_reg.csr_badv = cpu_to_dump64(s, env->CSR_BADV);
+ ret = f(&note, LOONGARCH_PRSTATUS_NOTE_SIZE, s);
+ if (ret < 0) {
+ return -1;
+ }
+
+ ret = loongarch_write_elf64_fprpreg(f, env, cpuid, s);
+ if (ret < 0) {
+ return -1;
+ }
+
+ return ret;
+}
+
+int cpu_get_dump_info(ArchDumpInfo *info,
+ const GuestPhysBlockList *guest_phys_blocks)
+{
+ info->d_machine = EM_LOONGARCH;
+ info->d_endian = ELFDATA2LSB;
+ info->d_class = ELFCLASS64;
+
+ return 0;
+}
+
+ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
+{
+ size_t note_size = 0;
+
+ if (class == ELFCLASS64) {
+ note_size = LOONGARCH_PRSTATUS_NOTE_SIZE + LOONGARCH_PRFPREG_NOTE_SIZE;
+ }
+
+ return note_size * nr_cpus;
+}
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 5e85b9d..7212fb5 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -549,6 +549,20 @@ static void loongarch_cpu_reset_hold(Object *obj, ResetType type)
env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 0);
env->CSR_MERRCTL = FIELD_DP64(env->CSR_MERRCTL, CSR_MERRCTL, ISMERR, 0);
env->CSR_TID = cs->cpu_index;
+ /*
+ * Workaround for edk2-stable202408, CSR PGD register is set only if
+ * its value is equal to zero for boot cpu, it causes reboot issue.
+ *
+ * Here clear CSR registers relative with TLB.
+ */
+ env->CSR_PGDH = 0;
+ env->CSR_PGDL = 0;
+ env->CSR_PWCL = 0;
+ env->CSR_PWCH = 0;
+ env->CSR_STLBPS = 0;
+ env->CSR_EENTRY = 0;
+ env->CSR_TLBRENTRY = 0;
+ env->CSR_MERRENTRY = 0;
for (n = 0; n < 4; n++) {
env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV0, 0);
@@ -563,7 +577,7 @@ static void loongarch_cpu_reset_hold(Object *obj, ResetType type)
memset(env->tlb, 0, sizeof(env->tlb));
#endif
if (kvm_enabled()) {
- kvm_arch_reset_vcpu(env);
+ kvm_arch_reset_vcpu(cs);
}
#endif
@@ -754,6 +768,7 @@ static const TCGCPUOps loongarch_tcg_ops = {
#include "hw/core/sysemu-cpu-ops.h"
static const struct SysemuCPUOps loongarch_sysemu_ops = {
+ .write_elf64_note = loongarch_cpu_write_elf64_note,
.get_phys_page_debug = loongarch_cpu_get_phys_page_debug,
};
diff --git a/target/loongarch/gdbstub.c b/target/loongarch/gdbstub.c
index a0e1439..dafa4fe 100644
--- a/target/loongarch/gdbstub.c
+++ b/target/loongarch/gdbstub.c
@@ -34,26 +34,28 @@ void write_fcc(CPULoongArchState *env, uint64_t val)
int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
CPULoongArchState *env = cpu_env(cs);
- uint64_t val;
-
- if (0 <= n && n < 32) {
- val = env->gpr[n];
- } else if (n == 32) {
- /* orig_a0 */
- val = 0;
- } else if (n == 33) {
- val = env->pc;
- } else if (n == 34) {
- val = env->CSR_BADV;
- }
if (0 <= n && n <= 34) {
+ uint64_t val;
+
+ if (n < 32) {
+ val = env->gpr[n];
+ } else if (n == 32) {
+ /* orig_a0 */
+ val = 0;
+ } else if (n == 33) {
+ val = env->pc;
+ } else /* if (n == 34) */ {
+ val = env->CSR_BADV;
+ }
+
if (is_la64(env)) {
return gdb_get_reg64(mem_buf, val);
} else {
return gdb_get_reg32(mem_buf, val);
}
}
+
return 0;
}
@@ -65,10 +67,10 @@ int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
int length = 0;
if (is_la64(env)) {
- tmp = ldq_p(mem_buf);
+ tmp = ldq_le_p(mem_buf);
read_length = 8;
} else {
- tmp = ldl_p(mem_buf);
+ tmp = ldl_le_p(mem_buf);
read_length = 4;
}
@@ -104,20 +106,89 @@ static int loongarch_gdb_set_fpu(CPUState *cs, uint8_t *mem_buf, int n)
int length = 0;
if (0 <= n && n < 32) {
- env->fpr[n].vreg.D(0) = ldq_p(mem_buf);
+ env->fpr[n].vreg.D(0) = ldq_le_p(mem_buf);
length = 8;
} else if (32 <= n && n < 40) {
env->cf[n - 32] = ldub_p(mem_buf);
length = 1;
} else if (n == 40) {
- env->fcsr0 = ldl_p(mem_buf);
+ env->fcsr0 = ldl_le_p(mem_buf);
length = 4;
}
return length;
}
+#define VREG_NUM 32
+#define REG64_LEN 64
+
+static int loongarch_gdb_get_vec(CPUState *cs, GByteArray *mem_buf, int n, int vl)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = &cpu->env;
+ int i, length = 0;
+
+ if (0 <= n && n < VREG_NUM) {
+ for (i = 0; i < vl / REG64_LEN; i++) {
+ length += gdb_get_reg64(mem_buf, env->fpr[n].vreg.D(i));
+ }
+ }
+
+ return length;
+}
+
+static int loongarch_gdb_set_vec(CPUState *cs, uint8_t *mem_buf, int n, int vl)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = &cpu->env;
+ int i, length = 0;
+
+ if (0 <= n && n < VREG_NUM) {
+ for (i = 0; i < vl / REG64_LEN; i++) {
+ env->fpr[n].vreg.D(i) = ldq_le_p(mem_buf + 8 * i);
+ length += 8;
+ }
+ }
+
+ return length;
+}
+
+static int loongarch_gdb_get_lsx(CPUState *cs, GByteArray *mem_buf, int n)
+{
+ return loongarch_gdb_get_vec(cs, mem_buf, n, LSX_LEN);
+}
+
+static int loongarch_gdb_set_lsx(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ return loongarch_gdb_set_vec(cs, mem_buf, n, LSX_LEN);
+}
+
+static int loongarch_gdb_get_lasx(CPUState *cs, GByteArray *mem_buf, int n)
+{
+ return loongarch_gdb_get_vec(cs, mem_buf, n, LASX_LEN);
+}
+
+static int loongarch_gdb_set_lasx(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ return loongarch_gdb_set_vec(cs, mem_buf, n, LASX_LEN);
+}
+
void loongarch_cpu_register_gdb_regs_for_features(CPUState *cs)
{
- gdb_register_coprocessor(cs, loongarch_gdb_get_fpu, loongarch_gdb_set_fpu,
- gdb_find_static_feature("loongarch-fpu.xml"), 0);
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = &cpu->env;
+
+ if (FIELD_EX32(env->cpucfg[2], CPUCFG2, FP)) {
+ gdb_register_coprocessor(cs, loongarch_gdb_get_fpu, loongarch_gdb_set_fpu,
+ gdb_find_static_feature("loongarch-fpu.xml"), 0);
+ }
+
+ if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LSX)) {
+ gdb_register_coprocessor(cs, loongarch_gdb_get_lsx, loongarch_gdb_set_lsx,
+ gdb_find_static_feature("loongarch-lsx.xml"), 0);
+ }
+
+ if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LASX)) {
+ gdb_register_coprocessor(cs, loongarch_gdb_get_lasx, loongarch_gdb_set_lasx,
+ gdb_find_static_feature("loongarch-lasx.xml"), 0);
+ }
}
diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
index 944153b..1a02427 100644
--- a/target/loongarch/internals.h
+++ b/target/loongarch/internals.h
@@ -72,5 +72,7 @@ void write_fcc(CPULoongArchState *env, uint64_t val);
int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n);
int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n);
void loongarch_cpu_register_gdb_regs_for_features(CPUState *cs);
+int loongarch_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu,
+ int cpuid, DumpState *s);
#endif
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index e1be6a6..30ec160 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -476,9 +476,12 @@ static int kvm_loongarch_put_regs_fp(CPUState *cs)
return ret;
}
-void kvm_arch_reset_vcpu(CPULoongArchState *env)
+void kvm_arch_reset_vcpu(CPUState *cs)
{
+ CPULoongArchState *env = cpu_env(cs);
+
env->mp_state = KVM_MP_STATE_RUNNABLE;
+ kvm_set_one_reg(cs, KVM_REG_LOONGARCH_VCPU_RESET, 0);
}
static int kvm_loongarch_get_mpstate(CPUState *cs)
@@ -585,7 +588,7 @@ static int kvm_loongarch_put_cpucfg(CPUState *cs)
return ret;
}
-int kvm_arch_get_registers(CPUState *cs)
+int kvm_arch_get_registers(CPUState *cs, Error **errp)
{
int ret;
@@ -613,7 +616,7 @@ int kvm_arch_get_registers(CPUState *cs)
return ret;
}
-int kvm_arch_put_registers(CPUState *cs, int level)
+int kvm_arch_put_registers(CPUState *cs, int level, Error **errp)
{
int ret;
diff --git a/target/loongarch/kvm/kvm_loongarch.h b/target/loongarch/kvm/kvm_loongarch.h
index d945b6b..1051a34 100644
--- a/target/loongarch/kvm/kvm_loongarch.h
+++ b/target/loongarch/kvm/kvm_loongarch.h
@@ -11,6 +11,6 @@
#define QEMU_KVM_LOONGARCH_H
int kvm_loongarch_set_interrupt(LoongArchCPU *cpu, int irq, int level);
-void kvm_arch_reset_vcpu(CPULoongArchState *env);
+void kvm_arch_reset_vcpu(CPUState *cs);
#endif
diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build
index e002e9a..7817318 100644
--- a/target/loongarch/meson.build
+++ b/target/loongarch/meson.build
@@ -8,6 +8,7 @@ loongarch_ss.add(files(
loongarch_system_ss = ss.source_set()
loongarch_system_ss.add(files(
+ 'arch_dump.c',
'cpu_helper.c',
'loongarch-qmp-cmds.c',
'machine.c',
diff --git a/target/loongarch/tcg/op_helper.c b/target/loongarch/tcg/op_helper.c
index fe79c62..b17208e 100644
--- a/target/loongarch/tcg/op_helper.c
+++ b/target/loongarch/tcg/op_helper.c
@@ -14,7 +14,7 @@
#include "exec/cpu_ldst.h"
#include "internals.h"
#include "qemu/crc32c.h"
-#include <zlib.h>
+#include <zlib.h> /* for crc32 */
#include "cpu-csr.h"
/* Exceptions helpers */
diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c
index d6331f9..97f38fc 100644
--- a/target/loongarch/tcg/tlb_helper.c
+++ b/target/loongarch/tcg/tlb_helper.c
@@ -525,6 +525,7 @@ target_ulong helper_lddir(CPULoongArchState *env, target_ulong base,
if (unlikely(level == 4)) {
qemu_log_mask(LOG_GUEST_ERROR,
"Attempted use of level 4 huge page\n");
+ return base;
}
if (FIELD_EX64(base, TLBENTRY, LEVEL)) {
diff --git a/target/m68k/Kconfig b/target/m68k/Kconfig
index 9eae714..23aae24 100644
--- a/target/m68k/Kconfig
+++ b/target/m68k/Kconfig
@@ -1,3 +1,3 @@
config M68K
bool
- select SEMIHOSTING
+ imply SEMIHOSTING if TCG
diff --git a/target/m68k/cpu-param.h b/target/m68k/cpu-param.h
index 39dcbce..5bbe623 100644
--- a/target/m68k/cpu-param.h
+++ b/target/m68k/cpu-param.h
@@ -2,7 +2,7 @@
* m68k cpu parameters for qemu.
*
* Copyright (c) 2005-2007 CodeSourcery
- * SPDX-License-Identifier: LGPL-2.0+
+ * SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef M68K_CPU_PARAM_H
diff --git a/target/m68k/gdbstub.c b/target/m68k/gdbstub.c
index 15547e2..136159f 100644
--- a/target/m68k/gdbstub.c
+++ b/target/m68k/gdbstub.c
@@ -52,7 +52,7 @@ int m68k_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
CPUM68KState *env = cpu_env(cs);
uint32_t tmp;
- tmp = ldl_p(mem_buf);
+ tmp = ldl_be_p(mem_buf);
if (n < 8) {
/* D0-D7 */
diff --git a/target/m68k/helper.c b/target/m68k/helper.c
index 7967ad1..9d3db84 100644
--- a/target/m68k/helper.c
+++ b/target/m68k/helper.c
@@ -57,15 +57,15 @@ static int cf_fpu_gdb_set_reg(CPUState *cs, uint8_t *mem_buf, int n)
if (n < 8) {
float_status s;
- env->fregs[n].d = float64_to_floatx80(ldq_p(mem_buf), &s);
+ env->fregs[n].d = float64_to_floatx80(ldq_be_p(mem_buf), &s);
return 8;
}
switch (n) {
case 8: /* fpcontrol */
- cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
+ cpu_m68k_set_fpcr(env, ldl_be_p(mem_buf));
return 4;
case 9: /* fpstatus */
- env->fpsr = ldl_p(mem_buf);
+ env->fpsr = ldl_be_p(mem_buf);
return 4;
case 10: /* fpiar, not implemented */
return 4;
@@ -107,10 +107,10 @@ static int m68k_fpu_gdb_set_reg(CPUState *cs, uint8_t *mem_buf, int n)
}
switch (n) {
case 8: /* fpcontrol */
- cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
+ cpu_m68k_set_fpcr(env, ldl_be_p(mem_buf));
return 4;
case 9: /* fpstatus */
- cpu_m68k_set_fpsr(env, ldl_p(mem_buf));
+ cpu_m68k_set_fpsr(env, ldl_be_p(mem_buf));
return 4;
case 10: /* fpiar, not implemented */
return 4;
@@ -479,7 +479,6 @@ static void print_address_zone(uint32_t logical, uint32_t physical,
static void dump_address_map(CPUM68KState *env, uint32_t root_pointer)
{
- int i, j, k;
int tic_size, tic_shift;
uint32_t tib_mask;
uint32_t tia, tib, tic;
@@ -502,19 +501,19 @@ static void dump_address_map(CPUM68KState *env, uint32_t root_pointer)
tic_shift = 12;
tib_mask = M68K_4K_PAGE_MASK;
}
- for (i = 0; i < M68K_ROOT_POINTER_ENTRIES; i++) {
+ for (unsigned i = 0; i < M68K_ROOT_POINTER_ENTRIES; i++) {
tia = address_space_ldl(cs->as, M68K_POINTER_BASE(root_pointer) + i * 4,
MEMTXATTRS_UNSPECIFIED, &txres);
if (txres != MEMTX_OK || !M68K_UDT_VALID(tia)) {
continue;
}
- for (j = 0; j < M68K_ROOT_POINTER_ENTRIES; j++) {
+ for (unsigned j = 0; j < M68K_ROOT_POINTER_ENTRIES; j++) {
tib = address_space_ldl(cs->as, M68K_POINTER_BASE(tia) + j * 4,
MEMTXATTRS_UNSPECIFIED, &txres);
if (txres != MEMTX_OK || !M68K_UDT_VALID(tib)) {
continue;
}
- for (k = 0; k < tic_size; k++) {
+ for (unsigned k = 0; k < tic_size; k++) {
tic = address_space_ldl(cs->as, (tib & tib_mask) + k * 4,
MEMTXATTRS_UNSPECIFIED, &txres);
if (txres != MEMTX_OK || !M68K_PDT_VALID(tic)) {
diff --git a/target/m68k/meson.build b/target/m68k/meson.build
index 8d3f9ce..4d213da 100644
--- a/target/m68k/meson.build
+++ b/target/m68k/meson.build
@@ -11,9 +11,12 @@ m68k_ss.add(files(
m68k_system_ss = ss.source_set()
m68k_system_ss.add(files(
- 'm68k-semi.c',
'monitor.c'
))
+m68k_system_ss.add(when: ['CONFIG_SEMIHOSTING'],
+ if_true: files('m68k-semi.c'),
+ if_false: files('semihosting-stub.c')
+)
target_arch += {'m68k': m68k_ss}
target_system_arch += {'m68k': m68k_system_ss}
diff --git a/target/m68k/semihosting-stub.c b/target/m68k/semihosting-stub.c
new file mode 100644
index 0000000..d6a5965
--- /dev/null
+++ b/target/m68k/semihosting-stub.c
@@ -0,0 +1,15 @@
+/*
+ * m68k/ColdFire semihosting stub
+ *
+ * SPDX-FileContributor: Philippe Mathieu-DaudƩ <philmd@linaro.org>
+ * SPDX-FileCopyrightText: 2024 Linaro Ltd.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+
+void do_m68k_semihosting(CPUM68KState *env, int nr)
+{
+ g_assert_not_reached();
+}
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index 445966f..ad3ce34 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -720,7 +720,9 @@ static TCGv gen_lea_mode(CPUM68KState *env, DisasContext *s,
}
/* fallthru */
case 2: /* Indirect register */
- return get_areg(s, reg0);
+ tmp = tcg_temp_new();
+ tcg_gen_mov_i32(tmp, get_areg(s, reg0));
+ return tmp;
case 4: /* Indirect predecrememnt. */
if (opsize == OS_UNSIZED) {
return NULL_QREG;
@@ -747,20 +749,23 @@ static TCGv gen_lea_mode(CPUM68KState *env, DisasContext *s,
switch (reg0) {
case 0: /* Absolute short. */
offset = (int16_t)read_im16(env, s);
- return tcg_constant_i32(offset);
+ break;
case 1: /* Absolute long. */
offset = read_im32(env, s);
- return tcg_constant_i32(offset);
+ break;
case 2: /* pc displacement */
offset = s->pc;
offset += (int16_t)read_im16(env, s);
- return tcg_constant_i32(offset);
+ break;
case 3: /* pc index+displacement. */
return gen_lea_indexed(env, s, NULL_QREG);
case 4: /* Immediate. */
default:
return NULL_QREG;
}
+ tmp = tcg_temp_new();
+ tcg_gen_movi_i32(tmp, offset);
+ return tmp;
}
/* Should never happen. */
return NULL_QREG;
diff --git a/target/meson.build b/target/meson.build
index 1c2e6f2..b29598e 100644
--- a/target/meson.build
+++ b/target/meson.build
@@ -1,7 +1,6 @@
subdir('alpha')
subdir('arm')
subdir('avr')
-subdir('cris')
subdir('hexagon')
subdir('hppa')
subdir('i386')
diff --git a/target/microblaze/cpu-param.h b/target/microblaze/cpu-param.h
index e530fea..00efb50 100644
--- a/target/microblaze/cpu-param.h
+++ b/target/microblaze/cpu-param.h
@@ -2,7 +2,7 @@
* MicroBlaze cpu parameters for qemu.
*
* Copyright (c) 2009 Edgar E. Iglesias
- * SPDX-License-Identifier: LGPL-2.0+
+ * SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef MICROBLAZE_CPU_PARAM_H
diff --git a/target/mips/Kconfig b/target/mips/Kconfig
index eb19c94..876048b 100644
--- a/target/mips/Kconfig
+++ b/target/mips/Kconfig
@@ -1,6 +1,6 @@
config MIPS
bool
- select SEMIHOSTING
+ imply SEMIHOSTING if TCG
config MIPS64
bool
diff --git a/target/mips/cpu-param.h b/target/mips/cpu-param.h
index 6f6ac16..f3a37e2 100644
--- a/target/mips/cpu-param.h
+++ b/target/mips/cpu-param.h
@@ -1,7 +1,7 @@
/*
* MIPS cpu parameters for qemu.
*
- * SPDX-License-Identifier: LGPL-2.0+
+ * SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef MIPS_CPU_PARAM_H
diff --git a/target/mips/cpu.c b/target/mips/cpu.c
index 89655b1..9724e71 100644
--- a/target/mips/cpu.c
+++ b/target/mips/cpu.c
@@ -200,10 +200,8 @@ static void mips_cpu_reset_hold(Object *obj, ResetType type)
/* Reset registers to their default values */
env->CP0_PRid = env->cpu_model->CP0_PRid;
- env->CP0_Config0 = env->cpu_model->CP0_Config0;
-#if TARGET_BIG_ENDIAN
- env->CP0_Config0 |= (1 << CP0C0_BE);
-#endif
+ env->CP0_Config0 = deposit32(env->cpu_model->CP0_Config0,
+ CP0C0_BE, 1, cpu->is_big_endian);
env->CP0_Config1 = env->cpu_model->CP0_Config1;
env->CP0_Config2 = env->cpu_model->CP0_Config2;
env->CP0_Config3 = env->cpu_model->CP0_Config3;
@@ -541,6 +539,11 @@ static const struct SysemuCPUOps mips_sysemu_ops = {
};
#endif
+static Property mips_cpu_properties[] = {
+ DEFINE_PROP_BOOL("big-endian", MIPSCPU, is_big_endian, TARGET_BIG_ENDIAN),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
#ifdef CONFIG_TCG
#include "hw/core/tcg-cpu-ops.h"
/*
@@ -571,6 +574,7 @@ static void mips_cpu_class_init(ObjectClass *c, void *data)
DeviceClass *dc = DEVICE_CLASS(c);
ResettableClass *rc = RESETTABLE_CLASS(c);
+ device_class_set_props(dc, mips_cpu_properties);
device_class_set_parent_realize(dc, mips_cpu_realizefn,
&mcc->parent_realize);
resettable_class_set_parent_phases(rc, NULL, mips_cpu_reset_hold, NULL,
@@ -639,12 +643,15 @@ static void mips_cpu_register_types(void)
type_init(mips_cpu_register_types)
/* Could be used by generic CPU object */
-MIPSCPU *mips_cpu_create_with_clock(const char *cpu_type, Clock *cpu_refclk)
+MIPSCPU *mips_cpu_create_with_clock(const char *cpu_type, Clock *cpu_refclk,
+ bool is_big_endian)
{
DeviceState *cpu;
cpu = DEVICE(object_new(cpu_type));
qdev_connect_clock_in(cpu, "clk-in", cpu_refclk);
+ object_property_set_bool(OBJECT(cpu), "big-endian", is_big_endian,
+ &error_abort);
qdev_realize(cpu, NULL, &error_abort);
return MIPS_CPU(cpu);
diff --git a/target/mips/cpu.h b/target/mips/cpu.h
index 3e906a1..a4a46eb 100644
--- a/target/mips/cpu.h
+++ b/target/mips/cpu.h
@@ -1209,6 +1209,9 @@ struct ArchCPU {
Clock *clock;
Clock *count_div; /* Divider for CP0_Count clock */
+
+ /* Properties */
+ bool is_big_endian;
};
/**
@@ -1373,12 +1376,14 @@ static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, vaddr *pc,
* mips_cpu_create_with_clock:
* @typename: a MIPS CPU type.
* @cpu_refclk: this cpu input clock (an output clock of another device)
+ * @is_big_endian: whether this CPU is configured in big endianness
*
* Instantiates a MIPS CPU, set the input clock of the CPU to @cpu_refclk,
* then realizes the CPU.
*
* Returns: A #CPUState or %NULL if an error occurred.
*/
-MIPSCPU *mips_cpu_create_with_clock(const char *cpu_type, Clock *cpu_refclk);
+MIPSCPU *mips_cpu_create_with_clock(const char *cpu_type, Clock *cpu_refclk,
+ bool is_big_endian);
#endif /* MIPS_CPU_H */
diff --git a/target/mips/internal.h b/target/mips/internal.h
index a9a22ea..91c786c 100644
--- a/target/mips/internal.h
+++ b/target/mips/internal.h
@@ -225,6 +225,16 @@ static inline void mips_env_set_pc(CPUMIPSState *env, target_ulong value)
}
}
+static inline bool mips_env_is_bigendian(CPUMIPSState *env)
+{
+ return extract32(env->CP0_Config0, CP0C0_BE, 1);
+}
+
+static inline MemOp mo_endian_env(CPUMIPSState *env)
+{
+ return mips_env_is_bigendian(env) ? MO_BE : MO_LE;
+}
+
static inline void restore_pamask(CPUMIPSState *env)
{
if (env->hflags & MIPS_HFLAG_ELPA) {
diff --git a/target/mips/kvm.c b/target/mips/kvm.c
index a631ab5..a98798c 100644
--- a/target/mips/kvm.c
+++ b/target/mips/kvm.c
@@ -1172,7 +1172,7 @@ static int kvm_mips_get_cp0_registers(CPUState *cs)
return ret;
}
-int kvm_arch_put_registers(CPUState *cs, int level)
+int kvm_arch_put_registers(CPUState *cs, int level, Error **errp)
{
CPUMIPSState *env = cpu_env(cs);
struct kvm_regs regs;
@@ -1207,7 +1207,7 @@ int kvm_arch_put_registers(CPUState *cs, int level)
return ret;
}
-int kvm_arch_get_registers(CPUState *cs)
+int kvm_arch_get_registers(CPUState *cs, Error **errp)
{
CPUMIPSState *env = cpu_env(cs);
int ret = 0;
diff --git a/target/mips/tcg/ldst_helper.c b/target/mips/tcg/ldst_helper.c
index 97056d0..f92a923 100644
--- a/target/mips/tcg/ldst_helper.c
+++ b/target/mips/tcg/ldst_helper.c
@@ -53,11 +53,6 @@ HELPER_LD_ATOMIC(lld, ldq, 0x7, (target_ulong))
#endif /* !CONFIG_USER_ONLY */
-static inline bool cpu_is_bigendian(CPUMIPSState *env)
-{
- return extract32(env->CP0_Config0, CP0C0_BE, 1);
-}
-
static inline target_ulong get_lmask(CPUMIPSState *env,
target_ulong value, unsigned bits)
{
@@ -65,7 +60,7 @@ static inline target_ulong get_lmask(CPUMIPSState *env,
value &= mask;
- if (!cpu_is_bigendian(env)) {
+ if (!mips_env_is_bigendian(env)) {
value ^= mask;
}
@@ -76,7 +71,7 @@ void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
int mem_idx)
{
target_ulong lmask = get_lmask(env, arg2, 32);
- int dir = cpu_is_bigendian(env) ? 1 : -1;
+ int dir = mips_env_is_bigendian(env) ? 1 : -1;
cpu_stb_mmuidx_ra(env, arg2, (uint8_t)(arg1 >> 24), mem_idx, GETPC());
@@ -100,7 +95,7 @@ void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
int mem_idx)
{
target_ulong lmask = get_lmask(env, arg2, 32);
- int dir = cpu_is_bigendian(env) ? 1 : -1;
+ int dir = mips_env_is_bigendian(env) ? 1 : -1;
cpu_stb_mmuidx_ra(env, arg2, (uint8_t)arg1, mem_idx, GETPC());
@@ -130,7 +125,7 @@ void helper_sdl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
int mem_idx)
{
target_ulong lmask = get_lmask(env, arg2, 64);
- int dir = cpu_is_bigendian(env) ? 1 : -1;
+ int dir = mips_env_is_bigendian(env) ? 1 : -1;
cpu_stb_mmuidx_ra(env, arg2, (uint8_t)(arg1 >> 56), mem_idx, GETPC());
@@ -174,7 +169,7 @@ void helper_sdr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
int mem_idx)
{
target_ulong lmask = get_lmask(env, arg2, 64);
- int dir = cpu_is_bigendian(env) ? 1 : -1;
+ int dir = mips_env_is_bigendian(env) ? 1 : -1;
cpu_stb_mmuidx_ra(env, arg2, (uint8_t)arg1, mem_idx, GETPC());
diff --git a/target/mips/tcg/micromips_translate.c.inc b/target/mips/tcg/micromips_translate.c.inc
index 7510831..3cbf53b 100644
--- a/target/mips/tcg/micromips_translate.c.inc
+++ b/target/mips/tcg/micromips_translate.c.inc
@@ -977,23 +977,21 @@ static void gen_ldst_pair(DisasContext *ctx, uint32_t opc, int rd,
gen_reserved_instruction(ctx);
return;
}
- tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TESL |
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_SL |
ctx->default_tcg_memop_mask);
gen_store_gpr(t1, rd);
- tcg_gen_movi_tl(t1, 4);
- gen_op_addr_add(ctx, t0, t0, t1);
- tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TESL |
+ gen_op_addr_addi(ctx, t0, t0, 4);
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_SL |
ctx->default_tcg_memop_mask);
gen_store_gpr(t1, rd + 1);
break;
case SWP:
gen_load_gpr(t1, rd);
- tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL |
+ tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UL |
ctx->default_tcg_memop_mask);
- tcg_gen_movi_tl(t1, 4);
- gen_op_addr_add(ctx, t0, t0, t1);
+ gen_op_addr_addi(ctx, t0, t0, 4);
gen_load_gpr(t1, rd + 1);
- tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL |
+ tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UL |
ctx->default_tcg_memop_mask);
break;
#ifdef TARGET_MIPS64
@@ -1002,23 +1000,21 @@ static void gen_ldst_pair(DisasContext *ctx, uint32_t opc, int rd,
gen_reserved_instruction(ctx);
return;
}
- tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ |
ctx->default_tcg_memop_mask);
gen_store_gpr(t1, rd);
- tcg_gen_movi_tl(t1, 8);
- gen_op_addr_add(ctx, t0, t0, t1);
- tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
+ gen_op_addr_addi(ctx, t0, t0, 8);
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ |
ctx->default_tcg_memop_mask);
gen_store_gpr(t1, rd + 1);
break;
case SDP:
gen_load_gpr(t1, rd);
- tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
+ tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ |
ctx->default_tcg_memop_mask);
- tcg_gen_movi_tl(t1, 8);
- gen_op_addr_add(ctx, t0, t0, t1);
+ gen_op_addr_addi(ctx, t0, t0, 8);
gen_load_gpr(t1, rd + 1);
- tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
+ tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ |
ctx->default_tcg_memop_mask);
break;
#endif
@@ -2572,13 +2568,13 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx)
gen_st(ctx, mips32_op, rt, rs, offset);
break;
case SC:
- gen_st_cond(ctx, rt, rs, offset, MO_TESL, false);
+ gen_st_cond(ctx, rt, rs, offset, mo_endian(ctx) | MO_SL, false);
break;
#if defined(TARGET_MIPS64)
case SCD:
check_insn(ctx, ISA_MIPS3);
check_mips_64(ctx);
- gen_st_cond(ctx, rt, rs, offset, MO_TEUQ, false);
+ gen_st_cond(ctx, rt, rs, offset, mo_endian(ctx) | MO_UQ, false);
break;
#endif
case LD_EVA:
@@ -2659,7 +2655,7 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx)
mips32_op = OPC_SHE;
goto do_st_lr;
case SCE:
- gen_st_cond(ctx, rt, rs, offset, MO_TESL, true);
+ gen_st_cond(ctx, rt, rs, offset, mo_endian(ctx) | MO_SL, true);
break;
case SWE:
mips32_op = OPC_SWE;
diff --git a/target/mips/tcg/mips16e_translate.c.inc b/target/mips/tcg/mips16e_translate.c.inc
index 5cffe0e..a9af8f1 100644
--- a/target/mips/tcg/mips16e_translate.c.inc
+++ b/target/mips/tcg/mips16e_translate.c.inc
@@ -122,11 +122,21 @@ enum {
static int xlat(int r)
{
- static int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
+ static const int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
return map[r];
}
+static void decr_and_store(DisasContext *ctx, unsigned regidx, TCGv t0)
+{
+ TCGv t1 = tcg_temp_new();
+
+ gen_op_addr_addi(ctx, t0, t0, -4);
+ gen_load_gpr(t1, regidx);
+ tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UL |
+ ctx->default_tcg_memop_mask);
+}
+
static void gen_mips16_save(DisasContext *ctx,
int xsregs, int aregs,
int do_ra, int do_s0, int do_s1,
@@ -134,7 +144,6 @@ static void gen_mips16_save(DisasContext *ctx,
{
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
- TCGv t2 = tcg_temp_new();
int args, astatic;
switch (aregs) {
@@ -172,70 +181,62 @@ static void gen_mips16_save(DisasContext *ctx,
case 4:
gen_base_offset_addr(ctx, t0, 29, 12);
gen_load_gpr(t1, 7);
- tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL |
+ tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UL |
ctx->default_tcg_memop_mask);
/* Fall through */
case 3:
gen_base_offset_addr(ctx, t0, 29, 8);
gen_load_gpr(t1, 6);
- tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL |
+ tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UL |
ctx->default_tcg_memop_mask);
/* Fall through */
case 2:
gen_base_offset_addr(ctx, t0, 29, 4);
gen_load_gpr(t1, 5);
- tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL |
+ tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UL |
ctx->default_tcg_memop_mask);
/* Fall through */
case 1:
gen_base_offset_addr(ctx, t0, 29, 0);
gen_load_gpr(t1, 4);
- tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL |
+ tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UL |
ctx->default_tcg_memop_mask);
}
gen_load_gpr(t0, 29);
-#define DECR_AND_STORE(reg) do { \
- tcg_gen_movi_tl(t2, -4); \
- gen_op_addr_add(ctx, t0, t0, t2); \
- gen_load_gpr(t1, reg); \
- tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL | \
- ctx->default_tcg_memop_mask); \
- } while (0)
-
if (do_ra) {
- DECR_AND_STORE(31);
+ decr_and_store(ctx, 31, t0);
}
switch (xsregs) {
case 7:
- DECR_AND_STORE(30);
+ decr_and_store(ctx, 30, t0);
/* Fall through */
case 6:
- DECR_AND_STORE(23);
+ decr_and_store(ctx, 23, t0);
/* Fall through */
case 5:
- DECR_AND_STORE(22);
+ decr_and_store(ctx, 22, t0);
/* Fall through */
case 4:
- DECR_AND_STORE(21);
+ decr_and_store(ctx, 21, t0);
/* Fall through */
case 3:
- DECR_AND_STORE(20);
+ decr_and_store(ctx, 20, t0);
/* Fall through */
case 2:
- DECR_AND_STORE(19);
+ decr_and_store(ctx, 19, t0);
/* Fall through */
case 1:
- DECR_AND_STORE(18);
+ decr_and_store(ctx, 18, t0);
}
if (do_s1) {
- DECR_AND_STORE(17);
+ decr_and_store(ctx, 17, t0);
}
if (do_s0) {
- DECR_AND_STORE(16);
+ decr_and_store(ctx, 16, t0);
}
switch (aregs) {
@@ -270,21 +271,31 @@ static void gen_mips16_save(DisasContext *ctx,
}
if (astatic > 0) {
- DECR_AND_STORE(7);
+ decr_and_store(ctx, 7, t0);
if (astatic > 1) {
- DECR_AND_STORE(6);
+ decr_and_store(ctx, 6, t0);
if (astatic > 2) {
- DECR_AND_STORE(5);
+ decr_and_store(ctx, 5, t0);
if (astatic > 3) {
- DECR_AND_STORE(4);
+ decr_and_store(ctx, 4, t0);
}
}
}
}
-#undef DECR_AND_STORE
- tcg_gen_movi_tl(t2, -framesize);
- gen_op_addr_add(ctx, cpu_gpr[29], cpu_gpr[29], t2);
+ gen_op_addr_addi(ctx, cpu_gpr[29], cpu_gpr[29], -framesize);
+}
+
+static void decr_and_load(DisasContext *ctx, unsigned regidx, TCGv t0)
+{
+ TCGv t1 = tcg_temp_new();
+ TCGv t2 = tcg_temp_new();
+
+ tcg_gen_movi_tl(t2, -4);
+ gen_op_addr_add(ctx, t0, t0, t2);
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TE | MO_SL |
+ ctx->default_tcg_memop_mask);
+ gen_store_gpr(t1, regidx);
}
static void gen_mips16_restore(DisasContext *ctx,
@@ -294,52 +305,41 @@ static void gen_mips16_restore(DisasContext *ctx,
{
int astatic;
TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- TCGv t2 = tcg_temp_new();
-
- tcg_gen_movi_tl(t2, framesize);
- gen_op_addr_add(ctx, t0, cpu_gpr[29], t2);
-#define DECR_AND_LOAD(reg) do { \
- tcg_gen_movi_tl(t2, -4); \
- gen_op_addr_add(ctx, t0, t0, t2); \
- tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TESL | \
- ctx->default_tcg_memop_mask); \
- gen_store_gpr(t1, reg); \
- } while (0)
+ gen_op_addr_addi(ctx, t0, cpu_gpr[29], -framesize);
if (do_ra) {
- DECR_AND_LOAD(31);
+ decr_and_load(ctx, 31, t0);
}
switch (xsregs) {
case 7:
- DECR_AND_LOAD(30);
+ decr_and_load(ctx, 30, t0);
/* Fall through */
case 6:
- DECR_AND_LOAD(23);
+ decr_and_load(ctx, 23, t0);
/* Fall through */
case 5:
- DECR_AND_LOAD(22);
+ decr_and_load(ctx, 22, t0);
/* Fall through */
case 4:
- DECR_AND_LOAD(21);
+ decr_and_load(ctx, 21, t0);
/* Fall through */
case 3:
- DECR_AND_LOAD(20);
+ decr_and_load(ctx, 20, t0);
/* Fall through */
case 2:
- DECR_AND_LOAD(19);
+ decr_and_load(ctx, 19, t0);
/* Fall through */
case 1:
- DECR_AND_LOAD(18);
+ decr_and_load(ctx, 18, t0);
}
if (do_s1) {
- DECR_AND_LOAD(17);
+ decr_and_load(ctx, 17, t0);
}
if (do_s0) {
- DECR_AND_LOAD(16);
+ decr_and_load(ctx, 16, t0);
}
switch (aregs) {
@@ -374,21 +374,19 @@ static void gen_mips16_restore(DisasContext *ctx,
}
if (astatic > 0) {
- DECR_AND_LOAD(7);
+ decr_and_load(ctx, 7, t0);
if (astatic > 1) {
- DECR_AND_LOAD(6);
+ decr_and_load(ctx, 6, t0);
if (astatic > 2) {
- DECR_AND_LOAD(5);
+ decr_and_load(ctx, 5, t0);
if (astatic > 3) {
- DECR_AND_LOAD(4);
+ decr_and_load(ctx, 4, t0);
}
}
}
}
-#undef DECR_AND_LOAD
- tcg_gen_movi_tl(t2, framesize);
- gen_op_addr_add(ctx, cpu_gpr[29], cpu_gpr[29], t2);
+ gen_op_addr_addi(ctx, cpu_gpr[29], cpu_gpr[29], -framesize);
}
#if defined(TARGET_MIPS64)
diff --git a/target/mips/tcg/msa_helper.c b/target/mips/tcg/msa_helper.c
index d218176..1d40383 100644
--- a/target/mips/tcg/msa_helper.c
+++ b/target/mips/tcg/msa_helper.c
@@ -8211,14 +8211,6 @@ void helper_msa_ffint_u_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
/* Element-by-element access macros */
#define DF_ELEMENTS(df) (MSA_WRLEN / DF_BITS(df))
-#if !defined(CONFIG_USER_ONLY)
-#define MEMOP_IDX(DF) \
- MemOpIdx oi = make_memop_idx(MO_TE | DF | MO_UNALN, \
- mips_env_mmu_index(env));
-#else
-#define MEMOP_IDX(DF)
-#endif
-
#if TARGET_BIG_ENDIAN
static inline uint64_t bswap16x4(uint64_t x)
{
diff --git a/target/mips/tcg/mxu_translate.c b/target/mips/tcg/mxu_translate.c
index c517258..35ebb03 100644
--- a/target/mips/tcg/mxu_translate.c
+++ b/target/mips/tcg/mxu_translate.c
@@ -1533,7 +1533,7 @@ static void gen_mxu_s32ldxx(DisasContext *ctx, bool reversed, bool postinc)
tcg_gen_add_tl(t0, t0, t1);
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx,
- (MO_TESL ^ (reversed ? MO_BSWAP : 0)) |
+ MO_SL | mo_endian_rev(ctx, reversed) |
ctx->default_tcg_memop_mask);
gen_store_mxu_gpr(t1, XRa);
@@ -1569,7 +1569,7 @@ static void gen_mxu_s32stxx(DisasContext *ctx, bool reversed, bool postinc)
gen_load_mxu_gpr(t1, XRa);
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx,
- (MO_TESL ^ (reversed ? MO_BSWAP : 0)) |
+ MO_SL | mo_endian_rev(ctx, reversed) |
ctx->default_tcg_memop_mask);
if (postinc) {
@@ -1605,7 +1605,7 @@ static void gen_mxu_s32ldxvx(DisasContext *ctx, bool reversed,
tcg_gen_add_tl(t0, t0, t1);
tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx,
- (MO_TESL ^ (reversed ? MO_BSWAP : 0)) |
+ MO_SL | mo_endian_rev(ctx, reversed) |
ctx->default_tcg_memop_mask);
gen_store_mxu_gpr(t1, XRa);
@@ -1675,7 +1675,7 @@ static void gen_mxu_s32stxvx(DisasContext *ctx, bool reversed,
gen_load_mxu_gpr(t1, XRa);
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx,
- (MO_TESL ^ (reversed ? MO_BSWAP : 0)) |
+ MO_SL | mo_endian_rev(ctx, reversed) |
ctx->default_tcg_memop_mask);
if (postinc) {
@@ -4803,19 +4803,19 @@ static void decode_opc_mxu__pool17(DisasContext *ctx)
switch (opcode) {
case OPC_MXU_LXW:
- gen_mxu_lxx(ctx, strd2, MO_TE | MO_UL);
+ gen_mxu_lxx(ctx, strd2, mo_endian(ctx) | MO_UL);
break;
case OPC_MXU_LXB:
- gen_mxu_lxx(ctx, strd2, MO_TE | MO_SB);
+ gen_mxu_lxx(ctx, strd2, mo_endian(ctx) | MO_SB);
break;
case OPC_MXU_LXH:
- gen_mxu_lxx(ctx, strd2, MO_TE | MO_SW);
+ gen_mxu_lxx(ctx, strd2, mo_endian(ctx) | MO_SW);
break;
case OPC_MXU_LXBU:
- gen_mxu_lxx(ctx, strd2, MO_TE | MO_UB);
+ gen_mxu_lxx(ctx, strd2, mo_endian(ctx) | MO_UB);
break;
case OPC_MXU_LXHU:
- gen_mxu_lxx(ctx, strd2, MO_TE | MO_UW);
+ gen_mxu_lxx(ctx, strd2, mo_endian(ctx) | MO_UW);
break;
default:
MIPS_INVAL("decode_opc_mxu");
diff --git a/target/mips/tcg/nanomips_translate.c.inc b/target/mips/tcg/nanomips_translate.c.inc
index b4b746d..1e27414 100644
--- a/target/mips/tcg/nanomips_translate.c.inc
+++ b/target/mips/tcg/nanomips_translate.c.inc
@@ -998,8 +998,9 @@ static void gen_llwp(DisasContext *ctx, uint32_t base, int16_t offset,
TCGv tmp2 = tcg_temp_new();
gen_base_offset_addr(ctx, taddr, base, offset);
- tcg_gen_qemu_ld_i64(tval, taddr, ctx->mem_idx, MO_TEUQ | MO_ALIGN);
- if (cpu_is_bigendian(ctx)) {
+ tcg_gen_qemu_ld_i64(tval, taddr, ctx->mem_idx,
+ mo_endian(ctx) | MO_UQ | MO_ALIGN);
+ if (disas_is_bigendian(ctx)) {
tcg_gen_extr_i64_tl(tmp2, tmp1, tval);
} else {
tcg_gen_extr_i64_tl(tmp1, tmp2, tval);
@@ -1031,7 +1032,7 @@ static void gen_scwp(DisasContext *ctx, uint32_t base, int16_t offset,
gen_load_gpr(tmp1, reg1);
gen_load_gpr(tmp2, reg2);
- if (cpu_is_bigendian(ctx)) {
+ if (disas_is_bigendian(ctx)) {
tcg_gen_concat_tl_i64(tval, tmp2, tmp1);
} else {
tcg_gen_concat_tl_i64(tval, tmp1, tmp2);
@@ -1052,8 +1053,7 @@ static void gen_scwp(DisasContext *ctx, uint32_t base, int16_t offset,
tcg_gen_movi_tl(cpu_gpr[reg1], 0);
}
gen_set_label(lab_done);
- tcg_gen_movi_tl(lladdr, -1);
- tcg_gen_st_tl(lladdr, tcg_env, offsetof(CPUMIPSState, lladdr));
+ tcg_gen_st_tl(tcg_constant_tl(-1), tcg_env, offsetof(CPUMIPSState, lladdr));
}
static void gen_adjust_sp(DisasContext *ctx, int u)
@@ -1075,7 +1075,7 @@ static void gen_save(DisasContext *ctx, uint8_t rt, uint8_t count,
gen_base_offset_addr(ctx, va, 29, this_offset);
gen_load_gpr(t0, this_rt);
tcg_gen_qemu_st_tl(t0, va, ctx->mem_idx,
- (MO_TEUL | ctx->default_tcg_memop_mask));
+ mo_endian(ctx) | MO_UL | ctx->default_tcg_memop_mask);
counter++;
}
@@ -1095,8 +1095,8 @@ static void gen_restore(DisasContext *ctx, uint8_t rt, uint8_t count,
int this_rt = use_gp ? 28 : (rt & 0x10) | ((rt + counter) & 0x1f);
int this_offset = u - ((counter + 1) << 2);
gen_base_offset_addr(ctx, va, 29, this_offset);
- tcg_gen_qemu_ld_tl(t0, va, ctx->mem_idx, MO_TESL |
- ctx->default_tcg_memop_mask);
+ tcg_gen_qemu_ld_tl(t0, va, ctx->mem_idx,
+ mo_endian(ctx) | MO_SL | ctx->default_tcg_memop_mask);
tcg_gen_ext32s_tl(t0, t0);
gen_store_gpr(t0, this_rt);
counter++;
@@ -1543,7 +1543,6 @@ static void gen_pool32axf_1_nanomips_insn(DisasContext *ctx, uint32_t opc,
{
int16_t imm;
TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
TCGv v0_t = tcg_temp_new();
gen_load_gpr(v0_t, v1);
@@ -1570,12 +1569,10 @@ static void gen_pool32axf_1_nanomips_insn(DisasContext *ctx, uint32_t opc,
check_dsp(ctx);
switch (extract32(ctx->opcode, 12, 2)) {
case NM_MTHLIP:
- tcg_gen_movi_tl(t0, v2 >> 3);
- gen_helper_mthlip(t0, v0_t, tcg_env);
+ gen_helper_mthlip(tcg_constant_tl(v2 >> 3), v0_t, tcg_env);
break;
case NM_SHILOV:
- tcg_gen_movi_tl(t0, v2 >> 3);
- gen_helper_shilo(t0, v0_t, tcg_env);
+ gen_helper_shilo(tcg_constant_tl(v2 >> 3), v0_t, tcg_env);
break;
default:
gen_reserved_instruction(ctx);
@@ -1587,39 +1584,34 @@ static void gen_pool32axf_1_nanomips_insn(DisasContext *ctx, uint32_t opc,
imm = extract32(ctx->opcode, 14, 7);
switch (extract32(ctx->opcode, 12, 2)) {
case NM_RDDSP:
- tcg_gen_movi_tl(t0, imm);
- gen_helper_rddsp(t0, t0, tcg_env);
+ gen_helper_rddsp(t0, tcg_constant_tl(imm), tcg_env);
gen_store_gpr(t0, ret);
break;
case NM_WRDSP:
gen_load_gpr(t0, ret);
- tcg_gen_movi_tl(t1, imm);
- gen_helper_wrdsp(t0, t1, tcg_env);
+ gen_helper_wrdsp(t0, tcg_constant_tl(imm), tcg_env);
break;
case NM_EXTP:
- tcg_gen_movi_tl(t0, v2 >> 3);
- tcg_gen_movi_tl(t1, v1);
- gen_helper_extp(t0, t0, t1, tcg_env);
+ gen_helper_extp(t0, tcg_constant_tl(v2 >> 3),
+ tcg_constant_tl(v1), tcg_env);
gen_store_gpr(t0, ret);
break;
case NM_EXTPDP:
- tcg_gen_movi_tl(t0, v2 >> 3);
- tcg_gen_movi_tl(t1, v1);
- gen_helper_extpdp(t0, t0, t1, tcg_env);
+ gen_helper_extpdp(t0, tcg_constant_tl(v2 >> 3),
+ tcg_constant_tl(v1), tcg_env);
gen_store_gpr(t0, ret);
break;
}
break;
case NM_POOL32AXF_1_4:
check_dsp(ctx);
- tcg_gen_movi_tl(t0, v2 >> 2);
switch (extract32(ctx->opcode, 12, 1)) {
case NM_SHLL_QB:
- gen_helper_shll_qb(t0, t0, v0_t, tcg_env);
+ gen_helper_shll_qb(t0, tcg_constant_tl(v2 >> 2), v0_t, tcg_env);
gen_store_gpr(t0, ret);
break;
case NM_SHRL_QB:
- gen_helper_shrl_qb(t0, t0, v0_t);
+ gen_helper_shrl_qb(t0, tcg_constant_tl(v2 >> 2), v0_t);
gen_store_gpr(t0, ret);
break;
}
@@ -1630,23 +1622,25 @@ static void gen_pool32axf_1_nanomips_insn(DisasContext *ctx, uint32_t opc,
break;
case NM_POOL32AXF_1_7:
check_dsp(ctx);
- tcg_gen_movi_tl(t0, v2 >> 3);
- tcg_gen_movi_tl(t1, v1);
switch (extract32(ctx->opcode, 12, 2)) {
case NM_EXTR_W:
- gen_helper_extr_w(t0, t0, t1, tcg_env);
+ gen_helper_extr_w(t0, tcg_constant_tl(v2 >> 3),
+ tcg_constant_tl(v1), tcg_env);
gen_store_gpr(t0, ret);
break;
case NM_EXTR_R_W:
- gen_helper_extr_r_w(t0, t0, t1, tcg_env);
+ gen_helper_extr_r_w(t0, tcg_constant_tl(v2 >> 3),
+ tcg_constant_tl(v1), tcg_env);
gen_store_gpr(t0, ret);
break;
case NM_EXTR_RS_W:
- gen_helper_extr_rs_w(t0, t0, t1, tcg_env);
+ gen_helper_extr_rs_w(t0, tcg_constant_tl(v2 >> 3),
+ tcg_constant_tl(v1), tcg_env);
gen_store_gpr(t0, ret);
break;
case NM_EXTR_S_H:
- gen_helper_extr_s_h(t0, t0, t1, tcg_env);
+ gen_helper_extr_s_h(t0, tcg_constant_tl(v2 >> 3),
+ tcg_constant_tl(v1), tcg_env);
gen_store_gpr(t0, ret);
break;
}
@@ -1848,8 +1842,7 @@ static void gen_pool32axf_2_nanomips_insn(DisasContext *ctx, uint32_t opc,
case NM_EXTRV_W:
check_dsp(ctx);
gen_load_gpr(v1_t, rs);
- tcg_gen_movi_tl(t0, rd >> 3);
- gen_helper_extr_w(t0, t0, v1_t, tcg_env);
+ gen_helper_extr_w(t0, tcg_constant_tl(rd >> 3), v1_t, tcg_env);
gen_store_gpr(t0, ret);
break;
}
@@ -1903,8 +1896,7 @@ static void gen_pool32axf_2_nanomips_insn(DisasContext *ctx, uint32_t opc,
break;
case NM_EXTRV_R_W:
check_dsp(ctx);
- tcg_gen_movi_tl(t0, rd >> 3);
- gen_helper_extr_r_w(t0, t0, v1_t, tcg_env);
+ gen_helper_extr_r_w(t0, tcg_constant_tl(rd >> 3), v1_t, tcg_env);
gen_store_gpr(t0, ret);
break;
default:
@@ -1923,8 +1915,7 @@ static void gen_pool32axf_2_nanomips_insn(DisasContext *ctx, uint32_t opc,
break;
case NM_EXTPV:
check_dsp(ctx);
- tcg_gen_movi_tl(t0, rd >> 3);
- gen_helper_extp(t0, t0, v1_t, tcg_env);
+ gen_helper_extp(t0, tcg_constant_tl(rd >> 3), v1_t, tcg_env);
gen_store_gpr(t0, ret);
break;
case NM_MSUB:
@@ -1947,8 +1938,7 @@ static void gen_pool32axf_2_nanomips_insn(DisasContext *ctx, uint32_t opc,
break;
case NM_EXTRV_RS_W:
check_dsp(ctx);
- tcg_gen_movi_tl(t0, rd >> 3);
- gen_helper_extr_rs_w(t0, t0, v1_t, tcg_env);
+ gen_helper_extr_rs_w(t0, tcg_constant_tl(rd >> 3), v1_t, tcg_env);
gen_store_gpr(t0, ret);
break;
}
@@ -1964,8 +1954,7 @@ static void gen_pool32axf_2_nanomips_insn(DisasContext *ctx, uint32_t opc,
break;
case NM_EXTPDPV:
check_dsp(ctx);
- tcg_gen_movi_tl(t0, rd >> 3);
- gen_helper_extpdp(t0, t0, v1_t, tcg_env);
+ gen_helper_extpdp(t0, tcg_constant_tl(rd >> 3), v1_t, tcg_env);
gen_store_gpr(t0, ret);
break;
case NM_MSUBU:
@@ -1990,8 +1979,7 @@ static void gen_pool32axf_2_nanomips_insn(DisasContext *ctx, uint32_t opc,
break;
case NM_EXTRV_S_H:
check_dsp(ctx);
- tcg_gen_movi_tl(t0, rd >> 3);
- gen_helper_extr_s_h(t0, t0, v1_t, tcg_env);
+ gen_helper_extr_s_h(t0, tcg_constant_tl(rd >> 3), v1_t, tcg_env);
gen_store_gpr(t0, ret);
break;
}
@@ -2149,24 +2137,22 @@ static void gen_pool32axf_7_nanomips_insn(DisasContext *ctx, uint32_t opc,
switch (opc) {
case NM_SHRA_R_QB:
check_dsp_r2(ctx);
- tcg_gen_movi_tl(t0, rd >> 2);
switch (extract32(ctx->opcode, 12, 1)) {
case 0:
/* NM_SHRA_QB */
- gen_helper_shra_qb(t0, t0, rs_t);
+ gen_helper_shra_qb(t0, tcg_constant_tl(rd >> 2), rs_t);
gen_store_gpr(t0, rt);
break;
case 1:
/* NM_SHRA_R_QB */
- gen_helper_shra_r_qb(t0, t0, rs_t);
+ gen_helper_shra_r_qb(t0, tcg_constant_tl(rd >> 2), rs_t);
gen_store_gpr(t0, rt);
break;
}
break;
case NM_SHRL_PH:
check_dsp_r2(ctx);
- tcg_gen_movi_tl(t0, rd >> 1);
- gen_helper_shrl_ph(t0, t0, rs_t);
+ gen_helper_shrl_ph(t0, tcg_constant_tl(rd >> 1), rs_t);
gen_store_gpr(t0, rt);
break;
case NM_REPL_QB:
@@ -2180,8 +2166,7 @@ static void gen_pool32axf_7_nanomips_insn(DisasContext *ctx, uint32_t opc,
(uint32_t)imm << 8 |
(uint32_t)imm;
result = (int32_t)result;
- tcg_gen_movi_tl(t0, result);
- gen_store_gpr(t0, rt);
+ gen_store_gpr(tcg_constant_tl(result), rt);
}
break;
default:
@@ -2302,10 +2287,9 @@ static void gen_compute_imm_branch(DisasContext *ctx, uint32_t opc,
{
TCGCond cond = TCG_COND_ALWAYS;
TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
+ TCGv timm = tcg_constant_tl(imm);
gen_load_gpr(t0, rt);
- tcg_gen_movi_tl(t1, imm);
ctx->btarget = addr_add(ctx, ctx->base.pc_next + 4, offset);
/* Load needed operands and calculate btarget */
@@ -2334,7 +2318,7 @@ static void gen_compute_imm_branch(DisasContext *ctx, uint32_t opc,
} else {
tcg_gen_shri_tl(t0, t0, imm);
tcg_gen_andi_tl(t0, t0, 1);
- tcg_gen_movi_tl(t1, 0);
+ timm = tcg_constant_tl(0);
if (opc == NM_BBEQZC) {
cond = TCG_COND_EQ;
} else {
@@ -2389,7 +2373,7 @@ static void gen_compute_imm_branch(DisasContext *ctx, uint32_t opc,
/* Conditional compact branch */
TCGLabel *fs = gen_new_label();
- tcg_gen_brcond_tl(tcg_invert_cond(cond), t0, t1, fs);
+ tcg_gen_brcond_tl(tcg_invert_cond(cond), t0, timm, fs);
gen_goto_tb(ctx, 1, ctx->btarget);
gen_set_label(fs);
@@ -2403,7 +2387,6 @@ static void gen_compute_nanomips_pbalrsc_branch(DisasContext *ctx, int rs,
int rt)
{
TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
/* load rs */
gen_load_gpr(t0, rs);
@@ -2415,8 +2398,7 @@ static void gen_compute_nanomips_pbalrsc_branch(DisasContext *ctx, int rs,
/* calculate btarget */
tcg_gen_shli_tl(t0, t0, 1);
- tcg_gen_movi_tl(t1, ctx->base.pc_next + 4);
- gen_op_addr_add(ctx, btarget, t1, t0);
+ gen_op_addr_add(ctx, btarget, tcg_constant_tl(ctx->base.pc_next + 4), t0);
/* branch completion */
clear_branch_hflags(ctx);
@@ -2469,11 +2451,9 @@ static void gen_compute_compact_branch_nm(DisasContext *ctx, uint32_t opc,
} else {
/* OPC_JIC, OPC_JIALC */
TCGv tbase = tcg_temp_new();
- TCGv toffset = tcg_temp_new();
gen_load_gpr(tbase, rt);
- tcg_gen_movi_tl(toffset, offset);
- gen_op_addr_add(ctx, btarget, tbase, toffset);
+ gen_op_addr_addi(ctx, btarget, tbase, offset);
}
break;
default:
@@ -2647,13 +2627,13 @@ static void gen_p_lsx(DisasContext *ctx, int rd, int rs, int rt)
case NM_LHX:
/*case NM_LHXS:*/
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx,
- MO_TESW | ctx->default_tcg_memop_mask);
+ mo_endian(ctx) | MO_SW | ctx->default_tcg_memop_mask);
gen_store_gpr(t0, rd);
break;
case NM_LWX:
/*case NM_LWXS:*/
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx,
- MO_TESL | ctx->default_tcg_memop_mask);
+ mo_endian(ctx) | MO_SL | ctx->default_tcg_memop_mask);
gen_store_gpr(t0, rd);
break;
case NM_LBUX:
@@ -2663,7 +2643,7 @@ static void gen_p_lsx(DisasContext *ctx, int rd, int rs, int rt)
case NM_LHUX:
/*case NM_LHUXS:*/
tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx,
- MO_TEUW | ctx->default_tcg_memop_mask);
+ mo_endian(ctx) | MO_UW | ctx->default_tcg_memop_mask);
gen_store_gpr(t0, rd);
break;
case NM_SBX:
@@ -2676,14 +2656,14 @@ static void gen_p_lsx(DisasContext *ctx, int rd, int rs, int rt)
check_nms(ctx);
gen_load_gpr(t1, rd);
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx,
- MO_TEUW | ctx->default_tcg_memop_mask);
+ mo_endian(ctx) | MO_UW | ctx->default_tcg_memop_mask);
break;
case NM_SWX:
/*case NM_SWXS:*/
check_nms(ctx);
gen_load_gpr(t1, rd);
tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx,
- MO_TEUL | ctx->default_tcg_memop_mask);
+ mo_endian(ctx) | MO_UL | ctx->default_tcg_memop_mask);
break;
case NM_LWC1X:
/*case NM_LWC1XS:*/
@@ -3445,13 +3425,10 @@ static void gen_pool32a5_nanomips_insn(DisasContext *ctx, int opc,
case NM_SHILO:
check_dsp(ctx);
{
- TCGv tv0 = tcg_temp_new();
- TCGv tv1 = tcg_temp_new();
int16_t imm = extract32(ctx->opcode, 16, 7);
- tcg_gen_movi_tl(tv0, rd >> 3);
- tcg_gen_movi_tl(tv1, imm);
- gen_helper_shilo(tv0, tv1, tcg_env);
+ gen_helper_shilo(tcg_constant_tl(rd >> 3),
+ tcg_constant_tl(imm), tcg_env);
}
break;
case NM_MULEQ_S_W_PHL:
@@ -3506,8 +3483,7 @@ static void gen_pool32a5_nanomips_insn(DisasContext *ctx, int opc,
break;
case NM_SHRA_R_W:
check_dsp(ctx);
- tcg_gen_movi_tl(t0, rd);
- gen_helper_shra_r_w(v1_t, t0, v1_t);
+ gen_helper_shra_r_w(v1_t, tcg_constant_tl(rd), v1_t);
gen_store_gpr(v1_t, rt);
break;
case NM_SHRA_R_PH:
@@ -3547,8 +3523,7 @@ static void gen_pool32a5_nanomips_insn(DisasContext *ctx, int opc,
break;
case NM_SHLL_S_W:
check_dsp(ctx);
- tcg_gen_movi_tl(t0, rd);
- gen_helper_shll_s_w(v1_t, t0, v1_t, tcg_env);
+ gen_helper_shll_s_w(v1_t, tcg_constant_tl(rd), v1_t, tcg_env);
gen_store_gpr(v1_t, rt);
break;
case NM_REPL_PH:
@@ -3729,32 +3704,29 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx)
case NM_LWPC48:
check_nms(ctx);
if (rt != 0) {
- TCGv t0;
- t0 = tcg_temp_new();
-
target_long addr = addr_add(ctx, ctx->base.pc_next + 6,
addr_off);
- tcg_gen_movi_tl(t0, addr);
- tcg_gen_qemu_ld_tl(cpu_gpr[rt], t0, ctx->mem_idx,
- MO_TESL | ctx->default_tcg_memop_mask);
+ tcg_gen_qemu_ld_tl(cpu_gpr[rt], tcg_constant_tl(addr),
+ ctx->mem_idx,
+ mo_endian(ctx) | MO_SL
+ | ctx->default_tcg_memop_mask);
}
break;
case NM_SWPC48:
check_nms(ctx);
{
- TCGv t0, t1;
- t0 = tcg_temp_new();
+ TCGv t1;
t1 = tcg_temp_new();
target_long addr = addr_add(ctx, ctx->base.pc_next + 6,
addr_off);
- tcg_gen_movi_tl(t0, addr);
gen_load_gpr(t1, rt);
- tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx,
- MO_TEUL | ctx->default_tcg_memop_mask);
+ tcg_gen_qemu_st_tl(t1, tcg_constant_tl(addr), ctx->mem_idx,
+ mo_endian(ctx) | MO_UL
+ | ctx->default_tcg_memop_mask);
}
break;
default:
@@ -4132,14 +4104,14 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx)
switch (extract32(ctx->opcode, 11, 4)) {
case NM_UALH:
- tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESW |
- MO_UNALN);
+ tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx,
+ mo_endian(ctx) | MO_SW | MO_UNALN);
gen_store_gpr(t0, rt);
break;
case NM_UASH:
gen_load_gpr(t1, rt);
- tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUW |
- MO_UNALN);
+ tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx,
+ mo_endian(ctx) | MO_UW | MO_UNALN);
break;
}
}
@@ -4161,7 +4133,8 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx)
case NM_P_SC:
switch (ctx->opcode & 0x03) {
case NM_SC:
- gen_st_cond(ctx, rt, rs, s, MO_TESL, false);
+ gen_st_cond(ctx, rt, rs, s, mo_endian(ctx) | MO_SL,
+ false);
break;
case NM_SCWP:
check_xnp(ctx);
@@ -4274,7 +4247,8 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx)
check_xnp(ctx);
check_eva(ctx);
check_cp0_enabled(ctx);
- gen_st_cond(ctx, rt, rs, s, MO_TESL, true);
+ gen_st_cond(ctx, rt, rs, s, mo_endian(ctx) | MO_SL,
+ true);
break;
case NM_SCWPE:
check_xnp(ctx);
@@ -4317,7 +4291,7 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx)
switch (extract32(ctx->opcode, 11, 1)) {
case NM_LWM:
tcg_gen_qemu_ld_tl(t1, va, ctx->mem_idx,
- memop | MO_TESL);
+ memop | mo_endian(ctx) | MO_SL);
gen_store_gpr(t1, this_rt);
if ((this_rt == rs) &&
(counter != (count - 1))) {
@@ -4328,7 +4302,7 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx)
this_rt = (rt == 0) ? 0 : this_rt;
gen_load_gpr(t1, this_rt);
tcg_gen_qemu_st_tl(t1, va, ctx->mem_idx,
- memop | MO_TEUL);
+ memop | mo_endian(ctx) | MO_UL);
break;
}
counter++;
diff --git a/target/mips/tcg/sysemu/meson.build b/target/mips/tcg/sysemu/meson.build
index ec665a4..911341a 100644
--- a/target/mips/tcg/sysemu/meson.build
+++ b/target/mips/tcg/sysemu/meson.build
@@ -1,10 +1,12 @@
mips_system_ss.add(files(
'cp0_helper.c',
- 'mips-semi.c',
'special_helper.c',
'tlb_helper.c',
))
-
+mips_system_ss.add(when: ['CONFIG_SEMIHOSTING'],
+ if_true: files('mips-semi.c'),
+ if_false: files('semihosting-stub.c')
+)
mips_system_ss.add(when: 'TARGET_MIPS64', if_true: files(
'lcsr_helper.c',
))
diff --git a/target/mips/tcg/sysemu/semihosting-stub.c b/target/mips/tcg/sysemu/semihosting-stub.c
new file mode 100644
index 0000000..7ae27d7
--- /dev/null
+++ b/target/mips/tcg/sysemu/semihosting-stub.c
@@ -0,0 +1,15 @@
+/*
+ * MIPS semihosting stub
+ *
+ * SPDX-FileContributor: Philippe Mathieu-DaudƩ <philmd@linaro.org>
+ * SPDX-FileCopyrightText: 2024 Linaro Ltd.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "internal.h"
+
+void mips_semihosting(CPUMIPSState *env)
+{
+ g_assert_not_reached();
+}
diff --git a/target/mips/tcg/sysemu/tlb_helper.c b/target/mips/tcg/sysemu/tlb_helper.c
index 3ba6d36..e98bb95 100644
--- a/target/mips/tcg/sysemu/tlb_helper.c
+++ b/target/mips/tcg/sysemu/tlb_helper.c
@@ -592,23 +592,29 @@ static void raise_mmu_exception(CPUMIPSState *env, target_ulong address,
* resulting in a TLB or XTLB Refill exception.
*/
-static bool get_pte(CPUMIPSState *env, uint64_t vaddr, int entry_size,
- uint64_t *pte)
+static bool get_pte(CPUMIPSState *env, uint64_t vaddr, MemOp op,
+ uint64_t *pte, unsigned ptw_mmu_idx)
{
- if ((vaddr & ((entry_size >> 3) - 1)) != 0) {
+ MemOpIdx oi;
+
+ if ((vaddr & (memop_size(op) - 1)) != 0) {
return false;
}
- if (entry_size == 64) {
- *pte = cpu_ldq_code(env, vaddr);
+
+ oi = make_memop_idx(op | mo_endian_env(env), ptw_mmu_idx);
+ if (op == MO_64) {
+ *pte = cpu_ldq_mmu(env, vaddr, oi, 0);
} else {
- *pte = cpu_ldl_code(env, vaddr);
+ *pte = cpu_ldl_mmu(env, vaddr, oi, 0);
}
+
return true;
}
static uint64_t get_tlb_entry_layout(CPUMIPSState *env, uint64_t entry,
- int entry_size, int ptei)
+ MemOp op, int ptei)
{
+ unsigned entry_size = memop_size(op) << 3;
uint64_t result = entry;
uint64_t rixi;
if (ptei > entry_size) {
@@ -624,14 +630,12 @@ static uint64_t get_tlb_entry_layout(CPUMIPSState *env, uint64_t entry,
static int walk_directory(CPUMIPSState *env, uint64_t *vaddr,
int directory_index, bool *huge_page, bool *hgpg_directory_hit,
uint64_t *pw_entrylo0, uint64_t *pw_entrylo1,
- unsigned directory_shift, unsigned leaf_shift, int ptw_mmu_idx)
+ MemOp directory_mop, MemOp leaf_mop, int ptw_mmu_idx)
{
int dph = (env->CP0_PWCtl >> CP0PC_DPH) & 0x1;
int psn = (env->CP0_PWCtl >> CP0PC_PSN) & 0x3F;
int hugepg = (env->CP0_PWCtl >> CP0PC_HUGEPG) & 0x1;
int pf_ptew = (env->CP0_PWField >> CP0PF_PTEW) & 0x3F;
- uint32_t direntry_size = 1 << (directory_shift + 3);
- uint32_t leafentry_size = 1 << (leaf_shift + 3);
uint64_t entry;
uint64_t paddr;
int prot;
@@ -643,14 +647,14 @@ static int walk_directory(CPUMIPSState *env, uint64_t *vaddr,
/* wrong base address */
return 0;
}
- if (!get_pte(env, *vaddr, direntry_size, &entry)) {
+ if (!get_pte(env, *vaddr, directory_mop, &entry, ptw_mmu_idx)) {
return 0;
}
if ((entry & (1 << psn)) && hugepg) {
*huge_page = true;
*hgpg_directory_hit = true;
- entry = get_tlb_entry_layout(env, entry, leafentry_size, pf_ptew);
+ entry = get_tlb_entry_layout(env, entry, leaf_mop, pf_ptew);
w = directory_index - 1;
if (directory_index & 0x1) {
/* Generate adjacent page from same PTE for odd TLB page */
@@ -658,7 +662,7 @@ static int walk_directory(CPUMIPSState *env, uint64_t *vaddr,
*pw_entrylo0 = entry & ~lsb; /* even page */
*pw_entrylo1 = entry | lsb; /* odd page */
} else if (dph) {
- int oddpagebit = 1 << leaf_shift;
+ int oddpagebit = 1 << leaf_mop;
uint64_t vaddr2 = *vaddr ^ oddpagebit;
if (*vaddr & oddpagebit) {
*pw_entrylo1 = entry;
@@ -669,10 +673,10 @@ static int walk_directory(CPUMIPSState *env, uint64_t *vaddr,
ptw_mmu_idx) != TLBRET_MATCH) {
return 0;
}
- if (!get_pte(env, vaddr2, leafentry_size, &entry)) {
+ if (!get_pte(env, vaddr2, leaf_mop, &entry, ptw_mmu_idx)) {
return 0;
}
- entry = get_tlb_entry_layout(env, entry, leafentry_size, pf_ptew);
+ entry = get_tlb_entry_layout(env, entry, leaf_mop, pf_ptew);
if (*vaddr & oddpagebit) {
*pw_entrylo0 = entry;
} else {
@@ -711,7 +715,7 @@ static bool page_table_walk_refill(CPUMIPSState *env, vaddr address,
/* Native pointer size */
/*For the 32-bit architectures, this bit is fixed to 0.*/
- int native_shift = (((env->CP0_PWSize >> CP0PS_PS) & 1) == 0) ? 2 : 3;
+ MemOp native_op = (((env->CP0_PWSize >> CP0PS_PS) & 1) == 0) ? MO_32 : MO_64;
/* Indices from PWField */
int pf_gdw = (env->CP0_PWField >> CP0PF_GDW) & 0x3F;
@@ -728,11 +732,10 @@ static bool page_table_walk_refill(CPUMIPSState *env, vaddr address,
/* Other HTW configs */
int hugepg = (env->CP0_PWCtl >> CP0PC_HUGEPG) & 0x1;
- unsigned directory_shift, leaf_shift;
+ MemOp directory_mop, leaf_mop;
/* Offsets into tables */
unsigned goffset, uoffset, moffset, ptoffset0, ptoffset1;
- uint32_t leafentry_size;
/* Starting address - Page Table Base */
uint64_t vaddr = env->CP0_PWBase;
@@ -759,23 +762,21 @@ static bool page_table_walk_refill(CPUMIPSState *env, vaddr address,
}
/* HTW Shift values (depend on entry size) */
- directory_shift = (hugepg && (ptew == 1)) ? native_shift + 1 : native_shift;
- leaf_shift = (ptew == 1) ? native_shift + 1 : native_shift;
-
- goffset = gindex << directory_shift;
- uoffset = uindex << directory_shift;
- moffset = mindex << directory_shift;
- ptoffset0 = (ptindex >> 1) << (leaf_shift + 1);
- ptoffset1 = ptoffset0 | (1 << (leaf_shift));
+ directory_mop = (hugepg && (ptew == 1)) ? native_op + 1 : native_op;
+ leaf_mop = (ptew == 1) ? native_op + 1 : native_op;
- leafentry_size = 1 << (leaf_shift + 3);
+ goffset = gindex << directory_mop;
+ uoffset = uindex << directory_mop;
+ moffset = mindex << directory_mop;
+ ptoffset0 = (ptindex >> 1) << (leaf_mop + 1);
+ ptoffset1 = ptoffset0 | (1 << (leaf_mop));
/* Global Directory */
if (gdw > 0) {
vaddr |= goffset;
switch (walk_directory(env, &vaddr, pf_gdw, &huge_page, &hgpg_gdhit,
&pw_entrylo0, &pw_entrylo1,
- directory_shift, leaf_shift, ptw_mmu_idx))
+ directory_mop, leaf_mop, ptw_mmu_idx))
{
case 0:
return false;
@@ -792,7 +793,7 @@ static bool page_table_walk_refill(CPUMIPSState *env, vaddr address,
vaddr |= uoffset;
switch (walk_directory(env, &vaddr, pf_udw, &huge_page, &hgpg_udhit,
&pw_entrylo0, &pw_entrylo1,
- directory_shift, leaf_shift, ptw_mmu_idx))
+ directory_mop, leaf_mop, ptw_mmu_idx))
{
case 0:
return false;
@@ -809,7 +810,7 @@ static bool page_table_walk_refill(CPUMIPSState *env, vaddr address,
vaddr |= moffset;
switch (walk_directory(env, &vaddr, pf_mdw, &huge_page, &hgpg_mdhit,
&pw_entrylo0, &pw_entrylo1,
- directory_shift, leaf_shift, ptw_mmu_idx))
+ directory_mop, leaf_mop, ptw_mmu_idx))
{
case 0:
return false;
@@ -827,10 +828,10 @@ static bool page_table_walk_refill(CPUMIPSState *env, vaddr address,
ptw_mmu_idx) != TLBRET_MATCH) {
return false;
}
- if (!get_pte(env, vaddr, leafentry_size, &dir_entry)) {
+ if (!get_pte(env, vaddr, leaf_mop, &dir_entry, ptw_mmu_idx)) {
return false;
}
- dir_entry = get_tlb_entry_layout(env, dir_entry, leafentry_size, pf_ptew);
+ dir_entry = get_tlb_entry_layout(env, dir_entry, leaf_mop, pf_ptew);
pw_entrylo0 = dir_entry;
/* Leaf Level Page Table - Second half of PTE pair */
@@ -839,10 +840,10 @@ static bool page_table_walk_refill(CPUMIPSState *env, vaddr address,
ptw_mmu_idx) != TLBRET_MATCH) {
return false;
}
- if (!get_pte(env, vaddr, leafentry_size, &dir_entry)) {
+ if (!get_pte(env, vaddr, leaf_mop, &dir_entry, ptw_mmu_idx)) {
return false;
}
- dir_entry = get_tlb_entry_layout(env, dir_entry, leafentry_size, pf_ptew);
+ dir_entry = get_tlb_entry_layout(env, dir_entry, leaf_mop, pf_ptew);
pw_entrylo1 = dir_entry;
refill:
diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c
index 333469b..d92fc41 100644
--- a/target/mips/tcg/translate.c
+++ b/target/mips/tcg/translate.c
@@ -1456,8 +1456,7 @@ void gen_op_addr_add(DisasContext *ctx, TCGv ret, TCGv arg0, TCGv arg1)
#endif
}
-static inline void gen_op_addr_addi(DisasContext *ctx, TCGv ret, TCGv base,
- target_long ofs)
+void gen_op_addr_addi(DisasContext *ctx, TCGv ret, TCGv base, target_long ofs)
{
tcg_gen_addi_tl(ret, base, ofs);
@@ -1957,16 +1956,16 @@ static inline void op_ld_##insn(TCGv ret, TCGv arg1, int mem_idx, \
tcg_gen_st_tl(ret, tcg_env, offsetof(CPUMIPSState, llval)); \
}
#else
-#define OP_LD_ATOMIC(insn, fname) \
+#define OP_LD_ATOMIC(insn, ignored_memop) \
static inline void op_ld_##insn(TCGv ret, TCGv arg1, int mem_idx, \
DisasContext *ctx) \
{ \
gen_helper_##insn(ret, tcg_env, arg1, tcg_constant_i32(mem_idx)); \
}
#endif
-OP_LD_ATOMIC(ll, MO_TESL);
+OP_LD_ATOMIC(ll, mo_endian(ctx) | MO_SL);
#if defined(TARGET_MIPS64)
-OP_LD_ATOMIC(lld, MO_TEUQ);
+OP_LD_ATOMIC(lld, mo_endian(ctx) | MO_UQ);
#endif
#undef OP_LD_ATOMIC
@@ -2010,7 +2009,7 @@ static void gen_lxl(DisasContext *ctx, TCGv reg, TCGv addr,
*/
tcg_gen_qemu_ld_tl(t1, addr, mem_idx, MO_UB);
tcg_gen_andi_tl(t1, addr, sizem1);
- if (!cpu_is_bigendian(ctx)) {
+ if (!disas_is_bigendian(ctx)) {
tcg_gen_xori_tl(t1, t1, sizem1);
}
tcg_gen_shli_tl(t1, t1, 3);
@@ -2037,7 +2036,7 @@ static void gen_lxr(DisasContext *ctx, TCGv reg, TCGv addr,
*/
tcg_gen_qemu_ld_tl(t1, addr, mem_idx, MO_UB);
tcg_gen_andi_tl(t1, addr, sizem1);
- if (cpu_is_bigendian(ctx)) {
+ if (disas_is_bigendian(ctx)) {
tcg_gen_xori_tl(t1, t1, sizem1);
}
tcg_gen_shli_tl(t1, t1, 3);
@@ -2073,12 +2072,12 @@ static void gen_ld(DisasContext *ctx, uint32_t opc,
switch (opc) {
#if defined(TARGET_MIPS64)
case OPC_LWU:
- tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TEUL |
+ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, mo_endian(ctx) | MO_UL |
ctx->default_tcg_memop_mask);
gen_store_gpr(t0, rt);
break;
case OPC_LD:
- tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TEUQ |
+ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, mo_endian(ctx) | MO_UQ |
ctx->default_tcg_memop_mask);
gen_store_gpr(t0, rt);
break;
@@ -2090,33 +2089,33 @@ static void gen_ld(DisasContext *ctx, uint32_t opc,
case OPC_LDL:
t1 = tcg_temp_new();
gen_load_gpr(t1, rt);
- gen_lxl(ctx, t1, t0, mem_idx, MO_TEUQ);
+ gen_lxl(ctx, t1, t0, mem_idx, mo_endian(ctx) | MO_UQ);
gen_store_gpr(t1, rt);
break;
case OPC_LDR:
t1 = tcg_temp_new();
gen_load_gpr(t1, rt);
- gen_lxr(ctx, t1, t0, mem_idx, MO_TEUQ);
+ gen_lxr(ctx, t1, t0, mem_idx, mo_endian(ctx) | MO_UQ);
gen_store_gpr(t1, rt);
break;
case OPC_LDPC:
t1 = tcg_constant_tl(pc_relative_pc(ctx));
gen_op_addr_add(ctx, t0, t0, t1);
- tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TEUQ);
+ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, mo_endian(ctx) | MO_UQ);
gen_store_gpr(t0, rt);
break;
#endif
case OPC_LWPC:
t1 = tcg_constant_tl(pc_relative_pc(ctx));
gen_op_addr_add(ctx, t0, t0, t1);
- tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TESL);
+ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, mo_endian(ctx) | MO_SL);
gen_store_gpr(t0, rt);
break;
case OPC_LWE:
mem_idx = MIPS_HFLAG_UM;
/* fall through */
case OPC_LW:
- tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TESL |
+ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, mo_endian(ctx) | MO_SL |
ctx->default_tcg_memop_mask);
gen_store_gpr(t0, rt);
break;
@@ -2124,7 +2123,7 @@ static void gen_ld(DisasContext *ctx, uint32_t opc,
mem_idx = MIPS_HFLAG_UM;
/* fall through */
case OPC_LH:
- tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TESW |
+ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, mo_endian(ctx) | MO_SW |
ctx->default_tcg_memop_mask);
gen_store_gpr(t0, rt);
break;
@@ -2132,7 +2131,7 @@ static void gen_ld(DisasContext *ctx, uint32_t opc,
mem_idx = MIPS_HFLAG_UM;
/* fall through */
case OPC_LHU:
- tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TEUW |
+ tcg_gen_qemu_ld_tl(t0, t0, mem_idx, mo_endian(ctx) | MO_UW |
ctx->default_tcg_memop_mask);
gen_store_gpr(t0, rt);
break;
@@ -2156,7 +2155,7 @@ static void gen_ld(DisasContext *ctx, uint32_t opc,
case OPC_LWL:
t1 = tcg_temp_new();
gen_load_gpr(t1, rt);
- gen_lxl(ctx, t1, t0, mem_idx, MO_TEUL);
+ gen_lxl(ctx, t1, t0, mem_idx, mo_endian(ctx) | MO_UL);
tcg_gen_ext32s_tl(t1, t1);
gen_store_gpr(t1, rt);
break;
@@ -2166,7 +2165,7 @@ static void gen_ld(DisasContext *ctx, uint32_t opc,
case OPC_LWR:
t1 = tcg_temp_new();
gen_load_gpr(t1, rt);
- gen_lxr(ctx, t1, t0, mem_idx, MO_TEUL);
+ gen_lxr(ctx, t1, t0, mem_idx, mo_endian(ctx) | MO_UL);
tcg_gen_ext32s_tl(t1, t1);
gen_store_gpr(t1, rt);
break;
@@ -2194,7 +2193,7 @@ static void gen_st(DisasContext *ctx, uint32_t opc, int rt,
switch (opc) {
#if defined(TARGET_MIPS64)
case OPC_SD:
- tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEUQ |
+ tcg_gen_qemu_st_tl(t1, t0, mem_idx, mo_endian(ctx) | MO_UQ |
ctx->default_tcg_memop_mask);
break;
case OPC_SDL:
@@ -2208,14 +2207,14 @@ static void gen_st(DisasContext *ctx, uint32_t opc, int rt,
mem_idx = MIPS_HFLAG_UM;
/* fall through */
case OPC_SW:
- tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEUL |
+ tcg_gen_qemu_st_tl(t1, t0, mem_idx, mo_endian(ctx) | MO_UL |
ctx->default_tcg_memop_mask);
break;
case OPC_SHE:
mem_idx = MIPS_HFLAG_UM;
/* fall through */
case OPC_SH:
- tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEUW |
+ tcg_gen_qemu_st_tl(t1, t0, mem_idx, mo_endian(ctx) | MO_UW |
ctx->default_tcg_memop_mask);
break;
case OPC_SBE:
@@ -2253,8 +2252,7 @@ static void gen_st_cond(DisasContext *ctx, int rt, int base, int offset,
/* compare the address against that of the preceding LL */
gen_base_offset_addr(ctx, addr, base, offset);
tcg_gen_brcond_tl(TCG_COND_EQ, addr, cpu_lladdr, l1);
- tcg_gen_movi_tl(t0, 0);
- gen_store_gpr(t0, rt);
+ gen_store_gpr(tcg_constant_tl(0), rt);
tcg_gen_br(done);
gen_set_label(l1);
@@ -2281,7 +2279,7 @@ static void gen_flt_ldst(DisasContext *ctx, uint32_t opc, int ft,
case OPC_LWC1:
{
TCGv_i32 fp0 = tcg_temp_new_i32();
- tcg_gen_qemu_ld_i32(fp0, t0, ctx->mem_idx, MO_TESL |
+ tcg_gen_qemu_ld_i32(fp0, t0, ctx->mem_idx, mo_endian(ctx) | MO_SL |
ctx->default_tcg_memop_mask);
gen_store_fpr32(ctx, fp0, ft);
}
@@ -2290,14 +2288,14 @@ static void gen_flt_ldst(DisasContext *ctx, uint32_t opc, int ft,
{
TCGv_i32 fp0 = tcg_temp_new_i32();
gen_load_fpr32(ctx, fp0, ft);
- tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, MO_TEUL |
+ tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, mo_endian(ctx) | MO_UL |
ctx->default_tcg_memop_mask);
}
break;
case OPC_LDC1:
{
TCGv_i64 fp0 = tcg_temp_new_i64();
- tcg_gen_qemu_ld_i64(fp0, t0, ctx->mem_idx, MO_TEUQ |
+ tcg_gen_qemu_ld_i64(fp0, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ |
ctx->default_tcg_memop_mask);
gen_store_fpr64(ctx, fp0, ft);
}
@@ -2306,7 +2304,7 @@ static void gen_flt_ldst(DisasContext *ctx, uint32_t opc, int ft,
{
TCGv_i64 fp0 = tcg_temp_new_i64();
gen_load_fpr64(ctx, fp0, ft);
- tcg_gen_qemu_st_i64(fp0, t0, ctx->mem_idx, MO_TEUQ |
+ tcg_gen_qemu_st_i64(fp0, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ |
ctx->default_tcg_memop_mask);
}
break;
@@ -2987,14 +2985,14 @@ static inline void gen_pcrel(DisasContext *ctx, int opc, target_ulong pc,
case R6_OPC_LWPC:
offset = sextract32(ctx->opcode << 2, 0, 21);
addr = addr_add(ctx, pc, offset);
- gen_r6_ld(addr, rs, ctx->mem_idx, MO_TESL);
+ gen_r6_ld(addr, rs, ctx->mem_idx, mo_endian(ctx) | MO_SL);
break;
#if defined(TARGET_MIPS64)
case OPC_LWUPC:
check_mips_64(ctx);
offset = sextract32(ctx->opcode << 2, 0, 21);
addr = addr_add(ctx, pc, offset);
- gen_r6_ld(addr, rs, ctx->mem_idx, MO_TEUL);
+ gen_r6_ld(addr, rs, ctx->mem_idx, mo_endian(ctx) | MO_UL);
break;
#endif
default:
@@ -3021,7 +3019,7 @@ static inline void gen_pcrel(DisasContext *ctx, int opc, target_ulong pc,
check_mips_64(ctx);
offset = sextract32(ctx->opcode << 3, 0, 21);
addr = addr_add(ctx, (pc & ~0x7), offset);
- gen_r6_ld(addr, rs, ctx->mem_idx, MO_TEUQ);
+ gen_r6_ld(addr, rs, ctx->mem_idx, mo_endian(ctx) | MO_UQ);
break;
#endif
default:
@@ -3060,8 +3058,7 @@ static void gen_r6_muldiv(DisasContext *ctx, int opc, int rd, int rs, int rt)
tcg_gen_and_tl(t2, t2, t3);
tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0);
tcg_gen_or_tl(t2, t2, t3);
- tcg_gen_movi_tl(t3, 0);
- tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
+ tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, tcg_constant_tl(0), t2, t1);
tcg_gen_div_tl(cpu_gpr[rd], t0, t1);
tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
}
@@ -3077,30 +3074,27 @@ static void gen_r6_muldiv(DisasContext *ctx, int opc, int rd, int rs, int rt)
tcg_gen_and_tl(t2, t2, t3);
tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0);
tcg_gen_or_tl(t2, t2, t3);
- tcg_gen_movi_tl(t3, 0);
- tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
+ tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, tcg_constant_tl(0), t2, t1);
tcg_gen_rem_tl(cpu_gpr[rd], t0, t1);
tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
}
break;
case R6_OPC_DIVU:
{
- TCGv t2 = tcg_constant_tl(0);
- TCGv t3 = tcg_constant_tl(1);
tcg_gen_ext32u_tl(t0, t0);
tcg_gen_ext32u_tl(t1, t1);
- tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1);
+ tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1,
+ tcg_constant_tl(0), tcg_constant_tl(1), t1);
tcg_gen_divu_tl(cpu_gpr[rd], t0, t1);
tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
}
break;
case R6_OPC_MODU:
{
- TCGv t2 = tcg_constant_tl(0);
- TCGv t3 = tcg_constant_tl(1);
tcg_gen_ext32u_tl(t0, t0);
tcg_gen_ext32u_tl(t1, t1);
- tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1);
+ tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1,
+ tcg_constant_tl(0), tcg_constant_tl(1), t1);
tcg_gen_remu_tl(cpu_gpr[rd], t0, t1);
tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]);
}
@@ -3155,8 +3149,7 @@ static void gen_r6_muldiv(DisasContext *ctx, int opc, int rd, int rs, int rt)
tcg_gen_and_tl(t2, t2, t3);
tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0);
tcg_gen_or_tl(t2, t2, t3);
- tcg_gen_movi_tl(t3, 0);
- tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
+ tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, tcg_constant_tl(0), t2, t1);
tcg_gen_div_tl(cpu_gpr[rd], t0, t1);
}
break;
@@ -3169,24 +3162,21 @@ static void gen_r6_muldiv(DisasContext *ctx, int opc, int rd, int rs, int rt)
tcg_gen_and_tl(t2, t2, t3);
tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0);
tcg_gen_or_tl(t2, t2, t3);
- tcg_gen_movi_tl(t3, 0);
- tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
+ tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, tcg_constant_tl(0), t2, t1);
tcg_gen_rem_tl(cpu_gpr[rd], t0, t1);
}
break;
case R6_OPC_DDIVU:
{
- TCGv t2 = tcg_constant_tl(0);
- TCGv t3 = tcg_constant_tl(1);
- tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1);
+ tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1,
+ tcg_constant_tl(0), tcg_constant_tl(1), t1);
tcg_gen_divu_i64(cpu_gpr[rd], t0, t1);
}
break;
case R6_OPC_DMODU:
{
- TCGv t2 = tcg_constant_tl(0);
- TCGv t3 = tcg_constant_tl(1);
- tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1);
+ tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1,
+ tcg_constant_tl(0), tcg_constant_tl(1), t1);
tcg_gen_remu_i64(cpu_gpr[rd], t0, t1);
}
break;
@@ -3239,8 +3229,7 @@ static void gen_div1_tx79(DisasContext *ctx, uint32_t opc, int rs, int rt)
tcg_gen_and_tl(t2, t2, t3);
tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0);
tcg_gen_or_tl(t2, t2, t3);
- tcg_gen_movi_tl(t3, 0);
- tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
+ tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, tcg_constant_tl(0), t2, t1);
tcg_gen_div_tl(cpu_LO[1], t0, t1);
tcg_gen_rem_tl(cpu_HI[1], t0, t1);
tcg_gen_ext32s_tl(cpu_LO[1], cpu_LO[1]);
@@ -3295,8 +3284,7 @@ static void gen_muldiv(DisasContext *ctx, uint32_t opc,
tcg_gen_and_tl(t2, t2, t3);
tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0);
tcg_gen_or_tl(t2, t2, t3);
- tcg_gen_movi_tl(t3, 0);
- tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
+ tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, tcg_constant_tl(0), t2, t1);
tcg_gen_div_tl(cpu_LO[acc], t0, t1);
tcg_gen_rem_tl(cpu_HI[acc], t0, t1);
tcg_gen_ext32s_tl(cpu_LO[acc], cpu_LO[acc]);
@@ -3348,17 +3336,15 @@ static void gen_muldiv(DisasContext *ctx, uint32_t opc,
tcg_gen_and_tl(t2, t2, t3);
tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0);
tcg_gen_or_tl(t2, t2, t3);
- tcg_gen_movi_tl(t3, 0);
- tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
+ tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, tcg_constant_tl(0), t2, t1);
tcg_gen_div_tl(cpu_LO[acc], t0, t1);
tcg_gen_rem_tl(cpu_HI[acc], t0, t1);
}
break;
case OPC_DDIVU:
{
- TCGv t2 = tcg_constant_tl(0);
- TCGv t3 = tcg_constant_tl(1);
- tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1);
+ tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1,
+ tcg_constant_tl(0), tcg_constant_tl(1), t1);
tcg_gen_divu_i64(cpu_LO[acc], t0, t1);
tcg_gen_remu_i64(cpu_HI[acc], t0, t1);
}
@@ -4160,10 +4146,10 @@ static void gen_loongson_lswc2(DisasContext *ctx, int rt,
case OPC_GSLQ:
t1 = tcg_temp_new();
gen_base_offset_addr(ctx, t0, rs, lsq_offset);
- tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ |
ctx->default_tcg_memop_mask);
gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
- tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ |
+ tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ |
ctx->default_tcg_memop_mask);
gen_store_gpr(t1, rt);
gen_store_gpr(t0, lsq_rt1);
@@ -4172,10 +4158,10 @@ static void gen_loongson_lswc2(DisasContext *ctx, int rt,
check_cp1_enabled(ctx);
t1 = tcg_temp_new();
gen_base_offset_addr(ctx, t0, rs, lsq_offset);
- tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ |
ctx->default_tcg_memop_mask);
gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
- tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ |
+ tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ |
ctx->default_tcg_memop_mask);
gen_store_fpr64(ctx, t1, rt);
gen_store_fpr64(ctx, t0, lsq_rt1);
@@ -4184,11 +4170,11 @@ static void gen_loongson_lswc2(DisasContext *ctx, int rt,
t1 = tcg_temp_new();
gen_base_offset_addr(ctx, t0, rs, lsq_offset);
gen_load_gpr(t1, rt);
- tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
+ tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ |
ctx->default_tcg_memop_mask);
gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
gen_load_gpr(t1, lsq_rt1);
- tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
+ tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ |
ctx->default_tcg_memop_mask);
break;
case OPC_GSSQC1:
@@ -4196,11 +4182,11 @@ static void gen_loongson_lswc2(DisasContext *ctx, int rt,
t1 = tcg_temp_new();
gen_base_offset_addr(ctx, t0, rs, lsq_offset);
gen_load_fpr64(ctx, t1, rt);
- tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
+ tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ |
ctx->default_tcg_memop_mask);
gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
gen_load_fpr64(ctx, t1, lsq_rt1);
- tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
+ tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ |
ctx->default_tcg_memop_mask);
break;
#endif
@@ -4213,7 +4199,7 @@ static void gen_loongson_lswc2(DisasContext *ctx, int rt,
gen_load_fpr32(ctx, fp0, rt);
t1 = tcg_temp_new();
tcg_gen_ext_i32_tl(t1, fp0);
- gen_lxl(ctx, t1, t0, ctx->mem_idx, MO_TEUL);
+ gen_lxl(ctx, t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UL);
tcg_gen_trunc_tl_i32(fp0, t1);
gen_store_fpr32(ctx, fp0, rt);
break;
@@ -4224,7 +4210,7 @@ static void gen_loongson_lswc2(DisasContext *ctx, int rt,
gen_load_fpr32(ctx, fp0, rt);
t1 = tcg_temp_new();
tcg_gen_ext_i32_tl(t1, fp0);
- gen_lxr(ctx, t1, t0, ctx->mem_idx, MO_TEUL);
+ gen_lxr(ctx, t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UL);
tcg_gen_trunc_tl_i32(fp0, t1);
gen_store_fpr32(ctx, fp0, rt);
break;
@@ -4234,7 +4220,7 @@ static void gen_loongson_lswc2(DisasContext *ctx, int rt,
gen_base_offset_addr(ctx, t0, rs, shf_offset);
t1 = tcg_temp_new();
gen_load_fpr64(ctx, t1, rt);
- gen_lxl(ctx, t1, t0, ctx->mem_idx, MO_TEUQ);
+ gen_lxl(ctx, t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ);
gen_store_fpr64(ctx, t1, rt);
break;
case OPC_GSLDRC1:
@@ -4242,7 +4228,7 @@ static void gen_loongson_lswc2(DisasContext *ctx, int rt,
gen_base_offset_addr(ctx, t0, rs, shf_offset);
t1 = tcg_temp_new();
gen_load_fpr64(ctx, t1, rt);
- gen_lxr(ctx, t1, t0, ctx->mem_idx, MO_TEUQ);
+ gen_lxr(ctx, t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ);
gen_store_fpr64(ctx, t1, rt);
break;
#endif
@@ -4360,7 +4346,7 @@ static void gen_loongson_lsdc2(DisasContext *ctx, int rt,
gen_store_gpr(t0, rt);
break;
case OPC_GSLHX:
- tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESW |
+ tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, mo_endian(ctx) | MO_SW |
ctx->default_tcg_memop_mask);
gen_store_gpr(t0, rt);
break;
@@ -4369,7 +4355,7 @@ static void gen_loongson_lsdc2(DisasContext *ctx, int rt,
if (rd) {
gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
}
- tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESL |
+ tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, mo_endian(ctx) | MO_SL |
ctx->default_tcg_memop_mask);
gen_store_gpr(t0, rt);
break;
@@ -4379,7 +4365,7 @@ static void gen_loongson_lsdc2(DisasContext *ctx, int rt,
if (rd) {
gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
}
- tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ |
+ tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ |
ctx->default_tcg_memop_mask);
gen_store_gpr(t0, rt);
break;
@@ -4390,7 +4376,7 @@ static void gen_loongson_lsdc2(DisasContext *ctx, int rt,
gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
}
fp0 = tcg_temp_new_i32();
- tcg_gen_qemu_ld_i32(fp0, t0, ctx->mem_idx, MO_TESL |
+ tcg_gen_qemu_ld_i32(fp0, t0, ctx->mem_idx, mo_endian(ctx) | MO_SL |
ctx->default_tcg_memop_mask);
gen_store_fpr32(ctx, fp0, rt);
break;
@@ -4400,7 +4386,7 @@ static void gen_loongson_lsdc2(DisasContext *ctx, int rt,
if (rd) {
gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
}
- tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ |
+ tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ |
ctx->default_tcg_memop_mask);
gen_store_fpr64(ctx, t0, rt);
break;
@@ -4413,34 +4399,34 @@ static void gen_loongson_lsdc2(DisasContext *ctx, int rt,
case OPC_GSSHX:
t1 = tcg_temp_new();
gen_load_gpr(t1, rt);
- tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUW |
+ tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UW |
ctx->default_tcg_memop_mask);
break;
case OPC_GSSWX:
t1 = tcg_temp_new();
gen_load_gpr(t1, rt);
- tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL |
+ tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UL |
ctx->default_tcg_memop_mask);
break;
#if defined(TARGET_MIPS64)
case OPC_GSSDX:
t1 = tcg_temp_new();
gen_load_gpr(t1, rt);
- tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUQ |
+ tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ |
ctx->default_tcg_memop_mask);
break;
#endif
case OPC_GSSWXC1:
fp0 = tcg_temp_new_i32();
gen_load_fpr32(ctx, fp0, rt);
- tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, MO_TEUL |
+ tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, mo_endian(ctx) | MO_UL |
ctx->default_tcg_memop_mask);
break;
#if defined(TARGET_MIPS64)
case OPC_GSSDXC1:
t1 = tcg_temp_new();
gen_load_fpr64(ctx, t1, rt);
- tcg_gen_qemu_st_i64(t1, t0, ctx->mem_idx, MO_TEUQ |
+ tcg_gen_qemu_st_i64(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ |
ctx->default_tcg_memop_mask);
break;
#endif
@@ -10779,7 +10765,7 @@ static void gen_flt3_ldst(DisasContext *ctx, uint32_t opc,
{
TCGv_i32 fp0 = tcg_temp_new_i32();
- tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESL);
+ tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, mo_endian(ctx) | MO_SL);
tcg_gen_trunc_tl_i32(fp0, t0);
gen_store_fpr32(ctx, fp0, fd);
}
@@ -10789,7 +10775,7 @@ static void gen_flt3_ldst(DisasContext *ctx, uint32_t opc,
check_cp1_registers(ctx, fd);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
- tcg_gen_qemu_ld_i64(fp0, t0, ctx->mem_idx, MO_TEUQ);
+ tcg_gen_qemu_ld_i64(fp0, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ);
gen_store_fpr64(ctx, fp0, fd);
}
break;
@@ -10799,7 +10785,7 @@ static void gen_flt3_ldst(DisasContext *ctx, uint32_t opc,
{
TCGv_i64 fp0 = tcg_temp_new_i64();
- tcg_gen_qemu_ld_i64(fp0, t0, ctx->mem_idx, MO_TEUQ);
+ tcg_gen_qemu_ld_i64(fp0, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ);
gen_store_fpr64(ctx, fp0, fd);
}
break;
@@ -10808,7 +10794,7 @@ static void gen_flt3_ldst(DisasContext *ctx, uint32_t opc,
{
TCGv_i32 fp0 = tcg_temp_new_i32();
gen_load_fpr32(ctx, fp0, fs);
- tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, MO_TEUL);
+ tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, mo_endian(ctx) | MO_UL);
}
break;
case OPC_SDXC1:
@@ -10817,7 +10803,7 @@ static void gen_flt3_ldst(DisasContext *ctx, uint32_t opc,
{
TCGv_i64 fp0 = tcg_temp_new_i64();
gen_load_fpr64(ctx, fp0, fs);
- tcg_gen_qemu_st_i64(fp0, t0, ctx->mem_idx, MO_TEUQ);
+ tcg_gen_qemu_st_i64(fp0, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ);
}
break;
case OPC_SUXC1:
@@ -10826,7 +10812,7 @@ static void gen_flt3_ldst(DisasContext *ctx, uint32_t opc,
{
TCGv_i64 fp0 = tcg_temp_new_i64();
gen_load_fpr64(ctx, fp0, fs);
- tcg_gen_qemu_st_i64(fp0, t0, ctx->mem_idx, MO_TEUQ);
+ tcg_gen_qemu_st_i64(fp0, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ);
}
break;
}
@@ -10856,7 +10842,7 @@ static void gen_flt3_arith(DisasContext *ctx, uint32_t opc,
tcg_gen_br(l2);
gen_set_label(l1);
tcg_gen_brcondi_tl(TCG_COND_NE, t0, 4, l2);
- if (cpu_is_bigendian(ctx)) {
+ if (disas_is_bigendian(ctx)) {
gen_load_fpr32(ctx, fp, fs);
gen_load_fpr32h(ctx, fph, ft);
gen_store_fpr32h(ctx, fp, fd);
@@ -11265,10 +11251,9 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc,
} else {
/* OPC_JIC, OPC_JIALC */
TCGv tbase = tcg_temp_new();
- TCGv toffset = tcg_constant_tl(offset);
gen_load_gpr(tbase, rt);
- gen_op_addr_add(ctx, btarget, tbase, toffset);
+ gen_op_addr_addi(ctx, btarget, tbase, offset);
}
break;
default:
@@ -11428,20 +11413,18 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc,
void gen_addiupc(DisasContext *ctx, int rx, int imm,
int is_64_bit, int extended)
{
- TCGv t0;
+ target_ulong npc;
if (extended && (ctx->hflags & MIPS_HFLAG_BMASK)) {
gen_reserved_instruction(ctx);
return;
}
- t0 = tcg_temp_new();
-
- tcg_gen_movi_tl(t0, pc_relative_pc(ctx));
- tcg_gen_addi_tl(cpu_gpr[rx], t0, imm);
+ npc = pc_relative_pc(ctx) + imm;
if (!is_64_bit) {
- tcg_gen_ext32s_tl(cpu_gpr[rx], cpu_gpr[rx]);
+ npc = (int32_t)npc;
}
+ tcg_gen_movi_tl(cpu_gpr[rx], npc);
}
static void gen_cache_operation(DisasContext *ctx, uint32_t op, int base,
@@ -11476,7 +11459,7 @@ void gen_ldxs(DisasContext *ctx, int base, int index, int rd)
gen_op_addr_add(ctx, t0, t1, t0);
}
- tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TESL);
+ tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, mo_endian(ctx) | MO_SL);
gen_store_gpr(t1, rd);
}
@@ -11567,16 +11550,16 @@ static void gen_mips_lx(DisasContext *ctx, uint32_t opc,
gen_store_gpr(t0, rd);
break;
case OPC_LHX:
- tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESW);
+ tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, mo_endian(ctx) | MO_SW);
gen_store_gpr(t0, rd);
break;
case OPC_LWX:
- tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESL);
+ tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, mo_endian(ctx) | MO_SL);
gen_store_gpr(t0, rd);
break;
#if defined(TARGET_MIPS64)
case OPC_LDX:
- tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUQ);
+ tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, mo_endian(ctx) | MO_UQ);
gen_store_gpr(t0, rd);
break;
#endif
@@ -13719,7 +13702,7 @@ static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx)
}
break;
case R6_OPC_SC:
- gen_st_cond(ctx, rt, rs, imm, MO_TESL, false);
+ gen_st_cond(ctx, rt, rs, imm, mo_endian(ctx) | MO_SL, false);
break;
case R6_OPC_LL:
gen_ld(ctx, op1, rt, rs, imm);
@@ -13765,7 +13748,7 @@ static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx)
#endif
#if defined(TARGET_MIPS64)
case R6_OPC_SCD:
- gen_st_cond(ctx, rt, rs, imm, MO_TEUQ, false);
+ gen_st_cond(ctx, rt, rs, imm, mo_endian(ctx) | MO_UQ, false);
break;
case R6_OPC_LLD:
gen_ld(ctx, op1, rt, rs, imm);
@@ -14448,7 +14431,7 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
return;
case OPC_SCE:
check_cp0_enabled(ctx);
- gen_st_cond(ctx, rt, rs, imm, MO_TESL, true);
+ gen_st_cond(ctx, rt, rs, imm, mo_endian(ctx) | MO_SL, true);
return;
case OPC_CACHEE:
check_eva(ctx);
@@ -14912,7 +14895,7 @@ static bool decode_opc_legacy(CPUMIPSState *env, DisasContext *ctx)
if (ctx->insn_flags & INSN_R5900) {
check_insn_opc_user_only(ctx, INSN_R5900);
}
- gen_st_cond(ctx, rt, rs, imm, MO_TESL, false);
+ gen_st_cond(ctx, rt, rs, imm, mo_endian(ctx) | MO_SL, false);
break;
case OPC_CACHE:
check_cp0_enabled(ctx);
@@ -15191,7 +15174,7 @@ static bool decode_opc_legacy(CPUMIPSState *env, DisasContext *ctx)
check_insn_opc_user_only(ctx, INSN_R5900);
}
check_mips_64(ctx);
- gen_st_cond(ctx, rt, rs, imm, MO_TEUQ, false);
+ gen_st_cond(ctx, rt, rs, imm, mo_endian(ctx) | MO_UQ, false);
break;
case OPC_BNVC: /* OPC_BNEZALC, OPC_BNEC, OPC_DADDI */
if (ctx->insn_flags & ISA_MIPS_R6) {
@@ -15362,7 +15345,8 @@ static void mips_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
* hardware does (e.g. if a delay slot instruction faults, the
* reported PC is the PC of the branch).
*/
- if (ctx->base.singlestep_enabled && (ctx->hflags & MIPS_HFLAG_BMASK)) {
+ if ((tb_cflags(ctx->base.tb) & CF_SINGLE_STEP) &&
+ (ctx->hflags & MIPS_HFLAG_BMASK)) {
ctx->base.max_insns = 2;
}
@@ -15445,7 +15429,7 @@ static void mips_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
* together with its delay slot.
*/
if (ctx->base.pc_next - ctx->page_start >= TARGET_PAGE_SIZE
- && !ctx->base.singlestep_enabled) {
+ && !(tb_cflags(ctx->base.tb) & CF_SINGLE_STEP)) {
ctx->base.is_jmp = DISAS_TOO_MANY;
}
}
diff --git a/target/mips/tcg/translate.h b/target/mips/tcg/translate.h
index 2b6646b..5d196e6 100644
--- a/target/mips/tcg/translate.h
+++ b/target/mips/tcg/translate.h
@@ -176,6 +176,7 @@ void gen_addiupc(DisasContext *ctx, int rx, int imm,
* Address Computation and Large Constant Instructions
*/
void gen_op_addr_add(DisasContext *ctx, TCGv ret, TCGv arg0, TCGv arg1);
+void gen_op_addr_addi(DisasContext *ctx, TCGv ret, TCGv base, target_long ofs);
bool gen_lsa(DisasContext *ctx, int rd, int rt, int rs, int sa);
bool gen_dlsa(DisasContext *ctx, int rd, int rt, int rs, int sa);
@@ -235,9 +236,19 @@ bool decode_ext_vr54xx(DisasContext *ctx, uint32_t insn);
static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \
{ return FUNC(ctx, a, __VA_ARGS__); }
-static inline bool cpu_is_bigendian(DisasContext *ctx)
+static inline bool disas_is_bigendian(DisasContext *ctx)
{
return extract32(ctx->CP0_Config0, CP0C0_BE, 1);
}
+static inline MemOp mo_endian(DisasContext *dc)
+{
+ return disas_is_bigendian(dc) ? MO_BE : MO_LE;
+}
+
+static inline MemOp mo_endian_rev(DisasContext *dc, bool reversed)
+{
+ return disas_is_bigendian(dc) ^ reversed ? MO_BE : MO_LE;
+}
+
#endif
diff --git a/target/mips/tcg/tx79_translate.c b/target/mips/tcg/tx79_translate.c
index dd6fb8a..ae3f5e1 100644
--- a/target/mips/tcg/tx79_translate.c
+++ b/target/mips/tcg/tx79_translate.c
@@ -340,12 +340,12 @@ static bool trans_LQ(DisasContext *ctx, arg_i *a)
tcg_gen_andi_tl(addr, addr, ~0xf);
/* Lower half */
- tcg_gen_qemu_ld_i64(t0, addr, ctx->mem_idx, MO_TEUQ);
+ tcg_gen_qemu_ld_i64(t0, addr, ctx->mem_idx, mo_endian(ctx) | MO_UQ);
gen_store_gpr(t0, a->rt);
/* Upper half */
tcg_gen_addi_i64(addr, addr, 8);
- tcg_gen_qemu_ld_i64(t0, addr, ctx->mem_idx, MO_TEUQ);
+ tcg_gen_qemu_ld_i64(t0, addr, ctx->mem_idx, mo_endian(ctx) | MO_UQ);
gen_store_gpr_hi(t0, a->rt);
return true;
}
@@ -364,12 +364,12 @@ static bool trans_SQ(DisasContext *ctx, arg_i *a)
/* Lower half */
gen_load_gpr(t0, a->rt);
- tcg_gen_qemu_st_i64(t0, addr, ctx->mem_idx, MO_TEUQ);
+ tcg_gen_qemu_st_i64(t0, addr, ctx->mem_idx, mo_endian(ctx) | MO_UQ);
/* Upper half */
tcg_gen_addi_i64(addr, addr, 8);
gen_load_gpr_hi(t0, a->rt);
- tcg_gen_qemu_st_i64(t0, addr, ctx->mem_idx, MO_TEUQ);
+ tcg_gen_qemu_st_i64(t0, addr, ctx->mem_idx, mo_endian(ctx) | MO_UQ);
return true;
}
diff --git a/target/openrisc/cpu-param.h b/target/openrisc/cpu-param.h
index fbfc0f5..6169ed9 100644
--- a/target/openrisc/cpu-param.h
+++ b/target/openrisc/cpu-param.h
@@ -2,7 +2,7 @@
* OpenRISC cpu parameters for qemu.
*
* Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
- * SPDX-License-Identifier: LGPL-2.0+
+ * SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef OPENRISC_CPU_PARAM_H
diff --git a/target/ppc/arch_dump.c b/target/ppc/arch_dump.c
index a831565..f454741 100644
--- a/target/ppc/arch_dump.c
+++ b/target/ppc/arch_dump.c
@@ -47,9 +47,14 @@ struct PPCUserRegStruct {
} QEMU_PACKED;
struct PPCElfPrstatus {
- char pad1[112];
+ char pad1[32]; /* 32 == offsetof(struct elf_prstatus, pr_pid) */
+ uint32_t pid;
+ char pad2[76]; /* 76 == offsetof(struct elf_prstatus, pr_reg) -
+ offsetof(struct elf_prstatus, pr_ppid) */
struct PPCUserRegStruct pr_reg;
- char pad2[40];
+ char pad3[40]; /* 40 == sizeof(struct elf_prstatus) -
+ offsetof(struct elf_prstatus, pr_reg) -
+ sizeof(struct user_pt_regs) */
} QEMU_PACKED;
@@ -96,7 +101,7 @@ typedef struct NoteFuncArg {
DumpState *state;
} NoteFuncArg;
-static void ppc_write_elf_prstatus(NoteFuncArg *arg, PowerPCCPU *cpu)
+static void ppc_write_elf_prstatus(NoteFuncArg *arg, PowerPCCPU *cpu, int id)
{
int i;
reg_t cr;
@@ -109,6 +114,7 @@ static void ppc_write_elf_prstatus(NoteFuncArg *arg, PowerPCCPU *cpu)
prstatus = &note->contents.prstatus;
memset(prstatus, 0, sizeof(*prstatus));
+ prstatus->pid = cpu_to_dump32(s, id);
reg = &prstatus->pr_reg;
for (i = 0; i < 32; i++) {
@@ -127,7 +133,7 @@ static void ppc_write_elf_prstatus(NoteFuncArg *arg, PowerPCCPU *cpu)
reg->ccr = cpu_to_dump_reg(s, cr);
}
-static void ppc_write_elf_fpregset(NoteFuncArg *arg, PowerPCCPU *cpu)
+static void ppc_write_elf_fpregset(NoteFuncArg *arg, PowerPCCPU *cpu, int id)
{
int i;
struct PPCElfFpregset *fpregset;
@@ -146,7 +152,7 @@ static void ppc_write_elf_fpregset(NoteFuncArg *arg, PowerPCCPU *cpu)
fpregset->fpscr = cpu_to_dump_reg(s, cpu->env.fpscr);
}
-static void ppc_write_elf_vmxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
+static void ppc_write_elf_vmxregset(NoteFuncArg *arg, PowerPCCPU *cpu, int id)
{
int i;
struct PPCElfVmxregset *vmxregset;
@@ -178,7 +184,7 @@ static void ppc_write_elf_vmxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
vmxregset->vscr.u32[3] = cpu_to_dump32(s, ppc_get_vscr(&cpu->env));
}
-static void ppc_write_elf_vsxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
+static void ppc_write_elf_vsxregset(NoteFuncArg *arg, PowerPCCPU *cpu, int id)
{
int i;
struct PPCElfVsxregset *vsxregset;
@@ -195,7 +201,7 @@ static void ppc_write_elf_vsxregset(NoteFuncArg *arg, PowerPCCPU *cpu)
}
}
-static void ppc_write_elf_speregset(NoteFuncArg *arg, PowerPCCPU *cpu)
+static void ppc_write_elf_speregset(NoteFuncArg *arg, PowerPCCPU *cpu, int id)
{
struct PPCElfSperegset *speregset;
Note *note = &arg->note;
@@ -211,7 +217,7 @@ static void ppc_write_elf_speregset(NoteFuncArg *arg, PowerPCCPU *cpu)
static const struct NoteFuncDescStruct {
int contents_size;
- void (*note_contents_func)(NoteFuncArg *arg, PowerPCCPU *cpu);
+ void (*note_contents_func)(NoteFuncArg *arg, PowerPCCPU *cpu, int id);
} note_func[] = {
{sizeof_field(Note, contents.prstatus), ppc_write_elf_prstatus},
{sizeof_field(Note, contents.fpregset), ppc_write_elf_fpregset},
@@ -282,7 +288,7 @@ static int ppc_write_all_elf_notes(const char *note_name,
arg.note.hdr.n_descsz = cpu_to_dump32(s, nf->contents_size);
strncpy(arg.note.name, note_name, sizeof(arg.note.name));
- (*nf->note_contents_func)(&arg, cpu);
+ (*nf->note_contents_func)(&arg, cpu, id);
note_size =
sizeof(arg.note) - sizeof(arg.note.contents) + nf->contents_size;
diff --git a/target/ppc/cpu-param.h b/target/ppc/cpu-param.h
index 77c5ed9..9c481b9 100644
--- a/target/ppc/cpu-param.h
+++ b/target/ppc/cpu-param.h
@@ -2,7 +2,7 @@
* PowerPC cpu parameters for qemu.
*
* Copyright (c) 2007 Jocelyn Mayer
- * SPDX-License-Identifier: LGPL-2.0+
+ * SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef PPC_CPU_PARAM_H
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 2015e60..321ed2d 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -1197,21 +1197,6 @@ DEXCR_ASPECT(NPHIE, 5)
DEXCR_ASPECT(PHIE, 6)
/*****************************************************************************/
-/* PowerNV ChipTOD and TimeBase State Machine */
-struct pnv_tod_tbst {
- int tb_ready_for_tod; /* core TB ready to receive TOD from chiptod */
- int tod_sent_to_tb; /* chiptod sent TOD to the core TB */
-
- /*
- * "Timers" for async TBST events are simulated by mfTFAC because TFAC
- * is polled for such events. These are just used to ensure firmware
- * performs the polling at least a few times.
- */
- int tb_state_timer;
- int tb_sync_pulse_timer;
-};
-
-/*****************************************************************************/
/* The whole PowerPC CPU context */
/*
@@ -1262,15 +1247,16 @@ struct CPUArchState {
/* when a memory exception occurs, the access type is stored here */
int access_type;
+ /* For SMT processors */
+ bool has_smt_siblings;
+ int core_index;
+
#if !defined(CONFIG_USER_ONLY)
/* MMU context, only relevant for full system emulation */
#if defined(TARGET_PPC64)
ppc_slb_t slb[MAX_SLB_ENTRIES]; /* PowerPC 64 SLB area */
struct CPUBreakpoint *ciabr_breakpoint;
struct CPUWatchpoint *dawr0_watchpoint;
-
- /* POWER CPU regs/state */
- target_ulong scratch[8]; /* SCRATCH registers (shared across core) */
#endif
target_ulong sr[32]; /* segment registers */
uint32_t nb_BATs; /* number of BATs */
@@ -1291,12 +1277,6 @@ struct CPUArchState {
uint32_t tlb_need_flush; /* Delayed flush needed */
#define TLB_NEED_LOCAL_FLUSH 0x1
#define TLB_NEED_GLOBAL_FLUSH 0x2
-
-#if defined(TARGET_PPC64)
- /* PowerNV chiptod / timebase facility state. */
- /* Would be nice to put these into PnvCore */
- struct pnv_tod_tbst pnv_tod_tbst;
-#endif
#endif
/* Other registers */
@@ -1426,12 +1406,10 @@ struct CPUArchState {
uint64_t pmu_base_time;
};
-#define _CORE_ID(cs) \
- (POWERPC_CPU(cs)->env.spr_cb[SPR_PIR].default_value & ~(cs->nr_threads - 1))
-
#define THREAD_SIBLING_FOREACH(cs, cs_sibling) \
CPU_FOREACH(cs_sibling) \
- if (_CORE_ID(cs) == _CORE_ID(cs_sibling))
+ if (POWERPC_CPU(cs)->env.core_index == \
+ POWERPC_CPU(cs_sibling)->env.core_index)
#define SET_FIT_PERIOD(a_, b_, c_, d_) \
do { \
@@ -1535,6 +1513,17 @@ struct PowerPCCPUClass {
int (*check_attn)(CPUPPCState *env);
};
+static inline bool ppc_cpu_core_single_threaded(CPUState *cs)
+{
+ return !POWERPC_CPU(cs)->env.has_smt_siblings;
+}
+
+static inline bool ppc_cpu_lpar_single_threaded(CPUState *cs)
+{
+ return !(POWERPC_CPU(cs)->env.flags & POWERPC_FLAG_SMT_1LPAR) ||
+ ppc_cpu_core_single_threaded(cs);
+}
+
ObjectClass *ppc_cpu_class_by_name(const char *name);
PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr);
PowerPCCPUClass *ppc_cpu_class_by_pvr_mask(uint32_t pvr);
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index cdada79..23881d0 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -5760,16 +5760,6 @@ static void register_power_common_book4_sprs(CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_core_write_generic,
0x00000000);
- spr_register_hv(env, SPR_POWER_SPRC, "SPRC",
- SPR_NOACCESS, SPR_NOACCESS,
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_sprc,
- 0x00000000);
- spr_register_hv(env, SPR_POWER_SPRD, "SPRD",
- SPR_NOACCESS, SPR_NOACCESS,
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_sprd, &spr_write_sprd,
- 0x00000000);
#endif
}
@@ -5803,6 +5793,17 @@ static void register_power8_book4_sprs(CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
KVM_REG_PPC_WORT, 0);
+ /* SPRC/SPRD exist in earlier CPUs but only tested on POWER9/10 */
+ spr_register_hv(env, SPR_POWER_SPRC, "SPRC",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_sprc,
+ 0x00000000);
+ spr_register_hv(env, SPR_POWER_SPRD, "SPRD",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_sprd, &spr_write_sprd,
+ 0x00000000);
#endif
}
@@ -5873,22 +5874,22 @@ static void register_power10_hash_sprs(CPUPPCState *env)
((uint64_t)g_rand_int(rand) << 32) | (uint64_t)g_rand_int(rand);
g_rand_free(rand);
#endif
- spr_register(env, SPR_HASHKEYR, "HASHKEYR",
+ spr_register_kvm(env, SPR_HASHKEYR, "HASHKEYR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
- hashkeyr_initial_value);
- spr_register_hv(env, SPR_HASHPKEYR, "HASHPKEYR",
+ KVM_REG_PPC_HASHKEYR, hashkeyr_initial_value);
+ spr_register_kvm_hv(env, SPR_HASHPKEYR, "HASHPKEYR",
SPR_NOACCESS, SPR_NOACCESS,
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
- hashpkeyr_initial_value);
+ KVM_REG_PPC_HASHPKEYR, hashpkeyr_initial_value);
}
static void register_power10_dexcr_sprs(CPUPPCState *env)
{
- spr_register(env, SPR_DEXCR, "DEXCR",
+ spr_register_kvm(env, SPR_DEXCR, "DEXCR",
SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
+ &spr_read_generic, &spr_write_generic, KVM_REG_PPC_DEXCR,
0);
spr_register(env, SPR_UDEXCR, "UDEXCR",
@@ -6785,7 +6786,8 @@ void cpu_ppc_set_1lpar(PowerPCCPU *cpu)
/*
* pseries SMT means "LPAR per core" mode, e.g., msgsndp is usable
- * between threads.
+ * between threads. powernv be in either mode, and it mostly affects
+ * supervisor visible registers and instructions.
*/
if (env->flags & POWERPC_FLAG_SMT) {
env->flags |= POWERPC_FLAG_SMT_1LPAR;
@@ -6975,7 +6977,7 @@ static void ppc_cpu_realize(DeviceState *dev, Error **errp)
pcc->parent_realize(dev, errp);
- if (env_cpu(env)->nr_threads > 1) {
+ if (!ppc_cpu_core_single_threaded(cs)) {
env->flags |= POWERPC_FLAG_SMT;
}
diff --git a/target/ppc/dfp_helper.c b/target/ppc/dfp_helper.c
index 5967ea0..ecc3f79 100644
--- a/target/ppc/dfp_helper.c
+++ b/target/ppc/dfp_helper.c
@@ -249,7 +249,7 @@ static void dfp_set_FPRF_from_FRT_with_context(struct PPC_DFP *dfp,
fprf = 0x05;
break;
default:
- assert(0); /* should never get here */
+ g_assert_not_reached();
}
dfp->env->fpscr &= ~FP_FPRF;
dfp->env->fpscr |= (fprf << FPSCR_FPRF);
@@ -1243,7 +1243,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \
} else if (decNumberIsQNaN(&dfp.b)) { \
vt.VsrD(1) = -2; \
} else { \
- assert(0); \
+ g_assert_not_reached(); \
} \
set_dfp64(t, &vt); \
} else { \
@@ -1252,7 +1252,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \
} else if ((size) == 128) { \
vt.VsrD(1) = dfp.b.exponent + 6176; \
} else { \
- assert(0); \
+ g_assert_not_reached(); \
} \
set_dfp64(t, &vt); \
} \
@@ -1300,7 +1300,7 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \
raw_inf = 0x1e000; \
bias = 6176; \
} else { \
- assert(0); \
+ g_assert_not_reached(); \
} \
\
if (unlikely((exp < 0) || (exp > max_exp))) { \
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 0cd5426..f33fc36 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -2998,6 +2998,34 @@ static inline bool dbell_bcast_subproc(target_ulong rb)
return (rb & DBELL_BRDCAST_MASK) == DBELL_BRDCAST_SUBPROC;
}
+/*
+ * Send an interrupt to a thread in the same core as env).
+ */
+static void msgsnd_core_tir(CPUPPCState *env, uint32_t target_tir, int irq)
+{
+ PowerPCCPU *cpu = env_archcpu(env);
+ CPUState *cs = env_cpu(env);
+
+ if (ppc_cpu_lpar_single_threaded(cs)) {
+ if (target_tir == 0) {
+ ppc_set_irq(cpu, irq, 1);
+ }
+ } else {
+ CPUState *ccs;
+
+ /* Does iothread need to be locked for walking CPU list? */
+ bql_lock();
+ THREAD_SIBLING_FOREACH(cs, ccs) {
+ PowerPCCPU *ccpu = POWERPC_CPU(ccs);
+ if (target_tir == ppc_cpu_tir(ccpu)) {
+ ppc_set_irq(ccpu, irq, 1);
+ break;
+ }
+ }
+ bql_unlock();
+ }
+}
+
void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb)
{
if (!dbell_type_server(rb)) {
@@ -3018,6 +3046,13 @@ void helper_book3s_msgsnd(CPUPPCState *env, target_ulong rb)
return;
}
+ /* POWER8 msgsnd is like msgsndp (targets a thread within core) */
+ if (!(env->insns_flags2 & PPC2_ISA300)) {
+ msgsnd_core_tir(env, rb & PPC_BITMASK(57, 63), PPC_INTERRUPT_HDOORBELL);
+ return;
+ }
+
+ /* POWER9 and later msgsnd is a global (targets any thread) */
cpu = ppc_get_vcpu_by_pir(pir);
if (!cpu) {
return;
@@ -3029,7 +3064,7 @@ void helper_book3s_msgsnd(CPUPPCState *env, target_ulong rb)
brdcast = true;
}
- if (cs->nr_threads == 1 || !brdcast) {
+ if (ppc_cpu_core_single_threaded(cs) || !brdcast) {
ppc_set_irq(cpu, PPC_INTERRUPT_HDOORBELL, 1);
return;
}
@@ -3064,41 +3099,13 @@ void helper_book3s_msgclrp(CPUPPCState *env, target_ulong rb)
*/
void helper_book3s_msgsndp(CPUPPCState *env, target_ulong rb)
{
- CPUState *cs = env_cpu(env);
- PowerPCCPU *cpu = env_archcpu(env);
- CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
- int ttir = rb & PPC_BITMASK(57, 63);
-
helper_hfscr_facility_check(env, HFSCR_MSGP, "msgsndp", HFSCR_IC_MSGP);
- if (!(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
- nr_threads = 1; /* msgsndp behaves as 1-thread in LPAR-per-thread mode*/
- }
-
- if (!dbell_type_server(rb) || ttir >= nr_threads) {
- return;
- }
-
- if (nr_threads == 1) {
- ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, 1);
+ if (!dbell_type_server(rb)) {
return;
}
- /* Does iothread need to be locked for walking CPU list? */
- bql_lock();
- THREAD_SIBLING_FOREACH(cs, ccs) {
- PowerPCCPU *ccpu = POWERPC_CPU(ccs);
- uint32_t thread_id = ppc_cpu_tir(ccpu);
-
- if (ttir == thread_id) {
- ppc_set_irq(ccpu, PPC_INTERRUPT_DOORBELL, 1);
- bql_unlock();
- return;
- }
- }
-
- g_assert_not_reached();
+ msgsnd_core_tir(env, rb & PPC_BITMASK(57, 63), PPC_INTERRUPT_DOORBELL);
}
#endif /* TARGET_PPC64 */
diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c
index 51bce99..230466a 100644
--- a/target/ppc/fpu_helper.c
+++ b/target/ppc/fpu_helper.c
@@ -1599,14 +1599,14 @@ void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \
do_float_check_status(env, sfifprf, GETPC()); \
}
-VSX_ADD_SUB(xsadddp, add, 1, float64, VsrD(0), 1, 0)
-VSX_ADD_SUB(xsaddsp, add, 1, float64, VsrD(0), 1, 1)
-VSX_ADD_SUB(xvadddp, add, 2, float64, VsrD(i), 0, 0)
-VSX_ADD_SUB(xvaddsp, add, 4, float32, VsrW(i), 0, 0)
-VSX_ADD_SUB(xssubdp, sub, 1, float64, VsrD(0), 1, 0)
-VSX_ADD_SUB(xssubsp, sub, 1, float64, VsrD(0), 1, 1)
-VSX_ADD_SUB(xvsubdp, sub, 2, float64, VsrD(i), 0, 0)
-VSX_ADD_SUB(xvsubsp, sub, 4, float32, VsrW(i), 0, 0)
+VSX_ADD_SUB(XSADDDP, add, 1, float64, VsrD(0), 1, 0)
+VSX_ADD_SUB(XSADDSP, add, 1, float64, VsrD(0), 1, 1)
+VSX_ADD_SUB(XVADDDP, add, 2, float64, VsrD(i), 0, 0)
+VSX_ADD_SUB(XVADDSP, add, 4, float32, VsrW(i), 0, 0)
+VSX_ADD_SUB(XSSUBDP, sub, 1, float64, VsrD(0), 1, 0)
+VSX_ADD_SUB(XSSUBSP, sub, 1, float64, VsrD(0), 1, 1)
+VSX_ADD_SUB(XVSUBDP, sub, 2, float64, VsrD(i), 0, 0)
+VSX_ADD_SUB(XVSUBSP, sub, 4, float32, VsrW(i), 0, 0)
void helper_xsaddqp(CPUPPCState *env, uint32_t opcode,
ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb)
@@ -1676,10 +1676,10 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
do_float_check_status(env, sfifprf, GETPC()); \
}
-VSX_MUL(xsmuldp, 1, float64, VsrD(0), 1, 0)
-VSX_MUL(xsmulsp, 1, float64, VsrD(0), 1, 1)
-VSX_MUL(xvmuldp, 2, float64, VsrD(i), 0, 0)
-VSX_MUL(xvmulsp, 4, float32, VsrW(i), 0, 0)
+VSX_MUL(XSMULDP, 1, float64, VsrD(0), 1, 0)
+VSX_MUL(XSMULSP, 1, float64, VsrD(0), 1, 1)
+VSX_MUL(XVMULDP, 2, float64, VsrD(i), 0, 0)
+VSX_MUL(XVMULSP, 4, float32, VsrW(i), 0, 0)
void helper_xsmulqp(CPUPPCState *env, uint32_t opcode,
ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb)
@@ -1750,10 +1750,10 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
do_float_check_status(env, sfifprf, GETPC()); \
}
-VSX_DIV(xsdivdp, 1, float64, VsrD(0), 1, 0)
-VSX_DIV(xsdivsp, 1, float64, VsrD(0), 1, 1)
-VSX_DIV(xvdivdp, 2, float64, VsrD(i), 0, 0)
-VSX_DIV(xvdivsp, 4, float32, VsrW(i), 0, 0)
+VSX_DIV(XSDIVDP, 1, float64, VsrD(0), 1, 0)
+VSX_DIV(XSDIVSP, 1, float64, VsrD(0), 1, 1)
+VSX_DIV(XVDIVDP, 2, float64, VsrD(i), 0, 0)
+VSX_DIV(XVDIVSP, 4, float32, VsrW(i), 0, 0)
void helper_xsdivqp(CPUPPCState *env, uint32_t opcode,
ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb)
@@ -2383,12 +2383,12 @@ void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \
do_float_check_status(env, false, GETPC()); \
}
-VSX_MAX_MIN(xsmaxdp, maxnum, 1, float64, VsrD(0))
-VSX_MAX_MIN(xvmaxdp, maxnum, 2, float64, VsrD(i))
-VSX_MAX_MIN(xvmaxsp, maxnum, 4, float32, VsrW(i))
-VSX_MAX_MIN(xsmindp, minnum, 1, float64, VsrD(0))
-VSX_MAX_MIN(xvmindp, minnum, 2, float64, VsrD(i))
-VSX_MAX_MIN(xvminsp, minnum, 4, float32, VsrW(i))
+VSX_MAX_MIN(XSMAXDP, maxnum, 1, float64, VsrD(0))
+VSX_MAX_MIN(XVMAXDP, maxnum, 2, float64, VsrD(i))
+VSX_MAX_MIN(XVMAXSP, maxnum, 4, float32, VsrW(i))
+VSX_MAX_MIN(XSMINDP, minnum, 1, float64, VsrD(0))
+VSX_MAX_MIN(XVMINDP, minnum, 2, float64, VsrD(i))
+VSX_MAX_MIN(XVMINSP, minnum, 4, float32, VsrW(i))
#define VSX_MAX_MINC(name, max, tp, fld) \
void helper_##name(CPUPPCState *env, \
@@ -2527,14 +2527,14 @@ uint32_t helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
return crf6; \
}
-VSX_CMP(xvcmpeqdp, 2, float64, VsrD(i), eq, 0, 1)
-VSX_CMP(xvcmpgedp, 2, float64, VsrD(i), le, 1, 1)
-VSX_CMP(xvcmpgtdp, 2, float64, VsrD(i), lt, 1, 1)
-VSX_CMP(xvcmpnedp, 2, float64, VsrD(i), eq, 0, 0)
-VSX_CMP(xvcmpeqsp, 4, float32, VsrW(i), eq, 0, 1)
-VSX_CMP(xvcmpgesp, 4, float32, VsrW(i), le, 1, 1)
-VSX_CMP(xvcmpgtsp, 4, float32, VsrW(i), lt, 1, 1)
-VSX_CMP(xvcmpnesp, 4, float32, VsrW(i), eq, 0, 0)
+VSX_CMP(XVCMPEQDP, 2, float64, VsrD(i), eq, 0, 1)
+VSX_CMP(XVCMPGEDP, 2, float64, VsrD(i), le, 1, 1)
+VSX_CMP(XVCMPGTDP, 2, float64, VsrD(i), lt, 1, 1)
+VSX_CMP(XVCMPNEDP, 2, float64, VsrD(i), eq, 0, 0)
+VSX_CMP(XVCMPEQSP, 4, float32, VsrW(i), eq, 0, 1)
+VSX_CMP(XVCMPGESP, 4, float32, VsrW(i), le, 1, 1)
+VSX_CMP(XVCMPGTSP, 4, float32, VsrW(i), lt, 1, 1)
+VSX_CMP(XVCMPNESP, 4, float32, VsrW(i), eq, 0, 0)
/*
* VSX_CVT_FP_TO_FP - VSX floating point/floating point conversion
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 76b8f25..5a77e76 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -46,8 +46,10 @@ DEF_HELPER_FLAGS_3(stmw, TCG_CALL_NO_WG, void, env, tl, i32)
DEF_HELPER_4(lsw, void, env, tl, i32, i32)
DEF_HELPER_5(lswx, void, env, tl, i32, i32, i32)
DEF_HELPER_FLAGS_4(stsw, TCG_CALL_NO_WG, void, env, tl, i32, i32)
-DEF_HELPER_FLAGS_3(dcbz, TCG_CALL_NO_WG, void, env, tl, i32)
-DEF_HELPER_FLAGS_3(dcbzep, TCG_CALL_NO_WG, void, env, tl, i32)
+DEF_HELPER_FLAGS_3(dcbz, TCG_CALL_NO_WG, void, env, tl, int)
+#ifdef TARGET_PPC64
+DEF_HELPER_FLAGS_2(dcbzl, TCG_CALL_NO_WG, void, env, tl)
+#endif
DEF_HELPER_FLAGS_2(icbi, TCG_CALL_NO_WG, void, env, tl)
DEF_HELPER_FLAGS_2(icbiep, TCG_CALL_NO_WG, void, env, tl)
DEF_HELPER_5(lscbx, tl, env, tl, i32, i32, i32)
@@ -201,18 +203,18 @@ DEF_HELPER_FLAGS_3(vsro, TCG_CALL_NO_RWG, void, avr, avr, avr)
DEF_HELPER_FLAGS_3(vsrv, TCG_CALL_NO_RWG, void, avr, avr, avr)
DEF_HELPER_FLAGS_3(vslv, TCG_CALL_NO_RWG, void, avr, avr, avr)
DEF_HELPER_FLAGS_3(VPRTYBQ, TCG_CALL_NO_RWG, void, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vaddsbs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vaddshs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vaddsws, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vsubsbs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vsubshs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vsubsws, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vaddubs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vadduhs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vadduws, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vsububs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vsubuhs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
-DEF_HELPER_FLAGS_5(vsubuws, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VADDSBS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VADDSHS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VADDSWS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VSUBSBS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VSUBSHS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VSUBSWS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VADDUBS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VADDUHS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VADDUWS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VSUBUBS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VSUBUHS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
+DEF_HELPER_FLAGS_5(VSUBUWS, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32)
DEF_HELPER_FLAGS_3(VADDUQM, TCG_CALL_NO_RWG, void, avr, avr, avr)
DEF_HELPER_FLAGS_4(VADDECUQ, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
DEF_HELPER_FLAGS_4(VADDEUQM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr)
@@ -275,10 +277,10 @@ DEF_HELPER_3(STVEBX, void, env, avr, tl)
DEF_HELPER_3(STVEHX, void, env, avr, tl)
DEF_HELPER_3(STVEWX, void, env, avr, tl)
#if defined(TARGET_PPC64)
-DEF_HELPER_4(lxvl, void, env, tl, vsr, tl)
-DEF_HELPER_4(lxvll, void, env, tl, vsr, tl)
-DEF_HELPER_4(stxvl, void, env, tl, vsr, tl)
-DEF_HELPER_4(stxvll, void, env, tl, vsr, tl)
+DEF_HELPER_4(LXVL, void, env, tl, vsr, tl)
+DEF_HELPER_4(LXVLL, void, env, tl, vsr, tl)
+DEF_HELPER_4(STXVL, void, env, tl, vsr, tl)
+DEF_HELPER_4(STXVLL, void, env, tl, vsr, tl)
#endif
DEF_HELPER_4(vsumsws, void, env, avr, avr, avr)
DEF_HELPER_4(vsum2sws, void, env, avr, avr, avr)
@@ -362,12 +364,12 @@ DEF_HELPER_FLAGS_4(bcdsr, TCG_CALL_NO_RWG, i32, avr, avr, avr, i32)
DEF_HELPER_FLAGS_4(bcdtrunc, TCG_CALL_NO_RWG, i32, avr, avr, avr, i32)
DEF_HELPER_FLAGS_4(bcdutrunc, TCG_CALL_NO_RWG, i32, avr, avr, avr, i32)
-DEF_HELPER_4(xsadddp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XSADDDP, void, env, vsr, vsr, vsr)
DEF_HELPER_5(xsaddqp, void, env, i32, vsr, vsr, vsr)
-DEF_HELPER_4(xssubdp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xsmuldp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XSSUBDP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XSMULDP, void, env, vsr, vsr, vsr)
DEF_HELPER_5(xsmulqp, void, env, i32, vsr, vsr, vsr)
-DEF_HELPER_4(xsdivdp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XSDIVDP, void, env, vsr, vsr, vsr)
DEF_HELPER_5(xsdivqp, void, env, i32, vsr, vsr, vsr)
DEF_HELPER_3(xsredp, void, env, vsr, vsr)
DEF_HELPER_3(xssqrtdp, void, env, vsr, vsr)
@@ -390,8 +392,8 @@ DEF_HELPER_4(xscmpodp, void, env, i32, vsr, vsr)
DEF_HELPER_4(xscmpudp, void, env, i32, vsr, vsr)
DEF_HELPER_4(xscmpoqp, void, env, i32, vsr, vsr)
DEF_HELPER_4(xscmpuqp, void, env, i32, vsr, vsr)
-DEF_HELPER_4(xsmaxdp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xsmindp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XSMAXDP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XSMINDP, void, env, vsr, vsr, vsr)
DEF_HELPER_4(XSMAXCDP, void, env, vsr, vsr, vsr)
DEF_HELPER_4(XSMINCDP, void, env, vsr, vsr, vsr)
DEF_HELPER_4(XSMAXJDP, void, env, vsr, vsr, vsr)
@@ -437,10 +439,10 @@ DEF_HELPER_4(xsrqpxp, void, env, i32, vsr, vsr)
DEF_HELPER_4(xssqrtqp, void, env, i32, vsr, vsr)
DEF_HELPER_5(xssubqp, void, env, i32, vsr, vsr, vsr)
-DEF_HELPER_4(xsaddsp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xssubsp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xsmulsp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xsdivsp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XSADDSP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XSSUBSP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XSMULSP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XSDIVSP, void, env, vsr, vsr, vsr)
DEF_HELPER_3(xsresp, void, env, vsr, vsr)
DEF_HELPER_2(xsrsp, i64, env, i64)
DEF_HELPER_3(xssqrtsp, void, env, vsr, vsr)
@@ -459,10 +461,10 @@ DEF_HELPER_5(XSNMADDQPO, void, env, vsr, vsr, vsr, vsr)
DEF_HELPER_5(XSNMSUBQP, void, env, vsr, vsr, vsr, vsr)
DEF_HELPER_5(XSNMSUBQPO, void, env, vsr, vsr, vsr, vsr)
-DEF_HELPER_4(xvadddp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xvsubdp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xvmuldp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xvdivdp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVADDDP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVSUBDP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVMULDP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVDIVDP, void, env, vsr, vsr, vsr)
DEF_HELPER_3(xvredp, void, env, vsr, vsr)
DEF_HELPER_3(xvsqrtdp, void, env, vsr, vsr)
DEF_HELPER_3(xvrsqrtedp, void, env, vsr, vsr)
@@ -472,12 +474,12 @@ DEF_HELPER_5(xvmadddp, void, env, vsr, vsr, vsr, vsr)
DEF_HELPER_5(xvmsubdp, void, env, vsr, vsr, vsr, vsr)
DEF_HELPER_5(xvnmadddp, void, env, vsr, vsr, vsr, vsr)
DEF_HELPER_5(xvnmsubdp, void, env, vsr, vsr, vsr, vsr)
-DEF_HELPER_4(xvmaxdp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xvmindp, void, env, vsr, vsr, vsr)
-DEF_HELPER_FLAGS_4(xvcmpeqdp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
-DEF_HELPER_FLAGS_4(xvcmpgedp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
-DEF_HELPER_FLAGS_4(xvcmpgtdp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
-DEF_HELPER_FLAGS_4(xvcmpnedp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVMAXDP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVMINDP, void, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(XVCMPEQDP, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(XVCMPGEDP, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(XVCMPGTDP, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(XVCMPNEDP, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
DEF_HELPER_3(xvcvdpsp, void, env, vsr, vsr)
DEF_HELPER_3(xvcvdpsxds, void, env, vsr, vsr)
DEF_HELPER_3(xvcvdpsxws, void, env, vsr, vsr)
@@ -493,10 +495,10 @@ DEF_HELPER_3(xvrdpim, void, env, vsr, vsr)
DEF_HELPER_3(xvrdpip, void, env, vsr, vsr)
DEF_HELPER_3(xvrdpiz, void, env, vsr, vsr)
-DEF_HELPER_4(xvaddsp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xvsubsp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xvmulsp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xvdivsp, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVADDSP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVSUBSP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVMULSP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVDIVSP, void, env, vsr, vsr, vsr)
DEF_HELPER_3(xvresp, void, env, vsr, vsr)
DEF_HELPER_3(xvsqrtsp, void, env, vsr, vsr)
DEF_HELPER_3(xvrsqrtesp, void, env, vsr, vsr)
@@ -506,12 +508,12 @@ DEF_HELPER_5(xvmaddsp, void, env, vsr, vsr, vsr, vsr)
DEF_HELPER_5(xvmsubsp, void, env, vsr, vsr, vsr, vsr)
DEF_HELPER_5(xvnmaddsp, void, env, vsr, vsr, vsr, vsr)
DEF_HELPER_5(xvnmsubsp, void, env, vsr, vsr, vsr, vsr)
-DEF_HELPER_4(xvmaxsp, void, env, vsr, vsr, vsr)
-DEF_HELPER_4(xvminsp, void, env, vsr, vsr, vsr)
-DEF_HELPER_FLAGS_4(xvcmpeqsp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
-DEF_HELPER_FLAGS_4(xvcmpgesp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
-DEF_HELPER_FLAGS_4(xvcmpgtsp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
-DEF_HELPER_FLAGS_4(xvcmpnesp, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVMAXSP, void, env, vsr, vsr, vsr)
+DEF_HELPER_4(XVMINSP, void, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(XVCMPEQSP, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(XVCMPGESP, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(XVCMPGTSP, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
+DEF_HELPER_FLAGS_4(XVCMPNESP, TCG_CALL_NO_RWG, i32, env, vsr, vsr, vsr)
DEF_HELPER_3(xvcvspdp, void, env, vsr, vsr)
DEF_HELPER_3(xvcvsphp, void, env, vsr, vsr)
DEF_HELPER_3(xvcvhpsp, void, env, vsr, vsr)
diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index ee33141..e53fd28 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -241,6 +241,9 @@
&XX3 xt xa xb
@XX3 ...... ..... ..... ..... ........ ... &XX3 xt=%xx_xt xa=%xx_xa xb=%xx_xb
+&XX3_rc xt xa xb rc:bool
+@XX3_rc ...... ..... ..... ..... rc:1 ....... ... &XX3_rc xt=%xx_xt xa=%xx_xa xb=%xx_xb
+
# 32 bit GER instructions have all mask bits considered 1
&MMIRR_XX3 xa xb xt pmsk xmsk ymsk
%xx_at 23:3
@@ -832,6 +835,14 @@ VADDCUW 000100 ..... ..... ..... 00110000000 @VX
VADDCUQ 000100 ..... ..... ..... 00101000000 @VX
VADDUQM 000100 ..... ..... ..... 00100000000 @VX
+VADDSBS 000100 ..... ..... ..... 01100000000 @VX
+VADDSHS 000100 ..... ..... ..... 01101000000 @VX
+VADDSWS 000100 ..... ..... ..... 01110000000 @VX
+
+VADDUBS 000100 ..... ..... ..... 01000000000 @VX
+VADDUHS 000100 ..... ..... ..... 01001000000 @VX
+VADDUWS 000100 ..... ..... ..... 01010000000 @VX
+
VADDEUQM 000100 ..... ..... ..... ..... 111100 @VA
VADDECUQ 000100 ..... ..... ..... ..... 111101 @VA
@@ -839,6 +850,14 @@ VSUBCUW 000100 ..... ..... ..... 10110000000 @VX
VSUBCUQ 000100 ..... ..... ..... 10101000000 @VX
VSUBUQM 000100 ..... ..... ..... 10100000000 @VX
+VSUBSBS 000100 ..... ..... ..... 11100000000 @VX
+VSUBSHS 000100 ..... ..... ..... 11101000000 @VX
+VSUBSWS 000100 ..... ..... ..... 11110000000 @VX
+
+VSUBUBS 000100 ..... ..... ..... 11000000000 @VX
+VSUBUHS 000100 ..... ..... ..... 11001000000 @VX
+VSUBUWS 000100 ..... ..... ..... 11010000000 @VX
+
VSUBECUQ 000100 ..... ..... ..... ..... 111111 @VA
VSUBEUQM 000100 ..... ..... ..... ..... 111110 @VA
@@ -977,6 +996,35 @@ STXVRHX 011111 ..... ..... ..... 0010101101 . @X_TSX
STXVRWX 011111 ..... ..... ..... 0011001101 . @X_TSX
STXVRDX 011111 ..... ..... ..... 0011101101 . @X_TSX
+LXSDX 011111 ..... ..... ..... 1001001100 . @X_TSX
+LXSIWAX 011111 ..... ..... ..... 0001001100 . @X_TSX
+LXSIBZX 011111 ..... ..... ..... 1100001101 . @X_TSX
+LXSIHZX 011111 ..... ..... ..... 1100101101 . @X_TSX
+LXSIWZX 011111 ..... ..... ..... 0000001100 . @X_TSX
+LXSSPX 011111 ..... ..... ..... 1000001100 . @X_TSX
+
+STXSDX 011111 ..... ..... ..... 1011001100 . @X_TSX
+STXSIBX 011111 ..... ..... ..... 1110001101 . @X_TSX
+STXSIHX 011111 ..... ..... ..... 1110101101 . @X_TSX
+STXSIWX 011111 ..... ..... ..... 0010001100 . @X_TSX
+STXSSPX 011111 ..... ..... ..... 1010001100 . @X_TSX
+
+LXVB16X 011111 ..... ..... ..... 1101101100 . @X_TSX
+LXVD2X 011111 ..... ..... ..... 1101001100 . @X_TSX
+LXVH8X 011111 ..... ..... ..... 1100101100 . @X_TSX
+LXVW4X 011111 ..... ..... ..... 1100001100 . @X_TSX
+LXVDSX 011111 ..... ..... ..... 0101001100 . @X_TSX
+LXVWSX 011111 ..... ..... ..... 0101101100 . @X_TSX
+LXVL 011111 ..... ..... ..... 0100001101 . @X_TSX
+LXVLL 011111 ..... ..... ..... 0100101101 . @X_TSX
+
+STXVB16X 011111 ..... ..... ..... 1111101100 . @X_TSX
+STXVD2X 011111 ..... ..... ..... 1111001100 . @X_TSX
+STXVH8X 011111 ..... ..... ..... 1110101100 . @X_TSX
+STXVW4X 011111 ..... ..... ..... 1110001100 . @X_TSX
+STXVL 011111 ..... ..... ..... 0110001101 . @X_TSX
+STXVLL 011111 ..... ..... ..... 0110101101 . @X_TSX
+
## VSX Vector Binary Floating-Point Sign Manipulation Instructions
XVABSDP 111100 ..... 00000 ..... 111011001 .. @XX2
@@ -988,6 +1036,28 @@ XVNEGSP 111100 ..... 00000 ..... 110111001 .. @XX2
XVCPSGNDP 111100 ..... ..... ..... 11110000 ... @XX3
XVCPSGNSP 111100 ..... ..... ..... 11010000 ... @XX3
+## VSX Binary Floating-Point Arithmetic Instructions
+
+XSADDSP 111100 ..... ..... ..... 00000000 ... @XX3
+XSSUBSP 111100 ..... ..... ..... 00001000 ... @XX3
+XSMULSP 111100 ..... ..... ..... 00010000 ... @XX3
+XSDIVSP 111100 ..... ..... ..... 00011000 ... @XX3
+
+XSADDDP 111100 ..... ..... ..... 00100000 ... @XX3
+XSSUBDP 111100 ..... ..... ..... 00101000 ... @XX3
+XSMULDP 111100 ..... ..... ..... 00110000 ... @XX3
+XSDIVDP 111100 ..... ..... ..... 00111000 ... @XX3
+
+XVADDSP 111100 ..... ..... ..... 01000000 ... @XX3
+XVSUBSP 111100 ..... ..... ..... 01001000 ... @XX3
+XVMULSP 111100 ..... ..... ..... 01010000 ... @XX3
+XVDIVSP 111100 ..... ..... ..... 01011000 ... @XX3
+
+XVADDDP 111100 ..... ..... ..... 01100000 ... @XX3
+XVSUBDP 111100 ..... ..... ..... 01101000 ... @XX3
+XVMULDP 111100 ..... ..... ..... 01110000 ... @XX3
+XVDIVDP 111100 ..... ..... ..... 01111000 ... @XX3
+
## VSX Scalar Multiply-Add Instructions
XSMADDADP 111100 ..... ..... ..... 00100001 . . . @XX3
@@ -1057,6 +1127,23 @@ XSCMPEQQP 111111 ..... ..... ..... 0001000100 - @X
XSCMPGEQP 111111 ..... ..... ..... 0011000100 - @X
XSCMPGTQP 111111 ..... ..... ..... 0011100100 - @X
+XVCMPEQSP 111100 ..... ..... ..... . 1000011 ... @XX3_rc
+XVCMPGTSP 111100 ..... ..... ..... . 1001011 ... @XX3_rc
+XVCMPGESP 111100 ..... ..... ..... . 1010011 ... @XX3_rc
+XVCMPNESP 111100 ..... ..... ..... . 1011011 ... @XX3_rc
+XVCMPEQDP 111100 ..... ..... ..... . 1100011 ... @XX3_rc
+XVCMPGTDP 111100 ..... ..... ..... . 1101011 ... @XX3_rc
+XVCMPGEDP 111100 ..... ..... ..... . 1110011 ... @XX3_rc
+XVCMPNEDP 111100 ..... ..... ..... . 1111011 ... @XX3_rc
+
+XSMAXDP 111100 ..... ..... ..... 10100000 ... @XX3
+XSMINDP 111100 ..... ..... ..... 10101000 ... @XX3
+
+XVMAXSP 111100 ..... ..... ..... 11000000 ... @XX3
+XVMINSP 111100 ..... ..... ..... 11001000 ... @XX3
+XVMAXDP 111100 ..... ..... ..... 11100000 ... @XX3
+XVMINDP 111100 ..... ..... ..... 11101000 ... @XX3
+
## VSX Binary Floating-Point Convert Instructions
XSCVQPDP 111111 ..... 10100 ..... 1101000100 . @X_tb_rc
@@ -1092,6 +1179,17 @@ XXMFACC 011111 ... -- 00000 ----- 0010110001 - @X_a
XXMTACC 011111 ... -- 00001 ----- 0010110001 - @X_a
XXSETACCZ 011111 ... -- 00011 ----- 0010110001 - @X_a
+## VSX Vector Logical instructions
+
+XXLAND 111100 ..... ..... ..... 10000010 ... @XX3
+XXLANDC 111100 ..... ..... ..... 10001010 ... @XX3
+XXLOR 111100 ..... ..... ..... 10010010 ... @XX3
+XXLXOR 111100 ..... ..... ..... 10011010 ... @XX3
+XXLNOR 111100 ..... ..... ..... 10100010 ... @XX3
+XXLEQV 111100 ..... ..... ..... 10111010 ... @XX3
+XXLNAND 111100 ..... ..... ..... 10110010 ... @XX3
+XXLORC 111100 ..... ..... ..... 10101010 ... @XX3
+
## VSX GER instruction
XVI4GER8 111011 ... -- ..... ..... 00100011 ..- @XX3_at xa=%xx_xa
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index 2c6b633..ef4b2e7 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -541,7 +541,7 @@ VARITHFPFMA(nmsubfp, float_muladd_negate_result | float_muladd_negate_c);
}
#define VARITHSAT_DO(name, op, optype, cvt, element) \
- void helper_v##name(ppc_avr_t *r, ppc_avr_t *vscr_sat, \
+ void helper_V##name(ppc_avr_t *r, ppc_avr_t *vscr_sat, \
ppc_avr_t *a, ppc_avr_t *b, uint32_t desc) \
{ \
int sat = 0; \
@@ -555,17 +555,17 @@ VARITHFPFMA(nmsubfp, float_muladd_negate_result | float_muladd_negate_c);
} \
}
#define VARITHSAT_SIGNED(suffix, element, optype, cvt) \
- VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \
- VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element)
+ VARITHSAT_DO(ADDS##suffix##S, +, optype, cvt, element) \
+ VARITHSAT_DO(SUBS##suffix##S, -, optype, cvt, element)
#define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \
- VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \
- VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element)
-VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
-VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
-VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
-VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
-VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
-VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw)
+ VARITHSAT_DO(ADDU##suffix##S, +, optype, cvt, element) \
+ VARITHSAT_DO(SUBU##suffix##S, -, optype, cvt, element)
+VARITHSAT_SIGNED(B, s8, int16_t, cvtshsb)
+VARITHSAT_SIGNED(H, s16, int32_t, cvtswsh)
+VARITHSAT_SIGNED(W, s32, int64_t, cvtsdsw)
+VARITHSAT_UNSIGNED(B, u8, uint16_t, cvtshub)
+VARITHSAT_UNSIGNED(H, u16, uint32_t, cvtswuh)
+VARITHSAT_UNSIGNED(W, u32, uint64_t, cvtsduw)
#undef VARITHSAT_CASE
#undef VARITHSAT_DO
#undef VARITHSAT_SIGNED
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 2c39322..3efc28f 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -48,6 +48,8 @@
#include "qemu/mmap-alloc.h"
#include "elf.h"
#include "sysemu/kvm_int.h"
+#include "sysemu/kvm.h"
+#include "hw/core/accel-cpu.h"
#include CONFIG_DEVICES
@@ -898,7 +900,7 @@ int kvmppc_put_books_sregs(PowerPCCPU *cpu)
return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_SREGS, &sregs);
}
-int kvm_arch_put_registers(CPUState *cs, int level)
+int kvm_arch_put_registers(CPUState *cs, int level, Error **errp)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
@@ -1203,7 +1205,7 @@ static int kvmppc_get_books_sregs(PowerPCCPU *cpu)
return 0;
}
-int kvm_arch_get_registers(CPUState *cs)
+int kvm_arch_get_registers(CPUState *cs, Error **errp)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
@@ -2346,6 +2348,30 @@ static void alter_insns(uint64_t *word, uint64_t flags, bool on)
}
}
+static bool kvmppc_cpu_realize(CPUState *cs, Error **errp)
+{
+ int ret;
+ const char *vcpu_str = (cs->parent_obj.hotplugged == true) ?
+ "hotplug" : "create";
+ cs->cpu_index = cpu_get_free_index();
+
+ POWERPC_CPU(cs)->vcpu_id = cs->cpu_index;
+
+ /* create and park to fail gracefully in case vcpu hotplug fails */
+ ret = kvm_create_and_park_vcpu(cs);
+ if (ret) {
+ /*
+ * This causes QEMU to terminate if initial CPU creation
+ * fails, and only CPU hotplug failure if the error happens
+ * there.
+ */
+ error_setg(errp, "%s: vcpu %s failed with %d",
+ __func__, vcpu_str, ret);
+ return false;
+ }
+ return true;
+}
+
static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data)
{
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
@@ -2966,3 +2992,23 @@ void kvmppc_set_reg_tb_offset(PowerPCCPU *cpu, int64_t tb_offset)
void kvm_arch_accel_class_init(ObjectClass *oc)
{
}
+
+static void kvm_cpu_accel_class_init(ObjectClass *oc, void *data)
+{
+ AccelCPUClass *acc = ACCEL_CPU_CLASS(oc);
+
+ acc->cpu_target_realize = kvmppc_cpu_realize;
+}
+
+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/ppc/machine.c b/target/ppc/machine.c
index 731dd8d..d433fd4 100644
--- a/target/ppc/machine.c
+++ b/target/ppc/machine.c
@@ -621,7 +621,7 @@ static bool tlbemb_needed(void *opaque)
}
static const VMStateDescription vmstate_tlbemb = {
- .name = "cpu/tlb6xx",
+ .name = "cpu/tlbemb",
.version_id = 1,
.minimum_version_id = 1,
.needed = tlbemb_needed,
diff --git a/target/ppc/mem_helper.c b/target/ppc/mem_helper.c
index f88155a..51b137f 100644
--- a/target/ppc/mem_helper.c
+++ b/target/ppc/mem_helper.c
@@ -271,51 +271,59 @@ void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb,
}
static void dcbz_common(CPUPPCState *env, target_ulong addr,
- uint32_t opcode, bool epid, uintptr_t retaddr)
+ int mmu_idx, int dcbz_size, uintptr_t retaddr)
{
- target_ulong mask, dcbz_size = env->dcache_line_size;
- uint32_t i;
+ target_ulong mask = ~(target_ulong)(dcbz_size - 1);
void *haddr;
- int mmu_idx = epid ? PPC_TLB_EPID_STORE : ppc_env_mmu_index(env, false);
-
-#if defined(TARGET_PPC64)
- /* Check for dcbz vs dcbzl on 970 */
- if (env->excp_model == POWERPC_EXCP_970 &&
- !(opcode & 0x00200000) && ((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
- dcbz_size = 32;
- }
-#endif
/* Align address */
- mask = ~(dcbz_size - 1);
addr &= mask;
/* Check reservation */
- if ((env->reserve_addr & mask) == addr) {
+ if (unlikely((env->reserve_addr & mask) == addr)) {
env->reserve_addr = (target_ulong)-1ULL;
}
/* Try fast path translate */
+#ifdef CONFIG_USER_ONLY
+ haddr = tlb_vaddr_to_host(env, addr, MMU_DATA_STORE, mmu_idx);
+#else
haddr = probe_write(env, addr, dcbz_size, mmu_idx, retaddr);
- if (haddr) {
- memset(haddr, 0, dcbz_size);
- } else {
+ if (unlikely(!haddr)) {
/* Slow path */
- for (i = 0; i < dcbz_size; i += 8) {
+ for (int i = 0; i < dcbz_size; i += 8) {
cpu_stq_mmuidx_ra(env, addr + i, 0, mmu_idx, retaddr);
}
+ return;
}
+#endif
+
+ set_helper_retaddr(retaddr);
+ memset(haddr, 0, dcbz_size);
+ clear_helper_retaddr();
}
-void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t opcode)
+void helper_dcbz(CPUPPCState *env, target_ulong addr, int mmu_idx)
{
- dcbz_common(env, addr, opcode, false, GETPC());
+ dcbz_common(env, addr, mmu_idx, env->dcache_line_size, GETPC());
}
-void helper_dcbzep(CPUPPCState *env, target_ulong addr, uint32_t opcode)
+#ifdef TARGET_PPC64
+void helper_dcbzl(CPUPPCState *env, target_ulong addr)
{
- dcbz_common(env, addr, opcode, true, GETPC());
+ int dcbz_size = env->dcache_line_size;
+
+ /*
+ * The translator checked for POWERPC_EXCP_970.
+ * All that's left is to check HID5.
+ */
+ if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
+ dcbz_size = 32;
+ }
+
+ dcbz_common(env, addr, ppc_env_mmu_index(env, false), dcbz_size, GETPC());
}
+#endif
void helper_icbi(CPUPPCState *env, target_ulong addr)
{
@@ -467,8 +475,8 @@ void helper_##name(CPUPPCState *env, target_ulong addr, \
*xt = t; \
}
-VSX_LXVL(lxvl, 0)
-VSX_LXVL(lxvll, 1)
+VSX_LXVL(LXVL, 0)
+VSX_LXVL(LXVLL, 1)
#undef VSX_LXVL
#define VSX_STXVL(name, lj) \
@@ -496,8 +504,8 @@ void helper_##name(CPUPPCState *env, target_ulong addr, \
} \
}
-VSX_STXVL(stxvl, 0)
-VSX_STXVL(stxvll, 1)
+VSX_STXVL(STXVL, 0)
+VSX_STXVL(STXVLL, 1)
#undef VSX_STXVL
#undef GET_NB
#endif /* TARGET_PPC64 */
diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c
index fa47be2..1b83971 100644
--- a/target/ppc/misc_helper.c
+++ b/target/ppc/misc_helper.c
@@ -48,9 +48,8 @@ void helper_spr_core_write_generic(CPUPPCState *env, uint32_t sprn,
{
CPUState *cs = env_cpu(env);
CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
- if (nr_threads == 1) {
+ if (ppc_cpu_core_single_threaded(cs)) {
env->spr[sprn] = val;
return;
}
@@ -195,7 +194,7 @@ void helper_store_ptcr(CPUPPCState *env, target_ulong val)
return;
}
- if (cs->nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+ if (ppc_cpu_lpar_single_threaded(cs)) {
env->spr[SPR_PTCR] = val;
tlb_flush(cs);
} else {
@@ -242,16 +241,12 @@ target_ulong helper_load_dpdes(CPUPPCState *env)
{
CPUState *cs = env_cpu(env);
CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
target_ulong dpdes = 0;
helper_hfscr_facility_check(env, HFSCR_MSGP, "load DPDES", HFSCR_IC_MSGP);
- if (!(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
- nr_threads = 1; /* DPDES behaves as 1-thread in LPAR-per-thread mode */
- }
-
- if (nr_threads == 1) {
+ /* DPDES behaves as 1-thread in LPAR-per-thread mode */
+ if (ppc_cpu_lpar_single_threaded(cs)) {
if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
dpdes = 1;
}
@@ -278,21 +273,11 @@ void helper_store_dpdes(CPUPPCState *env, target_ulong val)
PowerPCCPU *cpu = env_archcpu(env);
CPUState *cs = env_cpu(env);
CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
helper_hfscr_facility_check(env, HFSCR_MSGP, "store DPDES", HFSCR_IC_MSGP);
- if (!(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
- nr_threads = 1; /* DPDES behaves as 1-thread in LPAR-per-thread mode */
- }
-
- if (val & ~(nr_threads - 1)) {
- qemu_log_mask(LOG_GUEST_ERROR, "Invalid DPDES register value "
- TARGET_FMT_lx"\n", val);
- val &= (nr_threads - 1); /* Ignore the invalid bits */
- }
-
- if (nr_threads == 1) {
+ /* DPDES behaves as 1-thread in LPAR-per-thread mode */
+ if (ppc_cpu_lpar_single_threaded(cs)) {
ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, val & 0x1);
return;
}
@@ -308,6 +293,13 @@ void helper_store_dpdes(CPUPPCState *env, target_ulong val)
bql_unlock();
}
+/*
+ * qemu-user breaks with pnv headers, so they go under ifdefs for now.
+ * A clean up may be to move powernv specific registers and helpers into
+ * target/ppc/pnv_helper.c
+ */
+#include "hw/ppc/pnv_core.h"
+
/* Indirect SCOM (SPRC/SPRD) access to SCRATCH0-7 are implemented. */
void helper_store_sprc(CPUPPCState *env, target_ulong val)
{
@@ -321,11 +313,35 @@ void helper_store_sprc(CPUPPCState *env, target_ulong val)
target_ulong helper_load_sprd(CPUPPCState *env)
{
+ /*
+ * SPRD is a HV-only register for Power CPUs, so this will only be
+ * accessed by powernv machines.
+ */
+ PowerPCCPU *cpu = env_archcpu(env);
+ PnvCore *pc = pnv_cpu_state(cpu)->pnv_core;
target_ulong sprc = env->spr[SPR_POWER_SPRC];
- switch (sprc & 0x3c0) {
- case 0: /* SCRATCH0-7 */
- return env->scratch[(sprc >> 3) & 0x7];
+ switch (sprc & 0x3e0) {
+ case 0: /* SCRATCH0-3 */
+ case 1: /* SCRATCH4-7 */
+ return pc->scratch[(sprc >> 3) & 0x7];
+
+ case 0x1e0: /* core thread state */
+ if (env->excp_model == POWERPC_EXCP_POWER9) {
+ /*
+ * Only implement for POWER9 because skiboot uses it to check
+ * big-core mode. Other bits are unimplemented so we would
+ * prefer to get unimplemented message on POWER10 if it were
+ * used anywhere.
+ */
+ if (pc->big_core) {
+ return PPC_BIT(63);
+ } else {
+ return 0;
+ }
+ }
+ /* fallthru */
+
default:
qemu_log_mask(LOG_UNIMP, "mfSPRD: Unimplemented SPRC:0x"
TARGET_FMT_lx"\n", sprc);
@@ -334,41 +350,28 @@ target_ulong helper_load_sprd(CPUPPCState *env)
return 0;
}
-static void do_store_scratch(CPUPPCState *env, int nr, target_ulong val)
-{
- CPUState *cs = env_cpu(env);
- CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
-
- /*
- * Log stores to SCRATCH, because some firmware uses these for debugging
- * and logging, but they would normally be read by the BMC, which is
- * not implemented in QEMU yet. This gives a way to get at the information.
- * Could also dump these upon checkstop.
- */
- qemu_log("SPRD write 0x" TARGET_FMT_lx " to SCRATCH%d\n", val, nr);
-
- if (nr_threads == 1) {
- env->scratch[nr] = val;
- return;
- }
-
- THREAD_SIBLING_FOREACH(cs, ccs) {
- CPUPPCState *cenv = &POWERPC_CPU(ccs)->env;
- cenv->scratch[nr] = val;
- }
-}
-
void helper_store_sprd(CPUPPCState *env, target_ulong val)
{
target_ulong sprc = env->spr[SPR_POWER_SPRC];
-
- switch (sprc & 0x3c0) {
- case 0: /* SCRATCH0-7 */
- do_store_scratch(env, (sprc >> 3) & 0x7, val);
+ PowerPCCPU *cpu = env_archcpu(env);
+ PnvCore *pc = pnv_cpu_state(cpu)->pnv_core;
+ int nr;
+
+ switch (sprc & 0x3e0) {
+ case 0: /* SCRATCH0-3 */
+ case 1: /* SCRATCH4-7 */
+ /*
+ * Log stores to SCRATCH, because some firmware uses these for
+ * debugging and logging, but they would normally be read by the BMC,
+ * which is not implemented in QEMU yet. This gives a way to get at the
+ * information. Could also dump these upon checkstop.
+ */
+ nr = (sprc >> 3) & 0x7;
+ qemu_log("SPRD write 0x" TARGET_FMT_lx " to SCRATCH%d\n", val, nr);
+ pc->scratch[nr] = val;
break;
default:
- qemu_log_mask(LOG_UNIMP, "mfSPRD: Unimplemented SPRC:0x"
+ qemu_log_mask(LOG_UNIMP, "mtSPRD: Unimplemented SPRC:0x"
TARGET_FMT_lx"\n", sprc);
break;
}
diff --git a/target/ppc/mmu-book3s-v3.c b/target/ppc/mmu-book3s-v3.c
index c8f69b3..a812cb5 100644
--- a/target/ppc/mmu-book3s-v3.c
+++ b/target/ppc/mmu-book3s-v3.c
@@ -21,7 +21,6 @@
#include "cpu.h"
#include "mmu-hash64.h"
#include "mmu-book3s-v3.h"
-#include "mmu-radix64.h"
bool ppc64_v3_get_pate(PowerPCCPU *cpu, target_ulong lpid, ppc_v3_pate_t *entry)
{
diff --git a/target/ppc/mmu-book3s-v3.h b/target/ppc/mmu-book3s-v3.h
index f3f7993..be66e26 100644
--- a/target/ppc/mmu-book3s-v3.h
+++ b/target/ppc/mmu-book3s-v3.h
@@ -20,9 +20,6 @@
#ifndef PPC_MMU_BOOK3S_V3_H
#define PPC_MMU_BOOK3S_V3_H
-#include "mmu-hash64.h"
-#include "mmu-books.h"
-
#ifndef CONFIG_USER_ONLY
/*
@@ -83,46 +80,6 @@ static inline bool ppc64_v3_radix(PowerPCCPU *cpu)
return !!(cpu->env.spr[SPR_LPCR] & LPCR_HR);
}
-static inline hwaddr ppc_hash64_hpt_base(PowerPCCPU *cpu)
-{
- uint64_t base;
-
- if (cpu->vhyp) {
- return 0;
- }
- if (cpu->env.mmu_model == POWERPC_MMU_3_00) {
- ppc_v3_pate_t pate;
-
- if (!ppc64_v3_get_pate(cpu, cpu->env.spr[SPR_LPIDR], &pate)) {
- return 0;
- }
- base = pate.dw0;
- } else {
- base = cpu->env.spr[SPR_SDR1];
- }
- return base & SDR_64_HTABORG;
-}
-
-static inline hwaddr ppc_hash64_hpt_mask(PowerPCCPU *cpu)
-{
- uint64_t base;
-
- if (cpu->vhyp) {
- return cpu->vhyp_class->hpt_mask(cpu->vhyp);
- }
- if (cpu->env.mmu_model == POWERPC_MMU_3_00) {
- ppc_v3_pate_t pate;
-
- if (!ppc64_v3_get_pate(cpu, cpu->env.spr[SPR_LPIDR], &pate)) {
- return 0;
- }
- base = pate.dw0;
- } else {
- base = cpu->env.spr[SPR_SDR1];
- }
- return (1ULL << ((base & SDR_64_HTABSIZE) + 18 - 7)) - 1;
-}
-
#endif /* TARGET_PPC64 */
#endif /* CONFIG_USER_ONLY */
diff --git a/target/ppc/mmu-hash32.c b/target/ppc/mmu-hash32.c
index d5f2057..44b1614 100644
--- a/target/ppc/mmu-hash32.c
+++ b/target/ppc/mmu-hash32.c
@@ -37,17 +37,6 @@
# define LOG_BATS(...) do { } while (0)
#endif
-static int ppc_hash32_pte_prot(int mmu_idx,
- target_ulong sr, ppc_hash_pte32_t pte)
-{
- unsigned pp, key;
-
- key = !!(mmuidx_pr(mmu_idx) ? (sr & SR32_KP) : (sr & SR32_KS));
- pp = pte.pte1 & HPTE32_R_PP;
-
- return ppc_hash32_pp_prot(key, pp, !!(sr & SR32_NX));
-}
-
static target_ulong hash32_bat_size(int mmu_idx,
target_ulong batu, target_ulong batl)
{
@@ -59,22 +48,6 @@ static target_ulong hash32_bat_size(int mmu_idx,
return BATU32_BEPI & ~((batu & BATU32_BL) << 15);
}
-static int hash32_bat_prot(PowerPCCPU *cpu,
- target_ulong batu, target_ulong batl)
-{
- int pp, prot;
-
- prot = 0;
- pp = batl & BATL32_PP;
- if (pp != 0) {
- prot = PAGE_READ | PAGE_EXEC;
- if (pp == 0x2) {
- prot |= PAGE_WRITE;
- }
- }
- return prot;
-}
-
static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea,
MMUAccessType access_type, int *prot,
int mmu_idx)
@@ -106,7 +79,7 @@ static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea,
if (mask && ((ea & mask) == (batu & BATU32_BEPI))) {
hwaddr raddr = (batl & mask) | (ea & ~mask);
- *prot = hash32_bat_prot(cpu, batu, batl);
+ *prot = ppc_hash32_bat_prot(batu, batl);
return raddr & TARGET_PAGE_MASK;
}
@@ -145,7 +118,6 @@ static bool ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
- int key = !!(mmuidx_pr(mmu_idx) ? (sr & SR32_KP) : (sr & SR32_KS));
qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
@@ -206,7 +178,11 @@ static bool ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
cpu_abort(cs, "ERROR: insn should not need address translation\n");
}
- *prot = key ? PAGE_READ | PAGE_WRITE : PAGE_READ;
+ if (ppc_hash32_key(mmuidx_pr(mmu_idx), sr)) {
+ *prot = PAGE_READ | PAGE_WRITE;
+ } else {
+ *prot = PAGE_READ;
+ }
if (check_prot_access_type(*prot, access_type)) {
*raddr = eaddr;
return true;
@@ -225,13 +201,6 @@ static bool ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
return false;
}
-hwaddr get_pteg_offset32(PowerPCCPU *cpu, hwaddr hash)
-{
- target_ulong mask = ppc_hash32_hpt_mask(cpu);
-
- return (hash * HASH_PTEG_SIZE_32) & mask;
-}
-
static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr pteg_off,
bool secondary, target_ulong ptem,
ppc_hash_pte32_t *pte)
@@ -322,15 +291,6 @@ static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu,
return pte_offset;
}
-static hwaddr ppc_hash32_pte_raddr(target_ulong sr, ppc_hash_pte32_t pte,
- target_ulong eaddr)
-{
- hwaddr rpn = pte.pte1 & HPTE32_R_RPN;
- hwaddr mask = ~TARGET_PAGE_MASK;
-
- return (rpn & ~mask) | (eaddr & mask);
-}
-
bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
hwaddr *raddrp, int *psizep, int *protp, int mmu_idx,
bool guest_visible)
@@ -338,10 +298,10 @@ bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
target_ulong sr;
- hwaddr pte_offset;
+ hwaddr pte_offset, raddr;
ppc_hash_pte32_t pte;
+ bool key;
int prot;
- hwaddr raddr;
/* There are no hash32 large pages. */
*psizep = TARGET_PAGE_BITS;
@@ -423,8 +383,8 @@ bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
"found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
/* 7. Check access permissions */
-
- prot = ppc_hash32_pte_prot(mmu_idx, sr, pte);
+ key = ppc_hash32_key(mmuidx_pr(mmu_idx), sr);
+ prot = ppc_hash32_prot(key, pte.pte1 & HPTE32_R_PP, sr & SR32_NX);
if (!check_prot_access_type(prot, access_type)) {
/* Access right violation */
@@ -464,11 +424,12 @@ bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
*/
prot &= ~PAGE_WRITE;
}
- }
+ }
+ *protp = prot;
/* 9. Determine the real address from the PTE */
-
- *raddrp = ppc_hash32_pte_raddr(sr, pte, eaddr);
- *protp = prot;
+ *raddrp = pte.pte1 & HPTE32_R_RPN;
+ *raddrp &= TARGET_PAGE_MASK;
+ *raddrp |= eaddr & ~TARGET_PAGE_MASK;
return true;
}
diff --git a/target/ppc/mmu-hash32.h b/target/ppc/mmu-hash32.h
index f0ce695..2838de0 100644
--- a/target/ppc/mmu-hash32.h
+++ b/target/ppc/mmu-hash32.h
@@ -3,7 +3,6 @@
#ifndef CONFIG_USER_ONLY
-hwaddr get_pteg_offset32(PowerPCCPU *cpu, hwaddr hash);
bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
hwaddr *raddrp, int *psizep, int *protp, int mmu_idx,
bool guest_visible);
@@ -102,48 +101,63 @@ static inline void ppc_hash32_store_hpte1(PowerPCCPU *cpu,
stl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2, pte1);
}
-static inline int ppc_hash32_pp_prot(bool key, int pp, bool nx)
+static inline hwaddr get_pteg_offset32(PowerPCCPU *cpu, hwaddr hash)
+{
+ return (hash * HASH_PTEG_SIZE_32) & ppc_hash32_hpt_mask(cpu);
+}
+
+static inline bool ppc_hash32_key(bool pr, target_ulong sr)
+{
+ return pr ? (sr & SR32_KP) : (sr & SR32_KS);
+}
+
+static inline int ppc_hash32_prot(bool key, int pp, bool nx)
{
int prot;
- if (key == 0) {
+ if (key) {
switch (pp) {
case 0x0:
- case 0x1:
- case 0x2:
- prot = PAGE_READ | PAGE_WRITE;
+ prot = 0;
break;
-
+ case 0x1:
case 0x3:
prot = PAGE_READ;
break;
-
+ case 0x2:
+ prot = PAGE_READ | PAGE_WRITE;
+ break;
default:
- abort();
+ g_assert_not_reached();
}
} else {
switch (pp) {
case 0x0:
- prot = 0;
- break;
-
case 0x1:
- case 0x3:
- prot = PAGE_READ;
- break;
-
case 0x2:
prot = PAGE_READ | PAGE_WRITE;
break;
-
+ case 0x3:
+ prot = PAGE_READ;
+ break;
default:
- abort();
+ g_assert_not_reached();
}
}
- if (nx == 0) {
- prot |= PAGE_EXEC;
- }
+ return nx ? prot : prot | PAGE_EXEC;
+}
+static inline int ppc_hash32_bat_prot(target_ulong batu, target_ulong batl)
+{
+ int prot = 0;
+ int pp = batl & BATL32_PP;
+
+ if (pp) {
+ prot = PAGE_READ | PAGE_EXEC;
+ if (pp == 0x2) {
+ prot |= PAGE_WRITE;
+ }
+ }
return prot;
}
diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
index cbc8efa..5e1983e 100644
--- a/target/ppc/mmu-hash64.c
+++ b/target/ppc/mmu-hash64.c
@@ -31,6 +31,7 @@
#include "hw/hw.h"
#include "internal.h"
#include "mmu-book3s-v3.h"
+#include "mmu-books.h"
#include "helper_regs.h"
#ifdef CONFIG_TCG
@@ -508,6 +509,46 @@ static int ppc_hash64_amr_prot(PowerPCCPU *cpu, ppc_hash_pte64_t pte)
return prot;
}
+static hwaddr ppc_hash64_hpt_base(PowerPCCPU *cpu)
+{
+ uint64_t base;
+
+ if (cpu->vhyp) {
+ return 0;
+ }
+ if (cpu->env.mmu_model == POWERPC_MMU_3_00) {
+ ppc_v3_pate_t pate;
+
+ if (!ppc64_v3_get_pate(cpu, cpu->env.spr[SPR_LPIDR], &pate)) {
+ return 0;
+ }
+ base = pate.dw0;
+ } else {
+ base = cpu->env.spr[SPR_SDR1];
+ }
+ return base & SDR_64_HTABORG;
+}
+
+static hwaddr ppc_hash64_hpt_mask(PowerPCCPU *cpu)
+{
+ uint64_t base;
+
+ if (cpu->vhyp) {
+ return cpu->vhyp_class->hpt_mask(cpu->vhyp);
+ }
+ if (cpu->env.mmu_model == POWERPC_MMU_3_00) {
+ ppc_v3_pate_t pate;
+
+ if (!ppc64_v3_get_pate(cpu, cpu->env.spr[SPR_LPIDR], &pate)) {
+ return 0;
+ }
+ base = pate.dw0;
+ } else {
+ base = cpu->env.spr[SPR_SDR1];
+ }
+ return (1ULL << ((base & SDR_64_HTABSIZE) + 18 - 7)) - 1;
+}
+
const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
hwaddr ptex, int n)
{
@@ -545,6 +586,15 @@ void ppc_hash64_unmap_hptes(PowerPCCPU *cpu, const ppc_hash_pte64_t *hptes,
false, n * HASH_PTE_SIZE_64);
}
+bool ppc_hash64_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 unsigned hpte_page_shift(const PPCHash64SegmentPageSizes *sps,
uint64_t pte0, uint64_t pte1)
{
diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
index de653fc..ae8d4b3 100644
--- a/target/ppc/mmu-hash64.h
+++ b/target/ppc/mmu-hash64.h
@@ -120,6 +120,7 @@ const ppc_hash_pte64_t *ppc_hash64_map_hptes(PowerPCCPU *cpu,
hwaddr ptex, int n);
void ppc_hash64_unmap_hptes(PowerPCCPU *cpu, const ppc_hash_pte64_t *hptes,
hwaddr ptex, int n);
+bool ppc_hash64_valid_ptex(PowerPCCPU *cpu, target_ulong ptex);
static inline uint64_t ppc_hash64_hpte0(PowerPCCPU *cpu,
const ppc_hash_pte64_t *hptes, int i)
diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c
index 5a02e49..be7a45f 100644
--- a/target/ppc/mmu-radix64.c
+++ b/target/ppc/mmu-radix64.c
@@ -28,6 +28,38 @@
#include "internal.h"
#include "mmu-radix64.h"
#include "mmu-book3s-v3.h"
+#include "mmu-books.h"
+
+/* Radix Partition Table Entry Fields */
+#define PATE1_R_PRTB 0x0FFFFFFFFFFFF000
+#define PATE1_R_PRTS 0x000000000000001F
+
+/* Radix Process Table Entry Fields */
+#define PRTBE_R_GET_RTS(rts) \
+ ((((rts >> 58) & 0x18) | ((rts >> 5) & 0x7)) + 31)
+#define PRTBE_R_RPDB 0x0FFFFFFFFFFFFF00
+#define PRTBE_R_RPDS 0x000000000000001F
+
+/* Radix Page Directory/Table Entry Fields */
+#define R_PTE_VALID 0x8000000000000000
+#define R_PTE_LEAF 0x4000000000000000
+#define R_PTE_SW0 0x2000000000000000
+#define R_PTE_RPN 0x01FFFFFFFFFFF000
+#define R_PTE_SW1 0x0000000000000E00
+#define R_GET_SW(sw) (((sw >> 58) & 0x8) | ((sw >> 9) & 0x7))
+#define R_PTE_R 0x0000000000000100
+#define R_PTE_C 0x0000000000000080
+#define R_PTE_ATT 0x0000000000000030
+#define R_PTE_ATT_NORMAL 0x0000000000000000
+#define R_PTE_ATT_SAO 0x0000000000000010
+#define R_PTE_ATT_NI_IO 0x0000000000000020
+#define R_PTE_ATT_TOLERANT_IO 0x0000000000000030
+#define R_PTE_EAA_PRIV 0x0000000000000008
+#define R_PTE_EAA_R 0x0000000000000004
+#define R_PTE_EAA_RW 0x0000000000000002
+#define R_PTE_EAA_X 0x0000000000000001
+#define R_PDE_NLB PRTBE_R_RPDB
+#define R_PDE_NLS PRTBE_R_RPDS
static bool ppc_radix64_get_fully_qualified_addr(const CPUPPCState *env,
vaddr eaddr,
@@ -180,6 +212,24 @@ static void ppc_radix64_raise_hsi(PowerPCCPU *cpu, MMUAccessType access_type,
}
}
+static int ppc_radix64_get_prot_eaa(uint64_t pte)
+{
+ return (pte & R_PTE_EAA_R ? PAGE_READ : 0) |
+ (pte & R_PTE_EAA_RW ? PAGE_READ | PAGE_WRITE : 0) |
+ (pte & R_PTE_EAA_X ? PAGE_EXEC : 0);
+}
+
+static int ppc_radix64_get_prot_amr(const PowerPCCPU *cpu)
+{
+ const CPUPPCState *env = &cpu->env;
+ int amr = env->spr[SPR_AMR] >> 62; /* We only care about key0 AMR63:62 */
+ int iamr = env->spr[SPR_IAMR] >> 62; /* We only care about key0 IAMR63:62 */
+
+ return (amr & 0x2 ? 0 : PAGE_WRITE) | /* Access denied if bit is set */
+ (amr & 0x1 ? 0 : PAGE_READ) |
+ (iamr & 0x1 ? 0 : PAGE_EXEC);
+}
+
static bool ppc_radix64_check_prot(PowerPCCPU *cpu, MMUAccessType access_type,
uint64_t pte, int *fault_cause, int *prot,
int mmu_idx, bool partition_scoped)
diff --git a/target/ppc/mmu-radix64.h b/target/ppc/mmu-radix64.h
index c5c04a1..6620b3d 100644
--- a/target/ppc/mmu-radix64.h
+++ b/target/ppc/mmu-radix64.h
@@ -3,7 +3,7 @@
#ifndef CONFIG_USER_ONLY
-#include "exec/page-protection.h"
+#ifdef TARGET_PPC64
/* Radix Quadrants */
#define R_EADDR_MASK 0x3FFFFFFFFFFFFFFF
@@ -14,61 +14,10 @@
#define R_EADDR_QUADRANT2 0x8000000000000000
#define R_EADDR_QUADRANT3 0xC000000000000000
-/* Radix Partition Table Entry Fields */
-#define PATE1_R_PRTB 0x0FFFFFFFFFFFF000
-#define PATE1_R_PRTS 0x000000000000001F
-
-/* Radix Process Table Entry Fields */
-#define PRTBE_R_GET_RTS(rts) \
- ((((rts >> 58) & 0x18) | ((rts >> 5) & 0x7)) + 31)
-#define PRTBE_R_RPDB 0x0FFFFFFFFFFFFF00
-#define PRTBE_R_RPDS 0x000000000000001F
-
-/* Radix Page Directory/Table Entry Fields */
-#define R_PTE_VALID 0x8000000000000000
-#define R_PTE_LEAF 0x4000000000000000
-#define R_PTE_SW0 0x2000000000000000
-#define R_PTE_RPN 0x01FFFFFFFFFFF000
-#define R_PTE_SW1 0x0000000000000E00
-#define R_GET_SW(sw) (((sw >> 58) & 0x8) | ((sw >> 9) & 0x7))
-#define R_PTE_R 0x0000000000000100
-#define R_PTE_C 0x0000000000000080
-#define R_PTE_ATT 0x0000000000000030
-#define R_PTE_ATT_NORMAL 0x0000000000000000
-#define R_PTE_ATT_SAO 0x0000000000000010
-#define R_PTE_ATT_NI_IO 0x0000000000000020
-#define R_PTE_ATT_TOLERANT_IO 0x0000000000000030
-#define R_PTE_EAA_PRIV 0x0000000000000008
-#define R_PTE_EAA_R 0x0000000000000004
-#define R_PTE_EAA_RW 0x0000000000000002
-#define R_PTE_EAA_X 0x0000000000000001
-#define R_PDE_NLB PRTBE_R_RPDB
-#define R_PDE_NLS PRTBE_R_RPDS
-
-#ifdef TARGET_PPC64
-
bool ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
hwaddr *raddr, int *psizep, int *protp, int mmu_idx,
bool guest_visible);
-static inline int ppc_radix64_get_prot_eaa(uint64_t pte)
-{
- return (pte & R_PTE_EAA_R ? PAGE_READ : 0) |
- (pte & R_PTE_EAA_RW ? PAGE_READ | PAGE_WRITE : 0) |
- (pte & R_PTE_EAA_X ? PAGE_EXEC : 0);
-}
-
-static inline int ppc_radix64_get_prot_amr(const PowerPCCPU *cpu)
-{
- const CPUPPCState *env = &cpu->env;
- int amr = env->spr[SPR_AMR] >> 62; /* We only care about key0 AMR63:62 */
- int iamr = env->spr[SPR_IAMR] >> 62; /* We only care about key0 IAMR63:62 */
-
- return (amr & 0x2 ? 0 : PAGE_WRITE) | /* Access denied if bit is set */
- (amr & 0x1 ? 0 : PAGE_READ) |
- (iamr & 0x1 ? 0 : PAGE_EXEC);
-}
-
#endif /* TARGET_PPC64 */
#endif /* CONFIG_USER_ONLY */
diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index e254269..60f8736 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -37,17 +37,6 @@
/* #define DUMP_PAGE_TABLES */
-/* Context used internally during MMU translations */
-typedef struct {
- hwaddr raddr; /* Real address */
- hwaddr eaddr; /* Effective address */
- int prot; /* Protection bits */
- hwaddr hash[2]; /* Pagetable hash values */
- target_ulong ptem; /* Virtual segment ID | API */
- int key; /* Access key */
- int nx; /* Non-execute area */
-} mmu_ctx_t;
-
void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
{
PowerPCCPU *cpu = env_archcpu(env);
@@ -94,86 +83,23 @@ int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
return nr;
}
-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 ret, pteh, ptev, pp;
-
- ret = -1;
- /* Check validity and table match */
- ptev = pte_is_valid(pte0);
- pteh = (pte0 >> 6) & 1;
- if (ptev && h == pteh) {
- /* Check vsid & api */
- ptem = pte0 & PTE_PTEM_MASK;
- mmask = PTE_CHECK_MASK;
- pp = pte1 & 0x00000003;
- if (ptem == ctx->ptem) {
- if (ctx->raddr != (hwaddr)-1ULL) {
- /* all matches should have equal RPN, WIMG & PP */
- if ((ctx->raddr & mmask) != (pte1 & mmask)) {
- qemu_log_mask(CPU_LOG_MMU, "Bad RPN/WIMG/PP\n");
- return -3;
- }
- }
- /* Keep the matching PTE information */
- ctx->raddr = pte1;
- ctx->prot = ppc_hash32_pp_prot(ctx->key, pp, ctx->nx);
- if (check_prot_access_type(ctx->prot, access_type)) {
- /* Access granted */
- qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
- ret = 0;
- } else {
- /* Access right violation */
- qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
- ret = -2;
- }
- }
- }
-
- return ret;
-}
-
-static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
- int ret, MMUAccessType access_type)
-{
- int store = 0;
-
- /* Update page flags */
- if (!(*pte1p & 0x00000100)) {
- /* Update accessed flag */
- *pte1p |= 0x00000100;
- store = 1;
- }
- if (!(*pte1p & 0x00000080)) {
- if (access_type == MMU_DATA_STORE && ret == 0) {
- /* Update changed flag */
- *pte1p |= 0x00000080;
- store = 1;
- } else {
- /* Force page fault for first write access */
- ctx->prot &= ~PAGE_WRITE;
- }
- }
-
- return store;
-}
-
/* Software driven TLB helpers */
-static int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong eaddr, MMUAccessType access_type)
+static int ppc6xx_tlb_check(CPUPPCState *env, hwaddr *raddr, int *prot,
+ target_ulong eaddr, MMUAccessType access_type,
+ target_ulong ptem, bool key, bool nx)
{
ppc6xx_tlb_t *tlb;
- int nr, best, way;
- int ret;
+ target_ulong *pte1p;
+ int nr, best, way, ret;
+ bool is_code = (access_type == MMU_INST_FETCH);
+ /* Initialize real address with an invalid value */
+ *raddr = (hwaddr)-1ULL;
best = -1;
ret = -1; /* No TLB found */
for (way = 0; way < env->nb_ways; way++) {
- nr = ppc6xx_tlb_getnum(env, eaddr, way, access_type == MMU_INST_FETCH);
+ nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
tlb = &env->tlb.tlb6[nr];
/* This test "emulates" the PTE index match for hardware TLBs */
if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
@@ -191,37 +117,51 @@ static int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
tlb->EPN, eaddr, tlb->pte1,
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, access_type)) {
- case -2:
- /* Access violation */
- ret = -2;
- best = nr;
- break;
- case -1: /* No match */
- case -3: /* TLB inconsistency */
- default:
- break;
- case 0:
- /* access granted */
- /*
- * XXX: we should go on looping to check all TLBs
- * consistency but we can speed-up the whole thing as
- * the result would be undefined if TLBs are not
- * consistent.
- */
+ /* Check validity and table match */
+ if (!pte_is_valid(tlb->pte0) || ((tlb->pte0 >> 6) & 1) != 0 ||
+ (tlb->pte0 & PTE_PTEM_MASK) != ptem) {
+ continue;
+ }
+ /* all matches should have equal RPN, WIMG & PP */
+ if (*raddr != (hwaddr)-1ULL &&
+ (*raddr & PTE_CHECK_MASK) != (tlb->pte1 & PTE_CHECK_MASK)) {
+ qemu_log_mask(CPU_LOG_MMU, "Bad RPN/WIMG/PP\n");
+ /* TLB inconsistency */
+ continue;
+ }
+ /* Keep the matching PTE information */
+ best = nr;
+ *raddr = tlb->pte1;
+ *prot = ppc_hash32_prot(key, tlb->pte1 & HPTE32_R_PP, nx);
+ if (check_prot_access_type(*prot, access_type)) {
+ qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
ret = 0;
- best = nr;
- goto done;
+ break;
+ } else {
+ qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
+ ret = -2;
}
}
if (best != -1) {
-done:
qemu_log_mask(CPU_LOG_MMU, "found TLB at addr " HWADDR_FMT_plx
" prot=%01x ret=%d\n",
- ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
+ *raddr & TARGET_PAGE_MASK, *prot, ret);
/* Update page flags */
- pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, access_type);
+ pte1p = &env->tlb.tlb6[best].pte1;
+ *pte1p |= 0x00000100; /* Update accessed flag */
+ if (!(*pte1p & 0x00000080)) {
+ if (access_type == MMU_DATA_STORE && ret == 0) {
+ /* Update changed flag */
+ *pte1p |= 0x00000080;
+ } else {
+ /* Force page fault for first write access */
+ *prot &= ~PAGE_WRITE;
+ }
+ }
+ }
+ if (ret == -1) {
+ int r = is_code ? SPR_ICMP : SPR_DCMP;
+ env->spr[r] = ptem;
}
#if defined(DUMP_PAGE_TABLES)
if (qemu_loglevel_mask(CPU_LOG_MMU)) {
@@ -247,44 +187,17 @@ done:
return ret;
}
-/* Perform BAT hit & translation */
-static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
- int *validp, int *protp, target_ulong *BATu,
- target_ulong *BATl)
-{
- target_ulong bl;
- int pp, valid, prot;
-
- bl = (*BATu & 0x00001FFC) << 15;
- valid = 0;
- prot = 0;
- if ((!FIELD_EX64(env->msr, MSR, PR) && (*BATu & 0x00000002)) ||
- (FIELD_EX64(env->msr, MSR, PR) && (*BATu & 0x00000001))) {
- valid = 1;
- pp = *BATl & 0x00000003;
- if (pp != 0) {
- prot = PAGE_READ | PAGE_EXEC;
- if (pp == 0x2) {
- prot |= PAGE_WRITE;
- }
- }
- }
- *blp = bl;
- *validp = valid;
- *protp = prot;
-}
-
-static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong virtual, MMUAccessType access_type)
+static int get_bat_6xx_tlb(CPUPPCState *env, hwaddr *raddr, int *prot,
+ target_ulong eaddr, MMUAccessType access_type,
+ bool pr)
{
target_ulong *BATlt, *BATut, *BATu, *BATl;
target_ulong BEPIl, BEPIu, bl;
- int i, valid, prot;
- int ret = -1;
+ int i, ret = -1;
bool ifetch = access_type == MMU_INST_FETCH;
qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
- ifetch ? 'I' : 'D', virtual);
+ ifetch ? 'I' : 'D', eaddr);
if (ifetch) {
BATlt = env->IBAT[1];
BATut = env->IBAT[0];
@@ -295,27 +208,26 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
for (i = 0; i < env->nb_BATs; i++) {
BATu = &BATut[i];
BATl = &BATlt[i];
- BEPIu = *BATu & 0xF0000000;
- BEPIl = *BATu & 0x0FFE0000;
- bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
+ BEPIu = *BATu & BATU32_BEPIU;
+ BEPIl = *BATu & BATU32_BEPIL;
qemu_log_mask(CPU_LOG_MMU, "%s: %cBAT%d v " TARGET_FMT_lx " BATu "
TARGET_FMT_lx " BATl " TARGET_FMT_lx "\n", __func__,
- ifetch ? 'I' : 'D', i, virtual, *BATu, *BATl);
- if ((virtual & 0xF0000000) == BEPIu &&
- ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
- /* BAT matches */
- if (valid != 0) {
+ ifetch ? 'I' : 'D', i, eaddr, *BATu, *BATl);
+ bl = (*BATu & BATU32_BL) << 15;
+ if ((!pr && (*BATu & BATU32_VS)) || (pr && (*BATu & BATU32_VP))) {
+ if ((eaddr & BATU32_BEPIU) == BEPIu &&
+ ((eaddr & BATU32_BEPIL) & ~bl) == BEPIl) {
/* Get physical address */
- ctx->raddr = (*BATl & 0xF0000000) |
- ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
- (virtual & 0x0001F000);
+ *raddr = (*BATl & BATU32_BEPIU) |
+ ((eaddr & BATU32_BEPIL & bl) | (*BATl & BATU32_BEPIL)) |
+ (eaddr & 0x0001F000);
/* Compute access rights */
- ctx->prot = prot;
- if (check_prot_access_type(ctx->prot, access_type)) {
+ *prot = ppc_hash32_bat_prot(*BATu, *BATl);
+ if (check_prot_access_type(*prot, access_type)) {
qemu_log_mask(CPU_LOG_MMU, "BAT %d match: r " HWADDR_FMT_plx
- " prot=%c%c\n", i, ctx->raddr,
- ctx->prot & PAGE_READ ? 'R' : '-',
- ctx->prot & PAGE_WRITE ? 'W' : '-');
+ " prot=%c%c\n", i, *raddr,
+ *prot & PAGE_READ ? 'R' : '-',
+ *prot & PAGE_WRITE ? 'W' : '-');
ret = 0;
} else {
ret = -2;
@@ -327,18 +239,18 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
if (ret < 0) {
if (qemu_log_enabled()) {
qemu_log_mask(CPU_LOG_MMU, "no BAT match for "
- TARGET_FMT_lx ":\n", virtual);
+ TARGET_FMT_lx ":\n", eaddr);
for (i = 0; i < 4; i++) {
BATu = &BATut[i];
BATl = &BATlt[i];
- BEPIu = *BATu & 0xF0000000;
- BEPIl = *BATu & 0x0FFE0000;
- bl = (*BATu & 0x00001FFC) << 15;
+ BEPIu = *BATu & BATU32_BEPIU;
+ BEPIl = *BATu & BATU32_BEPIL;
+ bl = (*BATu & BATU32_BL) << 15;
qemu_log_mask(CPU_LOG_MMU, "%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__, ifetch ? 'I' : 'D',
- i, virtual, *BATu, *BATl, BEPIu, BEPIl, bl);
+ i, eaddr, *BATu, *BATl, BEPIu, BEPIl, bl);
}
}
}
@@ -346,32 +258,30 @@ static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
return ret;
}
-static int mmu6xx_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
- target_ulong eaddr,
+static int mmu6xx_get_physical_address(CPUPPCState *env, hwaddr *raddr,
+ int *prot, target_ulong eaddr,
+ hwaddr *hashp, bool *keyp,
MMUAccessType access_type, int type)
{
PowerPCCPU *cpu = env_archcpu(env);
hwaddr hash;
- target_ulong vsid, sr, pgidx;
- int ds, target_page_bits;
- bool pr;
+ target_ulong vsid, sr, pgidx, ptem;
+ bool key, ds, nx;
+ bool pr = FIELD_EX64(env->msr, MSR, PR);
/* First try to find a BAT entry if there are any */
- if (env->nb_BATs && get_bat_6xx_tlb(env, ctx, eaddr, access_type) == 0) {
+ if (env->nb_BATs &&
+ get_bat_6xx_tlb(env, raddr, prot, eaddr, access_type, pr) == 0) {
return 0;
}
/* Perform segment based translation when no BATs matched */
- pr = FIELD_EX64(env->msr, MSR, PR);
- ctx->eaddr = eaddr;
-
sr = env->sr[eaddr >> 28];
- ctx->key = (((sr & 0x20000000) && pr) ||
- ((sr & 0x40000000) && !pr)) ? 1 : 0;
- ds = sr & 0x80000000 ? 1 : 0;
- ctx->nx = sr & 0x10000000 ? 1 : 0;
- vsid = sr & 0x00FFFFFF;
- target_page_bits = TARGET_PAGE_BITS;
+ key = ppc_hash32_key(pr, sr);
+ *keyp = key;
+ ds = sr & SR32_T;
+ nx = sr & SR32_NX;
+ vsid = sr & SR32_VSID;
qemu_log_mask(CPU_LOG_MMU,
"Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx
" nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx
@@ -380,15 +290,15 @@ static int mmu6xx_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
(int)FIELD_EX64(env->msr, MSR, IR),
(int)FIELD_EX64(env->msr, MSR, DR), pr ? 1 : 0,
access_type == MMU_DATA_STORE, type);
- pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
+ pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS;
hash = vsid ^ pgidx;
- ctx->ptem = (vsid << 7) | (pgidx >> 10);
+ ptem = (vsid << 7) | (pgidx >> 10); /* Virtual segment ID | API */
qemu_log_mask(CPU_LOG_MMU, "pte segment: key=%d ds %d nx %d vsid "
- TARGET_FMT_lx "\n", ctx->key, ds, ctx->nx, vsid);
+ TARGET_FMT_lx "\n", key, ds, nx, vsid);
if (!ds) {
/* Check if instruction fetch is allowed, if needed */
- if (type == ACCESS_CODE && ctx->nx) {
+ if (type == ACCESS_CODE && nx) {
qemu_log_mask(CPU_LOG_MMU, "No access allowed\n");
return -3;
}
@@ -396,13 +306,11 @@ static int mmu6xx_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
qemu_log_mask(CPU_LOG_MMU, "htab_base " HWADDR_FMT_plx " htab_mask "
HWADDR_FMT_plx " hash " HWADDR_FMT_plx "\n",
ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
- ctx->hash[0] = hash;
- ctx->hash[1] = ~hash;
+ *hashp = hash;
- /* Initialize real address with an invalid value */
- ctx->raddr = (hwaddr)-1ULL;
/* Software TLB search */
- return ppc6xx_tlb_check(env, ctx, eaddr, access_type);
+ return ppc6xx_tlb_check(env, raddr, prot, eaddr,
+ access_type, ptem, key, nx);
}
/* Direct-store segment : absolutely *BUGGY* for now */
@@ -411,15 +319,6 @@ static int mmu6xx_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
case ACCESS_INT:
/* Integer load/store : only access allowed */
break;
- case ACCESS_CODE:
- /* No code fetch is allowed in direct-store areas */
- return -4;
- case ACCESS_FLOAT:
- /* Floating point load/store */
- return -4;
- case ACCESS_RES:
- /* lwarx, ldarx or srwcx. */
- return -4;
case ACCESS_CACHE:
/*
* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi
@@ -427,19 +326,17 @@ static int mmu6xx_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
* Should make the instruction do no-op. As it already do
* no-op, it's quite easy :-)
*/
- ctx->raddr = eaddr;
+ *raddr = eaddr;
return 0;
- case ACCESS_EXT:
- /* eciwx or ecowx */
- return -4;
- default:
- qemu_log_mask(CPU_LOG_MMU, "ERROR: instruction should not need address"
- " translation\n");
+ case ACCESS_CODE: /* No code fetch is allowed in direct-store areas */
+ case ACCESS_FLOAT: /* Floating point load/store */
+ case ACCESS_RES: /* lwarx, ldarx or srwcx. */
+ case ACCESS_EXT: /* eciwx or ecowx */
return -4;
}
- if ((access_type == MMU_DATA_STORE || ctx->key != 1) &&
- (access_type == MMU_DATA_LOAD || ctx->key != 0)) {
- ctx->raddr = eaddr;
+ if ((access_type == MMU_DATA_STORE || !key) &&
+ (access_type == MMU_DATA_LOAD || key)) {
+ *raddr = eaddr;
return 2;
}
return -2;
@@ -589,9 +486,9 @@ static void mmu6xx_dump_BATs(CPUPPCState *env, int type)
for (i = 0; i < env->nb_BATs; i++) {
BATu = &BATut[i];
BATl = &BATlt[i];
- BEPIu = *BATu & 0xF0000000;
- BEPIl = *BATu & 0x0FFE0000;
- bl = (*BATu & 0x00001FFC) << 15;
+ BEPIu = *BATu & BATU32_BEPIU;
+ BEPIl = *BATu & BATU32_BEPIL;
+ bl = (*BATu & BATU32_BL) << 15;
qemu_printf("%s BAT%d BATu " TARGET_FMT_lx
" BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
TARGET_FMT_lx " " TARGET_FMT_lx "\n",
@@ -777,9 +674,9 @@ static bool ppc_6xx_xlate(PowerPCCPU *cpu, vaddr eaddr,
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
- mmu_ctx_t ctx;
- int type;
- int ret;
+ hwaddr hash = 0; /* init to 0 to avoid used uninit warning */
+ bool key;
+ int type, ret;
if (ppc_real_mode_xlate(cpu, eaddr, access_type, raddrp, psizep, protp)) {
return true;
@@ -795,13 +692,9 @@ static bool ppc_6xx_xlate(PowerPCCPU *cpu, vaddr eaddr,
type = ACCESS_INT;
}
- ctx.prot = 0;
- ctx.hash[0] = 0;
- ctx.hash[1] = 0;
- ret = mmu6xx_get_physical_address(env, &ctx, eaddr, access_type, type);
+ ret = mmu6xx_get_physical_address(env, raddrp, protp, eaddr, &hash, &key,
+ access_type, type);
if (ret == 0) {
- *raddrp = ctx.raddr;
- *protp = ctx.prot;
*psizep = TARGET_PAGE_BITS;
return true;
} else if (!guest_visible) {
@@ -816,7 +709,7 @@ static bool ppc_6xx_xlate(PowerPCCPU *cpu, vaddr eaddr,
cs->exception_index = POWERPC_EXCP_IFTLB;
env->error_code = 1 << 18;
env->spr[SPR_IMISS] = eaddr;
- env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
+ env->spr[SPR_ICMP] |= 0x80000000;
goto tlb_miss;
case -2:
/* Access rights violation */
@@ -847,13 +740,13 @@ static bool ppc_6xx_xlate(PowerPCCPU *cpu, vaddr eaddr,
env->error_code = 0;
}
env->spr[SPR_DMISS] = eaddr;
- env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
+ env->spr[SPR_DCMP] |= 0x80000000;
tlb_miss:
- env->error_code |= ctx.key << 19;
+ env->error_code |= key << 19;
env->spr[SPR_HASH1] = ppc_hash32_hpt_base(cpu) +
- get_pteg_offset32(cpu, ctx.hash[0]);
+ get_pteg_offset32(cpu, hash);
env->spr[SPR_HASH2] = ppc_hash32_hpt_base(cpu) +
- get_pteg_offset32(cpu, ctx.hash[1]);
+ get_pteg_offset32(cpu, ~hash);
break;
case -2:
/* Access rights violation */
diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c
index b0a0676..b167b37 100644
--- a/target/ppc/mmu_helper.c
+++ b/target/ppc/mmu_helper.c
@@ -316,7 +316,7 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
break;
default:
/* Should never reach here with other MMU models */
- assert(0);
+ g_assert_not_reached();
}
#else
ppc_tlb_invalidate_all(env);
diff --git a/target/ppc/timebase_helper.c b/target/ppc/timebase_helper.c
index 39d3974..7312032 100644
--- a/target/ppc/timebase_helper.c
+++ b/target/ppc/timebase_helper.c
@@ -62,9 +62,8 @@ void helper_store_purr(CPUPPCState *env, target_ulong val)
{
CPUState *cs = env_cpu(env);
CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
- if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+ if (ppc_cpu_lpar_single_threaded(cs)) {
cpu_ppc_store_purr(env, val);
return;
}
@@ -81,9 +80,8 @@ void helper_store_tbl(CPUPPCState *env, target_ulong val)
{
CPUState *cs = env_cpu(env);
CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
- if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+ if (ppc_cpu_lpar_single_threaded(cs)) {
cpu_ppc_store_tbl(env, val);
return;
}
@@ -98,9 +96,8 @@ void helper_store_tbu(CPUPPCState *env, target_ulong val)
{
CPUState *cs = env_cpu(env);
CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
- if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+ if (ppc_cpu_lpar_single_threaded(cs)) {
cpu_ppc_store_tbu(env, val);
return;
}
@@ -140,9 +137,8 @@ void helper_store_hdecr(CPUPPCState *env, target_ulong val)
{
CPUState *cs = env_cpu(env);
CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
- if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+ if (ppc_cpu_lpar_single_threaded(cs)) {
cpu_ppc_store_hdecr(env, val);
return;
}
@@ -157,9 +153,8 @@ void helper_store_vtb(CPUPPCState *env, target_ulong val)
{
CPUState *cs = env_cpu(env);
CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
- if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+ if (ppc_cpu_lpar_single_threaded(cs)) {
cpu_ppc_store_vtb(env, val);
return;
}
@@ -174,9 +169,8 @@ void helper_store_tbu40(CPUPPCState *env, target_ulong val)
{
CPUState *cs = env_cpu(env);
CPUState *ccs;
- uint32_t nr_threads = cs->nr_threads;
- if (nr_threads == 1 || !(env->flags & POWERPC_FLAG_SMT_1LPAR)) {
+ if (ppc_cpu_lpar_single_threaded(cs)) {
cpu_ppc_store_tbu40(env, val);
return;
}
@@ -217,7 +211,14 @@ void helper_store_booke_tsr(CPUPPCState *env, target_ulong val)
store_booke_tsr(env, val);
}
-#if defined(TARGET_PPC64)
+#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
+/*
+ * qemu-user breaks with pnv headers, so they go under ifdefs for now.
+ * A clean up may be to move powernv specific registers and helpers into
+ * target/ppc/pnv_helper.c
+ */
+#include "hw/ppc/pnv_core.h"
+#include "hw/ppc/pnv_chip.h"
/*
* POWER processor Timebase Facility
*/
@@ -287,7 +288,7 @@ static void write_tfmr(CPUPPCState *env, target_ulong val)
{
CPUState *cs = env_cpu(env);
- if (cs->nr_threads == 1) {
+ if (ppc_cpu_core_single_threaded(cs)) {
env->spr[SPR_TFMR] = val;
} else {
CPUState *ccs;
@@ -298,8 +299,25 @@ static void write_tfmr(CPUPPCState *env, target_ulong val)
}
}
+static PnvCoreTODState *cpu_get_tbst(PowerPCCPU *cpu)
+{
+ PnvCore *pc = pnv_cpu_state(cpu)->pnv_core;
+
+ if (pc->big_core && pc->tod_state.big_core_quirk) {
+ /* Must operate on the even small core */
+ int core_id = CPU_CORE(pc)->core_id;
+ if (core_id & 1) {
+ pc = pc->chip->cores[core_id & ~1];
+ }
+ }
+
+ return &pc->tod_state;
+}
+
static void tb_state_machine_step(CPUPPCState *env)
{
+ PowerPCCPU *cpu = env_archcpu(env);
+ PnvCoreTODState *tod_state = cpu_get_tbst(cpu);
uint64_t tfmr = env->spr[SPR_TFMR];
unsigned int tbst = tfmr_get_tb_state(tfmr);
@@ -307,15 +325,15 @@ static void tb_state_machine_step(CPUPPCState *env)
return;
}
- if (env->pnv_tod_tbst.tb_sync_pulse_timer) {
- env->pnv_tod_tbst.tb_sync_pulse_timer--;
+ if (tod_state->tb_sync_pulse_timer) {
+ tod_state->tb_sync_pulse_timer--;
} else {
tfmr |= TFMR_TB_SYNC_OCCURED;
write_tfmr(env, tfmr);
}
- if (env->pnv_tod_tbst.tb_state_timer) {
- env->pnv_tod_tbst.tb_state_timer--;
+ if (tod_state->tb_state_timer) {
+ tod_state->tb_state_timer--;
return;
}
@@ -332,20 +350,20 @@ static void tb_state_machine_step(CPUPPCState *env)
} else if (tfmr & TFMR_MOVE_CHIP_TOD_TO_TB) {
if (tbst == TBST_SYNC_WAIT) {
tfmr = tfmr_new_tb_state(tfmr, TBST_GET_TOD);
- env->pnv_tod_tbst.tb_state_timer = 3;
+ tod_state->tb_state_timer = 3;
} else if (tbst == TBST_GET_TOD) {
- if (env->pnv_tod_tbst.tod_sent_to_tb) {
+ if (tod_state->tod_sent_to_tb) {
tfmr = tfmr_new_tb_state(tfmr, TBST_TB_RUNNING);
tfmr &= ~TFMR_MOVE_CHIP_TOD_TO_TB;
- env->pnv_tod_tbst.tb_ready_for_tod = 0;
- env->pnv_tod_tbst.tod_sent_to_tb = 0;
+ tod_state->tb_ready_for_tod = 0;
+ tod_state->tod_sent_to_tb = 0;
}
} else {
qemu_log_mask(LOG_GUEST_ERROR, "TFMR error: MOVE_CHIP_TOD_TO_TB "
"state machine in invalid state 0x%x\n", tbst);
tfmr = tfmr_new_tb_state(tfmr, TBST_TB_ERROR);
tfmr |= TFMR_FIRMWARE_CONTROL_ERROR;
- env->pnv_tod_tbst.tb_ready_for_tod = 0;
+ tod_state->tb_ready_for_tod = 0;
}
}
@@ -361,6 +379,8 @@ target_ulong helper_load_tfmr(CPUPPCState *env)
void helper_store_tfmr(CPUPPCState *env, target_ulong val)
{
+ PowerPCCPU *cpu = env_archcpu(env);
+ PnvCoreTODState *tod_state = cpu_get_tbst(cpu);
uint64_t tfmr = env->spr[SPR_TFMR];
uint64_t clear_on_write;
unsigned int tbst = tfmr_get_tb_state(tfmr);
@@ -384,14 +404,7 @@ void helper_store_tfmr(CPUPPCState *env, target_ulong val)
* after the second mfspr.
*/
tfmr &= ~TFMR_TB_SYNC_OCCURED;
- env->pnv_tod_tbst.tb_sync_pulse_timer = 1;
-
- if (ppc_cpu_tir(env_archcpu(env)) != 0 &&
- (val & (TFMR_LOAD_TOD_MOD | TFMR_MOVE_CHIP_TOD_TO_TB))) {
- qemu_log_mask(LOG_UNIMP, "TFMR timebase state machine can only be "
- "driven by thread 0\n");
- goto out;
- }
+ tod_state->tb_sync_pulse_timer = 1;
if (((tfmr | val) & (TFMR_LOAD_TOD_MOD | TFMR_MOVE_CHIP_TOD_TO_TB)) ==
(TFMR_LOAD_TOD_MOD | TFMR_MOVE_CHIP_TOD_TO_TB)) {
@@ -399,7 +412,7 @@ void helper_store_tfmr(CPUPPCState *env, target_ulong val)
"MOVE_CHIP_TOD_TO_TB both set\n");
tfmr = tfmr_new_tb_state(tfmr, TBST_TB_ERROR);
tfmr |= TFMR_FIRMWARE_CONTROL_ERROR;
- env->pnv_tod_tbst.tb_ready_for_tod = 0;
+ tod_state->tb_ready_for_tod = 0;
goto out;
}
@@ -413,8 +426,8 @@ void helper_store_tfmr(CPUPPCState *env, target_ulong val)
tfmr &= ~TFMR_LOAD_TOD_MOD;
tfmr &= ~TFMR_MOVE_CHIP_TOD_TO_TB;
tfmr &= ~TFMR_FIRMWARE_CONTROL_ERROR; /* XXX: should this be cleared? */
- env->pnv_tod_tbst.tb_ready_for_tod = 0;
- env->pnv_tod_tbst.tod_sent_to_tb = 0;
+ tod_state->tb_ready_for_tod = 0;
+ tod_state->tod_sent_to_tb = 0;
goto out;
}
@@ -427,19 +440,19 @@ void helper_store_tfmr(CPUPPCState *env, target_ulong val)
if (tfmr & TFMR_LOAD_TOD_MOD) {
/* Wait for an arbitrary 3 mfspr until the next state transition. */
- env->pnv_tod_tbst.tb_state_timer = 3;
+ tod_state->tb_state_timer = 3;
} else if (tfmr & TFMR_MOVE_CHIP_TOD_TO_TB) {
if (tbst == TBST_NOT_SET) {
tfmr = tfmr_new_tb_state(tfmr, TBST_SYNC_WAIT);
- env->pnv_tod_tbst.tb_ready_for_tod = 1;
- env->pnv_tod_tbst.tb_state_timer = 3; /* arbitrary */
+ tod_state->tb_ready_for_tod = 1;
+ tod_state->tb_state_timer = 3; /* arbitrary */
} else {
qemu_log_mask(LOG_GUEST_ERROR, "TFMR error: MOVE_CHIP_TOD_TO_TB "
"not in TB not set state 0x%x\n",
tbst);
tfmr = tfmr_new_tb_state(tfmr, TBST_TB_ERROR);
tfmr |= TFMR_FIRMWARE_CONTROL_ERROR;
- env->pnv_tod_tbst.tb_ready_for_tod = 0;
+ tod_state->tb_ready_for_tod = 0;
}
}
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 0bc16d7..7689b2a 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -178,6 +178,7 @@ struct DisasContext {
/* Translation flags */
MemOp default_tcg_memop_mask;
#if defined(TARGET_PPC64)
+ powerpc_excp_t excp_model;
bool sf_mode;
bool has_cfar;
bool has_bhrb;
@@ -1587,16 +1588,13 @@ static opc_handler_t invalid_handler = {
static inline void gen_op_cmp(TCGv arg0, TCGv arg1, int s, int crf)
{
TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
TCGv_i32 t = tcg_temp_new_i32();
- tcg_gen_movi_tl(t0, CRF_EQ);
- tcg_gen_movi_tl(t1, CRF_LT);
tcg_gen_movcond_tl((s ? TCG_COND_LT : TCG_COND_LTU),
- t0, arg0, arg1, t1, t0);
- tcg_gen_movi_tl(t1, CRF_GT);
+ t0, arg0, arg1,
+ tcg_constant_tl(CRF_LT), tcg_constant_tl(CRF_EQ));
tcg_gen_movcond_tl((s ? TCG_COND_GT : TCG_COND_GTU),
- t0, arg0, arg1, t1, t0);
+ t0, arg0, arg1, tcg_constant_tl(CRF_GT), t0);
tcg_gen_trunc_tl_i32(t, t0);
tcg_gen_trunc_tl_i32(cpu_crf[crf], cpu_so);
@@ -2542,6 +2540,7 @@ static inline void gen_align_no_le(DisasContext *ctx)
(ctx->opcode & 0x03FF0000) | POWERPC_EXCP_ALIGN_LE);
}
+/* EA <- {(ra == 0) ? 0 : GPR[ra]} + displ */
static TCGv do_ea_calc(DisasContext *ctx, int ra, TCGv displ)
{
TCGv ea = tcg_temp_new();
@@ -2556,6 +2555,22 @@ static TCGv do_ea_calc(DisasContext *ctx, int ra, TCGv displ)
return ea;
}
+#if defined(TARGET_PPC64)
+/* EA <- (ra == 0) ? 0 : GPR[ra] */
+static TCGv do_ea_calc_ra(DisasContext *ctx, int ra)
+{
+ TCGv EA = tcg_temp_new();
+ if (!ra) {
+ tcg_gen_movi_tl(EA, 0);
+ } else if (NARROW_MODE(ctx)) {
+ tcg_gen_ext32u_tl(EA, cpu_gpr[ra]);
+ } else {
+ tcg_gen_mov_tl(EA, cpu_gpr[ra]);
+ }
+ return EA;
+}
+#endif
+
/*** Integer load ***/
#define DEF_MEMOP(op) ((op) | ctx->default_tcg_memop_mask)
#define BSWAP_MEMOP(op) ((op) | (ctx->default_tcg_memop_mask ^ MO_BSWAP))
@@ -2956,8 +2971,8 @@ static void gen_fetch_inc_conditional(DisasContext *ctx, MemOp memop,
tcg_gen_qemu_st_tl(u, EA, ctx->mem_idx, memop);
/* RT = (t != t2 ? t : u = 1<<(s*8-1)) */
- tcg_gen_movi_tl(u, 1 << (memop_size(memop) * 8 - 1));
- tcg_gen_movcond_tl(cond, cpu_gpr[rD(ctx->opcode)], t, t2, t, u);
+ tcg_gen_movcond_tl(cond, cpu_gpr[rD(ctx->opcode)], t, t2, t,
+ tcg_constant_tl(1 << (memop_size(memop) * 8 - 1)));
}
static void gen_ld_atomic(DisasContext *ctx, MemOp memop)
@@ -4445,27 +4460,29 @@ static void gen_dcblc(DisasContext *ctx)
/* dcbz */
static void gen_dcbz(DisasContext *ctx)
{
- TCGv tcgv_addr;
- TCGv_i32 tcgv_op;
+ TCGv tcgv_addr = tcg_temp_new();
gen_set_access_type(ctx, ACCESS_CACHE);
- tcgv_addr = tcg_temp_new();
- tcgv_op = tcg_constant_i32(ctx->opcode & 0x03FF000);
gen_addr_reg_index(ctx, tcgv_addr);
- gen_helper_dcbz(tcg_env, tcgv_addr, tcgv_op);
+
+#ifdef TARGET_PPC64
+ if (ctx->excp_model == POWERPC_EXCP_970 && !(ctx->opcode & 0x00200000)) {
+ gen_helper_dcbzl(tcg_env, tcgv_addr);
+ return;
+ }
+#endif
+
+ gen_helper_dcbz(tcg_env, tcgv_addr, tcg_constant_i32(ctx->mem_idx));
}
/* dcbzep */
static void gen_dcbzep(DisasContext *ctx)
{
- TCGv tcgv_addr;
- TCGv_i32 tcgv_op;
+ TCGv tcgv_addr = tcg_temp_new();
gen_set_access_type(ctx, ACCESS_CACHE);
- tcgv_addr = tcg_temp_new();
- tcgv_op = tcg_constant_i32(ctx->opcode & 0x03FF000);
gen_addr_reg_index(ctx, tcgv_addr);
- gen_helper_dcbzep(tcg_env, tcgv_addr, tcgv_op);
+ gen_helper_dcbz(tcg_env, tcgv_addr, tcg_constant_i32(PPC_TLB_EPID_STORE));
}
/* dst / dstt */
@@ -5538,16 +5555,6 @@ static inline void set_fpr(int regno, TCGv_i64 src)
tcg_gen_st_i64(tcg_constant_i64(0), tcg_env, vsr64_offset(regno, false));
}
-static inline void get_avr64(TCGv_i64 dst, int regno, bool high)
-{
- tcg_gen_ld_i64(dst, tcg_env, avr64_offset(regno, high));
-}
-
-static inline void set_avr64(int regno, TCGv_i64 src, bool high)
-{
- tcg_gen_st_i64(src, tcg_env, avr64_offset(regno, high));
-}
-
/*
* Helpers for decodetree used by !function for decoding arguments.
*/
@@ -6486,6 +6493,7 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->default_tcg_memop_mask = ctx->le_mode ? MO_LE : MO_BE;
ctx->flags = env->flags;
#if defined(TARGET_PPC64)
+ ctx->excp_model = env->excp_model;
ctx->sf_mode = (hflags >> HFLAGS_64) & 1;
ctx->has_cfar = !!(env->flags & POWERPC_FLAG_CFAR);
ctx->has_bhrb = !!(env->flags & POWERPC_FLAG_BHRB);
diff --git a/target/ppc/translate/vmx-impl.c.inc b/target/ppc/translate/vmx-impl.c.inc
index 8084af7..70d0ad2 100644
--- a/target/ppc/translate/vmx-impl.c.inc
+++ b/target/ppc/translate/vmx-impl.c.inc
@@ -14,25 +14,39 @@ static inline TCGv_ptr gen_avr_ptr(int reg)
return r;
}
+static inline void get_avr64(TCGv_i64 dst, int regno, bool high)
+{
+ tcg_gen_ld_i64(dst, tcg_env, avr64_offset(regno, high));
+}
+
+static inline void set_avr64(int regno, TCGv_i64 src, bool high)
+{
+ tcg_gen_st_i64(src, tcg_env, avr64_offset(regno, high));
+}
+
+static inline void get_avr_full(TCGv_i128 dst, int regno)
+{
+ tcg_gen_ld_i128(dst, tcg_env, avr_full_offset(regno));
+}
+
+static inline void set_avr_full(int regno, TCGv_i128 src)
+{
+ tcg_gen_st_i128(src, tcg_env, avr_full_offset(regno));
+}
+
static bool trans_LVX(DisasContext *ctx, arg_X *a)
{
TCGv EA;
- TCGv_i64 avr;
+ TCGv_i128 avr;
REQUIRE_INSNS_FLAGS(ctx, ALTIVEC);
REQUIRE_VECTOR(ctx);
gen_set_access_type(ctx, ACCESS_INT);
- avr = tcg_temp_new_i64();
+ avr = tcg_temp_new_i128();
EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
tcg_gen_andi_tl(EA, EA, ~0xf);
- /*
- * We only need to swap high and low halves. gen_qemu_ld64_i64
- * does necessary 64-bit byteswap already.
- */
- gen_qemu_ld64_i64(ctx, avr, EA);
- set_avr64(a->rt, avr, !ctx->le_mode);
- tcg_gen_addi_tl(EA, EA, 8);
- gen_qemu_ld64_i64(ctx, avr, EA);
- set_avr64(a->rt, avr, ctx->le_mode);
+ tcg_gen_qemu_ld_i128(avr, EA, ctx->mem_idx,
+ DEF_MEMOP(MO_128 | MO_ATOM_IFALIGN_PAIR));
+ set_avr_full(a->rt, avr);
return true;
}
@@ -46,22 +60,16 @@ static bool trans_LVXL(DisasContext *ctx, arg_LVXL *a)
static bool trans_STVX(DisasContext *ctx, arg_STVX *a)
{
TCGv EA;
- TCGv_i64 avr;
+ TCGv_i128 avr;
REQUIRE_INSNS_FLAGS(ctx, ALTIVEC);
REQUIRE_VECTOR(ctx);
gen_set_access_type(ctx, ACCESS_INT);
- avr = tcg_temp_new_i64();
+ avr = tcg_temp_new_i128();
EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
tcg_gen_andi_tl(EA, EA, ~0xf);
- /*
- * We only need to swap high and low halves. gen_qemu_st64_i64
- * does necessary 64-bit byteswap already.
- */
- get_avr64(avr, a->rt, !ctx->le_mode);
- gen_qemu_st64_i64(ctx, avr, EA);
- tcg_gen_addi_tl(EA, EA, 8);
- get_avr64(avr, a->rt, ctx->le_mode);
- gen_qemu_st64_i64(ctx, avr, EA);
+ get_avr_full(avr, a->rt);
+ tcg_gen_qemu_st_i128(avr, EA, ctx->mem_idx,
+ DEF_MEMOP(MO_128 | MO_ATOM_IFALIGN_PAIR));
return true;
}
@@ -1047,58 +1055,6 @@ TRANS(VRLQ, do_vector_rotl_quad, false, false)
TRANS(VRLQNM, do_vector_rotl_quad, true, false)
TRANS(VRLQMI, do_vector_rotl_quad, false, true)
-#define GEN_VXFORM_SAT(NAME, VECE, NORM, SAT, OPC2, OPC3) \
-static void glue(glue(gen_, NAME), _vec)(unsigned vece, TCGv_vec t, \
- TCGv_vec sat, TCGv_vec a, \
- TCGv_vec b) \
-{ \
- TCGv_vec x = tcg_temp_new_vec_matching(t); \
- glue(glue(tcg_gen_, NORM), _vec)(VECE, x, a, b); \
- glue(glue(tcg_gen_, SAT), _vec)(VECE, t, a, b); \
- tcg_gen_cmp_vec(TCG_COND_NE, VECE, x, x, t); \
- tcg_gen_or_vec(VECE, sat, sat, x); \
-} \
-static void glue(gen_, NAME)(DisasContext *ctx) \
-{ \
- static const TCGOpcode vecop_list[] = { \
- glue(glue(INDEX_op_, NORM), _vec), \
- glue(glue(INDEX_op_, SAT), _vec), \
- INDEX_op_cmp_vec, 0 \
- }; \
- static const GVecGen4 g = { \
- .fniv = glue(glue(gen_, NAME), _vec), \
- .fno = glue(gen_helper_, NAME), \
- .opt_opc = vecop_list, \
- .write_aofs = true, \
- .vece = VECE, \
- }; \
- if (unlikely(!ctx->altivec_enabled)) { \
- gen_exception(ctx, POWERPC_EXCP_VPU); \
- return; \
- } \
- tcg_gen_gvec_4(avr_full_offset(rD(ctx->opcode)), \
- offsetof(CPUPPCState, vscr_sat), \
- avr_full_offset(rA(ctx->opcode)), \
- avr_full_offset(rB(ctx->opcode)), \
- 16, 16, &g); \
-}
-
-GEN_VXFORM_SAT(vaddubs, MO_8, add, usadd, 0, 8);
-GEN_VXFORM_DUAL_EXT(vaddubs, PPC_ALTIVEC, PPC_NONE, 0, \
- vmul10uq, PPC_NONE, PPC2_ISA300, 0x0000F800)
-GEN_VXFORM_SAT(vadduhs, MO_16, add, usadd, 0, 9);
-GEN_VXFORM_DUAL(vadduhs, PPC_ALTIVEC, PPC_NONE, \
- vmul10euq, PPC_NONE, PPC2_ISA300)
-GEN_VXFORM_SAT(vadduws, MO_32, add, usadd, 0, 10);
-GEN_VXFORM_SAT(vaddsbs, MO_8, add, ssadd, 0, 12);
-GEN_VXFORM_SAT(vaddshs, MO_16, add, ssadd, 0, 13);
-GEN_VXFORM_SAT(vaddsws, MO_32, add, ssadd, 0, 14);
-GEN_VXFORM_SAT(vsububs, MO_8, sub, ussub, 0, 24);
-GEN_VXFORM_SAT(vsubuhs, MO_16, sub, ussub, 0, 25);
-GEN_VXFORM_SAT(vsubuws, MO_32, sub, ussub, 0, 26);
-GEN_VXFORM_SAT(vsubsbs, MO_8, sub, sssub, 0, 28);
-GEN_VXFORM_SAT(vsubshs, MO_16, sub, sssub, 0, 29);
-GEN_VXFORM_SAT(vsubsws, MO_32, sub, sssub, 0, 30);
GEN_VXFORM_TRANS(vsl, 2, 7);
GEN_VXFORM_TRANS(vsr, 2, 11);
GEN_VXFORM_ENV(vpkuhum, 7, 0);
@@ -2641,26 +2597,14 @@ static void gen_xpnd04_2(DisasContext *ctx)
}
}
-
-GEN_VXFORM_DUAL(vsubsws, PPC_ALTIVEC, PPC_NONE, \
- xpnd04_2, PPC_NONE, PPC2_ISA300)
-
GEN_VXFORM_DUAL(vsububm, PPC_ALTIVEC, PPC_NONE, \
bcdadd, PPC_NONE, PPC2_ALTIVEC_207)
-GEN_VXFORM_DUAL(vsububs, PPC_ALTIVEC, PPC_NONE, \
- bcdadd, PPC_NONE, PPC2_ALTIVEC_207)
GEN_VXFORM_DUAL(vsubuhm, PPC_ALTIVEC, PPC_NONE, \
bcdsub, PPC_NONE, PPC2_ALTIVEC_207)
-GEN_VXFORM_DUAL(vsubuhs, PPC_ALTIVEC, PPC_NONE, \
- bcdsub, PPC_NONE, PPC2_ALTIVEC_207)
-GEN_VXFORM_DUAL(vaddshs, PPC_ALTIVEC, PPC_NONE, \
- bcdcpsgn, PPC_NONE, PPC2_ISA300)
GEN_VXFORM_DUAL(vsubudm, PPC2_ALTIVEC_207, PPC_NONE, \
bcds, PPC_NONE, PPC2_ISA300)
GEN_VXFORM_DUAL(vsubuwm, PPC_ALTIVEC, PPC_NONE, \
bcdus, PPC_NONE, PPC2_ISA300)
-GEN_VXFORM_DUAL(vsubsbs, PPC_ALTIVEC, PPC_NONE, \
- bcdtrunc, PPC_NONE, PPC2_ISA300)
static void gen_vsbox(DisasContext *ctx)
{
@@ -2937,6 +2881,180 @@ static bool do_vx_vaddsubcuw(DisasContext *ctx, arg_VX *a, int add)
TRANS(VSUBCUW, do_vx_vaddsubcuw, 0)
TRANS(VADDCUW, do_vx_vaddsubcuw, 1)
+/* Integer Add/Sub Saturate Instructions */
+static inline void do_vadd_vsub_sat
+(
+ unsigned vece, TCGv_vec t, TCGv_vec qc, TCGv_vec a, TCGv_vec b,
+ void (*norm_op)(unsigned, TCGv_vec, TCGv_vec, TCGv_vec),
+ void (*sat_op)(unsigned, TCGv_vec, TCGv_vec, TCGv_vec))
+{
+ TCGv_vec x = tcg_temp_new_vec_matching(t);
+ norm_op(vece, x, a, b);
+ sat_op(vece, t, a, b);
+ tcg_gen_xor_vec(vece, x, x, t);
+ tcg_gen_or_vec(vece, qc, qc, x);
+}
+
+static void gen_vadd_sat_u(unsigned vece, TCGv_vec t, TCGv_vec sat,
+ TCGv_vec a, TCGv_vec b)
+{
+ do_vadd_vsub_sat(vece, t, sat, a, b, tcg_gen_add_vec, tcg_gen_usadd_vec);
+}
+
+static void gen_vadd_sat_s(unsigned vece, TCGv_vec t, TCGv_vec sat,
+ TCGv_vec a, TCGv_vec b)
+{
+ do_vadd_vsub_sat(vece, t, sat, a, b, tcg_gen_add_vec, tcg_gen_ssadd_vec);
+}
+
+static void gen_vsub_sat_u(unsigned vece, TCGv_vec t, TCGv_vec sat,
+ TCGv_vec a, TCGv_vec b)
+{
+ do_vadd_vsub_sat(vece, t, sat, a, b, tcg_gen_sub_vec, tcg_gen_ussub_vec);
+}
+
+static void gen_vsub_sat_s(unsigned vece, TCGv_vec t, TCGv_vec sat,
+ TCGv_vec a, TCGv_vec b)
+{
+ do_vadd_vsub_sat(vece, t, sat, a, b, tcg_gen_sub_vec, tcg_gen_sssub_vec);
+}
+
+/*
+ * Signed/Unsigned add/sub helper ops for byte/halfword/word
+ * GVecGen4 struct variants.
+ */
+static const TCGOpcode vecop_list_sub_u[] = {
+ INDEX_op_sub_vec, INDEX_op_ussub_vec, 0
+};
+static const TCGOpcode vecop_list_sub_s[] = {
+ INDEX_op_sub_vec, INDEX_op_sssub_vec, 0
+};
+static const TCGOpcode vecop_list_add_u[] = {
+ INDEX_op_add_vec, INDEX_op_usadd_vec, 0
+};
+static const TCGOpcode vecop_list_add_s[] = {
+ INDEX_op_add_vec, INDEX_op_ssadd_vec, 0
+};
+
+static const GVecGen4 op_vsububs = {
+ .fniv = gen_vsub_sat_u,
+ .fno = gen_helper_VSUBUBS,
+ .opt_opc = vecop_list_sub_u,
+ .write_aofs = true,
+ .vece = MO_8
+};
+
+static const GVecGen4 op_vaddubs = {
+ .fniv = gen_vadd_sat_u,
+ .fno = gen_helper_VADDUBS,
+ .opt_opc = vecop_list_add_u,
+ .write_aofs = true,
+ .vece = MO_8
+};
+
+static const GVecGen4 op_vsubuhs = {
+ .fniv = gen_vsub_sat_u,
+ .fno = gen_helper_VSUBUHS,
+ .opt_opc = vecop_list_sub_u,
+ .write_aofs = true,
+ .vece = MO_16
+};
+
+static const GVecGen4 op_vadduhs = {
+ .fniv = gen_vadd_sat_u,
+ .fno = gen_helper_VADDUHS,
+ .opt_opc = vecop_list_add_u,
+ .write_aofs = true,
+ .vece = MO_16
+};
+
+static const GVecGen4 op_vsubuws = {
+ .fniv = gen_vsub_sat_u,
+ .fno = gen_helper_VSUBUWS,
+ .opt_opc = vecop_list_sub_u,
+ .write_aofs = true,
+ .vece = MO_32
+};
+
+static const GVecGen4 op_vadduws = {
+ .fniv = gen_vadd_sat_u,
+ .fno = gen_helper_VADDUWS,
+ .opt_opc = vecop_list_add_u,
+ .write_aofs = true,
+ .vece = MO_32
+};
+
+static const GVecGen4 op_vsubsbs = {
+ .fniv = gen_vsub_sat_s,
+ .fno = gen_helper_VSUBSBS,
+ .opt_opc = vecop_list_sub_s,
+ .write_aofs = true,
+ .vece = MO_8
+};
+
+static const GVecGen4 op_vaddsbs = {
+ .fniv = gen_vadd_sat_s,
+ .fno = gen_helper_VADDSBS,
+ .opt_opc = vecop_list_add_s,
+ .write_aofs = true,
+ .vece = MO_8
+};
+
+static const GVecGen4 op_vsubshs = {
+ .fniv = gen_vsub_sat_s,
+ .fno = gen_helper_VSUBSHS,
+ .opt_opc = vecop_list_sub_s,
+ .write_aofs = true,
+ .vece = MO_16
+};
+
+static const GVecGen4 op_vaddshs = {
+ .fniv = gen_vadd_sat_s,
+ .fno = gen_helper_VADDSHS,
+ .opt_opc = vecop_list_add_s,
+ .write_aofs = true,
+ .vece = MO_16
+};
+
+static const GVecGen4 op_vsubsws = {
+ .fniv = gen_vsub_sat_s,
+ .fno = gen_helper_VSUBSWS,
+ .opt_opc = vecop_list_sub_s,
+ .write_aofs = true,
+ .vece = MO_32
+};
+
+static const GVecGen4 op_vaddsws = {
+ .fniv = gen_vadd_sat_s,
+ .fno = gen_helper_VADDSWS,
+ .opt_opc = vecop_list_add_s,
+ .write_aofs = true,
+ .vece = MO_32
+};
+
+static bool do_vx_vadd_vsub_sat(DisasContext *ctx, arg_VX *a, const GVecGen4 *op)
+{
+ REQUIRE_VECTOR(ctx);
+ tcg_gen_gvec_4(avr_full_offset(a->vrt), offsetof(CPUPPCState, vscr_sat),
+ avr_full_offset(a->vra), avr_full_offset(a->vrb),
+ 16, 16, op);
+
+ return true;
+}
+
+TRANS_FLAGS(ALTIVEC, VSUBUBS, do_vx_vadd_vsub_sat, &op_vsububs)
+TRANS_FLAGS(ALTIVEC, VSUBUHS, do_vx_vadd_vsub_sat, &op_vsubuhs)
+TRANS_FLAGS(ALTIVEC, VSUBUWS, do_vx_vadd_vsub_sat, &op_vsubuws)
+TRANS_FLAGS(ALTIVEC, VSUBSBS, do_vx_vadd_vsub_sat, &op_vsubsbs)
+TRANS_FLAGS(ALTIVEC, VSUBSHS, do_vx_vadd_vsub_sat, &op_vsubshs)
+TRANS_FLAGS(ALTIVEC, VSUBSWS, do_vx_vadd_vsub_sat, &op_vsubsws)
+TRANS_FLAGS(ALTIVEC, VADDUBS, do_vx_vadd_vsub_sat, &op_vaddubs)
+TRANS_FLAGS(ALTIVEC, VADDUHS, do_vx_vadd_vsub_sat, &op_vadduhs)
+TRANS_FLAGS(ALTIVEC, VADDUWS, do_vx_vadd_vsub_sat, &op_vadduws)
+TRANS_FLAGS(ALTIVEC, VADDSBS, do_vx_vadd_vsub_sat, &op_vaddsbs)
+TRANS_FLAGS(ALTIVEC, VADDSHS, do_vx_vadd_vsub_sat, &op_vaddshs)
+TRANS_FLAGS(ALTIVEC, VADDSWS, do_vx_vadd_vsub_sat, &op_vaddsws)
+
static bool do_vx_vmuleo(DisasContext *ctx, arg_VX *a, bool even,
void (*gen_mul)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64))
{
diff --git a/target/ppc/translate/vmx-ops.c.inc b/target/ppc/translate/vmx-ops.c.inc
index 7bb11b0..e28958a 100644
--- a/target/ppc/translate/vmx-ops.c.inc
+++ b/target/ppc/translate/vmx-ops.c.inc
@@ -54,18 +54,13 @@ GEN_VXFORM(vsro, 6, 17),
GEN_VXFORM(xpnd04_1, 0, 22),
GEN_VXFORM_300(bcdsr, 0, 23),
GEN_VXFORM_300(bcdsr, 0, 31),
-GEN_VXFORM_DUAL(vaddubs, vmul10uq, 0, 8, PPC_ALTIVEC, PPC_NONE),
-GEN_VXFORM_DUAL(vadduhs, vmul10euq, 0, 9, PPC_ALTIVEC, PPC_NONE),
-GEN_VXFORM(vadduws, 0, 10),
-GEN_VXFORM(vaddsbs, 0, 12),
-GEN_VXFORM_DUAL(vaddshs, bcdcpsgn, 0, 13, PPC_ALTIVEC, PPC_NONE),
-GEN_VXFORM(vaddsws, 0, 14),
-GEN_VXFORM_DUAL(vsububs, bcdadd, 0, 24, PPC_ALTIVEC, PPC_NONE),
-GEN_VXFORM_DUAL(vsubuhs, bcdsub, 0, 25, PPC_ALTIVEC, PPC_NONE),
-GEN_VXFORM(vsubuws, 0, 26),
-GEN_VXFORM_DUAL(vsubsbs, bcdtrunc, 0, 28, PPC_ALTIVEC, PPC2_ISA300),
-GEN_VXFORM(vsubshs, 0, 29),
-GEN_VXFORM_DUAL(vsubsws, xpnd04_2, 0, 30, PPC_ALTIVEC, PPC_NONE),
+GEN_VXFORM_300_EXT(vmul10uq, 0, 8, 0x0000F800),
+GEN_VXFORM_300(vmul10euq, 0, 9),
+GEN_VXFORM_300(bcdcpsgn, 0, 13),
+GEN_VXFORM_207(bcdadd, 0, 24),
+GEN_VXFORM_207(bcdsub, 0, 25),
+GEN_VXFORM_300(bcdtrunc, 0, 28),
+GEN_VXFORM_300(xpnd04_2, 0, 30),
GEN_VXFORM_300(bcdtrunc, 0, 20),
GEN_VXFORM_300(bcdutrunc, 0, 21),
GEN_VXFORM(vsl, 2, 7),
diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc
index 0266f09..a869f30 100644
--- a/target/ppc/translate/vsx-impl.c.inc
+++ b/target/ppc/translate/vsx-impl.c.inc
@@ -10,6 +10,16 @@ static inline void set_cpu_vsr(int n, TCGv_i64 src, bool high)
tcg_gen_st_i64(src, tcg_env, vsr64_offset(n, high));
}
+static inline void get_vsr_full(TCGv_i128 dst, int reg)
+{
+ tcg_gen_ld_i128(dst, tcg_env, vsr_full_offset(reg));
+}
+
+static inline void set_vsr_full(int reg, TCGv_i128 src)
+{
+ tcg_gen_st_i128(src, tcg_env, vsr_full_offset(reg));
+}
+
static inline TCGv_ptr gen_vsr_ptr(int reg)
{
TCGv_ptr r = tcg_temp_new_ptr();
@@ -24,66 +34,59 @@ static inline TCGv_ptr gen_acc_ptr(int reg)
return r;
}
-#define VSX_LOAD_SCALAR(name, operation) \
-static void gen_##name(DisasContext *ctx) \
-{ \
- TCGv EA; \
- TCGv_i64 t0; \
- if (unlikely(!ctx->vsx_enabled)) { \
- gen_exception(ctx, POWERPC_EXCP_VSXU); \
- return; \
- } \
- t0 = tcg_temp_new_i64(); \
- gen_set_access_type(ctx, ACCESS_INT); \
- EA = tcg_temp_new(); \
- gen_addr_reg_index(ctx, EA); \
- gen_qemu_##operation(ctx, t0, EA); \
- set_cpu_vsr(xT(ctx->opcode), t0, true); \
- /* NOTE: cpu_vsrl is undefined */ \
+static bool do_lxs(DisasContext *ctx, arg_X *a,
+ void (*op)(DisasContext *, TCGv_i64, TCGv))
+{
+ TCGv EA;
+ TCGv_i64 t0;
+ REQUIRE_VSX(ctx);
+ t0 = tcg_temp_new_i64();
+ gen_set_access_type(ctx, ACCESS_INT);
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
+ op(ctx, t0, EA);
+ set_cpu_vsr(a->rt, t0, true);
+ /* NOTE: cpu_vsrl is undefined */
+ return true;
}
-VSX_LOAD_SCALAR(lxsdx, ld64_i64)
-VSX_LOAD_SCALAR(lxsiwax, ld32s_i64)
-VSX_LOAD_SCALAR(lxsibzx, ld8u_i64)
-VSX_LOAD_SCALAR(lxsihzx, ld16u_i64)
-VSX_LOAD_SCALAR(lxsiwzx, ld32u_i64)
-VSX_LOAD_SCALAR(lxsspx, ld32fs)
+TRANS_FLAGS2(VSX, LXSDX, do_lxs, gen_qemu_ld64_i64);
+TRANS_FLAGS2(VSX207, LXSIWAX, do_lxs, gen_qemu_ld32s_i64);
+TRANS_FLAGS2(ISA300, LXSIBZX, do_lxs, gen_qemu_ld8u_i64);
+TRANS_FLAGS2(ISA300, LXSIHZX, do_lxs, gen_qemu_ld16u_i64);
+TRANS_FLAGS2(VSX207, LXSIWZX, do_lxs, gen_qemu_ld32u_i64);
+TRANS_FLAGS2(VSX207, LXSSPX, do_lxs, gen_qemu_ld32fs);
-static void gen_lxvd2x(DisasContext *ctx)
+static bool trans_LXVD2X(DisasContext *ctx, arg_LXVD2X *a)
{
TCGv EA;
TCGv_i64 t0;
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
- }
+
+ REQUIRE_VSX(ctx);
+ REQUIRE_INSNS_FLAGS2(ctx, VSX);
+
t0 = tcg_temp_new_i64();
gen_set_access_type(ctx, ACCESS_INT);
- EA = tcg_temp_new();
- gen_addr_reg_index(ctx, EA);
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
gen_qemu_ld64_i64(ctx, t0, EA);
- set_cpu_vsr(xT(ctx->opcode), t0, true);
+ set_cpu_vsr(a->rt, t0, true);
tcg_gen_addi_tl(EA, EA, 8);
gen_qemu_ld64_i64(ctx, t0, EA);
- set_cpu_vsr(xT(ctx->opcode), t0, false);
+ set_cpu_vsr(a->rt, t0, false);
+ return true;
}
-static void gen_lxvw4x(DisasContext *ctx)
+static bool trans_LXVW4X(DisasContext *ctx, arg_LXVW4X *a)
{
TCGv EA;
- TCGv_i64 xth;
- TCGv_i64 xtl;
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
- }
+ TCGv_i64 xth, xtl;
+
+ REQUIRE_VSX(ctx);
+ REQUIRE_INSNS_FLAGS2(ctx, VSX);
+
xth = tcg_temp_new_i64();
xtl = tcg_temp_new_i64();
-
gen_set_access_type(ctx, ACCESS_INT);
- EA = tcg_temp_new();
-
- gen_addr_reg_index(ctx, EA);
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
if (ctx->le_mode) {
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
@@ -100,55 +103,45 @@ static void gen_lxvw4x(DisasContext *ctx)
tcg_gen_addi_tl(EA, EA, 8);
tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEUQ);
}
- set_cpu_vsr(xT(ctx->opcode), xth, true);
- set_cpu_vsr(xT(ctx->opcode), xtl, false);
+ set_cpu_vsr(a->rt, xth, true);
+ set_cpu_vsr(a->rt, xtl, false);
+ return true;
}
-static void gen_lxvwsx(DisasContext *ctx)
+static bool trans_LXVWSX(DisasContext *ctx, arg_LXVWSX *a)
{
TCGv EA;
TCGv_i32 data;
- if (xT(ctx->opcode) < 32) {
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
- }
+ if (a->rt < 32) {
+ REQUIRE_VSX(ctx);
} else {
- if (unlikely(!ctx->altivec_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VPU);
- return;
- }
+ REQUIRE_VECTOR(ctx);
}
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
gen_set_access_type(ctx, ACCESS_INT);
- EA = tcg_temp_new();
-
- gen_addr_reg_index(ctx, EA);
-
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
data = tcg_temp_new_i32();
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_gen_gvec_dup_i32(MO_UL, vsr_full_offset(a->rt), 16, 16, data);
+ return true;
}
-static void gen_lxvdsx(DisasContext *ctx)
+static bool trans_LXVDSX(DisasContext *ctx, arg_LXVDSX *a)
{
TCGv EA;
TCGv_i64 data;
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
- }
+ REQUIRE_VSX(ctx);
+ REQUIRE_INSNS_FLAGS2(ctx, VSX);
gen_set_access_type(ctx, ACCESS_INT);
- EA = tcg_temp_new();
-
- gen_addr_reg_index(ctx, EA);
-
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
data = tcg_temp_new_i64();
tcg_gen_qemu_ld_i64(data, EA, ctx->mem_idx, DEF_MEMOP(MO_UQ));
- tcg_gen_gvec_dup_i64(MO_UQ, vsr_full_offset(xT(ctx->opcode)), 16, 16, data);
+ tcg_gen_gvec_dup_i64(MO_UQ, vsr_full_offset(a->rt), 16, 16, data);
+ return true;
}
static void gen_bswap16x8(TCGv_i64 outh, TCGv_i64 outl,
@@ -187,145 +180,166 @@ static void gen_bswap32x4(TCGv_i64 outh, TCGv_i64 outl,
tcg_gen_deposit_i64(outl, outl, lo, 32, 32);
}
-static void gen_lxvh8x(DisasContext *ctx)
+static bool trans_LXVH8X(DisasContext *ctx, arg_LXVH8X *a)
{
TCGv EA;
- TCGv_i64 xth;
- TCGv_i64 xtl;
+ TCGv_i64 xth, xtl;
+
+ REQUIRE_VSX(ctx);
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
- }
xth = tcg_temp_new_i64();
xtl = tcg_temp_new_i64();
gen_set_access_type(ctx, ACCESS_INT);
-
- EA = tcg_temp_new();
- gen_addr_reg_index(ctx, EA);
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEUQ);
tcg_gen_addi_tl(EA, EA, 8);
tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEUQ);
if (ctx->le_mode) {
gen_bswap16x8(xth, xtl, xth, xtl);
}
- set_cpu_vsr(xT(ctx->opcode), xth, true);
- set_cpu_vsr(xT(ctx->opcode), xtl, false);
+ set_cpu_vsr(a->rt, xth, true);
+ set_cpu_vsr(a->rt, xtl, false);
+ return true;
}
-static void gen_lxvb16x(DisasContext *ctx)
+static bool trans_LXVB16X(DisasContext *ctx, arg_LXVB16X *a)
{
TCGv EA;
- TCGv_i64 xth;
- TCGv_i64 xtl;
+ TCGv_i128 data;
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
+ REQUIRE_VSX(ctx);
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+
+ data = tcg_temp_new_i128();
+ gen_set_access_type(ctx, ACCESS_INT);
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
+ tcg_gen_qemu_ld_i128(data, EA, ctx->mem_idx,
+ MO_BE | MO_128 | MO_ATOM_IFALIGN_PAIR);
+ set_vsr_full(a->rt, data);
+ return true;
+}
+
+#if defined(TARGET_PPC64)
+static bool do_ld_st_vl(DisasContext *ctx, arg_X *a,
+ void (*helper)(TCGv_ptr, TCGv, TCGv_ptr, TCGv))
+{
+ TCGv EA;
+ TCGv_ptr xt;
+ if (a->rt < 32) {
+ REQUIRE_VSX(ctx);
+ } else {
+ REQUIRE_VECTOR(ctx);
}
- xth = tcg_temp_new_i64();
- xtl = tcg_temp_new_i64();
+ xt = gen_vsr_ptr(a->rt);
gen_set_access_type(ctx, ACCESS_INT);
- EA = tcg_temp_new();
- gen_addr_reg_index(ctx, EA);
- tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEUQ);
- tcg_gen_addi_tl(EA, EA, 8);
- tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEUQ);
- set_cpu_vsr(xT(ctx->opcode), xth, true);
- set_cpu_vsr(xT(ctx->opcode), xtl, false);
+ EA = do_ea_calc_ra(ctx, a->ra);
+ helper(tcg_env, EA, xt, cpu_gpr[a->rb]);
+ return true;
}
+#endif
-#ifdef TARGET_PPC64
-#define VSX_VECTOR_LOAD_STORE_LENGTH(name) \
-static void gen_##name(DisasContext *ctx) \
-{ \
- TCGv EA; \
- TCGv_ptr xt; \
- \
- if (xT(ctx->opcode) < 32) { \
- if (unlikely(!ctx->vsx_enabled)) { \
- gen_exception(ctx, POWERPC_EXCP_VSXU); \
- return; \
- } \
- } else { \
- if (unlikely(!ctx->altivec_enabled)) { \
- gen_exception(ctx, POWERPC_EXCP_VPU); \
- return; \
- } \
- } \
- EA = tcg_temp_new(); \
- xt = gen_vsr_ptr(xT(ctx->opcode)); \
- gen_set_access_type(ctx, ACCESS_INT); \
- gen_addr_register(ctx, EA); \
- gen_helper_##name(tcg_env, EA, xt, cpu_gpr[rB(ctx->opcode)]); \
-}
-
-VSX_VECTOR_LOAD_STORE_LENGTH(lxvl)
-VSX_VECTOR_LOAD_STORE_LENGTH(lxvll)
-VSX_VECTOR_LOAD_STORE_LENGTH(stxvl)
-VSX_VECTOR_LOAD_STORE_LENGTH(stxvll)
+static bool trans_LXVL(DisasContext *ctx, arg_LXVL *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+#if defined(TARGET_PPC64)
+ return do_ld_st_vl(ctx, a, gen_helper_LXVL);
+#else
+ qemu_build_not_reached();
#endif
+ return true;
+}
-#define VSX_STORE_SCALAR(name, operation) \
-static void gen_##name(DisasContext *ctx) \
-{ \
- TCGv EA; \
- TCGv_i64 t0; \
- if (unlikely(!ctx->vsx_enabled)) { \
- gen_exception(ctx, POWERPC_EXCP_VSXU); \
- return; \
- } \
- t0 = tcg_temp_new_i64(); \
- gen_set_access_type(ctx, ACCESS_INT); \
- EA = tcg_temp_new(); \
- gen_addr_reg_index(ctx, EA); \
- get_cpu_vsr(t0, xS(ctx->opcode), true); \
- gen_qemu_##operation(ctx, t0, EA); \
+static bool trans_LXVLL(DisasContext *ctx, arg_LXVLL *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+#if defined(TARGET_PPC64)
+ return do_ld_st_vl(ctx, a, gen_helper_LXVLL);
+#else
+ qemu_build_not_reached();
+#endif
+ return true;
}
-VSX_STORE_SCALAR(stxsdx, st64_i64)
+static bool trans_STXVL(DisasContext *ctx, arg_STXVL *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+#if defined(TARGET_PPC64)
+ return do_ld_st_vl(ctx, a, gen_helper_STXVL);
+#else
+ qemu_build_not_reached();
+#endif
+ return true;
+}
-VSX_STORE_SCALAR(stxsibx, st8_i64)
-VSX_STORE_SCALAR(stxsihx, st16_i64)
-VSX_STORE_SCALAR(stxsiwx, st32_i64)
-VSX_STORE_SCALAR(stxsspx, st32fs)
+static bool trans_STXVLL(DisasContext *ctx, arg_STXVLL *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+#if defined(TARGET_PPC64)
+ return do_ld_st_vl(ctx, a, gen_helper_STXVLL);
+#else
+ qemu_build_not_reached();
+#endif
+ return true;
+}
-static void gen_stxvd2x(DisasContext *ctx)
+static bool do_stxs(DisasContext *ctx, arg_X *a,
+ void (*op)(DisasContext *, TCGv_i64, TCGv))
{
TCGv EA;
TCGv_i64 t0;
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
- }
+ REQUIRE_VSX(ctx);
t0 = tcg_temp_new_i64();
gen_set_access_type(ctx, ACCESS_INT);
- EA = tcg_temp_new();
- gen_addr_reg_index(ctx, EA);
- get_cpu_vsr(t0, xS(ctx->opcode), true);
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
+ get_cpu_vsr(t0, a->rt, true);
+ op(ctx, t0, EA);
+ return true;
+}
+
+TRANS_FLAGS2(VSX, STXSDX, do_stxs, gen_qemu_st64_i64);
+TRANS_FLAGS2(ISA300, STXSIBX, do_stxs, gen_qemu_st8_i64);
+TRANS_FLAGS2(ISA300, STXSIHX, do_stxs, gen_qemu_st16_i64);
+TRANS_FLAGS2(VSX207, STXSIWX, do_stxs, gen_qemu_st32_i64);
+TRANS_FLAGS2(VSX207, STXSSPX, do_stxs, gen_qemu_st32fs);
+
+static bool trans_STXVD2X(DisasContext *ctx, arg_STXVD2X *a)
+{
+ TCGv EA;
+ TCGv_i64 t0;
+
+ REQUIRE_VSX(ctx);
+ REQUIRE_INSNS_FLAGS2(ctx, VSX);
+
+ t0 = tcg_temp_new_i64();
+ gen_set_access_type(ctx, ACCESS_INT);
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
+ get_cpu_vsr(t0, a->rt, true);
gen_qemu_st64_i64(ctx, t0, EA);
tcg_gen_addi_tl(EA, EA, 8);
- get_cpu_vsr(t0, xS(ctx->opcode), false);
+ get_cpu_vsr(t0, a->rt, false);
gen_qemu_st64_i64(ctx, t0, EA);
+ return true;
}
-static void gen_stxvw4x(DisasContext *ctx)
+static bool trans_STXVW4X(DisasContext *ctx, arg_STXVW4X *a)
{
TCGv EA;
- TCGv_i64 xsh;
- TCGv_i64 xsl;
+ TCGv_i64 xsh, xsl;
+
+ REQUIRE_VSX(ctx);
+ REQUIRE_INSNS_FLAGS2(ctx, VSX);
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
- }
xsh = tcg_temp_new_i64();
xsl = tcg_temp_new_i64();
- get_cpu_vsr(xsh, xS(ctx->opcode), true);
- get_cpu_vsr(xsl, xS(ctx->opcode), false);
+ get_cpu_vsr(xsh, a->rt, true);
+ get_cpu_vsr(xsl, a->rt, false);
gen_set_access_type(ctx, ACCESS_INT);
- EA = tcg_temp_new();
- gen_addr_reg_index(ctx, EA);
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
if (ctx->le_mode) {
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i64 t1 = tcg_temp_new_i64();
@@ -342,25 +356,23 @@ static void gen_stxvw4x(DisasContext *ctx)
tcg_gen_addi_tl(EA, EA, 8);
tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEUQ);
}
+ return true;
}
-static void gen_stxvh8x(DisasContext *ctx)
+static bool trans_STXVH8X(DisasContext *ctx, arg_STXVH8X *a)
{
TCGv EA;
- TCGv_i64 xsh;
- TCGv_i64 xsl;
+ TCGv_i64 xsh, xsl;
+
+ REQUIRE_VSX(ctx);
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
- }
xsh = tcg_temp_new_i64();
xsl = tcg_temp_new_i64();
- get_cpu_vsr(xsh, xS(ctx->opcode), true);
- get_cpu_vsr(xsl, xS(ctx->opcode), false);
+ get_cpu_vsr(xsh, a->rt, true);
+ get_cpu_vsr(xsl, a->rt, false);
gen_set_access_type(ctx, ACCESS_INT);
- EA = tcg_temp_new();
- gen_addr_reg_index(ctx, EA);
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
if (ctx->le_mode) {
TCGv_i64 outh = tcg_temp_new_i64();
TCGv_i64 outl = tcg_temp_new_i64();
@@ -374,28 +386,24 @@ static void gen_stxvh8x(DisasContext *ctx)
tcg_gen_addi_tl(EA, EA, 8);
tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEUQ);
}
+ return true;
}
-static void gen_stxvb16x(DisasContext *ctx)
+static bool trans_STXVB16X(DisasContext *ctx, arg_STXVB16X *a)
{
TCGv EA;
- TCGv_i64 xsh;
- TCGv_i64 xsl;
+ TCGv_i128 data;
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
- }
- xsh = tcg_temp_new_i64();
- xsl = tcg_temp_new_i64();
- get_cpu_vsr(xsh, xS(ctx->opcode), true);
- get_cpu_vsr(xsl, xS(ctx->opcode), false);
+ REQUIRE_VSX(ctx);
+ REQUIRE_INSNS_FLAGS2(ctx, ISA300);
+
+ data = tcg_temp_new_i128();
gen_set_access_type(ctx, ACCESS_INT);
- EA = tcg_temp_new();
- gen_addr_reg_index(ctx, EA);
- tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEUQ);
- tcg_gen_addi_tl(EA, EA, 8);
- tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEUQ);
+ EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
+ get_vsr_full(data, a->rt);
+ tcg_gen_qemu_st_i128(data, EA, ctx->mem_idx,
+ MO_BE | MO_128 | MO_ATOM_IFALIGN_PAIR);
+ return true;
}
static void gen_mfvsrwz(DisasContext *ctx)
@@ -788,34 +796,28 @@ static bool do_xvcpsgn(DisasContext *ctx, arg_XX3 *a, unsigned vece)
TRANS(XVCPSGNSP, do_xvcpsgn, MO_32)
TRANS(XVCPSGNDP, do_xvcpsgn, MO_64)
-#define VSX_CMP(name, op1, op2, inval, type) \
-static void gen_##name(DisasContext *ctx) \
-{ \
- TCGv_i32 ignored; \
- TCGv_ptr xt, xa, xb; \
- if (unlikely(!ctx->vsx_enabled)) { \
- gen_exception(ctx, POWERPC_EXCP_VSXU); \
- return; \
- } \
- xt = gen_vsr_ptr(xT(ctx->opcode)); \
- xa = gen_vsr_ptr(xA(ctx->opcode)); \
- xb = gen_vsr_ptr(xB(ctx->opcode)); \
- if ((ctx->opcode >> (31 - 21)) & 1) { \
- gen_helper_##name(cpu_crf[6], tcg_env, xt, xa, xb); \
- } else { \
- ignored = tcg_temp_new_i32(); \
- gen_helper_##name(ignored, tcg_env, xt, xa, xb); \
- } \
+static bool do_cmp(DisasContext *ctx, arg_XX3_rc *a,
+ void (*helper)(TCGv_i32, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr))
+{
+ TCGv_i32 dest;
+ TCGv_ptr xt, xa, xb;
+ REQUIRE_VSX(ctx);
+ xt = gen_vsr_ptr(a->xt);
+ xa = gen_vsr_ptr(a->xa);
+ xb = gen_vsr_ptr(a->xb);
+ dest = a->rc ? cpu_crf[6] : tcg_temp_new_i32();
+ helper(dest, tcg_env, xt, xa, xb);
+ return true;
}
-VSX_CMP(xvcmpeqdp, 0x0C, 0x0C, 0, PPC2_VSX)
-VSX_CMP(xvcmpgedp, 0x0C, 0x0E, 0, PPC2_VSX)
-VSX_CMP(xvcmpgtdp, 0x0C, 0x0D, 0, PPC2_VSX)
-VSX_CMP(xvcmpnedp, 0x0C, 0x0F, 0, PPC2_ISA300)
-VSX_CMP(xvcmpeqsp, 0x0C, 0x08, 0, PPC2_VSX)
-VSX_CMP(xvcmpgesp, 0x0C, 0x0A, 0, PPC2_VSX)
-VSX_CMP(xvcmpgtsp, 0x0C, 0x09, 0, PPC2_VSX)
-VSX_CMP(xvcmpnesp, 0x0C, 0x0B, 0, PPC2_VSX)
+TRANS_FLAGS2(VSX, XVCMPEQSP, do_cmp, gen_helper_XVCMPEQSP);
+TRANS_FLAGS2(VSX, XVCMPGTSP, do_cmp, gen_helper_XVCMPGTSP);
+TRANS_FLAGS2(VSX, XVCMPGESP, do_cmp, gen_helper_XVCMPGESP);
+TRANS_FLAGS2(ISA300, XVCMPNESP, do_cmp, gen_helper_XVCMPNESP);
+TRANS_FLAGS2(VSX, XVCMPEQDP, do_cmp, gen_helper_XVCMPEQDP);
+TRANS_FLAGS2(VSX, XVCMPGTDP, do_cmp, gen_helper_XVCMPGTDP);
+TRANS_FLAGS2(VSX, XVCMPGEDP, do_cmp, gen_helper_XVCMPGEDP);
+TRANS_FLAGS2(ISA300, XVCMPNEDP, do_cmp, gen_helper_XVCMPNEDP);
static bool trans_XSCVQPDP(DisasContext *ctx, arg_X_tb_rc *a)
{
@@ -864,20 +866,6 @@ static void gen_##name(DisasContext *ctx) \
gen_helper_##name(tcg_env, opc); \
}
-#define GEN_VSX_HELPER_X3(name, op1, op2, inval, type) \
-static void gen_##name(DisasContext *ctx) \
-{ \
- TCGv_ptr xt, xa, xb; \
- if (unlikely(!ctx->vsx_enabled)) { \
- gen_exception(ctx, POWERPC_EXCP_VSXU); \
- return; \
- } \
- xt = gen_vsr_ptr(xT(ctx->opcode)); \
- xa = gen_vsr_ptr(xA(ctx->opcode)); \
- xb = gen_vsr_ptr(xB(ctx->opcode)); \
- gen_helper_##name(tcg_env, xt, xa, xb); \
-}
-
#define GEN_VSX_HELPER_X2(name, op1, op2, inval, type) \
static void gen_##name(DisasContext *ctx) \
{ \
@@ -983,12 +971,8 @@ static void gen_##name(DisasContext *ctx) \
set_cpu_vsr(xT(ctx->opcode), tcg_constant_i64(0), false); \
}
-GEN_VSX_HELPER_X3(xsadddp, 0x00, 0x04, 0, PPC2_VSX)
GEN_VSX_HELPER_R3(xsaddqp, 0x04, 0x00, 0, PPC2_ISA300)
-GEN_VSX_HELPER_X3(xssubdp, 0x00, 0x05, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xsmuldp, 0x00, 0x06, 0, PPC2_VSX)
GEN_VSX_HELPER_R3(xsmulqp, 0x04, 0x01, 0, PPC2_ISA300)
-GEN_VSX_HELPER_X3(xsdivdp, 0x00, 0x07, 0, PPC2_VSX)
GEN_VSX_HELPER_R3(xsdivqp, 0x04, 0x11, 0, PPC2_ISA300)
GEN_VSX_HELPER_X2(xsredp, 0x14, 0x05, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xssqrtdp, 0x16, 0x04, 0, PPC2_VSX)
@@ -1001,8 +985,6 @@ GEN_VSX_HELPER_X2_AB(xscmpodp, 0x0C, 0x05, 0, PPC2_VSX)
GEN_VSX_HELPER_X2_AB(xscmpudp, 0x0C, 0x04, 0, PPC2_VSX)
GEN_VSX_HELPER_R2_AB(xscmpoqp, 0x04, 0x04, 0, PPC2_VSX)
GEN_VSX_HELPER_R2_AB(xscmpuqp, 0x04, 0x14, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xsmaxdp, 0x00, 0x14, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xsmindp, 0x00, 0x15, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xscvdphp, 0x16, 0x15, 0x11, PPC2_ISA300)
GEN_VSX_HELPER_X2(xscvdpsp, 0x12, 0x10, 0, PPC2_VSX)
GEN_VSX_HELPER_R2(xscvdpqp, 0x04, 0x1A, 0x16, PPC2_ISA300)
@@ -1233,27 +1215,17 @@ GEN_VSX_HELPER_R2(xsrqpi, 0x05, 0x00, 0, PPC2_ISA300)
GEN_VSX_HELPER_R2(xsrqpxp, 0x05, 0x01, 0, PPC2_ISA300)
GEN_VSX_HELPER_R2(xssqrtqp, 0x04, 0x19, 0x1B, PPC2_ISA300)
GEN_VSX_HELPER_R3(xssubqp, 0x04, 0x10, 0, PPC2_ISA300)
-GEN_VSX_HELPER_X3(xsaddsp, 0x00, 0x00, 0, PPC2_VSX207)
-GEN_VSX_HELPER_X3(xssubsp, 0x00, 0x01, 0, PPC2_VSX207)
-GEN_VSX_HELPER_X3(xsmulsp, 0x00, 0x02, 0, PPC2_VSX207)
-GEN_VSX_HELPER_X3(xsdivsp, 0x00, 0x03, 0, PPC2_VSX207)
GEN_VSX_HELPER_X2(xsresp, 0x14, 0x01, 0, PPC2_VSX207)
GEN_VSX_HELPER_X2(xssqrtsp, 0x16, 0x00, 0, PPC2_VSX207)
GEN_VSX_HELPER_X2(xsrsqrtesp, 0x14, 0x00, 0, PPC2_VSX207)
GEN_VSX_HELPER_X2(xscvsxdsp, 0x10, 0x13, 0, PPC2_VSX207)
GEN_VSX_HELPER_X2(xscvuxdsp, 0x10, 0x12, 0, PPC2_VSX207)
-GEN_VSX_HELPER_X3(xvadddp, 0x00, 0x0C, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xvsubdp, 0x00, 0x0D, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xvmuldp, 0x00, 0x0E, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xvdivdp, 0x00, 0x0F, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvredp, 0x14, 0x0D, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvsqrtdp, 0x16, 0x0C, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvrsqrtedp, 0x14, 0x0C, 0, PPC2_VSX)
GEN_VSX_HELPER_X2_AB(xvtdivdp, 0x14, 0x0F, 0, PPC2_VSX)
GEN_VSX_HELPER_X1(xvtsqrtdp, 0x14, 0x0E, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xvmaxdp, 0x00, 0x1C, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xvmindp, 0x00, 0x1D, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvcvdpsp, 0x12, 0x18, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvcvdpsxds, 0x10, 0x1D, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvcvdpsxws, 0x10, 0x0D, 0, PPC2_VSX)
@@ -1269,17 +1241,11 @@ GEN_VSX_HELPER_X2(xvrdpim, 0x12, 0x0F, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvrdpip, 0x12, 0x0E, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvrdpiz, 0x12, 0x0D, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xvaddsp, 0x00, 0x08, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xvsubsp, 0x00, 0x09, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xvmulsp, 0x00, 0x0A, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xvdivsp, 0x00, 0x0B, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvresp, 0x14, 0x09, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvsqrtsp, 0x16, 0x08, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvrsqrtesp, 0x14, 0x08, 0, PPC2_VSX)
GEN_VSX_HELPER_X2_AB(xvtdivsp, 0x14, 0x0B, 0, PPC2_VSX)
GEN_VSX_HELPER_X1(xvtsqrtsp, 0x14, 0x0A, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xvmaxsp, 0x00, 0x18, 0, PPC2_VSX)
-GEN_VSX_HELPER_X3(xvminsp, 0x00, 0x19, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvcvspdp, 0x12, 0x1C, 0, PPC2_VSX)
GEN_VSX_HELPER_X2(xvcvhpsp, 0x16, 0x1D, 0x18, PPC2_ISA300)
GEN_VSX_HELPER_X2(xvcvsphp, 0x16, 0x1D, 0x19, PPC2_ISA300)
@@ -1609,26 +1575,24 @@ static void gen_xxbrw(DisasContext *ctx)
set_cpu_vsr(xT(ctx->opcode), xtl, false);
}
-#define VSX_LOGICAL(name, vece, tcg_op) \
-static void glue(gen_, name)(DisasContext *ctx) \
- { \
- if (unlikely(!ctx->vsx_enabled)) { \
- gen_exception(ctx, POWERPC_EXCP_VSXU); \
- return; \
- } \
- tcg_op(vece, vsr_full_offset(xT(ctx->opcode)), \
- vsr_full_offset(xA(ctx->opcode)), \
- vsr_full_offset(xB(ctx->opcode)), 16, 16); \
- }
+static bool do_logical_op(DisasContext *ctx, arg_XX3 *a, unsigned vece,
+ void (*helper)(unsigned, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t))
+{
+ REQUIRE_VSX(ctx);
+ helper(vece, vsr_full_offset(a->xt),
+ vsr_full_offset(a->xa),
+ vsr_full_offset(a->xb), 16, 16);
+ return true;
+}
-VSX_LOGICAL(xxland, MO_64, tcg_gen_gvec_and)
-VSX_LOGICAL(xxlandc, MO_64, tcg_gen_gvec_andc)
-VSX_LOGICAL(xxlor, MO_64, tcg_gen_gvec_or)
-VSX_LOGICAL(xxlxor, MO_64, tcg_gen_gvec_xor)
-VSX_LOGICAL(xxlnor, MO_64, tcg_gen_gvec_nor)
-VSX_LOGICAL(xxleqv, MO_64, tcg_gen_gvec_eqv)
-VSX_LOGICAL(xxlnand, MO_64, tcg_gen_gvec_nand)
-VSX_LOGICAL(xxlorc, MO_64, tcg_gen_gvec_orc)
+TRANS_FLAGS2(VSX, XXLAND, do_logical_op, MO_64, tcg_gen_gvec_and);
+TRANS_FLAGS2(VSX, XXLANDC, do_logical_op, MO_64, tcg_gen_gvec_andc);
+TRANS_FLAGS2(VSX, XXLOR, do_logical_op, MO_64, tcg_gen_gvec_or);
+TRANS_FLAGS2(VSX, XXLXOR, do_logical_op, MO_64, tcg_gen_gvec_xor);
+TRANS_FLAGS2(VSX, XXLNOR, do_logical_op, MO_64, tcg_gen_gvec_nor);
+TRANS_FLAGS2(VSX207, XXLEQV, do_logical_op, MO_64, tcg_gen_gvec_eqv);
+TRANS_FLAGS2(VSX207, XXLNAND, do_logical_op, MO_64, tcg_gen_gvec_nand);
+TRANS_FLAGS2(VSX207, XXLORC, do_logical_op, MO_64, tcg_gen_gvec_orc);
#define VSX_XXMRG(name, high) \
static void glue(gen_, name)(DisasContext *ctx) \
@@ -2215,13 +2179,13 @@ static bool do_lstxv(DisasContext *ctx, int ra, TCGv displ,
int rt, bool store, bool paired)
{
TCGv ea;
- TCGv_i64 xt;
+ TCGv_i128 data;
MemOp mop;
int rt1, rt2;
- xt = tcg_temp_new_i64();
+ data = tcg_temp_new_i128();
- mop = DEF_MEMOP(MO_UQ);
+ mop = DEF_MEMOP(MO_128 | MO_ATOM_IFALIGN_PAIR);
gen_set_access_type(ctx, ACCESS_INT);
ea = do_ea_calc(ctx, ra, displ);
@@ -2235,32 +2199,20 @@ static bool do_lstxv(DisasContext *ctx, int ra, TCGv displ,
}
if (store) {
- get_cpu_vsr(xt, rt1, !ctx->le_mode);
- tcg_gen_qemu_st_i64(xt, ea, ctx->mem_idx, mop);
- gen_addr_add(ctx, ea, ea, 8);
- get_cpu_vsr(xt, rt1, ctx->le_mode);
- tcg_gen_qemu_st_i64(xt, ea, ctx->mem_idx, mop);
+ get_vsr_full(data, rt1);
+ tcg_gen_qemu_st_i128(data, ea, ctx->mem_idx, mop);
if (paired) {
- gen_addr_add(ctx, ea, ea, 8);
- get_cpu_vsr(xt, rt2, !ctx->le_mode);
- tcg_gen_qemu_st_i64(xt, ea, ctx->mem_idx, mop);
- gen_addr_add(ctx, ea, ea, 8);
- get_cpu_vsr(xt, rt2, ctx->le_mode);
- tcg_gen_qemu_st_i64(xt, ea, ctx->mem_idx, mop);
+ gen_addr_add(ctx, ea, ea, 16);
+ get_vsr_full(data, rt2);
+ tcg_gen_qemu_st_i128(data, ea, ctx->mem_idx, mop);
}
} else {
- tcg_gen_qemu_ld_i64(xt, ea, ctx->mem_idx, mop);
- set_cpu_vsr(rt1, xt, !ctx->le_mode);
- gen_addr_add(ctx, ea, ea, 8);
- tcg_gen_qemu_ld_i64(xt, ea, ctx->mem_idx, mop);
- set_cpu_vsr(rt1, xt, ctx->le_mode);
+ tcg_gen_qemu_ld_i128(data, ea, ctx->mem_idx, mop);
+ set_vsr_full(rt1, data);
if (paired) {
- gen_addr_add(ctx, ea, ea, 8);
- tcg_gen_qemu_ld_i64(xt, ea, ctx->mem_idx, mop);
- set_cpu_vsr(rt2, xt, !ctx->le_mode);
- gen_addr_add(ctx, ea, ea, 8);
- tcg_gen_qemu_ld_i64(xt, ea, ctx->mem_idx, mop);
- set_cpu_vsr(rt2, xt, ctx->le_mode);
+ gen_addr_add(ctx, ea, ea, 16);
+ tcg_gen_qemu_ld_i128(data, ea, ctx->mem_idx, mop);
+ set_vsr_full(rt2, data);
}
}
return true;
@@ -2292,7 +2244,7 @@ static bool do_lstxv_PLS_D(DisasContext *ctx, arg_PLS_D *a,
static bool do_lstxv_X(DisasContext *ctx, arg_X *a, bool store, bool paired)
{
- if (paired || a->rt >= 32) {
+ if (paired || a->rt < 32) {
REQUIRE_VSX(ctx);
} else {
REQUIRE_VECTOR(ctx);
@@ -2712,8 +2664,6 @@ static bool do_helper_XX3(DisasContext *ctx, arg_XX3 *a,
void (*helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr))
{
TCGv_ptr xt, xa, xb;
-
- REQUIRE_INSNS_FLAGS2(ctx, ISA300);
REQUIRE_VSX(ctx);
xt = gen_vsr_ptr(a->xt);
@@ -2724,13 +2674,40 @@ static bool do_helper_XX3(DisasContext *ctx, arg_XX3 *a,
return true;
}
-TRANS(XSCMPEQDP, do_helper_XX3, gen_helper_XSCMPEQDP)
-TRANS(XSCMPGEDP, do_helper_XX3, gen_helper_XSCMPGEDP)
-TRANS(XSCMPGTDP, do_helper_XX3, gen_helper_XSCMPGTDP)
-TRANS(XSMAXCDP, do_helper_XX3, gen_helper_XSMAXCDP)
-TRANS(XSMINCDP, do_helper_XX3, gen_helper_XSMINCDP)
-TRANS(XSMAXJDP, do_helper_XX3, gen_helper_XSMAXJDP)
-TRANS(XSMINJDP, do_helper_XX3, gen_helper_XSMINJDP)
+TRANS_FLAGS2(ISA300, XSCMPEQDP, do_helper_XX3, gen_helper_XSCMPEQDP)
+TRANS_FLAGS2(ISA300, XSCMPGEDP, do_helper_XX3, gen_helper_XSCMPGEDP)
+TRANS_FLAGS2(ISA300, XSCMPGTDP, do_helper_XX3, gen_helper_XSCMPGTDP)
+TRANS_FLAGS2(ISA300, XSMAXCDP, do_helper_XX3, gen_helper_XSMAXCDP)
+TRANS_FLAGS2(ISA300, XSMINCDP, do_helper_XX3, gen_helper_XSMINCDP)
+TRANS_FLAGS2(ISA300, XSMAXJDP, do_helper_XX3, gen_helper_XSMAXJDP)
+TRANS_FLAGS2(ISA300, XSMINJDP, do_helper_XX3, gen_helper_XSMINJDP)
+
+TRANS_FLAGS2(VSX207, XSADDSP, do_helper_XX3, gen_helper_XSADDSP)
+TRANS_FLAGS2(VSX207, XSSUBSP, do_helper_XX3, gen_helper_XSSUBSP)
+TRANS_FLAGS2(VSX207, XSMULSP, do_helper_XX3, gen_helper_XSMULSP)
+TRANS_FLAGS2(VSX207, XSDIVSP, do_helper_XX3, gen_helper_XSDIVSP)
+
+TRANS_FLAGS2(VSX, XSADDDP, do_helper_XX3, gen_helper_XSADDDP)
+TRANS_FLAGS2(VSX, XSSUBDP, do_helper_XX3, gen_helper_XSSUBDP)
+TRANS_FLAGS2(VSX, XSMULDP, do_helper_XX3, gen_helper_XSMULDP)
+TRANS_FLAGS2(VSX, XSDIVDP, do_helper_XX3, gen_helper_XSDIVDP)
+
+TRANS_FLAGS2(VSX, XVADDSP, do_helper_XX3, gen_helper_XVADDSP)
+TRANS_FLAGS2(VSX, XVSUBSP, do_helper_XX3, gen_helper_XVSUBSP)
+TRANS_FLAGS2(VSX, XVMULSP, do_helper_XX3, gen_helper_XVMULSP)
+TRANS_FLAGS2(VSX, XVDIVSP, do_helper_XX3, gen_helper_XVDIVSP)
+
+TRANS_FLAGS2(VSX, XVADDDP, do_helper_XX3, gen_helper_XVADDDP)
+TRANS_FLAGS2(VSX, XVSUBDP, do_helper_XX3, gen_helper_XVSUBDP)
+TRANS_FLAGS2(VSX, XVMULDP, do_helper_XX3, gen_helper_XVMULDP)
+TRANS_FLAGS2(VSX, XVDIVDP, do_helper_XX3, gen_helper_XVDIVDP)
+
+TRANS_FLAGS2(VSX, XSMAXDP, do_helper_XX3, gen_helper_XSMAXDP)
+TRANS_FLAGS2(VSX, XSMINDP, do_helper_XX3, gen_helper_XSMINDP)
+TRANS_FLAGS2(VSX, XVMAXSP, do_helper_XX3, gen_helper_XVMAXSP)
+TRANS_FLAGS2(VSX, XVMINSP, do_helper_XX3, gen_helper_XVMINSP)
+TRANS_FLAGS2(VSX, XVMAXDP, do_helper_XX3, gen_helper_XVMAXDP)
+TRANS_FLAGS2(VSX, XVMINDP, do_helper_XX3, gen_helper_XVMINDP)
static bool do_helper_X(arg_X *a,
void (*helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr))
@@ -2910,4 +2887,3 @@ TRANS64(PMXVF64GERNN, do_ger, gen_helper_XVF64GERNN)
#undef GEN_XX2IFORM
#undef GEN_XX3_RC_FORM
#undef GEN_XX3FORM_DM
-#undef VSX_LOGICAL
diff --git a/target/ppc/translate/vsx-ops.c.inc b/target/ppc/translate/vsx-ops.c.inc
index a3ba094..e553b5b 100644
--- a/target/ppc/translate/vsx-ops.c.inc
+++ b/target/ppc/translate/vsx-ops.c.inc
@@ -1,34 +1,3 @@
-GEN_HANDLER_E(lxsdx, 0x1F, 0x0C, 0x12, 0, PPC_NONE, PPC2_VSX),
-GEN_HANDLER_E(lxsiwax, 0x1F, 0x0C, 0x02, 0, PPC_NONE, PPC2_VSX207),
-GEN_HANDLER_E(lxsiwzx, 0x1F, 0x0C, 0x00, 0, PPC_NONE, PPC2_VSX207),
-GEN_HANDLER_E(lxsibzx, 0x1F, 0x0D, 0x18, 0, PPC_NONE, PPC2_ISA300),
-GEN_HANDLER_E(lxsihzx, 0x1F, 0x0D, 0x19, 0, PPC_NONE, PPC2_ISA300),
-GEN_HANDLER_E(lxsspx, 0x1F, 0x0C, 0x10, 0, PPC_NONE, PPC2_VSX207),
-GEN_HANDLER_E(lxvd2x, 0x1F, 0x0C, 0x1A, 0, PPC_NONE, PPC2_VSX),
-GEN_HANDLER_E(lxvwsx, 0x1F, 0x0C, 0x0B, 0, PPC_NONE, PPC2_ISA300),
-GEN_HANDLER_E(lxvdsx, 0x1F, 0x0C, 0x0A, 0, PPC_NONE, PPC2_VSX),
-GEN_HANDLER_E(lxvw4x, 0x1F, 0x0C, 0x18, 0, PPC_NONE, PPC2_VSX),
-GEN_HANDLER_E(lxvh8x, 0x1F, 0x0C, 0x19, 0, PPC_NONE, PPC2_ISA300),
-GEN_HANDLER_E(lxvb16x, 0x1F, 0x0C, 0x1B, 0, PPC_NONE, PPC2_ISA300),
-#if defined(TARGET_PPC64)
-GEN_HANDLER_E(lxvl, 0x1F, 0x0D, 0x08, 0, PPC_NONE, PPC2_ISA300),
-GEN_HANDLER_E(lxvll, 0x1F, 0x0D, 0x09, 0, PPC_NONE, PPC2_ISA300),
-#endif
-
-GEN_HANDLER_E(stxsdx, 0x1F, 0xC, 0x16, 0, PPC_NONE, PPC2_VSX),
-GEN_HANDLER_E(stxsibx, 0x1F, 0xD, 0x1C, 0, PPC_NONE, PPC2_ISA300),
-GEN_HANDLER_E(stxsihx, 0x1F, 0xD, 0x1D, 0, PPC_NONE, PPC2_ISA300),
-GEN_HANDLER_E(stxsiwx, 0x1F, 0xC, 0x04, 0, PPC_NONE, PPC2_VSX207),
-GEN_HANDLER_E(stxsspx, 0x1F, 0xC, 0x14, 0, PPC_NONE, PPC2_VSX207),
-GEN_HANDLER_E(stxvd2x, 0x1F, 0xC, 0x1E, 0, PPC_NONE, PPC2_VSX),
-GEN_HANDLER_E(stxvw4x, 0x1F, 0xC, 0x1C, 0, PPC_NONE, PPC2_VSX),
-GEN_HANDLER_E(stxvh8x, 0x1F, 0x0C, 0x1D, 0, PPC_NONE, PPC2_ISA300),
-GEN_HANDLER_E(stxvb16x, 0x1F, 0x0C, 0x1F, 0, PPC_NONE, PPC2_ISA300),
-#if defined(TARGET_PPC64)
-GEN_HANDLER_E(stxvl, 0x1F, 0x0D, 0x0C, 0, PPC_NONE, PPC2_ISA300),
-GEN_HANDLER_E(stxvll, 0x1F, 0x0D, 0x0D, 0, PPC_NONE, PPC2_ISA300),
-#endif
-
GEN_HANDLER_E(mfvsrwz, 0x1F, 0x13, 0x03, 0x0000F800, PPC_NONE, PPC2_VSX207),
GEN_HANDLER_E(mtvsrwa, 0x1F, 0x13, 0x06, 0x0000F800, PPC_NONE, PPC2_VSX207),
GEN_HANDLER_E(mtvsrwz, 0x1F, 0x13, 0x07, 0x0000F800, PPC_NONE, PPC2_VSX207),
@@ -74,16 +43,6 @@ GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 1, PPC_NONE, fl2), \
GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 2, opc3, 1, PPC_NONE, fl2), \
GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 3, opc3, 1, PPC_NONE, fl2)
-#define GEN_XX3_RC_FORM(name, opc2, opc3, fl2) \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x00, opc3 | 0x00, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x01, opc3 | 0x00, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x02, opc3 | 0x00, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x03, opc3 | 0x00, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x00, opc3 | 0x10, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x01, opc3 | 0x10, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x02, opc3 | 0x10, 0, PPC_NONE, fl2), \
-GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x03, opc3 | 0x10, 0, PPC_NONE, fl2)
-
#define GEN_XX3FORM_DM(name, opc2, opc3) \
GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\
GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\
@@ -153,12 +112,8 @@ GEN_XX2FORM_EO(xvxexpdp, 0x16, 0x1D, 0x00, PPC2_ISA300),
GEN_XX2FORM_EO(xvxsigdp, 0x16, 0x1D, 0x01, PPC2_ISA300),
GEN_XX2FORM_EO(xvxexpsp, 0x16, 0x1D, 0x08, PPC2_ISA300),
-GEN_XX3FORM(xsadddp, 0x00, 0x04, PPC2_VSX),
GEN_VSX_XFORM_300(xsaddqp, 0x04, 0x00, 0x0),
-GEN_XX3FORM(xssubdp, 0x00, 0x05, PPC2_VSX),
-GEN_XX3FORM(xsmuldp, 0x00, 0x06, PPC2_VSX),
GEN_VSX_XFORM_300(xsmulqp, 0x04, 0x01, 0x0),
-GEN_XX3FORM(xsdivdp, 0x00, 0x07, PPC2_VSX),
GEN_XX2FORM(xsredp, 0x14, 0x05, PPC2_VSX),
GEN_XX2FORM(xssqrtdp, 0x16, 0x04, PPC2_VSX),
GEN_XX2FORM(xsrsqrtedp, 0x14, 0x04, PPC2_VSX),
@@ -170,8 +125,6 @@ GEN_XX2IFORM(xscmpodp, 0x0C, 0x05, PPC2_VSX),
GEN_XX2IFORM(xscmpudp, 0x0C, 0x04, PPC2_VSX),
GEN_VSX_XFORM_300(xscmpoqp, 0x04, 0x04, 0x00600001),
GEN_VSX_XFORM_300(xscmpuqp, 0x04, 0x14, 0x00600001),
-GEN_XX3FORM(xsmaxdp, 0x00, 0x14, PPC2_VSX),
-GEN_XX3FORM(xsmindp, 0x00, 0x15, PPC2_VSX),
GEN_XX2FORM_EO(xscvdphp, 0x16, 0x15, 0x11, PPC2_ISA300),
GEN_XX2FORM(xscvdpsp, 0x12, 0x10, PPC2_VSX),
GEN_XX2FORM(xscvdpspn, 0x16, 0x10, PPC2_VSX207),
@@ -191,10 +144,6 @@ GEN_XX2FORM(xsrdpim, 0x12, 0x07, PPC2_VSX),
GEN_XX2FORM(xsrdpip, 0x12, 0x06, PPC2_VSX),
GEN_XX2FORM(xsrdpiz, 0x12, 0x05, PPC2_VSX),
-GEN_XX3FORM(xsaddsp, 0x00, 0x00, PPC2_VSX207),
-GEN_XX3FORM(xssubsp, 0x00, 0x01, PPC2_VSX207),
-GEN_XX3FORM(xsmulsp, 0x00, 0x02, PPC2_VSX207),
-GEN_XX3FORM(xsdivsp, 0x00, 0x03, PPC2_VSX207),
GEN_VSX_XFORM_300(xsdivqp, 0x04, 0x11, 0x0),
GEN_XX2FORM(xsresp, 0x14, 0x01, PPC2_VSX207),
GEN_XX2FORM(xsrsp, 0x12, 0x11, PPC2_VSX207),
@@ -203,10 +152,6 @@ GEN_XX2FORM(xsrsqrtesp, 0x14, 0x00, PPC2_VSX207),
GEN_XX2FORM(xscvsxdsp, 0x10, 0x13, PPC2_VSX207),
GEN_XX2FORM(xscvuxdsp, 0x10, 0x12, PPC2_VSX207),
-GEN_XX3FORM(xvadddp, 0x00, 0x0C, PPC2_VSX),
-GEN_XX3FORM(xvsubdp, 0x00, 0x0D, PPC2_VSX),
-GEN_XX3FORM(xvmuldp, 0x00, 0x0E, PPC2_VSX),
-GEN_XX3FORM(xvdivdp, 0x00, 0x0F, PPC2_VSX),
GEN_XX2FORM(xvredp, 0x14, 0x0D, PPC2_VSX),
GEN_XX2FORM(xvsqrtdp, 0x16, 0x0C, PPC2_VSX),
GEN_XX2FORM(xvrsqrtedp, 0x14, 0x0C, PPC2_VSX),
@@ -220,12 +165,6 @@ GEN_XX3FORM_NAME(xvnmadddp, "xvnmaddadp", 0x04, 0x1C, PPC2_VSX),
GEN_XX3FORM_NAME(xvnmadddp, "xvnmaddmdp", 0x04, 0x1D, PPC2_VSX),
GEN_XX3FORM_NAME(xvnmsubdp, "xvnmsubadp", 0x04, 0x1E, PPC2_VSX),
GEN_XX3FORM_NAME(xvnmsubdp, "xvnmsubmdp", 0x04, 0x1F, PPC2_VSX),
-GEN_XX3FORM(xvmaxdp, 0x00, 0x1C, PPC2_VSX),
-GEN_XX3FORM(xvmindp, 0x00, 0x1D, PPC2_VSX),
-GEN_XX3_RC_FORM(xvcmpeqdp, 0x0C, 0x0C, PPC2_VSX),
-GEN_XX3_RC_FORM(xvcmpgtdp, 0x0C, 0x0D, PPC2_VSX),
-GEN_XX3_RC_FORM(xvcmpgedp, 0x0C, 0x0E, PPC2_VSX),
-GEN_XX3_RC_FORM(xvcmpnedp, 0x0C, 0x0F, PPC2_ISA300),
GEN_XX2FORM(xvcvdpsp, 0x12, 0x18, PPC2_VSX),
GEN_XX2FORM(xvcvdpsxds, 0x10, 0x1D, PPC2_VSX),
GEN_XX2FORM(xvcvdpsxws, 0x10, 0x0D, PPC2_VSX),
@@ -241,10 +180,6 @@ GEN_XX2FORM(xvrdpim, 0x12, 0x0F, PPC2_VSX),
GEN_XX2FORM(xvrdpip, 0x12, 0x0E, PPC2_VSX),
GEN_XX2FORM(xvrdpiz, 0x12, 0x0D, PPC2_VSX),
-GEN_XX3FORM(xvaddsp, 0x00, 0x08, PPC2_VSX),
-GEN_XX3FORM(xvsubsp, 0x00, 0x09, PPC2_VSX),
-GEN_XX3FORM(xvmulsp, 0x00, 0x0A, PPC2_VSX),
-GEN_XX3FORM(xvdivsp, 0x00, 0x0B, PPC2_VSX),
GEN_XX2FORM(xvresp, 0x14, 0x09, PPC2_VSX),
GEN_XX2FORM(xvsqrtsp, 0x16, 0x08, PPC2_VSX),
GEN_XX2FORM(xvrsqrtesp, 0x14, 0x08, PPC2_VSX),
@@ -258,12 +193,6 @@ GEN_XX3FORM_NAME(xvnmaddsp, "xvnmaddasp", 0x04, 0x18, PPC2_VSX),
GEN_XX3FORM_NAME(xvnmaddsp, "xvnmaddmsp", 0x04, 0x19, PPC2_VSX),
GEN_XX3FORM_NAME(xvnmsubsp, "xvnmsubasp", 0x04, 0x1A, PPC2_VSX),
GEN_XX3FORM_NAME(xvnmsubsp, "xvnmsubmsp", 0x04, 0x1B, PPC2_VSX),
-GEN_XX3FORM(xvmaxsp, 0x00, 0x18, PPC2_VSX),
-GEN_XX3FORM(xvminsp, 0x00, 0x19, PPC2_VSX),
-GEN_XX3_RC_FORM(xvcmpeqsp, 0x0C, 0x08, PPC2_VSX),
-GEN_XX3_RC_FORM(xvcmpgtsp, 0x0C, 0x09, PPC2_VSX),
-GEN_XX3_RC_FORM(xvcmpgesp, 0x0C, 0x0A, PPC2_VSX),
-GEN_XX3_RC_FORM(xvcmpnesp, 0x0C, 0x0B, PPC2_ISA300),
GEN_XX2FORM(xvcvspdp, 0x12, 0x1C, PPC2_VSX),
GEN_XX2FORM(xvcvspsxds, 0x10, 0x19, PPC2_VSX),
GEN_XX2FORM(xvcvspsxws, 0x10, 0x09, PPC2_VSX),
@@ -285,17 +214,6 @@ GEN_XX2FORM_EO(xvcvhpsp, 0x16, 0x1D, 0x18, PPC2_ISA300),
GEN_XX2FORM_EO(xvcvsphp, 0x16, 0x1D, 0x19, PPC2_ISA300),
GEN_XX2FORM_EO(xxbrq, 0x16, 0x1D, 0x1F, PPC2_ISA300),
-#define VSX_LOGICAL(name, opc2, opc3, fl2) \
-GEN_XX3FORM(name, opc2, opc3, fl2)
-
-VSX_LOGICAL(xxland, 0x8, 0x10, PPC2_VSX),
-VSX_LOGICAL(xxlandc, 0x8, 0x11, PPC2_VSX),
-VSX_LOGICAL(xxlor, 0x8, 0x12, PPC2_VSX),
-VSX_LOGICAL(xxlxor, 0x8, 0x13, PPC2_VSX),
-VSX_LOGICAL(xxlnor, 0x8, 0x14, PPC2_VSX),
-VSX_LOGICAL(xxleqv, 0x8, 0x17, PPC2_VSX207),
-VSX_LOGICAL(xxlnand, 0x8, 0x16, PPC2_VSX207),
-VSX_LOGICAL(xxlorc, 0x8, 0x15, PPC2_VSX207),
GEN_XX3FORM(xxmrghw, 0x08, 0x02, PPC2_VSX),
GEN_XX3FORM(xxmrglw, 0x08, 0x06, PPC2_VSX),
GEN_XX3FORM_DM(xxsldwi, 0x08, 0x00),
diff --git a/target/riscv/Kconfig b/target/riscv/Kconfig
index 5f30df2..11bc09b 100644
--- a/target/riscv/Kconfig
+++ b/target/riscv/Kconfig
@@ -1,9 +1,9 @@
config RISCV32
bool
- select ARM_COMPATIBLE_SEMIHOSTING # for do_common_semihosting()
+ select ARM_COMPATIBLE_SEMIHOSTING if TCG
select DEVICE_TREE # needed by boot.c
config RISCV64
bool
- select ARM_COMPATIBLE_SEMIHOSTING # for do_common_semihosting()
+ select ARM_COMPATIBLE_SEMIHOSTING if TCG
select DEVICE_TREE # needed by boot.c
diff --git a/target/riscv/cpu-param.h b/target/riscv/cpu-param.h
index 1fbd649..2568619 100644
--- a/target/riscv/cpu-param.h
+++ b/target/riscv/cpu-param.h
@@ -2,7 +2,7 @@
* RISC-V cpu parameters for qemu.
*
* Copyright (c) 2017-2018 SiFive, Inc.
- * SPDX-License-Identifier: GPL-2.0+
+ * SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef RISCV_CPU_PARAM_H
diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h
index 3670cfe..4464c0f 100644
--- a/target/riscv/cpu-qom.h
+++ b/target/riscv/cpu-qom.h
@@ -29,7 +29,6 @@
#define RISCV_CPU_TYPE_SUFFIX "-" TYPE_RISCV_CPU
#define RISCV_CPU_TYPE_NAME(name) (name RISCV_CPU_TYPE_SUFFIX)
-#define TYPE_RISCV_CPU_ANY RISCV_CPU_TYPE_NAME("any")
#define TYPE_RISCV_CPU_MAX RISCV_CPU_TYPE_NAME("max")
#define TYPE_RISCV_CPU_BASE32 RISCV_CPU_TYPE_NAME("rv32")
#define TYPE_RISCV_CPU_BASE64 RISCV_CPU_TYPE_NAME("rv64")
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index c53b0d5..658bdb4 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -113,10 +113,13 @@ const RISCVIsaExtData isa_edata_arr[] = {
ISA_EXT_DATA_ENTRY(zihintntl, PRIV_VERSION_1_10_0, ext_zihintntl),
ISA_EXT_DATA_ENTRY(zihintpause, PRIV_VERSION_1_10_0, ext_zihintpause),
ISA_EXT_DATA_ENTRY(zihpm, PRIV_VERSION_1_12_0, ext_zihpm),
+ ISA_EXT_DATA_ENTRY(zimop, PRIV_VERSION_1_13_0, ext_zimop),
ISA_EXT_DATA_ENTRY(zmmul, PRIV_VERSION_1_12_0, ext_zmmul),
- ISA_EXT_DATA_ENTRY(za64rs, PRIV_VERSION_1_12_0, has_priv_1_11),
+ ISA_EXT_DATA_ENTRY(za64rs, PRIV_VERSION_1_12_0, has_priv_1_12),
ISA_EXT_DATA_ENTRY(zaamo, PRIV_VERSION_1_12_0, ext_zaamo),
+ ISA_EXT_DATA_ENTRY(zabha, PRIV_VERSION_1_13_0, ext_zabha),
ISA_EXT_DATA_ENTRY(zacas, PRIV_VERSION_1_12_0, ext_zacas),
+ ISA_EXT_DATA_ENTRY(zama16b, PRIV_VERSION_1_13_0, ext_zama16b),
ISA_EXT_DATA_ENTRY(zalrsc, PRIV_VERSION_1_12_0, ext_zalrsc),
ISA_EXT_DATA_ENTRY(zawrs, PRIV_VERSION_1_12_0, ext_zawrs),
ISA_EXT_DATA_ENTRY(zfa, PRIV_VERSION_1_12_0, ext_zfa),
@@ -130,6 +133,7 @@ const RISCVIsaExtData isa_edata_arr[] = {
ISA_EXT_DATA_ENTRY(zcf, PRIV_VERSION_1_12_0, ext_zcf),
ISA_EXT_DATA_ENTRY(zcd, PRIV_VERSION_1_12_0, ext_zcd),
ISA_EXT_DATA_ENTRY(zce, PRIV_VERSION_1_12_0, ext_zce),
+ ISA_EXT_DATA_ENTRY(zcmop, PRIV_VERSION_1_13_0, ext_zcmop),
ISA_EXT_DATA_ENTRY(zcmp, PRIV_VERSION_1_12_0, ext_zcmp),
ISA_EXT_DATA_ENTRY(zcmt, PRIV_VERSION_1_12_0, ext_zcmt),
ISA_EXT_DATA_ENTRY(zba, PRIV_VERSION_1_12_0, ext_zba),
@@ -178,6 +182,7 @@ const RISCVIsaExtData isa_edata_arr[] = {
ISA_EXT_DATA_ENTRY(zhinx, PRIV_VERSION_1_12_0, ext_zhinx),
ISA_EXT_DATA_ENTRY(zhinxmin, PRIV_VERSION_1_12_0, ext_zhinxmin),
ISA_EXT_DATA_ENTRY(smaia, PRIV_VERSION_1_12_0, ext_smaia),
+ ISA_EXT_DATA_ENTRY(smcntrpmf, PRIV_VERSION_1_12_0, ext_smcntrpmf),
ISA_EXT_DATA_ENTRY(smepmp, PRIV_VERSION_1_12_0, ext_smepmp),
ISA_EXT_DATA_ENTRY(smstateen, PRIV_VERSION_1_12_0, ext_smstateen),
ISA_EXT_DATA_ENTRY(ssaia, PRIV_VERSION_1_12_0, ext_ssaia),
@@ -192,6 +197,7 @@ const RISCVIsaExtData isa_edata_arr[] = {
ISA_EXT_DATA_ENTRY(svinval, PRIV_VERSION_1_12_0, ext_svinval),
ISA_EXT_DATA_ENTRY(svnapot, PRIV_VERSION_1_12_0, ext_svnapot),
ISA_EXT_DATA_ENTRY(svpbmt, PRIV_VERSION_1_12_0, ext_svpbmt),
+ ISA_EXT_DATA_ENTRY(svvptc, PRIV_VERSION_1_13_0, ext_svvptc),
ISA_EXT_DATA_ENTRY(xtheadba, PRIV_VERSION_1_11_0, ext_xtheadba),
ISA_EXT_DATA_ENTRY(xtheadbb, PRIV_VERSION_1_11_0, ext_xtheadbb),
ISA_EXT_DATA_ENTRY(xtheadbs, PRIV_VERSION_1_11_0, ext_xtheadbs),
@@ -433,27 +439,6 @@ static void set_satp_mode_default_map(RISCVCPU *cpu)
}
#endif
-static void riscv_any_cpu_init(Object *obj)
-{
- RISCVCPU *cpu = RISCV_CPU(obj);
- CPURISCVState *env = &cpu->env;
- riscv_cpu_set_misa_ext(env, RVI | RVM | RVA | RVF | RVD | RVC | RVU);
-
-#ifndef CONFIG_USER_ONLY
- set_satp_mode_max_supported(RISCV_CPU(obj),
- riscv_cpu_mxl(&RISCV_CPU(obj)->env) == MXL_RV32 ?
- VM_1_10_SV32 : VM_1_10_SV57);
-#endif
-
- env->priv_ver = PRIV_VERSION_LATEST;
-
- /* inherited from parent obj via riscv_cpu_init() */
- cpu->cfg.ext_zifencei = true;
- cpu->cfg.ext_zicsr = true;
- cpu->cfg.mmu = true;
- cpu->cfg.pmp = true;
-}
-
static void riscv_max_cpu_init(Object *obj)
{
RISCVCPU *cpu = RISCV_CPU(obj);
@@ -696,6 +681,11 @@ static void rv32_ibex_cpu_init(Object *obj)
cpu->cfg.ext_zicsr = true;
cpu->cfg.pmp = true;
cpu->cfg.ext_smepmp = true;
+
+ cpu->cfg.ext_zba = true;
+ cpu->cfg.ext_zbb = true;
+ cpu->cfg.ext_zbc = true;
+ cpu->cfg.ext_zbs = true;
}
static void rv32_imafcu_nommu_cpu_init(Object *obj)
@@ -834,6 +824,12 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
}
}
if (flags & CPU_DUMP_FPU) {
+ target_ulong val = 0;
+ RISCVException res = riscv_csrrw_debug(env, CSR_FCSR, &val, 0, 0);
+ if (res == RISCV_EXCP_NONE) {
+ qemu_fprintf(f, " %-8s " TARGET_FMT_lx "\n",
+ csr_ops[CSR_FCSR].name, val);
+ }
for (i = 0; i < 32; i++) {
qemu_fprintf(f, " %-8s %016" PRIx64,
riscv_fpr_regnames[i], env->fpr[i]);
@@ -1156,11 +1152,6 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev);
Error *local_err = NULL;
- if (object_dynamic_cast(OBJECT(dev), TYPE_RISCV_CPU_ANY) != NULL) {
- warn_report("The 'any' CPU is deprecated and will be "
- "removed in the future.");
- }
-
cpu_exec_realizefn(cs, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
@@ -1467,11 +1458,16 @@ const char *riscv_get_misa_ext_description(uint32_t bit)
const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = {
/* Defaults for standard extensions */
MULTI_EXT_CFG_BOOL("sscofpmf", ext_sscofpmf, false),
+ MULTI_EXT_CFG_BOOL("smcntrpmf", ext_smcntrpmf, false),
MULTI_EXT_CFG_BOOL("zifencei", ext_zifencei, true),
MULTI_EXT_CFG_BOOL("zicsr", ext_zicsr, true),
MULTI_EXT_CFG_BOOL("zihintntl", ext_zihintntl, true),
MULTI_EXT_CFG_BOOL("zihintpause", ext_zihintpause, true),
+ MULTI_EXT_CFG_BOOL("zimop", ext_zimop, false),
+ MULTI_EXT_CFG_BOOL("zcmop", ext_zcmop, false),
MULTI_EXT_CFG_BOOL("zacas", ext_zacas, false),
+ MULTI_EXT_CFG_BOOL("zama16b", ext_zama16b, false),
+ MULTI_EXT_CFG_BOOL("zabha", ext_zabha, false),
MULTI_EXT_CFG_BOOL("zaamo", ext_zaamo, false),
MULTI_EXT_CFG_BOOL("zalrsc", ext_zalrsc, false),
MULTI_EXT_CFG_BOOL("zawrs", ext_zawrs, true),
@@ -1499,6 +1495,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = {
MULTI_EXT_CFG_BOOL("svinval", ext_svinval, false),
MULTI_EXT_CFG_BOOL("svnapot", ext_svnapot, false),
MULTI_EXT_CFG_BOOL("svpbmt", ext_svpbmt, false),
+ MULTI_EXT_CFG_BOOL("svvptc", ext_svvptc, true),
MULTI_EXT_CFG_BOOL("zicntr", ext_zicntr, true),
MULTI_EXT_CFG_BOOL("zihpm", ext_zihpm, true),
@@ -2677,6 +2674,7 @@ static Property riscv_cpu_properties[] = {
DEFINE_PROP_BOOL("rvv_ta_all_1s", RISCVCPU, cfg.rvv_ta_all_1s, false),
DEFINE_PROP_BOOL("rvv_ma_all_1s", RISCVCPU, cfg.rvv_ma_all_1s, false),
+ DEFINE_PROP_BOOL("rvv_vl_half_avl", RISCVCPU, cfg.rvv_vl_half_avl, false),
/*
* write_misa() is marked as experimental for now so mark
@@ -2942,7 +2940,6 @@ static const TypeInfo riscv_cpu_type_infos[] = {
.abstract = true,
},
#if defined(TARGET_RISCV32)
- DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_ANY, MXL_RV32, riscv_any_cpu_init),
DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_MAX, MXL_RV32, riscv_max_cpu_init),
DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE32, MXL_RV32, rv32_base_cpu_init),
DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_IBEX, MXL_RV32, rv32_ibex_cpu_init),
@@ -2952,7 +2949,6 @@ static const TypeInfo riscv_cpu_type_infos[] = {
DEFINE_BARE_CPU(TYPE_RISCV_CPU_RV32I, MXL_RV32, rv32i_bare_cpu_init),
DEFINE_BARE_CPU(TYPE_RISCV_CPU_RV32E, MXL_RV32, rv32e_bare_cpu_init),
#elif defined(TARGET_RISCV64)
- DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_ANY, MXL_RV64, riscv_any_cpu_init),
DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_MAX, MXL_RV64, riscv_max_cpu_init),
DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE64, MXL_RV64, rv64_base_cpu_init),
DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_E51, MXL_RV64, rv64_sifive_e_cpu_init),
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 8774204..1619c3a 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -176,11 +176,19 @@ typedef struct PMUCTRState {
target_ulong mhpmcounter_prev;
/* Snapshort value of a counter in RV32 */
target_ulong mhpmcounterh_prev;
- bool started;
/* Value beyond UINT32_MAX/UINT64_MAX before overflow interrupt trigger */
target_ulong irq_overflow_left;
} PMUCTRState;
+typedef struct PMUFixedCtrState {
+ /* Track cycle and icount for each privilege mode */
+ uint64_t counter[4];
+ uint64_t counter_prev[4];
+ /* Track cycle and icount for each privilege mode when V = 1*/
+ uint64_t counter_virt[2];
+ uint64_t counter_virt_prev[2];
+} PMUFixedCtrState;
+
struct CPUArchState {
target_ulong gpr[32];
target_ulong gprh[32]; /* 64 top bits of the 128-bit registers */
@@ -362,6 +370,12 @@ struct CPUArchState {
uint32_t mcountinhibit;
+ /* PMU cycle & instret privilege mode filtering */
+ target_ulong mcyclecfg;
+ target_ulong mcyclecfgh;
+ target_ulong minstretcfg;
+ target_ulong minstretcfgh;
+
/* PMU counter state */
PMUCTRState pmu_ctrs[RV_MAX_MHPMCOUNTERS];
@@ -371,6 +385,8 @@ struct CPUArchState {
/* PMU event selector configured values for RV32 */
target_ulong mhpmeventh_val[RV_MAX_MHPMEVENTS];
+ PMUFixedCtrState pmu_fixed_ctrs[2];
+
target_ulong sscratch;
target_ulong mscratch;
@@ -567,7 +583,7 @@ void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, uint32_t priv,
RISCVException smstateen_acc_ok(CPURISCVState *env, int index, uint64_t bit);
#endif /* !CONFIG_USER_ONLY */
-void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv);
+void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv, bool virt_en);
void riscv_translate_init(void);
G_NORETURN void riscv_raise_exception(CPURISCVState *env,
@@ -735,6 +751,8 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc,
void riscv_cpu_update_mask(CPURISCVState *env);
bool riscv_cpu_is_32bit(RISCVCPU *cpu);
+RISCVException riscv_csrr(CPURISCVState *env, int csrno,
+ target_ulong *ret_value);
RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
target_ulong *ret_value,
target_ulong new_value, target_ulong write_mask);
@@ -767,6 +785,8 @@ typedef RISCVException (*riscv_csr_op_fn)(CPURISCVState *env, int csrno,
target_ulong new_value,
target_ulong write_mask);
+RISCVException riscv_csrr_i128(CPURISCVState *env, int csrno,
+ Int128 *ret_value);
RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno,
Int128 *ret_value,
Int128 new_value, Int128 write_mask);
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index c257c5e..7e3f629 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -397,6 +397,10 @@
/* Machine counter-inhibit register */
#define CSR_MCOUNTINHIBIT 0x320
+/* Machine counter configuration registers */
+#define CSR_MCYCLECFG 0x321
+#define CSR_MINSTRETCFG 0x322
+
#define CSR_MHPMEVENT3 0x323
#define CSR_MHPMEVENT4 0x324
#define CSR_MHPMEVENT5 0x325
@@ -427,6 +431,9 @@
#define CSR_MHPMEVENT30 0x33e
#define CSR_MHPMEVENT31 0x33f
+#define CSR_MCYCLECFGH 0x721
+#define CSR_MINSTRETCFGH 0x722
+
#define CSR_MHPMEVENT3H 0x723
#define CSR_MHPMEVENT4H 0x724
#define CSR_MHPMEVENT5H 0x725
@@ -884,6 +891,28 @@ typedef enum RISCVException {
/* PMU related bits */
#define MIE_LCOFIE (1 << IRQ_PMU_OVF)
+#define MCYCLECFG_BIT_MINH BIT_ULL(62)
+#define MCYCLECFGH_BIT_MINH BIT(30)
+#define MCYCLECFG_BIT_SINH BIT_ULL(61)
+#define MCYCLECFGH_BIT_SINH BIT(29)
+#define MCYCLECFG_BIT_UINH BIT_ULL(60)
+#define MCYCLECFGH_BIT_UINH BIT(28)
+#define MCYCLECFG_BIT_VSINH BIT_ULL(59)
+#define MCYCLECFGH_BIT_VSINH BIT(27)
+#define MCYCLECFG_BIT_VUINH BIT_ULL(58)
+#define MCYCLECFGH_BIT_VUINH BIT(26)
+
+#define MINSTRETCFG_BIT_MINH BIT_ULL(62)
+#define MINSTRETCFGH_BIT_MINH BIT(30)
+#define MINSTRETCFG_BIT_SINH BIT_ULL(61)
+#define MINSTRETCFGH_BIT_SINH BIT(29)
+#define MINSTRETCFG_BIT_UINH BIT_ULL(60)
+#define MINSTRETCFGH_BIT_UINH BIT(28)
+#define MINSTRETCFG_BIT_VSINH BIT_ULL(59)
+#define MINSTRETCFGH_BIT_VSINH BIT(27)
+#define MINSTRETCFG_BIT_VUINH BIT_ULL(58)
+#define MINSTRETCFGH_BIT_VUINH BIT(26)
+
#define MHPMEVENT_BIT_OF BIT_ULL(63)
#define MHPMEVENTH_BIT_OF BIT(31)
#define MHPMEVENT_BIT_MINH BIT_ULL(62)
@@ -897,6 +926,18 @@ typedef enum RISCVException {
#define MHPMEVENT_BIT_VUINH BIT_ULL(58)
#define MHPMEVENTH_BIT_VUINH BIT(26)
+#define MHPMEVENT_FILTER_MASK (MHPMEVENT_BIT_MINH | \
+ MHPMEVENT_BIT_SINH | \
+ MHPMEVENT_BIT_UINH | \
+ MHPMEVENT_BIT_VSINH | \
+ MHPMEVENT_BIT_VUINH)
+
+#define MHPMEVENTH_FILTER_MASK (MHPMEVENTH_BIT_MINH | \
+ MHPMEVENTH_BIT_SINH | \
+ MHPMEVENTH_BIT_UINH | \
+ MHPMEVENTH_BIT_VSINH | \
+ MHPMEVENTH_BIT_VUINH)
+
#define MHPMEVENT_SSCOF_MASK _ULL(0xFFFF000000000000)
#define MHPMEVENT_IDX_MASK 0xFFFFF
#define MHPMEVENT_SSCOF_RESVD 16
@@ -906,6 +947,16 @@ typedef enum RISCVException {
#define JVT_BASE (~0x3F)
/* Debug Sdtrig CSR masks */
+#define TEXTRA32_MHVALUE 0xFC000000
+#define TEXTRA32_MHSELECT 0x03800000
+#define TEXTRA32_SBYTEMASK 0x000C0000
+#define TEXTRA32_SVALUE 0x0003FFFC
+#define TEXTRA32_SSELECT 0x00000003
+#define TEXTRA64_MHVALUE 0xFFF8000000000000ULL
+#define TEXTRA64_MHSELECT 0x0007000000000000ULL
+#define TEXTRA64_SBYTEMASK 0x000000F000000000ULL
+#define TEXTRA64_SVALUE 0x00000003FFFFFFFCULL
+#define TEXTRA64_SSELECT 0x0000000000000003ULL
#define MCONTEXT32 0x0000003F
#define MCONTEXT64 0x0000000000001FFFULL
#define MCONTEXT32_HCONTEXT 0x0000007F
diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
index fb7eebd..355afed 100644
--- a/target/riscv/cpu_cfg.h
+++ b/target/riscv/cpu_cfg.h
@@ -71,16 +71,22 @@ struct RISCVCPUConfig {
bool ext_zihintntl;
bool ext_zihintpause;
bool ext_zihpm;
+ bool ext_zimop;
+ bool ext_zcmop;
bool ext_ztso;
bool ext_smstateen;
bool ext_sstc;
+ bool ext_smcntrpmf;
bool ext_svadu;
bool ext_svinval;
bool ext_svnapot;
bool ext_svpbmt;
+ bool ext_svvptc;
bool ext_zdinx;
bool ext_zaamo;
bool ext_zacas;
+ bool ext_zama16b;
+ bool ext_zabha;
bool ext_zalrsc;
bool ext_zawrs;
bool ext_zfa;
@@ -122,6 +128,7 @@ struct RISCVCPUConfig {
bool ext_smepmp;
bool rvv_ta_all_1s;
bool rvv_ma_all_1s;
+ bool rvv_vl_half_avl;
uint32_t mvendorid;
uint64_t marchid;
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 6709622..a935377 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -619,30 +619,6 @@ void riscv_cpu_set_geilen(CPURISCVState *env, target_ulong geilen)
env->geilen = geilen;
}
-/* This function can only be called to set virt when RVH is enabled */
-void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable)
-{
- /* Flush the TLB on all virt mode changes. */
- if (env->virt_enabled != enable) {
- tlb_flush(env_cpu(env));
- }
-
- env->virt_enabled = enable;
-
- if (enable) {
- /*
- * The guest external interrupts from an interrupt controller are
- * delivered only when the Guest/VM is running (i.e. V=1). This means
- * any guest external interrupt which is triggered while the Guest/VM
- * is not running (i.e. V=0) will be missed on QEMU resulting in guest
- * with sluggish response to serial console input and other I/O events.
- *
- * To solve this, we check and inject interrupt after setting V=1.
- */
- riscv_cpu_update_mip(env, 0, 0);
- }
-}
-
int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts)
{
CPURISCVState *env = &cpu->env;
@@ -715,13 +691,18 @@ void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, uint32_t priv,
}
}
-void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
+void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv, bool virt_en)
{
g_assert(newpriv <= PRV_M && newpriv != PRV_RESERVED);
- if (icount_enabled() && newpriv != env->priv) {
- riscv_itrigger_update_priv(env);
+ if (newpriv != env->priv || env->virt_enabled != virt_en) {
+ if (icount_enabled()) {
+ riscv_itrigger_update_priv(env);
+ }
+
+ riscv_pmu_update_fixed_ctrs(env, newpriv, virt_en);
}
+
/* tlb_flush is unnecessary as mode is contained in mmu_idx */
env->priv = newpriv;
env->xl = cpu_recompute_xl(env);
@@ -736,6 +717,28 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
* preemptive context switch. As a result, do both.
*/
env->load_res = -1;
+
+ if (riscv_has_ext(env, RVH)) {
+ /* Flush the TLB on all virt mode changes. */
+ if (env->virt_enabled != virt_en) {
+ tlb_flush(env_cpu(env));
+ }
+
+ env->virt_enabled = virt_en;
+ if (virt_en) {
+ /*
+ * The guest external interrupts from an interrupt controller are
+ * delivered only when the Guest/VM is running (i.e. V=1). This
+ * means any guest external interrupt which is triggered while the
+ * Guest/VM is not running (i.e. V=0) will be missed on QEMU
+ * resulting in guest with sluggish response to serial console
+ * input and other I/O events.
+ *
+ * To solve this, we check and inject interrupt after setting V=1.
+ */
+ riscv_cpu_update_mip(env, 0, 0);
+ }
+ }
}
/*
@@ -1320,7 +1323,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
int ret = TRANSLATE_FAIL;
int mode = mmuidx_priv(mmu_idx);
/* default TLB page size */
- target_ulong tlb_size = TARGET_PAGE_SIZE;
+ hwaddr tlb_size = TARGET_PAGE_SIZE;
env->guest_phys_fault_addr = 0;
@@ -1372,7 +1375,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
qemu_log_mask(CPU_LOG_MMU,
"%s PMP address=" HWADDR_FMT_plx " ret %d prot"
- " %d tlb_size " TARGET_FMT_lu "\n",
+ " %d tlb_size %" HWADDR_PRIu "\n",
__func__, pa, ret, prot_pmp, tlb_size);
prot &= prot_pmp;
@@ -1406,7 +1409,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
qemu_log_mask(CPU_LOG_MMU,
"%s PMP address=" HWADDR_FMT_plx " ret %d prot"
- " %d tlb_size " TARGET_FMT_lu "\n",
+ " %d tlb_size %" HWADDR_PRIu "\n",
__func__, pa, ret, prot_pmp, tlb_size);
prot &= prot_pmp;
@@ -1648,6 +1651,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
{
RISCVCPU *cpu = RISCV_CPU(cs);
CPURISCVState *env = &cpu->env;
+ bool virt = env->virt_enabled;
bool write_gva = false;
uint64_t s;
@@ -1670,10 +1674,12 @@ void riscv_cpu_do_interrupt(CPUState *cs)
if (!async) {
/* set tval to badaddr for traps with address information */
switch (cause) {
+#ifdef CONFIG_TCG
case RISCV_EXCP_SEMIHOST:
do_common_semihosting(cs);
env->pc += 4;
return;
+#endif
case RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT:
case RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT:
case RISCV_EXCP_LOAD_ADDR_MIS:
@@ -1778,7 +1784,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
htval = env->guest_phys_fault_addr;
- riscv_cpu_set_virt_enabled(env, 0);
+ virt = false;
} else {
/* Trap into HS mode */
env->hstatus = set_field(env->hstatus, HSTATUS_SPV, false);
@@ -1799,7 +1805,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
env->htinst = tinst;
env->pc = (env->stvec >> 2 << 2) +
((async && (env->stvec & 3) == 1) ? cause * 4 : 0);
- riscv_cpu_set_mode(env, PRV_S);
+ riscv_cpu_set_mode(env, PRV_S, virt);
} else {
/* handle the trap in M-mode */
if (riscv_has_ext(env, RVH)) {
@@ -1815,7 +1821,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
mtval2 = env->guest_phys_fault_addr;
/* Trapping to M mode, virt is disabled */
- riscv_cpu_set_virt_enabled(env, 0);
+ virt = false;
}
s = env->mstatus;
@@ -1830,7 +1836,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
env->mtinst = tinst;
env->pc = (env->mtvec >> 2 << 2) +
((async && (env->mtvec & 3) == 1) ? cause * 4 : 0);
- riscv_cpu_set_mode(env, PRV_M);
+ riscv_cpu_set_mode(env, PRV_M, virt);
}
/*
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 432c59d..ea35603 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -30,7 +30,6 @@
#include "qemu/guest-random.h"
#include "qapi/error.h"
-
/* CSR function table public API */
void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops)
{
@@ -227,6 +226,33 @@ static RISCVException sscofpmf(CPURISCVState *env, int csrno)
return RISCV_EXCP_NONE;
}
+static RISCVException sscofpmf_32(CPURISCVState *env, int csrno)
+{
+ if (riscv_cpu_mxl(env) != MXL_RV32) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ return sscofpmf(env, csrno);
+}
+
+static RISCVException smcntrpmf(CPURISCVState *env, int csrno)
+{
+ if (!riscv_cpu_cfg(env)->ext_smcntrpmf) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException smcntrpmf_32(CPURISCVState *env, int csrno)
+{
+ if (riscv_cpu_mxl(env) != MXL_RV32) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ return smcntrpmf(env, csrno);
+}
+
static RISCVException any(CPURISCVState *env, int csrno)
{
return RISCV_EXCP_NONE;
@@ -761,36 +787,16 @@ static RISCVException write_vcsr(CPURISCVState *env, int csrno,
return RISCV_EXCP_NONE;
}
+#if defined(CONFIG_USER_ONLY)
/* User Timers and Counters */
-static target_ulong get_ticks(bool shift, bool instructions)
+static target_ulong get_ticks(bool shift)
{
- int64_t val;
- target_ulong result;
-
-#if !defined(CONFIG_USER_ONLY)
- if (icount_enabled()) {
- if (instructions) {
- val = icount_get_raw();
- } else {
- val = icount_get();
- }
- } else {
- val = cpu_get_host_ticks();
- }
-#else
- val = cpu_get_host_ticks();
-#endif
-
- if (shift) {
- result = val >> 32;
- } else {
- result = val;
- }
+ int64_t val = cpu_get_host_ticks();
+ target_ulong result = shift ? val >> 32 : val;
return result;
}
-#if defined(CONFIG_USER_ONLY)
static RISCVException read_time(CPURISCVState *env, int csrno,
target_ulong *val)
{
@@ -808,19 +814,124 @@ static RISCVException read_timeh(CPURISCVState *env, int csrno,
static RISCVException read_hpmcounter(CPURISCVState *env, int csrno,
target_ulong *val)
{
- *val = get_ticks(false, (csrno == CSR_INSTRET));
+ *val = get_ticks(false);
return RISCV_EXCP_NONE;
}
static RISCVException read_hpmcounterh(CPURISCVState *env, int csrno,
target_ulong *val)
{
- *val = get_ticks(true, (csrno == CSR_INSTRETH));
+ *val = get_ticks(true);
return RISCV_EXCP_NONE;
}
#else /* CONFIG_USER_ONLY */
+static RISCVException read_mcyclecfg(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mcyclecfg;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mcyclecfg(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ uint64_t inh_avail_mask;
+
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ env->mcyclecfg = val;
+ } else {
+ /* Set xINH fields if priv mode supported */
+ inh_avail_mask = ~MHPMEVENT_FILTER_MASK | MCYCLECFG_BIT_MINH;
+ inh_avail_mask |= riscv_has_ext(env, RVU) ? MCYCLECFG_BIT_UINH : 0;
+ inh_avail_mask |= riscv_has_ext(env, RVS) ? MCYCLECFG_BIT_SINH : 0;
+ inh_avail_mask |= (riscv_has_ext(env, RVH) &&
+ riscv_has_ext(env, RVU)) ? MCYCLECFG_BIT_VUINH : 0;
+ inh_avail_mask |= (riscv_has_ext(env, RVH) &&
+ riscv_has_ext(env, RVS)) ? MCYCLECFG_BIT_VSINH : 0;
+ env->mcyclecfg = val & inh_avail_mask;
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_mcyclecfgh(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mcyclecfgh;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mcyclecfgh(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ target_ulong inh_avail_mask = (target_ulong)(~MHPMEVENTH_FILTER_MASK |
+ MCYCLECFGH_BIT_MINH);
+
+ /* Set xINH fields if priv mode supported */
+ inh_avail_mask |= riscv_has_ext(env, RVU) ? MCYCLECFGH_BIT_UINH : 0;
+ inh_avail_mask |= riscv_has_ext(env, RVS) ? MCYCLECFGH_BIT_SINH : 0;
+ inh_avail_mask |= (riscv_has_ext(env, RVH) &&
+ riscv_has_ext(env, RVU)) ? MCYCLECFGH_BIT_VUINH : 0;
+ inh_avail_mask |= (riscv_has_ext(env, RVH) &&
+ riscv_has_ext(env, RVS)) ? MCYCLECFGH_BIT_VSINH : 0;
+
+ env->mcyclecfgh = val & inh_avail_mask;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_minstretcfg(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->minstretcfg;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_minstretcfg(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ uint64_t inh_avail_mask;
+
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ env->minstretcfg = val;
+ } else {
+ inh_avail_mask = ~MHPMEVENT_FILTER_MASK | MINSTRETCFG_BIT_MINH;
+ inh_avail_mask |= riscv_has_ext(env, RVU) ? MINSTRETCFG_BIT_UINH : 0;
+ inh_avail_mask |= riscv_has_ext(env, RVS) ? MINSTRETCFG_BIT_SINH : 0;
+ inh_avail_mask |= (riscv_has_ext(env, RVH) &&
+ riscv_has_ext(env, RVU)) ? MINSTRETCFG_BIT_VUINH : 0;
+ inh_avail_mask |= (riscv_has_ext(env, RVH) &&
+ riscv_has_ext(env, RVS)) ? MINSTRETCFG_BIT_VSINH : 0;
+ env->minstretcfg = val & inh_avail_mask;
+ }
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_minstretcfgh(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->minstretcfgh;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_minstretcfgh(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ target_ulong inh_avail_mask = (target_ulong)(~MHPMEVENTH_FILTER_MASK |
+ MINSTRETCFGH_BIT_MINH);
+
+ inh_avail_mask |= riscv_has_ext(env, RVU) ? MINSTRETCFGH_BIT_UINH : 0;
+ inh_avail_mask |= riscv_has_ext(env, RVS) ? MINSTRETCFGH_BIT_SINH : 0;
+ inh_avail_mask |= (riscv_has_ext(env, RVH) &&
+ riscv_has_ext(env, RVU)) ? MINSTRETCFGH_BIT_VUINH : 0;
+ inh_avail_mask |= (riscv_has_ext(env, RVH) &&
+ riscv_has_ext(env, RVS)) ? MINSTRETCFGH_BIT_VSINH : 0;
+
+ env->minstretcfgh = val & inh_avail_mask;
+ return RISCV_EXCP_NONE;
+}
+
static RISCVException read_mhpmevent(CPURISCVState *env, int csrno,
target_ulong *val)
{
@@ -836,13 +947,24 @@ static RISCVException write_mhpmevent(CPURISCVState *env, int csrno,
{
int evt_index = csrno - CSR_MCOUNTINHIBIT;
uint64_t mhpmevt_val = val;
-
- env->mhpmevent_val[evt_index] = val;
+ uint64_t inh_avail_mask;
if (riscv_cpu_mxl(env) == MXL_RV32) {
+ env->mhpmevent_val[evt_index] = val;
mhpmevt_val = mhpmevt_val |
((uint64_t)env->mhpmeventh_val[evt_index] << 32);
+ } else {
+ inh_avail_mask = ~MHPMEVENT_FILTER_MASK | MHPMEVENT_BIT_MINH;
+ inh_avail_mask |= riscv_has_ext(env, RVU) ? MHPMEVENT_BIT_UINH : 0;
+ inh_avail_mask |= riscv_has_ext(env, RVS) ? MHPMEVENT_BIT_SINH : 0;
+ inh_avail_mask |= (riscv_has_ext(env, RVH) &&
+ riscv_has_ext(env, RVU)) ? MHPMEVENT_BIT_VUINH : 0;
+ inh_avail_mask |= (riscv_has_ext(env, RVH) &&
+ riscv_has_ext(env, RVS)) ? MHPMEVENT_BIT_VSINH : 0;
+ mhpmevt_val = val & inh_avail_mask;
+ env->mhpmevent_val[evt_index] = mhpmevt_val;
}
+
riscv_pmu_update_event_map(env, mhpmevt_val, evt_index);
return RISCV_EXCP_NONE;
@@ -862,28 +984,107 @@ static RISCVException write_mhpmeventh(CPURISCVState *env, int csrno,
target_ulong val)
{
int evt_index = csrno - CSR_MHPMEVENT3H + 3;
- uint64_t mhpmevth_val = val;
+ uint64_t mhpmevth_val;
uint64_t mhpmevt_val = env->mhpmevent_val[evt_index];
+ target_ulong inh_avail_mask = (target_ulong)(~MHPMEVENTH_FILTER_MASK |
+ MHPMEVENTH_BIT_MINH);
+ inh_avail_mask |= riscv_has_ext(env, RVU) ? MHPMEVENTH_BIT_UINH : 0;
+ inh_avail_mask |= riscv_has_ext(env, RVS) ? MHPMEVENTH_BIT_SINH : 0;
+ inh_avail_mask |= (riscv_has_ext(env, RVH) &&
+ riscv_has_ext(env, RVU)) ? MHPMEVENTH_BIT_VUINH : 0;
+ inh_avail_mask |= (riscv_has_ext(env, RVH) &&
+ riscv_has_ext(env, RVS)) ? MHPMEVENTH_BIT_VSINH : 0;
+
+ mhpmevth_val = val & inh_avail_mask;
mhpmevt_val = mhpmevt_val | (mhpmevth_val << 32);
- env->mhpmeventh_val[evt_index] = val;
+ env->mhpmeventh_val[evt_index] = mhpmevth_val;
riscv_pmu_update_event_map(env, mhpmevt_val, evt_index);
return RISCV_EXCP_NONE;
}
+static target_ulong riscv_pmu_ctr_get_fixed_counters_val(CPURISCVState *env,
+ int counter_idx,
+ bool upper_half)
+{
+ int inst = riscv_pmu_ctr_monitor_instructions(env, counter_idx);
+ uint64_t *counter_arr_virt = env->pmu_fixed_ctrs[inst].counter_virt;
+ uint64_t *counter_arr = env->pmu_fixed_ctrs[inst].counter;
+ target_ulong result = 0;
+ uint64_t curr_val = 0;
+ uint64_t cfg_val = 0;
+
+ if (counter_idx == 0) {
+ cfg_val = upper_half ? ((uint64_t)env->mcyclecfgh << 32) :
+ env->mcyclecfg;
+ } else if (counter_idx == 2) {
+ cfg_val = upper_half ? ((uint64_t)env->minstretcfgh << 32) :
+ env->minstretcfg;
+ } else {
+ cfg_val = upper_half ?
+ ((uint64_t)env->mhpmeventh_val[counter_idx] << 32) :
+ env->mhpmevent_val[counter_idx];
+ cfg_val &= MHPMEVENT_FILTER_MASK;
+ }
+
+ if (!cfg_val) {
+ if (icount_enabled()) {
+ curr_val = inst ? icount_get_raw() : icount_get();
+ } else {
+ curr_val = cpu_get_host_ticks();
+ }
+
+ goto done;
+ }
+
+ /* Update counter before reading. */
+ riscv_pmu_update_fixed_ctrs(env, env->priv, env->virt_enabled);
+
+ if (!(cfg_val & MCYCLECFG_BIT_MINH)) {
+ curr_val += counter_arr[PRV_M];
+ }
+
+ if (!(cfg_val & MCYCLECFG_BIT_SINH)) {
+ curr_val += counter_arr[PRV_S];
+ }
+
+ if (!(cfg_val & MCYCLECFG_BIT_UINH)) {
+ curr_val += counter_arr[PRV_U];
+ }
+
+ if (!(cfg_val & MCYCLECFG_BIT_VSINH)) {
+ curr_val += counter_arr_virt[PRV_S];
+ }
+
+ if (!(cfg_val & MCYCLECFG_BIT_VUINH)) {
+ curr_val += counter_arr_virt[PRV_U];
+ }
+
+done:
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ result = upper_half ? curr_val >> 32 : curr_val;
+ } else {
+ result = curr_val;
+ }
+
+ return result;
+}
+
static RISCVException write_mhpmcounter(CPURISCVState *env, int csrno,
target_ulong val)
{
int ctr_idx = csrno - CSR_MCYCLE;
PMUCTRState *counter = &env->pmu_ctrs[ctr_idx];
uint64_t mhpmctr_val = val;
- bool instr = riscv_pmu_ctr_monitor_instructions(env, ctr_idx);
counter->mhpmcounter_val = val;
- if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || instr) {
- counter->mhpmcounter_prev = get_ticks(false, instr);
+ if (!get_field(env->mcountinhibit, BIT(ctr_idx)) &&
+ (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) ||
+ riscv_pmu_ctr_monitor_instructions(env, ctr_idx))) {
+ counter->mhpmcounter_prev = riscv_pmu_ctr_get_fixed_counters_val(env,
+ ctr_idx, false);
if (ctr_idx > 2) {
if (riscv_cpu_mxl(env) == MXL_RV32) {
mhpmctr_val = mhpmctr_val |
@@ -906,12 +1107,14 @@ static RISCVException write_mhpmcounterh(CPURISCVState *env, int csrno,
PMUCTRState *counter = &env->pmu_ctrs[ctr_idx];
uint64_t mhpmctr_val = counter->mhpmcounter_val;
uint64_t mhpmctrh_val = val;
- bool instr = riscv_pmu_ctr_monitor_instructions(env, ctr_idx);
counter->mhpmcounterh_val = val;
mhpmctr_val = mhpmctr_val | (mhpmctrh_val << 32);
- if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || instr) {
- counter->mhpmcounterh_prev = get_ticks(true, instr);
+ if (!get_field(env->mcountinhibit, BIT(ctr_idx)) &&
+ (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) ||
+ riscv_pmu_ctr_monitor_instructions(env, ctr_idx))) {
+ counter->mhpmcounterh_prev = riscv_pmu_ctr_get_fixed_counters_val(env,
+ ctr_idx, true);
if (ctr_idx > 2) {
riscv_pmu_setup_timer(env, mhpmctr_val, ctr_idx);
}
@@ -922,7 +1125,7 @@ static RISCVException write_mhpmcounterh(CPURISCVState *env, int csrno,
return RISCV_EXCP_NONE;
}
-static RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val,
+RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val,
bool upper_half, uint32_t ctr_idx)
{
PMUCTRState *counter = &env->pmu_ctrs[ctr_idx];
@@ -930,29 +1133,24 @@ static RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val,
counter->mhpmcounter_prev;
target_ulong ctr_val = upper_half ? counter->mhpmcounterh_val :
counter->mhpmcounter_val;
- bool instr = riscv_pmu_ctr_monitor_instructions(env, ctr_idx);
if (get_field(env->mcountinhibit, BIT(ctr_idx))) {
/*
- * Counter should not increment if inhibit bit is set. We can't really
- * stop the icount counting. Just return the counter value written by
- * the supervisor to indicate that counter was not incremented.
+ * Counter should not increment if inhibit bit is set. Just return the
+ * current counter value.
*/
- if (!counter->started) {
- *val = ctr_val;
- return RISCV_EXCP_NONE;
- } else {
- /* Mark that the counter has been stopped */
- counter->started = false;
- }
+ *val = ctr_val;
+ return RISCV_EXCP_NONE;
}
/*
* The kernel computes the perf delta by subtracting the current value from
* the value it initialized previously (ctr_val).
*/
- if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) || instr) {
- *val = get_ticks(upper_half, instr) - ctr_prev + ctr_val;
+ if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) ||
+ riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) {
+ *val = riscv_pmu_ctr_get_fixed_counters_val(env, ctr_idx, upper_half) -
+ ctr_prev + ctr_val;
} else {
*val = ctr_val;
}
@@ -1977,16 +2175,61 @@ static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno,
int cidx;
PMUCTRState *counter;
RISCVCPU *cpu = env_archcpu(env);
+ uint32_t present_ctrs = cpu->pmu_avail_ctrs | COUNTEREN_CY | COUNTEREN_IR;
+ target_ulong updated_ctrs = (env->mcountinhibit ^ val) & present_ctrs;
+ uint64_t mhpmctr_val, prev_count, curr_count;
/* WARL register - disable unavailable counters; TM bit is always 0 */
- env->mcountinhibit =
- val & (cpu->pmu_avail_ctrs | COUNTEREN_CY | COUNTEREN_IR);
+ env->mcountinhibit = val & present_ctrs;
/* Check if any other counter is also monitoring cycles/instructions */
for (cidx = 0; cidx < RV_MAX_MHPMCOUNTERS; cidx++) {
+ if (!(updated_ctrs & BIT(cidx)) ||
+ (!riscv_pmu_ctr_monitor_cycles(env, cidx) &&
+ !riscv_pmu_ctr_monitor_instructions(env, cidx))) {
+ continue;
+ }
+
+ counter = &env->pmu_ctrs[cidx];
+
if (!get_field(env->mcountinhibit, BIT(cidx))) {
- counter = &env->pmu_ctrs[cidx];
- counter->started = true;
+ counter->mhpmcounter_prev =
+ riscv_pmu_ctr_get_fixed_counters_val(env, cidx, false);
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ counter->mhpmcounterh_prev =
+ riscv_pmu_ctr_get_fixed_counters_val(env, cidx, true);
+ }
+
+ if (cidx > 2) {
+ mhpmctr_val = counter->mhpmcounter_val;
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ mhpmctr_val = mhpmctr_val |
+ ((uint64_t)counter->mhpmcounterh_val << 32);
+ }
+ riscv_pmu_setup_timer(env, mhpmctr_val, cidx);
+ }
+ } else {
+ curr_count = riscv_pmu_ctr_get_fixed_counters_val(env, cidx, false);
+
+ mhpmctr_val = counter->mhpmcounter_val;
+ prev_count = counter->mhpmcounter_prev;
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ uint64_t tmp =
+ riscv_pmu_ctr_get_fixed_counters_val(env, cidx, true);
+
+ curr_count = curr_count | (tmp << 32);
+ mhpmctr_val = mhpmctr_val |
+ ((uint64_t)counter->mhpmcounterh_val << 32);
+ prev_count = prev_count |
+ ((uint64_t)counter->mhpmcounterh_prev << 32);
+ }
+
+ /* Adjust the counter for later reads. */
+ mhpmctr_val = curr_count - prev_count + mhpmctr_val;
+ counter->mhpmcounter_val = mhpmctr_val;
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ counter->mhpmcounterh_val = mhpmctr_val >> 32;
+ }
}
}
@@ -2854,7 +3097,11 @@ static RISCVException read_scounteren(CPURISCVState *env, int csrno,
static RISCVException write_scounteren(CPURISCVState *env, int csrno,
target_ulong val)
{
- env->scounteren = val;
+ RISCVCPU *cpu = env_archcpu(env);
+
+ /* WARL register - disable unavailable counters */
+ env->scounteren = val & (cpu->pmu_avail_ctrs | COUNTEREN_CY | COUNTEREN_TM |
+ COUNTEREN_IR);
return RISCV_EXCP_NONE;
}
@@ -3513,7 +3760,11 @@ static RISCVException read_hcounteren(CPURISCVState *env, int csrno,
static RISCVException write_hcounteren(CPURISCVState *env, int csrno,
target_ulong val)
{
- env->hcounteren = val;
+ RISCVCPU *cpu = env_archcpu(env);
+
+ /* WARL register - disable unavailable counters */
+ env->hcounteren = val & (cpu->pmu_avail_ctrs | COUNTEREN_CY | COUNTEREN_TM |
+ COUNTEREN_IR);
return RISCV_EXCP_NONE;
}
@@ -3791,7 +4042,12 @@ static RISCVException read_vstvec(CPURISCVState *env, int csrno,
static RISCVException write_vstvec(CPURISCVState *env, int csrno,
target_ulong val)
{
- env->vstvec = val;
+ /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */
+ if ((val & 3) < 2) {
+ env->vstvec = val;
+ } else {
+ qemu_log_mask(LOG_UNIMP, "CSR_VSTVEC: reserved mode not supported\n");
+ }
return RISCV_EXCP_NONE;
}
@@ -4368,7 +4624,7 @@ static RISCVException rmw_seed(CPURISCVState *env, int csrno,
static inline RISCVException riscv_csrrw_check(CPURISCVState *env,
int csrno,
- bool write_mask)
+ bool write)
{
/* check privileges and return RISCV_EXCP_ILLEGAL_INST if check fails */
bool read_only = get_field(csrno, 0xC00) == 3;
@@ -4390,7 +4646,7 @@ static inline RISCVException riscv_csrrw_check(CPURISCVState *env,
}
/* read / write check */
- if (write_mask && read_only) {
+ if (write && read_only) {
return RISCV_EXCP_ILLEGAL_INST;
}
@@ -4477,11 +4733,22 @@ static RISCVException riscv_csrrw_do64(CPURISCVState *env, int csrno,
return RISCV_EXCP_NONE;
}
+RISCVException riscv_csrr(CPURISCVState *env, int csrno,
+ target_ulong *ret_value)
+{
+ RISCVException ret = riscv_csrrw_check(env, csrno, false);
+ if (ret != RISCV_EXCP_NONE) {
+ return ret;
+ }
+
+ return riscv_csrrw_do64(env, csrno, ret_value, 0, 0);
+}
+
RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
target_ulong *ret_value,
target_ulong new_value, target_ulong write_mask)
{
- RISCVException ret = riscv_csrrw_check(env, csrno, write_mask);
+ RISCVException ret = riscv_csrrw_check(env, csrno, true);
if (ret != RISCV_EXCP_NONE) {
return ret;
}
@@ -4529,13 +4796,45 @@ static RISCVException riscv_csrrw_do128(CPURISCVState *env, int csrno,
return RISCV_EXCP_NONE;
}
+RISCVException riscv_csrr_i128(CPURISCVState *env, int csrno,
+ Int128 *ret_value)
+{
+ RISCVException ret;
+
+ ret = riscv_csrrw_check(env, csrno, false);
+ if (ret != RISCV_EXCP_NONE) {
+ return ret;
+ }
+
+ if (csr_ops[csrno].read128) {
+ return riscv_csrrw_do128(env, csrno, ret_value,
+ int128_zero(), int128_zero());
+ }
+
+ /*
+ * Fall back to 64-bit version for now, if the 128-bit alternative isn't
+ * at all defined.
+ * Note, some CSRs don't need to extend to MXLEN (64 upper bits non
+ * significant), for those, this fallback is correctly handling the
+ * accesses
+ */
+ target_ulong old_value;
+ ret = riscv_csrrw_do64(env, csrno, &old_value,
+ (target_ulong)0,
+ (target_ulong)0);
+ if (ret == RISCV_EXCP_NONE && ret_value) {
+ *ret_value = int128_make64(old_value);
+ }
+ return ret;
+}
+
RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno,
Int128 *ret_value,
Int128 new_value, Int128 write_mask)
{
RISCVException ret;
- ret = riscv_csrrw_check(env, csrno, int128_nz(write_mask));
+ ret = riscv_csrrw_check(env, csrno, true);
if (ret != RISCV_EXCP_NONE) {
return ret;
}
@@ -4574,7 +4873,11 @@ RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno,
#if !defined(CONFIG_USER_ONLY)
env->debugger = true;
#endif
- ret = riscv_csrrw(env, csrno, ret_value, new_value, write_mask);
+ if (!write_mask) {
+ ret = riscv_csrr(env, csrno, ret_value);
+ } else {
+ ret = riscv_csrrw(env, csrno, ret_value, new_value, write_mask);
+ }
#if !defined(CONFIG_USER_ONLY)
env->debugger = false;
#endif
@@ -5042,6 +5345,13 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
write_mcountinhibit,
.min_priv_ver = PRIV_VERSION_1_11_0 },
+ [CSR_MCYCLECFG] = { "mcyclecfg", smcntrpmf, read_mcyclecfg,
+ write_mcyclecfg,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MINSTRETCFG] = { "minstretcfg", smcntrpmf, read_minstretcfg,
+ write_minstretcfg,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+
[CSR_MHPMEVENT3] = { "mhpmevent3", any, read_mhpmevent,
write_mhpmevent },
[CSR_MHPMEVENT4] = { "mhpmevent4", any, read_mhpmevent,
@@ -5101,91 +5411,98 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_MHPMEVENT31] = { "mhpmevent31", any, read_mhpmevent,
write_mhpmevent },
- [CSR_MHPMEVENT3H] = { "mhpmevent3h", sscofpmf, read_mhpmeventh,
+ [CSR_MCYCLECFGH] = { "mcyclecfgh", smcntrpmf_32, read_mcyclecfgh,
+ write_mcyclecfgh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_MINSTRETCFGH] = { "minstretcfgh", smcntrpmf_32, read_minstretcfgh,
+ write_minstretcfgh,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+
+ [CSR_MHPMEVENT3H] = { "mhpmevent3h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT4H] = { "mhpmevent4h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT4H] = { "mhpmevent4h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT5H] = { "mhpmevent5h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT5H] = { "mhpmevent5h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT6H] = { "mhpmevent6h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT6H] = { "mhpmevent6h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT7H] = { "mhpmevent7h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT7H] = { "mhpmevent7h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT8H] = { "mhpmevent8h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT8H] = { "mhpmevent8h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT9H] = { "mhpmevent9h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT9H] = { "mhpmevent9h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT10H] = { "mhpmevent10h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT10H] = { "mhpmevent10h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT11H] = { "mhpmevent11h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT11H] = { "mhpmevent11h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT12H] = { "mhpmevent12h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT12H] = { "mhpmevent12h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT13H] = { "mhpmevent13h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT13H] = { "mhpmevent13h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT14H] = { "mhpmevent14h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT14H] = { "mhpmevent14h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT15H] = { "mhpmevent15h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT15H] = { "mhpmevent15h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT16H] = { "mhpmevent16h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT16H] = { "mhpmevent16h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT17H] = { "mhpmevent17h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT17H] = { "mhpmevent17h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT18H] = { "mhpmevent18h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT18H] = { "mhpmevent18h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT19H] = { "mhpmevent19h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT19H] = { "mhpmevent19h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT20H] = { "mhpmevent20h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT20H] = { "mhpmevent20h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT21H] = { "mhpmevent21h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT21H] = { "mhpmevent21h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT22H] = { "mhpmevent22h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT22H] = { "mhpmevent22h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT23H] = { "mhpmevent23h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT23H] = { "mhpmevent23h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT24H] = { "mhpmevent24h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT24H] = { "mhpmevent24h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT25H] = { "mhpmevent25h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT25H] = { "mhpmevent25h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT26H] = { "mhpmevent26h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT26H] = { "mhpmevent26h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT27H] = { "mhpmevent27h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT27H] = { "mhpmevent27h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT28H] = { "mhpmevent28h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT28H] = { "mhpmevent28h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT29H] = { "mhpmevent29h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT29H] = { "mhpmevent29h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT30H] = { "mhpmevent30h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT30H] = { "mhpmevent30h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
- [CSR_MHPMEVENT31H] = { "mhpmevent31h", sscofpmf, read_mhpmeventh,
+ [CSR_MHPMEVENT31H] = { "mhpmevent31h", sscofpmf_32, read_mhpmeventh,
write_mhpmeventh,
.min_priv_ver = PRIV_VERSION_1_12_0 },
diff --git a/target/riscv/debug.c b/target/riscv/debug.c
index 0b5099f..c79b51a 100644
--- a/target/riscv/debug.c
+++ b/target/riscv/debug.c
@@ -217,6 +217,66 @@ static inline void warn_always_zero_bit(target_ulong val, target_ulong mask,
}
}
+static target_ulong textra_validate(CPURISCVState *env, target_ulong tdata3)
+{
+ target_ulong mhvalue, mhselect;
+ target_ulong mhselect_new;
+ target_ulong textra;
+ const uint32_t mhselect_no_rvh[8] = { 0, 0, 0, 0, 4, 4, 4, 4 };
+
+ switch (riscv_cpu_mxl(env)) {
+ case MXL_RV32:
+ mhvalue = get_field(tdata3, TEXTRA32_MHVALUE);
+ mhselect = get_field(tdata3, TEXTRA32_MHSELECT);
+ /* Validate unimplemented (always zero) bits */
+ warn_always_zero_bit(tdata3, (target_ulong)TEXTRA32_SBYTEMASK,
+ "sbytemask");
+ warn_always_zero_bit(tdata3, (target_ulong)TEXTRA32_SVALUE,
+ "svalue");
+ warn_always_zero_bit(tdata3, (target_ulong)TEXTRA32_SSELECT,
+ "sselect");
+ break;
+ case MXL_RV64:
+ case MXL_RV128:
+ mhvalue = get_field(tdata3, TEXTRA64_MHVALUE);
+ mhselect = get_field(tdata3, TEXTRA64_MHSELECT);
+ /* Validate unimplemented (always zero) bits */
+ warn_always_zero_bit(tdata3, (target_ulong)TEXTRA64_SBYTEMASK,
+ "sbytemask");
+ warn_always_zero_bit(tdata3, (target_ulong)TEXTRA64_SVALUE,
+ "svalue");
+ warn_always_zero_bit(tdata3, (target_ulong)TEXTRA64_SSELECT,
+ "sselect");
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ /* Validate mhselect. */
+ mhselect_new = mhselect_no_rvh[mhselect];
+ if (mhselect != mhselect_new) {
+ qemu_log_mask(LOG_UNIMP, "mhselect only supports 0 or 4 for now\n");
+ }
+
+ /* Write legal values into textra */
+ textra = 0;
+ switch (riscv_cpu_mxl(env)) {
+ case MXL_RV32:
+ textra = set_field(textra, TEXTRA32_MHVALUE, mhvalue);
+ textra = set_field(textra, TEXTRA32_MHSELECT, mhselect_new);
+ break;
+ case MXL_RV64:
+ case MXL_RV128:
+ textra = set_field(textra, TEXTRA64_MHVALUE, mhvalue);
+ textra = set_field(textra, TEXTRA64_MHSELECT, mhselect_new);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ return textra;
+}
+
static void do_trigger_action(CPURISCVState *env, target_ulong trigger_index)
{
trigger_action_t action = get_trigger_action(env, trigger_index);
@@ -304,11 +364,54 @@ static bool trigger_priv_match(CPURISCVState *env, trigger_type_t type,
return false;
}
+static bool trigger_textra_match(CPURISCVState *env, trigger_type_t type,
+ int trigger_index)
+{
+ target_ulong textra = env->tdata3[trigger_index];
+ target_ulong mhvalue, mhselect;
+
+ if (type < TRIGGER_TYPE_AD_MATCH || type > TRIGGER_TYPE_AD_MATCH6) {
+ /* textra checking is only applicable when type is 2, 3, 4, 5, or 6 */
+ return true;
+ }
+
+ switch (riscv_cpu_mxl(env)) {
+ case MXL_RV32:
+ mhvalue = get_field(textra, TEXTRA32_MHVALUE);
+ mhselect = get_field(textra, TEXTRA32_MHSELECT);
+ break;
+ case MXL_RV64:
+ case MXL_RV128:
+ mhvalue = get_field(textra, TEXTRA64_MHVALUE);
+ mhselect = get_field(textra, TEXTRA64_MHSELECT);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ /* Check mhvalue and mhselect. */
+ switch (mhselect) {
+ case MHSELECT_IGNORE:
+ break;
+ case MHSELECT_MCONTEXT:
+ /* Match if the low bits of mcontext/hcontext equal mhvalue. */
+ if (mhvalue != env->mcontext) {
+ return false;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return true;
+}
+
/* Common matching conditions for all types of the triggers. */
static bool trigger_common_match(CPURISCVState *env, trigger_type_t type,
int trigger_index)
{
- return trigger_priv_match(env, type, trigger_index);
+ return trigger_priv_match(env, type, trigger_index) &&
+ trigger_textra_match(env, type, trigger_index);
}
/* type 2 trigger */
@@ -441,8 +544,7 @@ static void type2_reg_write(CPURISCVState *env, target_ulong index,
}
break;
case TDATA3:
- qemu_log_mask(LOG_UNIMP,
- "tdata3 is not supported for type 2 trigger\n");
+ env->tdata3[index] = textra_validate(env, val);
break;
default:
g_assert_not_reached();
@@ -558,8 +660,7 @@ static void type6_reg_write(CPURISCVState *env, target_ulong index,
}
break;
case TDATA3:
- qemu_log_mask(LOG_UNIMP,
- "tdata3 is not supported for type 6 trigger\n");
+ env->tdata3[index] = textra_validate(env, val);
break;
default:
g_assert_not_reached();
@@ -741,8 +842,7 @@ static void itrigger_reg_write(CPURISCVState *env, target_ulong index,
"tdata2 is not supported for icount trigger\n");
break;
case TDATA3:
- qemu_log_mask(LOG_UNIMP,
- "tdata3 is not supported for icount trigger\n");
+ env->tdata3[index] = textra_validate(env, val);
break;
default:
g_assert_not_reached();
diff --git a/target/riscv/debug.h b/target/riscv/debug.h
index c347863..f76b8f9 100644
--- a/target/riscv/debug.h
+++ b/target/riscv/debug.h
@@ -131,6 +131,9 @@ enum {
#define ITRIGGER_VU BIT(25)
#define ITRIGGER_VS BIT(26)
+#define MHSELECT_IGNORE 0
+#define MHSELECT_MCONTEXT 4
+
bool tdata_available(CPURISCVState *env, int tdata_index);
target_ulong tselect_csr_read(CPURISCVState *env);
diff --git a/target/riscv/insn16.decode b/target/riscv/insn16.decode
index b96c534..3953bcf 100644
--- a/target/riscv/insn16.decode
+++ b/target/riscv/insn16.decode
@@ -140,6 +140,7 @@ sw 110 ... ... .. ... 00 @cs_w
addi 000 . ..... ..... 01 @ci
addi 010 . ..... ..... 01 @c_li
{
+ c_mop_n 011 0 0 n:3 1 00000 01
illegal 011 0 ----- 00000 01 # c.addi16sp and c.lui, RES nzimm=0
addi 011 . 00010 ..... 01 @c_addi16sp
lui 011 . ..... ..... 01 @c_lui
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index f22df04..c45b8fa 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -38,6 +38,8 @@
%imm_bs 30:2 !function=ex_shift_3
%imm_rnum 20:4
%imm_z6 26:1 15:5
+%imm_mop5 30:1 26:2 20:2
+%imm_mop3 30:1 26:2
# Argument sets:
&empty
@@ -56,6 +58,8 @@
&r2nfvm vm rd rs1 nf
&rnfvm vm rd rs1 rs2 nf
&k_aes shamt rs2 rs1 rd
+&mop5 imm rd rs1
+&mop3 imm rd rs1 rs2
# Formats 32:
@r ....... ..... ..... ... ..... ....... &r %rs2 %rs1 %rd
@@ -98,6 +102,9 @@
@k_aes .. ..... ..... ..... ... ..... ....... &k_aes shamt=%imm_bs %rs2 %rs1 %rd
@i_aes .. ..... ..... ..... ... ..... ....... &i imm=%imm_rnum %rs1 %rd
+@mop5 . . .. .. .... .. ..... ... ..... ....... &mop5 imm=%imm_mop5 %rd %rs1
+@mop3 . . .. .. . ..... ..... ... ..... ....... &mop3 imm=%imm_mop3 %rd %rs1 %rs2
+
# Formats 64:
@sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd
@@ -1010,3 +1017,29 @@ amocas_w 00101 . . ..... ..... 010 ..... 0101111 @atom_st
amocas_d 00101 . . ..... ..... 011 ..... 0101111 @atom_st
# *** RV64 Zacas Standard Extension ***
amocas_q 00101 . . ..... ..... 100 ..... 0101111 @atom_st
+
+# *** Zimop may-be-operation extension ***
+mop_r_n 1 . 00 .. 0111 .. ..... 100 ..... 1110011 @mop5
+mop_rr_n 1 . 00 .. 1 ..... ..... 100 ..... 1110011 @mop3
+
+# *** Zabhb Standard Extension ***
+amoswap_b 00001 . . ..... ..... 000 ..... 0101111 @atom_st
+amoadd_b 00000 . . ..... ..... 000 ..... 0101111 @atom_st
+amoxor_b 00100 . . ..... ..... 000 ..... 0101111 @atom_st
+amoand_b 01100 . . ..... ..... 000 ..... 0101111 @atom_st
+amoor_b 01000 . . ..... ..... 000 ..... 0101111 @atom_st
+amomin_b 10000 . . ..... ..... 000 ..... 0101111 @atom_st
+amomax_b 10100 . . ..... ..... 000 ..... 0101111 @atom_st
+amominu_b 11000 . . ..... ..... 000 ..... 0101111 @atom_st
+amomaxu_b 11100 . . ..... ..... 000 ..... 0101111 @atom_st
+amoswap_h 00001 . . ..... ..... 001 ..... 0101111 @atom_st
+amoadd_h 00000 . . ..... ..... 001 ..... 0101111 @atom_st
+amoxor_h 00100 . . ..... ..... 001 ..... 0101111 @atom_st
+amoand_h 01100 . . ..... ..... 001 ..... 0101111 @atom_st
+amoor_h 01000 . . ..... ..... 001 ..... 0101111 @atom_st
+amomin_h 10000 . . ..... ..... 001 ..... 0101111 @atom_st
+amomax_h 10100 . . ..... ..... 001 ..... 0101111 @atom_st
+amominu_h 11000 . . ..... ..... 001 ..... 0101111 @atom_st
+amomaxu_h 11100 . . ..... ..... 001 ..... 0101111 @atom_st
+amocas_b 00101 . . ..... ..... 000 ..... 0101111 @atom_st
+amocas_h 00101 . . ..... ..... 001 ..... 0101111 @atom_st
diff --git a/target/riscv/insn_trans/trans_rva.c.inc b/target/riscv/insn_trans/trans_rva.c.inc
index 4a9e459..39bbf60 100644
--- a/target/riscv/insn_trans/trans_rva.c.inc
+++ b/target/riscv/insn_trans/trans_rva.c.inc
@@ -96,21 +96,6 @@ static bool gen_sc(DisasContext *ctx, arg_atomic *a, MemOp mop)
return true;
}
-static bool gen_amo(DisasContext *ctx, arg_atomic *a,
- void(*func)(TCGv, TCGv, TCGv, TCGArg, MemOp),
- MemOp mop)
-{
- TCGv dest = dest_gpr(ctx, a->rd);
- TCGv src1, src2 = get_gpr(ctx, a->rs2, EXT_NONE);
-
- decode_save_opc(ctx);
- src1 = get_address(ctx, a->rs1, 0);
- func(dest, src1, src2, ctx->mem_idx, mop);
-
- gen_set_gpr(ctx, a->rd, dest);
- return true;
-}
-
static bool trans_lr_w(DisasContext *ctx, arg_lr_w *a)
{
REQUIRE_A_OR_ZALRSC(ctx);
@@ -126,55 +111,55 @@ static bool trans_sc_w(DisasContext *ctx, arg_sc_w *a)
static bool trans_amoswap_w(DisasContext *ctx, arg_amoswap_w *a)
{
REQUIRE_A_OR_ZAAMO(ctx);
- return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TESL));
+ return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, MO_TESL);
}
static bool trans_amoadd_w(DisasContext *ctx, arg_amoadd_w *a)
{
REQUIRE_A_OR_ZAAMO(ctx);
- return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TESL));
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, MO_TESL);
}
static bool trans_amoxor_w(DisasContext *ctx, arg_amoxor_w *a)
{
REQUIRE_A_OR_ZAAMO(ctx);
- return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TESL));
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, MO_TESL);
}
static bool trans_amoand_w(DisasContext *ctx, arg_amoand_w *a)
{
REQUIRE_A_OR_ZAAMO(ctx);
- return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TESL));
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, MO_TESL);
}
static bool trans_amoor_w(DisasContext *ctx, arg_amoor_w *a)
{
REQUIRE_A_OR_ZAAMO(ctx);
- return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TESL));
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, MO_TESL);
}
static bool trans_amomin_w(DisasContext *ctx, arg_amomin_w *a)
{
REQUIRE_A_OR_ZAAMO(ctx);
- return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TESL));
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, MO_TESL);
}
static bool trans_amomax_w(DisasContext *ctx, arg_amomax_w *a)
{
REQUIRE_A_OR_ZAAMO(ctx);
- return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TESL));
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, MO_TESL);
}
static bool trans_amominu_w(DisasContext *ctx, arg_amominu_w *a)
{
REQUIRE_A_OR_ZAAMO(ctx);
- return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TESL));
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, MO_TESL);
}
static bool trans_amomaxu_w(DisasContext *ctx, arg_amomaxu_w *a)
{
REQUIRE_A_OR_ZAAMO(ctx);
- return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TESL));
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, MO_TESL);
}
static bool trans_lr_d(DisasContext *ctx, arg_lr_d *a)
@@ -195,61 +180,61 @@ static bool trans_amoswap_d(DisasContext *ctx, arg_amoswap_d *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_A_OR_ZAAMO(ctx);
- return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TEUQ));
+ return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, MO_TEUQ);
}
static bool trans_amoadd_d(DisasContext *ctx, arg_amoadd_d *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_A_OR_ZAAMO(ctx);
- return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TEUQ));
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, MO_TEUQ);
}
static bool trans_amoxor_d(DisasContext *ctx, arg_amoxor_d *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_A_OR_ZAAMO(ctx);
- return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TEUQ));
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, MO_TEUQ);
}
static bool trans_amoand_d(DisasContext *ctx, arg_amoand_d *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_A_OR_ZAAMO(ctx);
- return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TEUQ));
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, MO_TEUQ);
}
static bool trans_amoor_d(DisasContext *ctx, arg_amoor_d *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_A_OR_ZAAMO(ctx);
- return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TEUQ));
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, MO_TEUQ);
}
static bool trans_amomin_d(DisasContext *ctx, arg_amomin_d *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_A_OR_ZAAMO(ctx);
- return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TEUQ));
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, MO_TEUQ);
}
static bool trans_amomax_d(DisasContext *ctx, arg_amomax_d *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_A_OR_ZAAMO(ctx);
- return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TEUQ));
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, MO_TEUQ);
}
static bool trans_amominu_d(DisasContext *ctx, arg_amominu_d *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_A_OR_ZAAMO(ctx);
- return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TEUQ));
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, MO_TEUQ);
}
static bool trans_amomaxu_d(DisasContext *ctx, arg_amomaxu_d *a)
{
REQUIRE_64BIT(ctx);
REQUIRE_A_OR_ZAAMO(ctx);
- return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TEUQ));
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, MO_TEUQ);
}
diff --git a/target/riscv/insn_trans/trans_rvd.c.inc b/target/riscv/insn_trans/trans_rvd.c.inc
index d9ce9e4..8a46124 100644
--- a/target/riscv/insn_trans/trans_rvd.c.inc
+++ b/target/riscv/insn_trans/trans_rvd.c.inc
@@ -42,13 +42,28 @@
static bool trans_fld(DisasContext *ctx, arg_fld *a)
{
TCGv addr;
+ MemOp memop = MO_TEUQ;
REQUIRE_FPU;
REQUIRE_EXT(ctx, RVD);
+ /*
+ * FLD and FSD are only guaranteed to execute atomically if the effective
+ * address is naturally aligned and XLENā‰„64. Also, zama16b applies to
+ * loads and stores of no more than MXLEN bits defined in the F, D, and
+ * Q extensions.
+ */
+ if (get_xl_max(ctx) == MXL_RV32) {
+ memop |= MO_ATOM_NONE;
+ } else if (ctx->cfg_ptr->ext_zama16b) {
+ memop |= MO_ATOM_WITHIN16;
+ } else {
+ memop |= MO_ATOM_IFALIGN;
+ }
+
decode_save_opc(ctx);
addr = get_address(ctx, a->rs1, a->imm);
- tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], addr, ctx->mem_idx, MO_TEUQ);
+ tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], addr, ctx->mem_idx, memop);
mark_fs_dirty(ctx);
return true;
@@ -57,13 +72,22 @@ static bool trans_fld(DisasContext *ctx, arg_fld *a)
static bool trans_fsd(DisasContext *ctx, arg_fsd *a)
{
TCGv addr;
+ MemOp memop = MO_TEUQ;
REQUIRE_FPU;
REQUIRE_EXT(ctx, RVD);
+ if (get_xl_max(ctx) == MXL_RV32) {
+ memop |= MO_ATOM_NONE;
+ } else if (ctx->cfg_ptr->ext_zama16b) {
+ memop |= MO_ATOM_WITHIN16;
+ } else {
+ memop |= MO_ATOM_IFALIGN;
+ }
+
decode_save_opc(ctx);
addr = get_address(ctx, a->rs1, a->imm);
- tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEUQ);
+ tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, memop);
return true;
}
diff --git a/target/riscv/insn_trans/trans_rvf.c.inc b/target/riscv/insn_trans/trans_rvf.c.inc
index 97a3689..0222a72 100644
--- a/target/riscv/insn_trans/trans_rvf.c.inc
+++ b/target/riscv/insn_trans/trans_rvf.c.inc
@@ -43,14 +43,19 @@ static bool trans_flw(DisasContext *ctx, arg_flw *a)
{
TCGv_i64 dest;
TCGv addr;
+ MemOp memop = MO_TEUL;
REQUIRE_FPU;
REQUIRE_EXT(ctx, RVF);
+ if (ctx->cfg_ptr->ext_zama16b) {
+ memop |= MO_ATOM_WITHIN16;
+ }
+
decode_save_opc(ctx);
addr = get_address(ctx, a->rs1, a->imm);
dest = cpu_fpr[a->rd];
- tcg_gen_qemu_ld_i64(dest, addr, ctx->mem_idx, MO_TEUL);
+ tcg_gen_qemu_ld_i64(dest, addr, ctx->mem_idx, memop);
gen_nanbox_s(dest, dest);
mark_fs_dirty(ctx);
@@ -60,13 +65,18 @@ static bool trans_flw(DisasContext *ctx, arg_flw *a)
static bool trans_fsw(DisasContext *ctx, arg_fsw *a)
{
TCGv addr;
+ MemOp memop = MO_TEUL;
REQUIRE_FPU;
REQUIRE_EXT(ctx, RVF);
+ if (ctx->cfg_ptr->ext_zama16b) {
+ memop |= MO_ATOM_WITHIN16;
+ }
+
decode_save_opc(ctx);
addr = get_address(ctx, a->rs1, a->imm);
- tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEUL);
+ tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, memop);
return true;
}
diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc
index ad40d3e..fab5c06 100644
--- a/target/riscv/insn_trans/trans_rvi.c.inc
+++ b/target/riscv/insn_trans/trans_rvi.c.inc
@@ -268,6 +268,9 @@ static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop)
{
bool out;
+ if (ctx->cfg_ptr->ext_zama16b) {
+ memop |= MO_ATOM_WITHIN16;
+ }
decode_save_opc(ctx);
if (get_xl(ctx) == MXL_RV128) {
out = gen_load_i128(ctx, a, memop);
@@ -366,6 +369,9 @@ static bool gen_store_i128(DisasContext *ctx, arg_sb *a, MemOp memop)
static bool gen_store(DisasContext *ctx, arg_sb *a, MemOp memop)
{
+ if (ctx->cfg_ptr->ext_zama16b) {
+ memop |= MO_ATOM_WITHIN16;
+ }
decode_save_opc(ctx);
if (get_xl(ctx) == MXL_RV128) {
return gen_store_i128(ctx, a, memop);
diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc
index 3a3896b..f8928c4 100644
--- a/target/riscv/insn_trans/trans_rvv.c.inc
+++ b/target/riscv/insn_trans/trans_rvv.c.inc
@@ -3172,7 +3172,6 @@ static void load_element(TCGv_i64 dest, TCGv_ptr base,
break;
default:
g_assert_not_reached();
- break;
}
}
@@ -3257,7 +3256,6 @@ static void store_element(TCGv_i64 val, TCGv_ptr base,
break;
default:
g_assert_not_reached();
- break;
}
}
diff --git a/target/riscv/insn_trans/trans_rvzabha.c.inc b/target/riscv/insn_trans/trans_rvzabha.c.inc
new file mode 100644
index 0000000..ce8edcb
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvzabha.c.inc
@@ -0,0 +1,145 @@
+/*
+ * RISC-V translation routines for the Zabha Standard Extension.
+ *
+ * Copyright (c) 2024 Alibaba Group
+ *
+ * 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/>.
+ */
+
+#define REQUIRE_ZABHA(ctx) do { \
+ if (!ctx->cfg_ptr->ext_zabha) { \
+ return false; \
+ } \
+} while (0)
+
+static bool trans_amoswap_b(DisasContext *ctx, arg_amoswap_b *a)
+{
+ REQUIRE_ZABHA(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, MO_SB);
+}
+
+static bool trans_amoadd_b(DisasContext *ctx, arg_amoadd_b *a)
+{
+ REQUIRE_ZABHA(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, MO_SB);
+}
+
+static bool trans_amoxor_b(DisasContext *ctx, arg_amoxor_b *a)
+{
+ REQUIRE_ZABHA(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, MO_SB);
+}
+
+static bool trans_amoand_b(DisasContext *ctx, arg_amoand_b *a)
+{
+ REQUIRE_ZABHA(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, MO_SB);
+}
+
+static bool trans_amoor_b(DisasContext *ctx, arg_amoor_b *a)
+{
+ REQUIRE_ZABHA(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, MO_SB);
+}
+
+static bool trans_amomin_b(DisasContext *ctx, arg_amomin_b *a)
+{
+ REQUIRE_ZABHA(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, MO_SB);
+}
+
+static bool trans_amomax_b(DisasContext *ctx, arg_amomax_b *a)
+{
+ REQUIRE_ZABHA(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, MO_SB);
+}
+
+static bool trans_amominu_b(DisasContext *ctx, arg_amominu_b *a)
+{
+ REQUIRE_ZABHA(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, MO_SB);
+}
+
+static bool trans_amomaxu_b(DisasContext *ctx, arg_amomaxu_b *a)
+{
+ REQUIRE_ZABHA(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, MO_SB);
+}
+
+static bool trans_amoswap_h(DisasContext *ctx, arg_amoswap_h *a)
+{
+ REQUIRE_ZABHA(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, MO_TESW);
+}
+
+static bool trans_amoadd_h(DisasContext *ctx, arg_amoadd_h *a)
+{
+ REQUIRE_ZABHA(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, MO_TESW);
+}
+
+static bool trans_amoxor_h(DisasContext *ctx, arg_amoxor_h *a)
+{
+ REQUIRE_ZABHA(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, MO_TESW);
+}
+
+static bool trans_amoand_h(DisasContext *ctx, arg_amoand_h *a)
+{
+ REQUIRE_ZABHA(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, MO_TESW);
+}
+
+static bool trans_amoor_h(DisasContext *ctx, arg_amoor_h *a)
+{
+ REQUIRE_ZABHA(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, MO_TESW);
+}
+
+static bool trans_amomin_h(DisasContext *ctx, arg_amomin_h *a)
+{
+ REQUIRE_ZABHA(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, MO_TESW);
+}
+
+static bool trans_amomax_h(DisasContext *ctx, arg_amomax_h *a)
+{
+ REQUIRE_ZABHA(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, MO_TESW);
+}
+
+static bool trans_amominu_h(DisasContext *ctx, arg_amominu_h *a)
+{
+ REQUIRE_ZABHA(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, MO_TESW);
+}
+
+static bool trans_amomaxu_h(DisasContext *ctx, arg_amomaxu_h *a)
+{
+ REQUIRE_ZABHA(ctx);
+ return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, MO_TESW);
+}
+
+static bool trans_amocas_b(DisasContext *ctx, arg_amocas_b *a)
+{
+ REQUIRE_ZACAS(ctx);
+ REQUIRE_ZABHA(ctx);
+ return gen_cmpxchg(ctx, a, MO_SB);
+}
+
+static bool trans_amocas_h(DisasContext *ctx, arg_amocas_h *a)
+{
+ REQUIRE_ZACAS(ctx);
+ REQUIRE_ZABHA(ctx);
+ return gen_cmpxchg(ctx, a, MO_ALIGN | MO_TESW);
+}
diff --git a/target/riscv/insn_trans/trans_rvzacas.c.inc b/target/riscv/insn_trans/trans_rvzacas.c.inc
index 5d274d4..fcced99 100644
--- a/target/riscv/insn_trans/trans_rvzacas.c.inc
+++ b/target/riscv/insn_trans/trans_rvzacas.c.inc
@@ -22,19 +22,6 @@
} \
} while (0)
-static bool gen_cmpxchg(DisasContext *ctx, arg_atomic *a, MemOp mop)
-{
- TCGv dest = get_gpr(ctx, a->rd, EXT_NONE);
- TCGv src1 = get_address(ctx, a->rs1, 0);
- TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);
-
- decode_save_opc(ctx);
- tcg_gen_atomic_cmpxchg_tl(dest, src1, dest, src2, ctx->mem_idx, mop);
-
- gen_set_gpr(ctx, a->rd, dest);
- return true;
-}
-
static bool trans_amocas_w(DisasContext *ctx, arg_amocas_w *a)
{
REQUIRE_ZACAS(ctx);
diff --git a/target/riscv/insn_trans/trans_rvzcmop.c.inc b/target/riscv/insn_trans/trans_rvzcmop.c.inc
new file mode 100644
index 0000000..7205586
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvzcmop.c.inc
@@ -0,0 +1,29 @@
+/*
+ * RISC-V translation routines for compressed May-Be-Operation(zcmop).
+ *
+ * Copyright (c) 2024 Alibaba Group.
+ *
+ * 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/>.
+ */
+
+#define REQUIRE_ZCMOP(ctx) do { \
+ if (!ctx->cfg_ptr->ext_zcmop) { \
+ return false; \
+ } \
+} while (0)
+
+static bool trans_c_mop_n(DisasContext *ctx, arg_c_mop_n *a)
+{
+ REQUIRE_ZCMOP(ctx);
+ return true;
+}
diff --git a/target/riscv/insn_trans/trans_rvzimop.c.inc b/target/riscv/insn_trans/trans_rvzimop.c.inc
new file mode 100644
index 0000000..165aacd
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvzimop.c.inc
@@ -0,0 +1,37 @@
+/*
+ * RISC-V translation routines for May-Be-Operation(zimop).
+ *
+ * Copyright (c) 2024 Alibaba Group.
+ *
+ * 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/>.
+ */
+
+#define REQUIRE_ZIMOP(ctx) do { \
+ if (!ctx->cfg_ptr->ext_zimop) { \
+ return false; \
+ } \
+} while (0)
+
+static bool trans_mop_r_n(DisasContext *ctx, arg_mop_r_n *a)
+{
+ REQUIRE_ZIMOP(ctx);
+ gen_set_gpr(ctx, a->rd, ctx->zero);
+ return true;
+}
+
+static bool trans_mop_rr_n(DisasContext *ctx, arg_mop_rr_n *a)
+{
+ REQUIRE_ZIMOP(ctx);
+ gen_set_gpr(ctx, a->rd, ctx->zero);
+ return true;
+}
diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index 1047961..8233a32 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -281,6 +281,7 @@ static KVMCPUConfig kvm_multi_ext_cfgs[] = {
KVM_EXT_CFG("zihintntl", ext_zihintntl, KVM_RISCV_ISA_EXT_ZIHINTNTL),
KVM_EXT_CFG("zihintpause", ext_zihintpause, KVM_RISCV_ISA_EXT_ZIHINTPAUSE),
KVM_EXT_CFG("zihpm", ext_zihpm, KVM_RISCV_ISA_EXT_ZIHPM),
+ KVM_EXT_CFG("zacas", ext_zacas, KVM_RISCV_ISA_EXT_ZACAS),
KVM_EXT_CFG("zfa", ext_zfa, KVM_RISCV_ISA_EXT_ZFA),
KVM_EXT_CFG("zfh", ext_zfh, KVM_RISCV_ISA_EXT_ZFH),
KVM_EXT_CFG("zfhmin", ext_zfhmin, KVM_RISCV_ISA_EXT_ZFHMIN),
@@ -298,6 +299,7 @@ static KVMCPUConfig kvm_multi_ext_cfgs[] = {
KVM_EXT_CFG("zksed", ext_zksed, KVM_RISCV_ISA_EXT_ZKSED),
KVM_EXT_CFG("zksh", ext_zksh, KVM_RISCV_ISA_EXT_ZKSH),
KVM_EXT_CFG("zkt", ext_zkt, KVM_RISCV_ISA_EXT_ZKT),
+ KVM_EXT_CFG("ztso", ext_ztso, KVM_RISCV_ISA_EXT_ZTSO),
KVM_EXT_CFG("zvbb", ext_zvbb, KVM_RISCV_ISA_EXT_ZVBB),
KVM_EXT_CFG("zvbc", ext_zvbc, KVM_RISCV_ISA_EXT_ZVBC),
KVM_EXT_CFG("zvfh", ext_zvfh, KVM_RISCV_ISA_EXT_ZVFH),
@@ -1190,7 +1192,7 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
KVM_CAP_LAST_INFO
};
-int kvm_arch_get_registers(CPUState *cs)
+int kvm_arch_get_registers(CPUState *cs, Error **errp)
{
int ret = 0;
@@ -1235,7 +1237,7 @@ int kvm_riscv_sync_mpstate_to_kvm(RISCVCPU *cpu, int state)
return 0;
}
-int kvm_arch_put_registers(CPUState *cs, int level)
+int kvm_arch_put_registers(CPUState *cs, int level, Error **errp)
{
int ret = 0;
@@ -1693,6 +1695,7 @@ void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift,
uint64_t max_hart_per_socket = 0;
uint64_t socket, base_hart, hart_count, socket_imsic_base, imsic_addr;
uint64_t socket_bits, hart_bits, guest_bits;
+ uint64_t max_group_id;
aia_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_RISCV_AIA, false);
@@ -1740,7 +1743,8 @@ void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift,
if (socket_count > 1) {
- socket_bits = find_last_bit(&socket_count, BITS_PER_LONG) + 1;
+ max_group_id = socket_count - 1;
+ socket_bits = find_last_bit(&max_group_id, BITS_PER_LONG) + 1;
ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG,
KVM_DEV_RISCV_AIA_CONFIG_GROUP_BITS,
&socket_bits, true, NULL);
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 76f2150..492c2c6 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -320,15 +320,14 @@ static bool pmu_needed(void *opaque)
static const VMStateDescription vmstate_pmu_ctr_state = {
.name = "cpu/pmu",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.needed = pmu_needed,
.fields = (const VMStateField[]) {
VMSTATE_UINTTL(mhpmcounter_val, PMUCTRState),
VMSTATE_UINTTL(mhpmcounterh_val, PMUCTRState),
VMSTATE_UINTTL(mhpmcounter_prev, PMUCTRState),
VMSTATE_UINTTL(mhpmcounterh_prev, PMUCTRState),
- VMSTATE_BOOL(started, PMUCTRState),
VMSTATE_END_OF_LIST()
}
};
diff --git a/target/riscv/monitor.c b/target/riscv/monitor.c
index f5b1ffe..100005e 100644
--- a/target/riscv/monitor.c
+++ b/target/riscv/monitor.c
@@ -184,7 +184,6 @@ static void mem_info_svxx(Monitor *mon, CPUArchState *env)
break;
default:
g_assert_not_reached();
- break;
}
/* calculate virtual address bits */
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 2baf5bc..25a5263 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -51,7 +51,7 @@ target_ulong helper_csrr(CPURISCVState *env, int csr)
}
target_ulong val = 0;
- RISCVException ret = riscv_csrrw(env, csr, &val, 0, 0);
+ RISCVException ret = riscv_csrr(env, csr, &val);
if (ret != RISCV_EXCP_NONE) {
riscv_raise_exception(env, ret, GETPC());
@@ -84,9 +84,7 @@ target_ulong helper_csrrw(CPURISCVState *env, int csr,
target_ulong helper_csrr_i128(CPURISCVState *env, int csr)
{
Int128 rv = int128_zero();
- RISCVException ret = riscv_csrrw_i128(env, csr, &rv,
- int128_zero(),
- int128_zero());
+ RISCVException ret = riscv_csrr_i128(env, csr, &rv);
if (ret != RISCV_EXCP_NONE) {
riscv_raise_exception(env, ret, GETPC());
@@ -264,7 +262,7 @@ void helper_cbo_inval(CPURISCVState *env, target_ulong address)
target_ulong helper_sret(CPURISCVState *env)
{
uint64_t mstatus;
- target_ulong prev_priv, prev_virt;
+ target_ulong prev_priv, prev_virt = env->virt_enabled;
if (!(env->priv >= PRV_S)) {
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
@@ -307,11 +305,9 @@ target_ulong helper_sret(CPURISCVState *env)
if (prev_virt) {
riscv_cpu_swap_hypervisor_regs(env);
}
-
- riscv_cpu_set_virt_enabled(env, prev_virt);
}
- riscv_cpu_set_mode(env, prev_priv);
+ riscv_cpu_set_mode(env, prev_priv, prev_virt);
return retpc;
}
@@ -347,16 +343,13 @@ target_ulong helper_mret(CPURISCVState *env)
mstatus = set_field(mstatus, MSTATUS_MPRV, 0);
}
env->mstatus = mstatus;
- riscv_cpu_set_mode(env, prev_priv);
- if (riscv_has_ext(env, RVH)) {
- if (prev_virt) {
- riscv_cpu_swap_hypervisor_regs(env);
- }
-
- riscv_cpu_set_virt_enabled(env, prev_virt);
+ if (riscv_has_ext(env, RVH) && prev_virt) {
+ riscv_cpu_swap_hypervisor_regs(env);
}
+ riscv_cpu_set_mode(env, prev_priv, prev_virt);
+
return retpc;
}
diff --git a/target/riscv/pmu.c b/target/riscv/pmu.c
index 0e7d58b..e05ab06 100644
--- a/target/riscv/pmu.c
+++ b/target/riscv/pmu.c
@@ -19,6 +19,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
+#include "qemu/timer.h"
#include "cpu.h"
#include "pmu.h"
#include "sysemu/cpu-timers.h"
@@ -176,6 +177,101 @@ static int riscv_pmu_incr_ctr_rv64(RISCVCPU *cpu, uint32_t ctr_idx)
return 0;
}
+/*
+ * Information needed to update counters:
+ * new_priv, new_virt: To correctly save starting snapshot for the newly
+ * started mode. Look at array being indexed with newprv.
+ * old_priv, old_virt: To correctly select previous snapshot for old priv
+ * and compute delta. Also to select correct counter
+ * to inc. Look at arrays being indexed with env->priv.
+ *
+ * To avoid the complexity of calling this function, we assume that
+ * env->priv and env->virt_enabled contain old priv and old virt and
+ * new priv and new virt values are passed in as arguments.
+ */
+static void riscv_pmu_icount_update_priv(CPURISCVState *env,
+ target_ulong newpriv, bool new_virt)
+{
+ uint64_t *snapshot_prev, *snapshot_new;
+ uint64_t current_icount;
+ uint64_t *counter_arr;
+ uint64_t delta;
+
+ if (icount_enabled()) {
+ current_icount = icount_get_raw();
+ } else {
+ current_icount = cpu_get_host_ticks();
+ }
+
+ if (env->virt_enabled) {
+ g_assert(env->priv <= PRV_S);
+ counter_arr = env->pmu_fixed_ctrs[1].counter_virt;
+ snapshot_prev = env->pmu_fixed_ctrs[1].counter_virt_prev;
+ } else {
+ counter_arr = env->pmu_fixed_ctrs[1].counter;
+ snapshot_prev = env->pmu_fixed_ctrs[1].counter_prev;
+ }
+
+ if (new_virt) {
+ g_assert(newpriv <= PRV_S);
+ snapshot_new = env->pmu_fixed_ctrs[1].counter_virt_prev;
+ } else {
+ snapshot_new = env->pmu_fixed_ctrs[1].counter_prev;
+ }
+
+ /*
+ * new_priv can be same as env->priv. So we need to calculate
+ * delta first before updating snapshot_new[new_priv].
+ */
+ delta = current_icount - snapshot_prev[env->priv];
+ snapshot_new[newpriv] = current_icount;
+
+ counter_arr[env->priv] += delta;
+}
+
+static void riscv_pmu_cycle_update_priv(CPURISCVState *env,
+ target_ulong newpriv, bool new_virt)
+{
+ uint64_t *snapshot_prev, *snapshot_new;
+ uint64_t current_ticks;
+ uint64_t *counter_arr;
+ uint64_t delta;
+
+ if (icount_enabled()) {
+ current_ticks = icount_get();
+ } else {
+ current_ticks = cpu_get_host_ticks();
+ }
+
+ if (env->virt_enabled) {
+ g_assert(env->priv <= PRV_S);
+ counter_arr = env->pmu_fixed_ctrs[0].counter_virt;
+ snapshot_prev = env->pmu_fixed_ctrs[0].counter_virt_prev;
+ } else {
+ counter_arr = env->pmu_fixed_ctrs[0].counter;
+ snapshot_prev = env->pmu_fixed_ctrs[0].counter_prev;
+ }
+
+ if (new_virt) {
+ g_assert(newpriv <= PRV_S);
+ snapshot_new = env->pmu_fixed_ctrs[0].counter_virt_prev;
+ } else {
+ snapshot_new = env->pmu_fixed_ctrs[0].counter_prev;
+ }
+
+ delta = current_ticks - snapshot_prev[env->priv];
+ snapshot_new[newpriv] = current_ticks;
+
+ counter_arr[env->priv] += delta;
+}
+
+void riscv_pmu_update_fixed_ctrs(CPURISCVState *env, target_ulong newpriv,
+ bool new_virt)
+{
+ riscv_pmu_cycle_update_priv(env, newpriv, new_virt);
+ riscv_pmu_icount_update_priv(env, newpriv, new_virt);
+}
+
int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx)
{
uint32_t ctr_idx;
@@ -193,8 +289,7 @@ int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx)
}
ctr_idx = GPOINTER_TO_UINT(value);
- if (!riscv_pmu_counter_enabled(cpu, ctr_idx) ||
- get_field(env->mcountinhibit, BIT(ctr_idx))) {
+ if (!riscv_pmu_counter_enabled(cpu, ctr_idx)) {
return -1;
}
@@ -325,15 +420,52 @@ int riscv_pmu_update_event_map(CPURISCVState *env, uint64_t value,
return 0;
}
+static bool pmu_hpmevent_is_of_set(CPURISCVState *env, uint32_t ctr_idx)
+{
+ target_ulong mhpmevent_val;
+ uint64_t of_bit_mask;
+
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ mhpmevent_val = env->mhpmeventh_val[ctr_idx];
+ of_bit_mask = MHPMEVENTH_BIT_OF;
+ } else {
+ mhpmevent_val = env->mhpmevent_val[ctr_idx];
+ of_bit_mask = MHPMEVENT_BIT_OF;
+ }
+
+ return get_field(mhpmevent_val, of_bit_mask);
+}
+
+static bool pmu_hpmevent_set_of_if_clear(CPURISCVState *env, uint32_t ctr_idx)
+{
+ target_ulong *mhpmevent_val;
+ uint64_t of_bit_mask;
+
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ mhpmevent_val = &env->mhpmeventh_val[ctr_idx];
+ of_bit_mask = MHPMEVENTH_BIT_OF;
+ } else {
+ mhpmevent_val = &env->mhpmevent_val[ctr_idx];
+ of_bit_mask = MHPMEVENT_BIT_OF;
+ }
+
+ if (!get_field(*mhpmevent_val, of_bit_mask)) {
+ *mhpmevent_val |= of_bit_mask;
+ return true;
+ }
+
+ return false;
+}
+
static void pmu_timer_trigger_irq(RISCVCPU *cpu,
enum riscv_pmu_event_idx evt_idx)
{
uint32_t ctr_idx;
CPURISCVState *env = &cpu->env;
PMUCTRState *counter;
- target_ulong *mhpmevent_val;
- uint64_t of_bit_mask;
int64_t irq_trigger_at;
+ uint64_t curr_ctr_val, curr_ctrh_val;
+ uint64_t ctr_val;
if (evt_idx != RISCV_PMU_EVENT_HW_CPU_CYCLES &&
evt_idx != RISCV_PMU_EVENT_HW_INSTRUCTIONS) {
@@ -346,12 +478,9 @@ static void pmu_timer_trigger_irq(RISCVCPU *cpu,
return;
}
- if (riscv_cpu_mxl(env) == MXL_RV32) {
- mhpmevent_val = &env->mhpmeventh_val[ctr_idx];
- of_bit_mask = MHPMEVENTH_BIT_OF;
- } else {
- mhpmevent_val = &env->mhpmevent_val[ctr_idx];
- of_bit_mask = MHPMEVENT_BIT_OF;
+ /* Generate interrupt only if OF bit is clear */
+ if (pmu_hpmevent_is_of_set(env, ctr_idx)) {
+ return;
}
counter = &env->pmu_ctrs[ctr_idx];
@@ -363,10 +492,28 @@ static void pmu_timer_trigger_irq(RISCVCPU *cpu,
return;
}
+ riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctr_val, false, ctr_idx);
+ ctr_val = counter->mhpmcounter_val;
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctrh_val, true, ctr_idx);
+ curr_ctr_val = curr_ctr_val | (curr_ctrh_val << 32);
+ ctr_val = ctr_val |
+ ((uint64_t)counter->mhpmcounterh_val << 32);
+ }
+
+ /*
+ * We can not accommodate for inhibited modes when setting up timer. Check
+ * if the counter has actually overflowed or not by comparing current
+ * counter value (accommodated for inhibited modes) with software written
+ * counter value.
+ */
+ if (curr_ctr_val >= ctr_val) {
+ riscv_pmu_setup_timer(env, curr_ctr_val, ctr_idx);
+ return;
+ }
+
if (cpu->pmu_avail_ctrs & BIT(ctr_idx)) {
- /* Generate interrupt only if OF bit is clear */
- if (!(*mhpmevent_val & of_bit_mask)) {
- *mhpmevent_val |= of_bit_mask;
+ if (pmu_hpmevent_set_of_if_clear(env, ctr_idx)) {
riscv_cpu_update_mip(env, MIP_LCOFIP, BOOL_TO_MASK(1));
}
}
@@ -384,12 +531,14 @@ void riscv_pmu_timer_cb(void *priv)
int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t value, uint32_t ctr_idx)
{
- uint64_t overflow_delta, overflow_at;
+ uint64_t overflow_delta, overflow_at, curr_ns;
int64_t overflow_ns, overflow_left = 0;
RISCVCPU *cpu = env_archcpu(env);
PMUCTRState *counter = &env->pmu_ctrs[ctr_idx];
- if (!riscv_pmu_counter_valid(cpu, ctr_idx) || !cpu->cfg.ext_sscofpmf) {
+ /* No need to setup a timer if LCOFI is disabled when OF is set */
+ if (!riscv_pmu_counter_valid(cpu, ctr_idx) || !cpu->cfg.ext_sscofpmf ||
+ pmu_hpmevent_is_of_set(env, ctr_idx)) {
return -1;
}
@@ -415,8 +564,10 @@ int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t value, uint32_t ctr_idx)
} else {
return -1;
}
- overflow_at = (uint64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- overflow_ns;
+ curr_ns = (uint64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ overflow_at = curr_ns + overflow_ns;
+ if (overflow_at <= curr_ns)
+ overflow_at = UINT64_MAX;
if (overflow_at > INT64_MAX) {
overflow_left += overflow_at - INT64_MAX;
diff --git a/target/riscv/pmu.h b/target/riscv/pmu.h
index 7c0ad66..3853d0e 100644
--- a/target/riscv/pmu.h
+++ b/target/riscv/pmu.h
@@ -34,5 +34,9 @@ int riscv_pmu_incr_ctr(RISCVCPU *cpu, enum riscv_pmu_event_idx event_idx);
void riscv_pmu_generate_fdt_node(void *fdt, uint32_t cmask, char *pmu_name);
int riscv_pmu_setup_timer(CPURISCVState *env, uint64_t value,
uint32_t ctr_idx);
+void riscv_pmu_update_fixed_ctrs(CPURISCVState *env, target_ulong newpriv,
+ bool new_virt);
+RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val,
+ bool upper_half, uint32_t ctr_idx);
#endif /* RISCV_PMU_H */
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index ecf366d..dea8ab7 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -549,6 +549,11 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
}
}
+ if (cpu->cfg.ext_zcmop && !cpu->cfg.ext_zca) {
+ error_setg(errp, "Zcmop extensions require Zca");
+ return;
+ }
+
if (mcc->misa_mxl_max != MXL_RV32 && cpu->cfg.ext_zcf) {
error_setg(errp, "Zcf extension is only relevant to RV32");
return;
@@ -773,11 +778,18 @@ static void cpu_enable_implied_rule(RISCVCPU *cpu,
if (!enabled) {
/* Enable the implied MISAs. */
if (rule->implied_misa_exts) {
- riscv_cpu_set_misa_ext(env,
- env->misa_ext | rule->implied_misa_exts);
-
for (i = 0; misa_bits[i] != 0; i++) {
if (rule->implied_misa_exts & misa_bits[i]) {
+ /*
+ * If the user disabled the misa_bit do not re-enable it
+ * and do not apply any implied rules related to it.
+ */
+ if (cpu_misa_ext_is_user_set(misa_bits[i]) &&
+ !(env->misa_ext & misa_bits[i])) {
+ continue;
+ }
+
+ riscv_cpu_set_misa_ext(env, env->misa_ext | misa_bits[i]);
ir = g_hash_table_lookup(misa_ext_implied_rules,
GUINT_TO_POINTER(misa_bits[i]));
diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c
index 8d245be..bc0d9a0 100644
--- a/target/riscv/time_helper.c
+++ b/target/riscv/time_helper.c
@@ -92,6 +92,7 @@ void riscv_timer_write_timecmp(CPURISCVState *env, QEMUTimer *timer,
* equals UINT64_MAX.
*/
if (timecmp == UINT64_MAX) {
+ timer_del(timer);
return;
}
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 0569224..acba90f 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -1077,6 +1077,41 @@ static bool gen_unary_per_ol(DisasContext *ctx, arg_r2 *a, DisasExtend ext,
return gen_unary(ctx, a, ext, f_tl);
}
+static bool gen_amo(DisasContext *ctx, arg_atomic *a,
+ void(*func)(TCGv, TCGv, TCGv, TCGArg, MemOp),
+ MemOp mop)
+{
+ TCGv dest = dest_gpr(ctx, a->rd);
+ TCGv src1, src2 = get_gpr(ctx, a->rs2, EXT_NONE);
+ MemOp size = mop & MO_SIZE;
+
+ if (ctx->cfg_ptr->ext_zama16b && size >= MO_32) {
+ mop |= MO_ATOM_WITHIN16;
+ } else {
+ mop |= MO_ALIGN;
+ }
+
+ decode_save_opc(ctx);
+ src1 = get_address(ctx, a->rs1, 0);
+ func(dest, src1, src2, ctx->mem_idx, mop);
+
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
+static bool gen_cmpxchg(DisasContext *ctx, arg_atomic *a, MemOp mop)
+{
+ TCGv dest = get_gpr(ctx, a->rd, EXT_NONE);
+ TCGv src1 = get_address(ctx, a->rs1, 0);
+ TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);
+
+ decode_save_opc(ctx);
+ tcg_gen_atomic_cmpxchg_tl(dest, src1, dest, src2, ctx->mem_idx, mop);
+
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
{
DisasContext *ctx = container_of(dcbase, DisasContext, base);
@@ -1097,8 +1132,10 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
#include "insn_trans/trans_rvb.c.inc"
#include "insn_trans/trans_rvzicond.c.inc"
#include "insn_trans/trans_rvzacas.c.inc"
+#include "insn_trans/trans_rvzabha.c.inc"
#include "insn_trans/trans_rvzawrs.c.inc"
#include "insn_trans/trans_rvzicbo.c.inc"
+#include "insn_trans/trans_rvzimop.c.inc"
#include "insn_trans/trans_rvzfa.c.inc"
#include "insn_trans/trans_rvzfh.c.inc"
#include "insn_trans/trans_rvk.c.inc"
@@ -1113,6 +1150,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
/* Include the auto-generated decoder for 16 bit insn */
#include "decode-insn16.c.inc"
#include "insn_trans/trans_rvzce.c.inc"
+#include "insn_trans/trans_rvzcmop.c.inc"
/* Include decoders for factored-out extensions */
#include "decode-XVentanaCondOps.c.inc"
diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c
index 1b4d5a8..072bd44 100644
--- a/target/riscv/vector_helper.c
+++ b/target/riscv/vector_helper.c
@@ -75,6 +75,8 @@ target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1,
vlmax = vext_get_vlmax(cpu->cfg.vlenb, vsew, lmul);
if (s1 <= vlmax) {
vl = s1;
+ } else if (s1 < 2 * vlmax && cpu->cfg.rvv_vl_half_avl) {
+ vl = (s1 + 1) >> 1;
} else {
vl = vlmax;
}
@@ -474,7 +476,6 @@ vext_ldff(void *vd, void *v0, target_ulong base,
vext_ldst_elem_fn *ldst_elem,
uint32_t log2_esz, uintptr_t ra)
{
- void *host;
uint32_t i, k, vl = 0;
uint32_t nf = vext_nf(desc);
uint32_t vm = vext_vm(desc);
@@ -493,27 +494,31 @@ vext_ldff(void *vd, void *v0, target_ulong base,
}
addr = adjust_addr(env, base + i * (nf << log2_esz));
if (i == 0) {
+ /* Allow fault on first element. */
probe_pages(env, addr, nf << log2_esz, ra, MMU_DATA_LOAD);
} else {
- /* if it triggers an exception, no need to check watchpoint */
remain = nf << log2_esz;
while (remain > 0) {
+ void *host;
+ int flags;
+
offset = -(addr | TARGET_PAGE_MASK);
- host = tlb_vaddr_to_host(env, addr, MMU_DATA_LOAD, mmu_index);
- if (host) {
-#ifdef CONFIG_USER_ONLY
- if (!page_check_range(addr, offset, PAGE_READ)) {
- vl = i;
- goto ProbeSuccess;
- }
-#else
- probe_pages(env, addr, offset, ra, MMU_DATA_LOAD);
-#endif
- } else {
+
+ /* Probe nonfault on subsequent elements. */
+ flags = probe_access_flags(env, addr, offset, MMU_DATA_LOAD,
+ mmu_index, true, &host, 0);
+
+ /*
+ * Stop if invalid (unmapped) or mmio (transaction may fail).
+ * Do not stop if watchpoint, as the spec says that
+ * first-fault should continue to access the same
+ * elements regardless of any watchpoint.
+ */
+ if (flags & ~TLB_WATCHPOINT) {
vl = i;
goto ProbeSuccess;
}
- if (remain <= offset) {
+ if (remain <= offset) {
break;
}
remain -= offset;
diff --git a/target/rx/translate.c b/target/rx/translate.c
index 9b81cf2..9aade2b 100644
--- a/target/rx/translate.c
+++ b/target/rx/translate.c
@@ -85,7 +85,8 @@ static uint32_t decode_load_bytes(DisasContext *ctx, uint32_t insn,
static uint32_t li(DisasContext *ctx, int sz)
{
- int32_t tmp, addr;
+ target_ulong addr;
+ uint32_t tmp;
CPURXState *env = ctx->env;
addr = ctx->base.pc_next;
diff --git a/target/s390x/cpu-param.h b/target/s390x/cpu-param.h
index 11d23b6..a05ffcf 100644
--- a/target/s390x/cpu-param.h
+++ b/target/s390x/cpu-param.h
@@ -2,7 +2,7 @@
* S/390 cpu parameters for qemu.
*
* Copyright (c) 2009 Ulrich Hecht
- * SPDX-License-Identifier: GPL-2.0+
+ * SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef S390_CPU_PARAM_H
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
index 0fbfcd3..4e41a3d 100644
--- a/target/s390x/cpu.c
+++ b/target/s390x/cpu.c
@@ -32,6 +32,7 @@
#include "sysemu/hw_accel.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
+#include "hw/resettable.h"
#include "fpu/softfloat-helpers.h"
#include "disas/capstone.h"
#include "sysemu/tcg.h"
@@ -162,23 +163,25 @@ static void s390_query_cpu_fast(CPUState *cpu, CpuInfoFast *value)
#endif
}
-/* S390CPUClass::reset() */
-static void s390_cpu_reset(CPUState *s, cpu_reset_type type)
+/* S390CPUClass Resettable reset_hold phase method */
+static void s390_cpu_reset_hold(Object *obj, ResetType type)
{
- S390CPU *cpu = S390_CPU(s);
+ S390CPU *cpu = S390_CPU(obj);
S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
CPUS390XState *env = &cpu->env;
- DeviceState *dev = DEVICE(s);
- scc->parent_reset(dev);
+ if (scc->parent_phases.hold) {
+ scc->parent_phases.hold(obj, type);
+ }
cpu->env.sigp_order = 0;
s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
switch (type) {
- case S390_CPU_RESET_CLEAR:
+ default:
+ /* RESET_TYPE_COLD: power on or "clear" reset */
memset(env, 0, offsetof(CPUS390XState, start_initial_reset_fields));
/* fall through */
- case S390_CPU_RESET_INITIAL:
+ case RESET_TYPE_S390_CPU_INITIAL:
/* initial reset does not clear everything! */
memset(&env->start_initial_reset_fields, 0,
offsetof(CPUS390XState, start_normal_reset_fields) -
@@ -203,7 +206,7 @@ static void s390_cpu_reset(CPUState *s, cpu_reset_type type)
set_float_detect_tininess(float_tininess_before_rounding,
&env->fpu_status);
/* fall through */
- case S390_CPU_RESET_NORMAL:
+ case RESET_TYPE_S390_CPU_NORMAL:
env->psw.mask &= ~PSW_MASK_RI;
memset(&env->start_normal_reset_fields, 0,
offsetof(CPUS390XState, end_reset_fields) -
@@ -212,20 +215,18 @@ static void s390_cpu_reset(CPUState *s, cpu_reset_type type)
env->pfault_token = -1UL;
env->bpbc = false;
break;
- default:
- g_assert_not_reached();
}
/* Reset state inside the kernel that we cannot access yet from QEMU. */
if (kvm_enabled()) {
switch (type) {
- case S390_CPU_RESET_CLEAR:
+ default:
kvm_s390_reset_vcpu_clear(cpu);
break;
- case S390_CPU_RESET_INITIAL:
+ case RESET_TYPE_S390_CPU_INITIAL:
kvm_s390_reset_vcpu_initial(cpu);
break;
- case S390_CPU_RESET_NORMAL:
+ case RESET_TYPE_S390_CPU_NORMAL:
kvm_s390_reset_vcpu_normal(cpu);
break;
}
@@ -315,12 +316,6 @@ static Property s390x_cpu_properties[] = {
DEFINE_PROP_END_OF_LIST()
};
-static void s390_cpu_reset_full(DeviceState *dev)
-{
- CPUState *s = CPU(dev);
- return s390_cpu_reset(s, S390_CPU_RESET_CLEAR);
-}
-
#ifdef CONFIG_TCG
#include "hw/core/tcg-cpu-ops.h"
@@ -383,15 +378,16 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data)
S390CPUClass *scc = S390_CPU_CLASS(oc);
CPUClass *cc = CPU_CLASS(scc);
DeviceClass *dc = DEVICE_CLASS(oc);
+ ResettableClass *rc = RESETTABLE_CLASS(oc);
device_class_set_parent_realize(dc, s390_cpu_realizefn,
&scc->parent_realize);
device_class_set_props(dc, s390x_cpu_properties);
dc->user_creatable = true;
- device_class_set_parent_reset(dc, s390_cpu_reset_full, &scc->parent_reset);
+ resettable_class_set_parent_phases(rc, NULL, s390_cpu_reset_hold, NULL,
+ &scc->parent_phases);
- scc->reset = s390_cpu_reset;
cc->class_by_name = s390_cpu_class_by_name,
cc->has_work = s390_cpu_has_work;
cc->mmu_index = s390x_cpu_mmu_index;
diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h
index d6b75ad..5ef61b1 100644
--- a/target/s390x/cpu.h
+++ b/target/s390x/cpu.h
@@ -133,7 +133,7 @@ typedef struct CPUArchState {
int32_t book_id;
int32_t drawer_id;
bool dedicated;
- CpuS390Entitlement entitlement; /* Used only for vertical polarization */
+ S390CpuEntitlement entitlement; /* Used only for vertical polarization */
uint64_t cpuid;
#endif
@@ -177,19 +177,11 @@ struct ArchCPU {
uint32_t irqstate_saved_size;
};
-typedef enum cpu_reset_type {
- S390_CPU_RESET_NORMAL,
- S390_CPU_RESET_INITIAL,
- S390_CPU_RESET_CLEAR,
-} cpu_reset_type;
-
/**
* S390CPUClass:
* @parent_realize: The parent class' realize handler.
- * @parent_reset: The parent class' reset handler.
+ * @parent_phases: The parent class' reset phase handlers.
* @load_normal: Performs a load normal.
- * @cpu_reset: Performs a CPU reset.
- * @initial_cpu_reset: Performs an initial CPU reset.
*
* An S/390 CPU model.
*/
@@ -203,9 +195,8 @@ struct S390CPUClass {
const char *desc;
DeviceRealize parent_realize;
- DeviceReset parent_reset;
+ ResettablePhases parent_phases;
void (*load_normal)(CPUState *cpu);
- void (*reset)(CPUState *cpu, cpu_reset_type type);
};
#ifndef CONFIG_USER_ONLY
@@ -872,16 +863,12 @@ static inline void s390_do_cpu_full_reset(CPUState *cs, run_on_cpu_data arg)
static inline void s390_do_cpu_reset(CPUState *cs, run_on_cpu_data arg)
{
- S390CPUClass *scc = S390_CPU_GET_CLASS(cs);
-
- scc->reset(cs, S390_CPU_RESET_NORMAL);
+ resettable_reset(OBJECT(cs), RESET_TYPE_S390_CPU_NORMAL);
}
static inline void s390_do_cpu_initial_reset(CPUState *cs, run_on_cpu_data arg)
{
- S390CPUClass *scc = S390_CPU_GET_CLASS(cs);
-
- scc->reset(cs, S390_CPU_RESET_INITIAL);
+ resettable_reset(OBJECT(cs), RESET_TYPE_S390_CPU_INITIAL);
}
static inline void s390_do_cpu_load_normal(CPUState *cs, run_on_cpu_data arg)
diff --git a/target/s390x/cpu_models_sysemu.c b/target/s390x/cpu_models_sysemu.c
index 977fbc6..f6df691 100644
--- a/target/s390x/cpu_models_sysemu.c
+++ b/target/s390x/cpu_models_sysemu.c
@@ -206,14 +206,6 @@ static void cpu_info_from_model(CpuModelInfo *info, const S390CPUModel *model,
} else {
info->props = QOBJECT(qdict);
}
-
- /* features flagged as deprecated */
- bitmap_zero(bitmap, S390_FEAT_MAX);
- s390_get_deprecated_features(bitmap);
-
- bitmap_and(bitmap, bitmap, model->def->full_feat, S390_FEAT_MAX);
- s390_feat_bitmap_to_ascii(bitmap, &info->deprecated_props, list_add_feat);
- info->has_deprecated_props = !!info->deprecated_props;
}
CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
@@ -224,6 +216,7 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
CpuModelExpansionInfo *expansion_info = NULL;
S390CPUModel s390_model;
bool delta_changes = false;
+ S390FeatBitmap deprecated_feats;
/* convert it to our internal representation */
cpu_model_from_info(&s390_model, model, "model", &err);
@@ -243,6 +236,22 @@ CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
expansion_info = g_new0(CpuModelExpansionInfo, 1);
expansion_info->model = g_malloc0(sizeof(*expansion_info->model));
cpu_info_from_model(expansion_info->model, &s390_model, delta_changes);
+
+ /* populate list of deprecated features */
+ bitmap_zero(deprecated_feats, S390_FEAT_MAX);
+ s390_get_deprecated_features(deprecated_feats);
+
+ if (delta_changes) {
+ /*
+ * Only populate deprecated features that are a
+ * subset of the features enabled on the CPU model.
+ */
+ bitmap_and(deprecated_feats, deprecated_feats,
+ s390_model.features, S390_FEAT_MAX);
+ }
+
+ s390_feat_bitmap_to_ascii(deprecated_feats,
+ &expansion_info->deprecated_props, list_add_feat);
return expansion_info;
}
diff --git a/target/s390x/diag.c b/target/s390x/diag.c
index 27ffd48..a1fd54d 100644
--- a/target/s390x/diag.c
+++ b/target/s390x/diag.c
@@ -133,7 +133,14 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
valid = subcode == DIAG308_PV_SET ? iplb_valid_pv(iplb) : iplb_valid(iplb);
if (!valid) {
- env->regs[r1 + 1] = DIAG_308_RC_INVALID;
+ if (subcode == DIAG308_SET && iplb->pbt == S390_IPL_TYPE_QEMU_SCSI) {
+ s390_rebuild_iplb(iplb->devno, iplb);
+ s390_ipl_update_diag308(iplb);
+ env->regs[r1 + 1] = DIAG_308_RC_OK;
+ } else {
+ env->regs[r1 + 1] = DIAG_308_RC_INVALID;
+ }
+
goto out;
}
diff --git a/target/s390x/gdbstub.c b/target/s390x/gdbstub.c
index a9f4eb9..63373f0 100644
--- a/target/s390x/gdbstub.c
+++ b/target/s390x/gdbstub.c
@@ -46,7 +46,7 @@ int s390_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
int s390_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
CPUS390XState *env = cpu_env(cs);
- target_ulong tmpl = ldtul_p(mem_buf);
+ target_ulong tmpl = ldq_be_p(mem_buf);
switch (n) {
case S390_PSWM_REGNUM:
@@ -88,7 +88,7 @@ static int cpu_write_ac_reg(CPUState *cs, uint8_t *mem_buf, int n)
switch (n) {
case S390_A0_REGNUM ... S390_A15_REGNUM:
- env->aregs[n] = ldl_p(mem_buf);
+ env->aregs[n] = ldl_be_p(mem_buf);
cpu_synchronize_post_init(env_cpu(env));
return 4;
default:
@@ -123,10 +123,10 @@ static int cpu_write_fp_reg(CPUState *cs, uint8_t *mem_buf, int n)
switch (n) {
case S390_FPC_REGNUM:
- env->fpc = ldl_p(mem_buf);
+ env->fpc = ldl_be_p(mem_buf);
return 4;
case S390_F0_REGNUM ... S390_F15_REGNUM:
- *get_freg(env, n - S390_F0_REGNUM) = ldtul_p(mem_buf);
+ *get_freg(env, n - S390_F0_REGNUM) = ldq_be_p(mem_buf);
return 8;
default:
return 0;
@@ -167,11 +167,11 @@ static int cpu_write_vreg(CPUState *cs, uint8_t *mem_buf, int n)
switch (n) {
case S390_V0L_REGNUM ... S390_V15L_REGNUM:
- env->vregs[n][1] = ldtul_p(mem_buf + 8);
+ env->vregs[n][1] = ldq_be_p(mem_buf + 8);
return 8;
case S390_V16_REGNUM ... S390_V31_REGNUM:
- env->vregs[n][0] = ldtul_p(mem_buf);
- env->vregs[n][1] = ldtul_p(mem_buf + 8);
+ env->vregs[n][0] = ldq_be_p(mem_buf);
+ env->vregs[n][1] = ldq_be_p(mem_buf + 8);
return 16;
default:
return 0;
@@ -203,7 +203,7 @@ static int cpu_write_c_reg(CPUState *cs, uint8_t *mem_buf, int n)
switch (n) {
case S390_C0_REGNUM ... S390_C15_REGNUM:
- env->cregs[n] = ldtul_p(mem_buf);
+ env->cregs[n] = ldq_be_p(mem_buf);
if (tcg_enabled()) {
tlb_flush(env_cpu(env));
}
@@ -246,19 +246,19 @@ static int cpu_write_virt_reg(CPUState *cs, uint8_t *mem_buf, int n)
switch (n) {
case S390_VIRT_CKC_REGNUM:
- env->ckc = ldtul_p(mem_buf);
+ env->ckc = ldq_be_p(mem_buf);
cpu_synchronize_post_init(cs);
return 8;
case S390_VIRT_CPUTM_REGNUM:
- env->cputm = ldtul_p(mem_buf);
+ env->cputm = ldq_be_p(mem_buf);
cpu_synchronize_post_init(cs);
return 8;
case S390_VIRT_BEA_REGNUM:
- env->gbea = ldtul_p(mem_buf);
+ env->gbea = ldq_be_p(mem_buf);
cpu_synchronize_post_init(cs);
return 8;
case S390_VIRT_PREFIX_REGNUM:
- env->psa = ldtul_p(mem_buf);
+ env->psa = ldq_be_p(mem_buf);
cpu_synchronize_post_init(cs);
return 8;
default:
@@ -298,19 +298,19 @@ static int cpu_write_virt_kvm_reg(CPUState *cs, uint8_t *mem_buf, int n)
switch (n) {
case S390_VIRT_KVM_PP_REGNUM:
- env->pp = ldtul_p(mem_buf);
+ env->pp = ldq_be_p(mem_buf);
cpu_synchronize_post_init(env_cpu(env));
return 8;
case S390_VIRT_KVM_PFT_REGNUM:
- env->pfault_token = ldtul_p(mem_buf);
+ env->pfault_token = ldq_be_p(mem_buf);
cpu_synchronize_post_init(env_cpu(env));
return 8;
case S390_VIRT_KVM_PFS_REGNUM:
- env->pfault_select = ldtul_p(mem_buf);
+ env->pfault_select = ldq_be_p(mem_buf);
cpu_synchronize_post_init(env_cpu(env));
return 8;
case S390_VIRT_KVM_PFC_REGNUM:
- env->pfault_compare = ldtul_p(mem_buf);
+ env->pfault_compare = ldq_be_p(mem_buf);
cpu_synchronize_post_init(env_cpu(env));
return 8;
default:
@@ -338,7 +338,7 @@ static int cpu_write_gs_reg(CPUState *cs, uint8_t *mem_buf, int n)
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
- env->gscb[n] = ldtul_p(mem_buf);
+ env->gscb[n] = ldq_be_p(mem_buf);
cpu_synchronize_post_init(env_cpu(env));
return 8;
}
diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c
index bbe45a4..a944f16 100644
--- a/target/s390x/ioinst.c
+++ b/target/s390x/ioinst.c
@@ -603,7 +603,7 @@ static int chsc_sei_nt2_have_event(void)
#define CHSC_SEI_NT2 (1ULL << 61)
static void ioinst_handle_chsc_sei(ChscReq *req, ChscResp *res)
{
- uint64_t selection_mask = ldq_p(&req->param1);
+ uint64_t selection_mask = ldq_be_p(&req->param1);
uint8_t *res_flags = (uint8_t *)res->data;
int have_event = 0;
int have_more = 0;
diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
index 94181d9..8ffe015 100644
--- a/target/s390x/kvm/kvm.c
+++ b/target/s390x/kvm/kvm.c
@@ -472,7 +472,7 @@ static int can_sync_regs(CPUState *cs, int regs)
#define KVM_SYNC_REQUIRED_REGS (KVM_SYNC_GPRS | KVM_SYNC_ACRS | \
KVM_SYNC_CRS | KVM_SYNC_PREFIX)
-int kvm_arch_put_registers(CPUState *cs, int level)
+int kvm_arch_put_registers(CPUState *cs, int level, Error **errp)
{
CPUS390XState *env = cpu_env(cs);
struct kvm_fpu fpu = {};
@@ -598,7 +598,7 @@ int kvm_arch_put_registers(CPUState *cs, int level)
return 0;
}
-int kvm_arch_get_registers(CPUState *cs)
+int kvm_arch_get_registers(CPUState *cs, Error **errp)
{
CPUS390XState *env = cpu_env(cs);
struct kvm_fpu fpu;
diff --git a/target/s390x/sigp.c b/target/s390x/sigp.c
index ad0ad61..08aaecf 100644
--- a/target/s390x/sigp.c
+++ b/target/s390x/sigp.c
@@ -251,24 +251,20 @@ static void sigp_restart(CPUState *cs, run_on_cpu_data arg)
static void sigp_initial_cpu_reset(CPUState *cs, run_on_cpu_data arg)
{
- S390CPU *cpu = S390_CPU(cs);
- S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
SigpInfo *si = arg.host_ptr;
cpu_synchronize_state(cs);
- scc->reset(cs, S390_CPU_RESET_INITIAL);
+ resettable_reset(OBJECT(cs), RESET_TYPE_S390_CPU_INITIAL);
cpu_synchronize_post_reset(cs);
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
static void sigp_cpu_reset(CPUState *cs, run_on_cpu_data arg)
{
- S390CPU *cpu = S390_CPU(cs);
- S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
SigpInfo *si = arg.host_ptr;
cpu_synchronize_state(cs);
- scc->reset(cs, S390_CPU_RESET_NORMAL);
+ resettable_reset(OBJECT(cs), RESET_TYPE_S390_CPU_NORMAL);
cpu_synchronize_post_reset(cs);
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c
index 6cdbc34..0e12dae 100644
--- a/target/s390x/tcg/mem_helper.c
+++ b/target/s390x/tcg/mem_helper.c
@@ -225,10 +225,7 @@ static void do_access_memset(CPUS390XState *env, vaddr vaddr, char *haddr,
uint8_t byte, uint16_t size, int mmu_idx,
uintptr_t ra)
{
-#ifdef CONFIG_USER_ONLY
- memset(haddr, byte, size);
-#else
- if (likely(haddr)) {
+ if (user_or_likely(haddr)) {
memset(haddr, byte, size);
} else {
MemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
@@ -236,20 +233,19 @@ static void do_access_memset(CPUS390XState *env, vaddr vaddr, char *haddr,
cpu_stb_mmu(env, vaddr + i, byte, oi, ra);
}
}
-#endif
}
static void access_memset(CPUS390XState *env, S390Access *desta,
uint8_t byte, uintptr_t ra)
{
-
+ set_helper_retaddr(ra);
do_access_memset(env, desta->vaddr1, desta->haddr1, byte, desta->size1,
desta->mmu_idx, ra);
- if (likely(!desta->size2)) {
- return;
+ if (unlikely(desta->size2)) {
+ do_access_memset(env, desta->vaddr2, desta->haddr2, byte,
+ desta->size2, desta->mmu_idx, ra);
}
- do_access_memset(env, desta->vaddr2, desta->haddr2, byte, desta->size2,
- desta->mmu_idx, ra);
+ clear_helper_retaddr();
}
static uint8_t access_get_byte(CPUS390XState *env, S390Access *access,
@@ -300,41 +296,39 @@ static void access_memmove(CPUS390XState *env, S390Access *desta,
S390Access *srca, uintptr_t ra)
{
int len = desta->size1 + desta->size2;
- int diff;
assert(len == srca->size1 + srca->size2);
/* Fallback to slow access in case we don't have access to all host pages */
- if (unlikely(!desta->haddr1 || (desta->size2 && !desta->haddr2) ||
- !srca->haddr1 || (srca->size2 && !srca->haddr2))) {
- int i;
-
- for (i = 0; i < len; i++) {
- uint8_t byte = access_get_byte(env, srca, i, ra);
-
- access_set_byte(env, desta, i, byte, ra);
- }
- return;
- }
-
- diff = desta->size1 - srca->size1;
- if (likely(diff == 0)) {
- memmove(desta->haddr1, srca->haddr1, srca->size1);
- if (unlikely(srca->size2)) {
- memmove(desta->haddr2, srca->haddr2, srca->size2);
- }
- } else if (diff > 0) {
- memmove(desta->haddr1, srca->haddr1, srca->size1);
- memmove(desta->haddr1 + srca->size1, srca->haddr2, diff);
- if (likely(desta->size2)) {
- memmove(desta->haddr2, srca->haddr2 + diff, desta->size2);
+ if (user_or_likely(desta->haddr1 &&
+ srca->haddr1 &&
+ (!desta->size2 || desta->haddr2) &&
+ (!srca->size2 || srca->haddr2))) {
+ int diff = desta->size1 - srca->size1;
+
+ if (likely(diff == 0)) {
+ memmove(desta->haddr1, srca->haddr1, srca->size1);
+ if (unlikely(srca->size2)) {
+ memmove(desta->haddr2, srca->haddr2, srca->size2);
+ }
+ } else if (diff > 0) {
+ memmove(desta->haddr1, srca->haddr1, srca->size1);
+ memmove(desta->haddr1 + srca->size1, srca->haddr2, diff);
+ if (likely(desta->size2)) {
+ memmove(desta->haddr2, srca->haddr2 + diff, desta->size2);
+ }
+ } else {
+ diff = -diff;
+ memmove(desta->haddr1, srca->haddr1, desta->size1);
+ memmove(desta->haddr2, srca->haddr1 + desta->size1, diff);
+ if (likely(srca->size2)) {
+ memmove(desta->haddr2 + diff, srca->haddr2, srca->size2);
+ }
}
} else {
- diff = -diff;
- memmove(desta->haddr1, srca->haddr1, desta->size1);
- memmove(desta->haddr2, srca->haddr1 + desta->size1, diff);
- if (likely(srca->size2)) {
- memmove(desta->haddr2 + diff, srca->haddr2, srca->size2);
+ for (int i = 0; i < len; i++) {
+ uint8_t byte = access_get_byte(env, srca, i, ra);
+ access_set_byte(env, desta, i, byte, ra);
}
}
}
@@ -372,6 +366,8 @@ static uint32_t do_helper_nc(CPUS390XState *env, uint32_t l, uint64_t dest,
access_prepare(&srca1, env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
access_prepare(&srca2, env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
access_prepare(&desta, env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
+ set_helper_retaddr(ra);
+
for (i = 0; i < l; i++) {
const uint8_t x = access_get_byte(env, &srca1, i, ra) &
access_get_byte(env, &srca2, i, ra);
@@ -379,6 +375,8 @@ static uint32_t do_helper_nc(CPUS390XState *env, uint32_t l, uint64_t dest,
c |= x;
access_set_byte(env, &desta, i, x, ra);
}
+
+ clear_helper_retaddr();
return c != 0;
}
@@ -413,6 +411,7 @@ static uint32_t do_helper_xc(CPUS390XState *env, uint32_t l, uint64_t dest,
return 0;
}
+ set_helper_retaddr(ra);
for (i = 0; i < l; i++) {
const uint8_t x = access_get_byte(env, &srca1, i, ra) ^
access_get_byte(env, &srca2, i, ra);
@@ -420,6 +419,7 @@ static uint32_t do_helper_xc(CPUS390XState *env, uint32_t l, uint64_t dest,
c |= x;
access_set_byte(env, &desta, i, x, ra);
}
+ clear_helper_retaddr();
return c != 0;
}
@@ -447,6 +447,8 @@ static uint32_t do_helper_oc(CPUS390XState *env, uint32_t l, uint64_t dest,
access_prepare(&srca1, env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
access_prepare(&srca2, env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
access_prepare(&desta, env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
+ set_helper_retaddr(ra);
+
for (i = 0; i < l; i++) {
const uint8_t x = access_get_byte(env, &srca1, i, ra) |
access_get_byte(env, &srca2, i, ra);
@@ -454,6 +456,8 @@ static uint32_t do_helper_oc(CPUS390XState *env, uint32_t l, uint64_t dest,
c |= x;
access_set_byte(env, &desta, i, x, ra);
}
+
+ clear_helper_retaddr();
return c != 0;
}
@@ -490,11 +494,13 @@ static uint32_t do_helper_mvc(CPUS390XState *env, uint32_t l, uint64_t dest,
} else if (!is_destructive_overlap(env, dest, src, l)) {
access_memmove(env, &desta, &srca, ra);
} else {
+ set_helper_retaddr(ra);
for (i = 0; i < l; i++) {
uint8_t byte = access_get_byte(env, &srca, i, ra);
access_set_byte(env, &desta, i, byte, ra);
}
+ clear_helper_retaddr();
}
return env->cc_op;
@@ -520,10 +526,12 @@ void HELPER(mvcrl)(CPUS390XState *env, uint64_t l, uint64_t dest, uint64_t src)
access_prepare(&srca, env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
access_prepare(&desta, env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
+ set_helper_retaddr(ra);
for (i = l - 1; i >= 0; i--) {
uint8_t byte = access_get_byte(env, &srca, i, ra);
access_set_byte(env, &desta, i, byte, ra);
}
+ clear_helper_retaddr();
}
/* move inverse */
@@ -540,11 +548,13 @@ void HELPER(mvcin)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
src = wrap_address(env, src - l + 1);
access_prepare(&srca, env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
access_prepare(&desta, env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
+
+ set_helper_retaddr(ra);
for (i = 0; i < l; i++) {
const uint8_t x = access_get_byte(env, &srca, l - i - 1, ra);
-
access_set_byte(env, &desta, i, x, ra);
}
+ clear_helper_retaddr();
}
/* move numerics */
@@ -561,12 +571,15 @@ void HELPER(mvn)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
access_prepare(&srca1, env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
access_prepare(&srca2, env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
access_prepare(&desta, env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
+
+ set_helper_retaddr(ra);
for (i = 0; i < l; i++) {
const uint8_t x = (access_get_byte(env, &srca1, i, ra) & 0x0f) |
(access_get_byte(env, &srca2, i, ra) & 0xf0);
access_set_byte(env, &desta, i, x, ra);
}
+ clear_helper_retaddr();
}
/* move with offset */
@@ -586,6 +599,8 @@ void HELPER(mvo)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
/* Handle rightmost byte */
byte_dest = cpu_ldub_data_ra(env, dest + len_dest - 1, ra);
+
+ set_helper_retaddr(ra);
byte_src = access_get_byte(env, &srca, len_src - 1, ra);
byte_dest = (byte_dest & 0x0f) | (byte_src << 4);
access_set_byte(env, &desta, len_dest - 1, byte_dest, ra);
@@ -601,6 +616,7 @@ void HELPER(mvo)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
byte_dest |= byte_src << 4;
access_set_byte(env, &desta, i, byte_dest, ra);
}
+ clear_helper_retaddr();
}
/* move zones */
@@ -617,12 +633,15 @@ void HELPER(mvz)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
access_prepare(&srca1, env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
access_prepare(&srca2, env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
access_prepare(&desta, env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
+
+ set_helper_retaddr(ra);
for (i = 0; i < l; i++) {
const uint8_t x = (access_get_byte(env, &srca1, i, ra) & 0xf0) |
(access_get_byte(env, &srca2, i, ra) & 0x0f);
access_set_byte(env, &desta, i, x, ra);
}
+ clear_helper_retaddr();
}
/* compare unsigned byte arrays */
@@ -967,15 +986,19 @@ uint32_t HELPER(mvst)(CPUS390XState *env, uint32_t r1, uint32_t r2)
*/
access_prepare(&srca, env, s, len, MMU_DATA_LOAD, mmu_idx, ra);
access_prepare(&desta, env, d, len, MMU_DATA_STORE, mmu_idx, ra);
+
+ set_helper_retaddr(ra);
for (i = 0; i < len; i++) {
const uint8_t v = access_get_byte(env, &srca, i, ra);
access_set_byte(env, &desta, i, v, ra);
if (v == c) {
+ clear_helper_retaddr();
set_address_zero(env, r1, d + i);
return 1;
}
}
+ clear_helper_retaddr();
set_address_zero(env, r1, d + len);
set_address_zero(env, r2, s + len);
return 3;
@@ -1066,6 +1089,7 @@ static inline uint32_t do_mvcl(CPUS390XState *env,
*dest = wrap_address(env, *dest + len);
} else {
access_prepare(&desta, env, *dest, len, MMU_DATA_STORE, mmu_idx, ra);
+ set_helper_retaddr(ra);
/* The remaining length selects the padding byte. */
for (i = 0; i < len; (*destlen)--, i++) {
@@ -1075,6 +1099,7 @@ static inline uint32_t do_mvcl(CPUS390XState *env,
access_set_byte(env, &desta, i, pad >> 8, ra);
}
}
+ clear_helper_retaddr();
*dest = wrap_address(env, *dest + len);
}
diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c
index c81e035..bcfff40 100644
--- a/target/s390x/tcg/translate.c
+++ b/target/s390x/tcg/translate.c
@@ -392,7 +392,6 @@ static int get_mem_index(DisasContext *s)
return MMU_HOME_IDX;
default:
g_assert_not_reached();
- break;
}
#endif
}
diff --git a/target/sh4/cpu-param.h b/target/sh4/cpu-param.h
index a7cdb7e..a30ba99 100644
--- a/target/sh4/cpu-param.h
+++ b/target/sh4/cpu-param.h
@@ -2,7 +2,7 @@
* SH4 cpu parameters for qemu.
*
* Copyright (c) 2005 Samuel Tardieu
- * SPDX-License-Identifier: LGPL-2.0+
+ * SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef SH4_CPU_PARAM_H
diff --git a/target/sh4/helper.c b/target/sh4/helper.c
index 6702910..9659c69 100644
--- a/target/sh4/helper.c
+++ b/target/sh4/helper.c
@@ -187,7 +187,7 @@ void superh_cpu_do_interrupt(CPUState *cs)
static void update_itlb_use(CPUSH4State * env, int itlbnb)
{
- uint8_t or_mask = 0, and_mask = (uint8_t) - 1;
+ uint32_t or_mask = 0, and_mask = 0xff;
switch (itlbnb) {
case 0:
diff --git a/target/sparc/cpu-param.h b/target/sparc/cpu-param.h
index 82293fb..14105dc 100644
--- a/target/sparc/cpu-param.h
+++ b/target/sparc/cpu-param.h
@@ -1,7 +1,7 @@
/*
* Sparc cpu parameters for qemu.
*
- * SPDX-License-Identifier: LGPL-2.0+
+ * SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef SPARC_CPU_PARAM_H
diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index dfd9512..f517e5a 100644
--- a/target/sparc/cpu.h
+++ b/target/sparc/cpu.h
@@ -184,6 +184,8 @@ enum {
#define FSR_FTT_SEQ_ERROR (4ULL << 14)
#define FSR_FTT_INVAL_FPR (6ULL << 14)
+#define FSR_QNE (1ULL << 13)
+
#define FSR_FCC0_SHIFT 10
#define FSR_FCC1_SHIFT 32
#define FSR_FCC2_SHIFT 34
@@ -438,6 +440,26 @@ struct CPUArchState {
uint32_t fsr_cexc_ftt; /* cexc, ftt */
uint32_t fcc[TARGET_FCCREGS]; /* fcc* */
+#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
+ /*
+ * Single-element FPU fault queue, with address and insn,
+ * packaged into the double-word with which it is stored.
+ */
+ uint32_t fsr_qne; /* qne */
+ union {
+ uint64_t d;
+ struct {
+#if HOST_BIG_ENDIAN
+ uint32_t addr;
+ uint32_t insn;
+#else
+ uint32_t insn;
+ uint32_t addr;
+#endif
+ } s;
+ } fq;
+#endif
+
CPU_DoubleU fpr[TARGET_DPREGS]; /* floating point registers */
uint32_t cwp; /* index of current register window (extracted
from PSR) */
@@ -722,6 +744,7 @@ trap_state* cpu_tsptr(CPUSPARCState* env);
#define TB_FLAG_AM_ENABLED (1 << 5)
#define TB_FLAG_SUPER (1 << 6)
#define TB_FLAG_HYPER (1 << 7)
+#define TB_FLAG_FSR_QNE (1 << 8)
#define TB_FLAG_ASI_SHIFT 24
static inline void cpu_get_tb_cpu_state(CPUSPARCState *env, vaddr *pc,
@@ -753,7 +776,12 @@ static inline void cpu_get_tb_cpu_state(CPUSPARCState *env, vaddr *pc,
if (env->psref) {
flags |= TB_FLAG_FPU_ENABLED;
}
-#endif
+#ifndef CONFIG_USER_ONLY
+ if (env->fsr_qne) {
+ flags |= TB_FLAG_FSR_QNE;
+ }
+#endif /* !CONFIG_USER_ONLY */
+#endif /* TARGET_SPARC64 */
*pflags = flags;
}
diff --git a/target/sparc/fop_helper.c b/target/sparc/fop_helper.c
index 0b30665..b669238 100644
--- a/target/sparc/fop_helper.c
+++ b/target/sparc/fop_helper.c
@@ -545,6 +545,8 @@ target_ulong cpu_get_fsr(CPUSPARCState *env)
fsr |= (uint64_t)env->fcc[1] << FSR_FCC1_SHIFT;
fsr |= (uint64_t)env->fcc[2] << FSR_FCC2_SHIFT;
fsr |= (uint64_t)env->fcc[3] << FSR_FCC3_SHIFT;
+#elif !defined(CONFIG_USER_ONLY)
+ fsr |= env->fsr_qne;
#endif
/* VER is kept completely separate until re-assembly. */
@@ -591,6 +593,8 @@ void cpu_put_fsr(CPUSPARCState *env, target_ulong fsr)
env->fcc[1] = extract64(fsr, FSR_FCC1_SHIFT, 2);
env->fcc[2] = extract64(fsr, FSR_FCC2_SHIFT, 2);
env->fcc[3] = extract64(fsr, FSR_FCC3_SHIFT, 2);
+#elif !defined(CONFIG_USER_ONLY)
+ env->fsr_qne = fsr & FSR_QNE;
#endif
set_fsr_nonsplit(env, fsr);
diff --git a/target/sparc/insns.decode b/target/sparc/insns.decode
index fbcb4f7..989c20b 100644
--- a/target/sparc/insns.decode
+++ b/target/sparc/insns.decode
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: LGPL-2.0+
+# SPDX-License-Identifier: LGPL-2.0-or-later
#
# Sparc instruction decode definitions.
# Copyright (c) 2023 Richard Henderson <rth@twiddle.net>
@@ -644,8 +644,8 @@ STF 11 ..... 100100 ..... . ............. @r_r_ri_na
STFSR 11 00000 100101 ..... . ............. @n_r_ri
STXFSR 11 00001 100101 ..... . ............. @n_r_ri
{
- STQF 11 ..... 100110 ..... . ............. @q_r_ri_na
- STDFQ 11 ----- 100110 ----- - -------------
+ STQF 11 ..... 100110 ..... . ............. @q_r_ri_na # v9
+ STDFQ 11 ..... 100110 ..... . ............. @r_r_ri # v7,v8
}
STDF 11 ..... 100111 ..... . ............. @d_r_ri_na
diff --git a/target/sparc/int32_helper.c b/target/sparc/int32_helper.c
index 6b7d65b..f2dd8bc 100644
--- a/target/sparc/int32_helper.c
+++ b/target/sparc/int32_helper.c
@@ -21,10 +21,10 @@
#include "qemu/main-loop.h"
#include "cpu.h"
#include "trace.h"
+#include "exec/cpu_ldst.h"
#include "exec/log.h"
#include "sysemu/runstate.h"
-
static const char * const excp_names[0x80] = {
[TT_TFAULT] = "Instruction Access Fault",
[TT_ILL_INSN] = "Illegal Instruction",
@@ -116,22 +116,9 @@ void sparc_cpu_do_interrupt(CPUState *cs)
qemu_log("%6d: %s (v=%02x)\n", count, name, intno);
log_cpu_state(cs, 0);
-#if 0
- {
- int i;
- uint8_t *ptr;
-
- qemu_log(" code=");
- ptr = (uint8_t *)env->pc;
- for (i = 0; i < 16; i++) {
- qemu_log(" %02x", ldub(ptr + i));
- }
- qemu_log("\n");
- }
-#endif
count++;
}
-#if !defined(CONFIG_USER_ONLY)
+#ifndef CONFIG_USER_ONLY
if (env->psret == 0) {
if (cs->exception_index == 0x80 &&
env->def.features & CPU_FEATURE_TA0_SHUTDOWN) {
@@ -143,6 +130,29 @@ void sparc_cpu_do_interrupt(CPUState *cs)
}
return;
}
+ if (intno == TT_FP_EXCP) {
+ /*
+ * The sparc32 fpu has three states related to exception handling.
+ * The FPop that signals an exception transitions from fp_execute
+ * to fp_exception_pending. A subsequent FPop transitions from
+ * fp_exception_pending to fp_exception, which forces the trap.
+ *
+ * If the queue is not empty, this trap is due to execution of an
+ * illegal FPop while in fp_exception state. Here we are to
+ * re-enter fp_exception_pending state without queuing the insn.
+ *
+ * We do not model the fp_exception_pending state, but instead
+ * skip directly to fp_exception state. We advance pc/npc to
+ * mimic delayed trap delivery as if by the subsequent insn.
+ */
+ if (!env->fsr_qne) {
+ env->fsr_qne = FSR_QNE;
+ env->fq.s.addr = env->pc;
+ env->fq.s.insn = cpu_ldl_code(env, env->pc);
+ }
+ env->pc = env->npc;
+ env->npc = env->npc + 4;
+ }
#endif
env->psret = 0;
cwp = cpu_cwp_dec(env, env->cwp - 1);
diff --git a/target/sparc/ldst_helper.c b/target/sparc/ldst_helper.c
index 2d48e98..d92c9f1 100644
--- a/target/sparc/ldst_helper.c
+++ b/target/sparc/ldst_helper.c
@@ -19,6 +19,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
+#include "qemu/range.h"
#include "cpu.h"
#include "tcg/tcg.h"
#include "exec/helper-proto.h"
@@ -240,9 +241,7 @@ static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
if (new_ctx == ctx) {
uint64_t vaddr = tlb[i].tag & ~0x1fffULL;
uint64_t size = 8192ULL << 3 * TTE_PGSIZE(tlb[i].tte);
- if (new_vaddr == vaddr
- || (new_vaddr < vaddr + size
- && vaddr < new_vaddr + new_size)) {
+ if (ranges_overlap(new_vaddr, new_size, vaddr, size)) {
DPRINTF_MMU("auto demap entry [%d] %lx->%lx\n", i, vaddr,
new_vaddr);
replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
diff --git a/target/sparc/machine.c b/target/sparc/machine.c
index 48e0cf2..222e570 100644
--- a/target/sparc/machine.c
+++ b/target/sparc/machine.c
@@ -143,6 +143,24 @@ static const VMStateInfo vmstate_xcc = {
.get = get_xcc,
.put = put_xcc,
};
+#else
+static bool fq_needed(void *opaque)
+{
+ SPARCCPU *cpu = opaque;
+ return cpu->env.fsr_qne;
+}
+
+static const VMStateDescription vmstate_fq = {
+ .name = "cpu/fq",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = fq_needed,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32(env.fq.s.addr, SPARCCPU),
+ VMSTATE_UINT32(env.fq.s.insn, SPARCCPU),
+ VMSTATE_END_OF_LIST()
+ },
+};
#endif
static int cpu_pre_save(void *opaque)
@@ -265,4 +283,11 @@ const VMStateDescription vmstate_sparc_cpu = {
#endif
VMSTATE_END_OF_LIST()
},
+#ifndef TARGET_SPARC64
+ .subsections = (const VMStateDescription * const []) {
+ &vmstate_fq,
+ NULL
+ },
+#endif
+
};
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index 1136390..cdd0a95 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -185,6 +185,8 @@ typedef struct DisasContext {
bool supervisor;
#ifdef TARGET_SPARC64
bool hypervisor;
+#else
+ bool fsr_qne;
#endif
#endif
@@ -1463,15 +1465,48 @@ static void gen_op_fpexception_im(DisasContext *dc, int ftt)
gen_exception(dc, TT_FP_EXCP);
}
-static int gen_trap_ifnofpu(DisasContext *dc)
+static bool gen_trap_ifnofpu(DisasContext *dc)
{
#if !defined(CONFIG_USER_ONLY)
if (!dc->fpu_enabled) {
gen_exception(dc, TT_NFPU_INSN);
- return 1;
+ return true;
+ }
+#endif
+ return false;
+}
+
+static bool gen_trap_iffpexception(DisasContext *dc)
+{
+#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
+ /*
+ * There are 3 states for the sparc32 fpu:
+ * Normally the fpu is in fp_execute, and all insns are allowed.
+ * When an exception is signaled, it moves to fp_exception_pending state.
+ * Upon seeing the next FPop, the fpu moves to fp_exception state,
+ * populates the FQ, and generates an fp_exception trap.
+ * The fpu remains in fp_exception state until FQ becomes empty
+ * after execution of a STDFQ instruction. While the fpu is in
+ * fp_exception state, and FPop, fp load or fp branch insn will
+ * return to fp_exception_pending state, set FSR.FTT to sequence_error,
+ * and the insn will not be entered into the FQ.
+ *
+ * In QEMU, we do not model the fp_exception_pending state and
+ * instead populate FQ and raise the exception immediately.
+ * But we can still honor fp_exception state by noticing when
+ * the FQ is not empty.
+ */
+ if (dc->fsr_qne) {
+ gen_op_fpexception_im(dc, FSR_FTT_SEQ_ERROR);
+ return true;
}
#endif
- return 0;
+ return false;
+}
+
+static bool gen_trap_if_nofpu_fpexception(DisasContext *dc)
+{
+ return gen_trap_ifnofpu(dc) || gen_trap_iffpexception(dc);
}
/* asi moves */
@@ -2641,7 +2676,7 @@ static bool do_fbpfcc(DisasContext *dc, arg_bcc *a)
{
DisasCompare cmp;
- if (gen_trap_ifnofpu(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
gen_fcompare(&cmp, a->cc, a->cond);
@@ -4480,7 +4515,7 @@ static bool do_ld_fpr(DisasContext *dc, arg_r_r_ri_asi *a, MemOp sz)
if (addr == NULL) {
return false;
}
- if (gen_trap_ifnofpu(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
if (sz == MO_128 && gen_trap_float128(dc)) {
@@ -4508,6 +4543,7 @@ static bool do_st_fpr(DisasContext *dc, arg_r_r_ri_asi *a, MemOp sz)
if (addr == NULL) {
return false;
}
+ /* Store insns are ok in fp_exception_pending state. */
if (gen_trap_ifnofpu(dc)) {
return true;
}
@@ -4521,7 +4557,7 @@ static bool do_st_fpr(DisasContext *dc, arg_r_r_ri_asi *a, MemOp sz)
TRANS(STF, ALL, do_st_fpr, a, MO_32)
TRANS(STDF, ALL, do_st_fpr, a, MO_64)
-TRANS(STQF, ALL, do_st_fpr, a, MO_128)
+TRANS(STQF, 64, do_st_fpr, a, MO_128)
TRANS(STFA, 64, do_st_fpr, a, MO_32)
TRANS(STDFA, 64, do_st_fpr, a, MO_64)
@@ -4529,17 +4565,41 @@ TRANS(STQFA, 64, do_st_fpr, a, MO_128)
static bool trans_STDFQ(DisasContext *dc, arg_STDFQ *a)
{
+ TCGv addr;
+
if (!avail_32(dc)) {
return false;
}
+ addr = gen_ldst_addr(dc, a->rs1, a->imm, a->rs2_or_imm);
+ if (addr == NULL) {
+ return false;
+ }
if (!supervisor(dc)) {
return raise_priv(dc);
}
+#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
if (gen_trap_ifnofpu(dc)) {
return true;
}
- gen_op_fpexception_im(dc, FSR_FTT_SEQ_ERROR);
- return true;
+ if (!dc->fsr_qne) {
+ gen_op_fpexception_im(dc, FSR_FTT_SEQ_ERROR);
+ return true;
+ }
+
+ /* Store the single element from the queue. */
+ TCGv_i64 fq = tcg_temp_new_i64();
+ tcg_gen_ld_i64(fq, tcg_env, offsetof(CPUSPARCState, fq.d));
+ tcg_gen_qemu_st_i64(fq, addr, dc->mem_idx, MO_TEUQ | MO_ALIGN_4);
+
+ /* Mark the queue empty, transitioning to fp_execute state. */
+ tcg_gen_st_i32(tcg_constant_i32(0), tcg_env,
+ offsetof(CPUSPARCState, fsr_qne));
+ dc->fsr_qne = 0;
+
+ return advance_pc(dc);
+#else
+ qemu_build_not_reached();
+#endif
}
static bool trans_LDFSR(DisasContext *dc, arg_r_r_ri *a)
@@ -4550,7 +4610,7 @@ static bool trans_LDFSR(DisasContext *dc, arg_r_r_ri *a)
if (addr == NULL) {
return false;
}
- if (gen_trap_ifnofpu(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
@@ -4574,7 +4634,7 @@ static bool do_ldxfsr(DisasContext *dc, arg_r_r_ri *a, bool entire)
if (addr == NULL) {
return false;
}
- if (gen_trap_ifnofpu(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
@@ -4611,6 +4671,7 @@ static bool do_stfsr(DisasContext *dc, arg_r_r_ri *a, MemOp mop)
if (addr == NULL) {
return false;
}
+ /* Store insns are ok in fp_exception_pending state. */
if (gen_trap_ifnofpu(dc)) {
return true;
}
@@ -4653,7 +4714,7 @@ static bool do_ff(DisasContext *dc, arg_r_r *a,
{
TCGv_i32 tmp;
- if (gen_trap_ifnofpu(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
@@ -4694,7 +4755,7 @@ static bool do_env_ff(DisasContext *dc, arg_r_r *a,
{
TCGv_i32 tmp;
- if (gen_trap_ifnofpu(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
@@ -4714,7 +4775,7 @@ static bool do_env_fd(DisasContext *dc, arg_r_r *a,
TCGv_i32 dst;
TCGv_i64 src;
- if (gen_trap_ifnofpu(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
@@ -4734,7 +4795,7 @@ static bool do_dd(DisasContext *dc, arg_r_r *a,
{
TCGv_i64 dst, src;
- if (gen_trap_ifnofpu(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
@@ -4756,7 +4817,7 @@ static bool do_env_dd(DisasContext *dc, arg_r_r *a,
{
TCGv_i64 dst, src;
- if (gen_trap_ifnofpu(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
@@ -4796,7 +4857,7 @@ static bool do_env_df(DisasContext *dc, arg_r_r *a,
TCGv_i64 dst;
TCGv_i32 src;
- if (gen_trap_ifnofpu(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
@@ -4839,7 +4900,7 @@ static bool do_env_qq(DisasContext *dc, arg_r_r *a,
{
TCGv_i128 t;
- if (gen_trap_ifnofpu(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
if (gen_trap_float128(dc)) {
@@ -4860,7 +4921,7 @@ static bool do_env_fq(DisasContext *dc, arg_r_r *a,
TCGv_i128 src;
TCGv_i32 dst;
- if (gen_trap_ifnofpu(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
if (gen_trap_float128(dc)) {
@@ -4883,7 +4944,7 @@ static bool do_env_dq(DisasContext *dc, arg_r_r *a,
TCGv_i128 src;
TCGv_i64 dst;
- if (gen_trap_ifnofpu(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
if (gen_trap_float128(dc)) {
@@ -4906,7 +4967,7 @@ static bool do_env_qf(DisasContext *dc, arg_r_r *a,
TCGv_i32 src;
TCGv_i128 dst;
- if (gen_trap_ifnofpu(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
if (gen_trap_float128(dc)) {
@@ -4929,10 +4990,7 @@ static bool do_env_qd(DisasContext *dc, arg_r_r *a,
TCGv_i64 src;
TCGv_i128 dst;
- if (gen_trap_ifnofpu(dc)) {
- return true;
- }
- if (gen_trap_float128(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
@@ -4989,7 +5047,7 @@ static bool do_env_fff(DisasContext *dc, arg_r_r_r *a,
{
TCGv_i32 src1, src2;
- if (gen_trap_ifnofpu(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
@@ -5198,7 +5256,7 @@ static bool do_env_ddd(DisasContext *dc, arg_r_r_r *a,
{
TCGv_i64 dst, src1, src2;
- if (gen_trap_ifnofpu(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
@@ -5222,7 +5280,7 @@ static bool trans_FsMULd(DisasContext *dc, arg_r_r_r *a)
TCGv_i64 dst;
TCGv_i32 src1, src2;
- if (gen_trap_ifnofpu(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
if (!(dc->def->features & CPU_FEATURE_FSMULD)) {
@@ -5331,7 +5389,7 @@ static bool do_env_qqq(DisasContext *dc, arg_r_r_r *a,
{
TCGv_i128 src1, src2;
- if (gen_trap_ifnofpu(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
if (gen_trap_float128(dc)) {
@@ -5355,7 +5413,7 @@ static bool trans_FdMULq(DisasContext *dc, arg_r_r_r *a)
TCGv_i64 src1, src2;
TCGv_i128 dst;
- if (gen_trap_ifnofpu(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
if (gen_trap_float128(dc)) {
@@ -5445,7 +5503,7 @@ static bool do_fcmps(DisasContext *dc, arg_FCMPs *a, bool e)
if (avail_32(dc) && a->cc != 0) {
return false;
}
- if (gen_trap_ifnofpu(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
@@ -5469,7 +5527,7 @@ static bool do_fcmpd(DisasContext *dc, arg_FCMPd *a, bool e)
if (avail_32(dc) && a->cc != 0) {
return false;
}
- if (gen_trap_ifnofpu(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
@@ -5493,7 +5551,7 @@ static bool do_fcmpq(DisasContext *dc, arg_FCMPq *a, bool e)
if (avail_32(dc) && a->cc != 0) {
return false;
}
- if (gen_trap_ifnofpu(dc)) {
+ if (gen_trap_if_nofpu_fpexception(dc)) {
return true;
}
if (gen_trap_float128(dc)) {
@@ -5596,13 +5654,15 @@ static void sparc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
dc->address_mask_32bit = tb_am_enabled(dc->base.tb->flags);
#ifndef CONFIG_USER_ONLY
dc->supervisor = (dc->base.tb->flags & TB_FLAG_SUPER) != 0;
+# ifdef TARGET_SPARC64
+ dc->hypervisor = (dc->base.tb->flags & TB_FLAG_HYPER) != 0;
+# else
+ dc->fsr_qne = (dc->base.tb->flags & TB_FLAG_FSR_QNE) != 0;
+# endif
#endif
#ifdef TARGET_SPARC64
dc->fprs_dirty = 0;
dc->asi = (dc->base.tb->flags >> TB_FLAG_ASI_SHIFT) & 0xff;
-#ifndef CONFIG_USER_ONLY
- dc->hypervisor = (dc->base.tb->flags & TB_FLAG_HYPER) != 0;
-#endif
#endif
/*
* if we reach a page boundary, we stop generation so that the
diff --git a/target/tricore/gdbstub.c b/target/tricore/gdbstub.c
index 29a7005..0b73b12 100644
--- a/target/tricore/gdbstub.c
+++ b/target/tricore/gdbstub.c
@@ -124,7 +124,7 @@ int tricore_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
CPUTriCoreState *env = cpu_env(cs);
uint32_t tmp;
- tmp = ldl_p(mem_buf);
+ tmp = ldl_le_p(mem_buf);
if (n < 16) { /* data registers */
env->gpr_d[n] = tmp;
diff --git a/target/tricore/op_helper.c b/target/tricore/op_helper.c
index ba9c444..a0d5a0d 100644
--- a/target/tricore/op_helper.c
+++ b/target/tricore/op_helper.c
@@ -1505,8 +1505,8 @@ uint32_t helper_sub_h(CPUTriCoreState *env, target_ulong r1, target_ulong r2)
uint32_t helper_eq_b(target_ulong r1, target_ulong r2)
{
- int32_t ret;
- int32_t i, msk;
+ uint32_t ret, msk;
+ int32_t i;
ret = 0;
msk = 0xff;
diff --git a/target/tricore/translate.c b/target/tricore/translate.c
index a46a03e..4a12d2c 100644
--- a/target/tricore/translate.c
+++ b/target/tricore/translate.c
@@ -2732,8 +2732,7 @@ static inline void gen_insert(TCGv ret, TCGv r1, TCGv r2, TCGv width, TCGv pos)
TCGv temp = tcg_temp_new();
TCGv temp2 = tcg_temp_new();
- tcg_gen_movi_tl(mask, 1);
- tcg_gen_shl_tl(mask, mask, width);
+ tcg_gen_shl_tl(mask, tcg_constant_tl(1), width);
tcg_gen_subi_tl(mask, mask, 1);
tcg_gen_shl_tl(mask, mask, pos);
diff --git a/target/xtensa/Kconfig b/target/xtensa/Kconfig
index 5e46049..e8c2598 100644
--- a/target/xtensa/Kconfig
+++ b/target/xtensa/Kconfig
@@ -1,3 +1,3 @@
config XTENSA
bool
- select SEMIHOSTING
+ imply SEMIHOSTING if TCG
diff --git a/target/xtensa/exc_helper.c b/target/xtensa/exc_helper.c
index 0514c2c..ca629f0 100644
--- a/target/xtensa/exc_helper.c
+++ b/target/xtensa/exc_helper.c
@@ -171,7 +171,7 @@ static void handle_interrupt(CPUXtensaState *env)
if (level > 1) {
/* env->config->nlevel check should have ensured this */
- assert(level < sizeof(env->config->interrupt_vector));
+ assert(level < ARRAY_SIZE(env->config->interrupt_vector));
env->sregs[EPC1 + level - 1] = env->pc;
env->sregs[EPS2 + level - 2] = env->sregs[PS];
diff --git a/target/xtensa/mmu_helper.c b/target/xtensa/mmu_helper.c
index 997b21d..29b84d5 100644
--- a/target/xtensa/mmu_helper.c
+++ b/target/xtensa/mmu_helper.c
@@ -991,7 +991,7 @@ uint32_t HELPER(rptlb1)(CPUXtensaState *env, uint32_t s)
uint32_t HELPER(pptlb)(CPUXtensaState *env, uint32_t v)
{
unsigned nhits;
- unsigned segment = XTENSA_MPU_PROBE_B;
+ unsigned segment;
unsigned bg_segment;
nhits = xtensa_mpu_lookup(env->mpu_fg, env->config->n_mpu_fg_segments,
@@ -1005,7 +1005,7 @@ uint32_t HELPER(pptlb)(CPUXtensaState *env, uint32_t v)
xtensa_mpu_lookup(env->config->mpu_bg,
env->config->n_mpu_bg_segments,
v, &bg_segment);
- return env->config->mpu_bg[bg_segment].attr | segment;
+ return env->config->mpu_bg[bg_segment].attr | XTENSA_MPU_PROBE_B;
}
}
diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c
index 75b7bfd..f4da4a4 100644
--- a/target/xtensa/translate.c
+++ b/target/xtensa/translate.c
@@ -521,7 +521,7 @@ static MemOp gen_load_store_alignment(DisasContext *dc, MemOp mop,
mop |= MO_ALIGN;
}
if (!option_enabled(dc, XTENSA_OPTION_UNALIGNED_EXCEPTION)) {
- tcg_gen_andi_i32(addr, addr, ~0 << get_alignment_bits(mop));
+ tcg_gen_andi_i32(addr, addr, ~0 << memop_alignment_bits(mop));
}
return mop;
}
diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc
index 3de5f50..56072d8 100644
--- a/tcg/arm/tcg-target.c.inc
+++ b/tcg/arm/tcg-target.c.inc
@@ -1587,7 +1587,7 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, MemOp opc, TCGReg datalo,
tcg_debug_assert((datalo & 1) == 0);
tcg_debug_assert(datahi == datalo + 1);
/* LDRD requires alignment; double-check that. */
- if (get_alignment_bits(opc) >= MO_64) {
+ if (memop_alignment_bits(opc) >= MO_64) {
if (h.index < 0) {
tcg_out_ldrd_8(s, h.cond, datalo, h.base, 0);
break;
@@ -1691,7 +1691,7 @@ static void tcg_out_qemu_st_direct(TCGContext *s, MemOp opc, TCGReg datalo,
tcg_debug_assert((datalo & 1) == 0);
tcg_debug_assert(datahi == datalo + 1);
/* STRD requires alignment; double-check that. */
- if (get_alignment_bits(opc) >= MO_64) {
+ if (memop_alignment_bits(opc) >= MO_64) {
if (h.index < 0) {
tcg_out_strd_8(s, h.cond, datalo, h.base, 0);
} else {
diff --git a/tcg/i386/tcg-target-con-set.h b/tcg/i386/tcg-target-con-set.h
index e24241c..06e6521 100644
--- a/tcg/i386/tcg-target-con-set.h
+++ b/tcg/i386/tcg-target-con-set.h
@@ -50,6 +50,7 @@ C_N1_I2(r, r, r)
C_N1_I2(r, r, rW)
C_O1_I3(x, 0, x, x)
C_O1_I3(x, x, x, x)
+C_O1_I4(x, x, x, xO, x)
C_O1_I4(r, r, reT, r, 0)
C_O1_I4(r, r, r, ri, ri)
C_O2_I1(r, r, L)
diff --git a/tcg/i386/tcg-target-con-str.h b/tcg/i386/tcg-target-con-str.h
index cc22db2..52142ab 100644
--- a/tcg/i386/tcg-target-con-str.h
+++ b/tcg/i386/tcg-target-con-str.h
@@ -28,6 +28,7 @@ REGS('s', ALL_BYTEL_REGS & ~SOFTMMU_RESERVE_REGS) /* qemu_st8_i32 data */
*/
CONST('e', TCG_CT_CONST_S32)
CONST('I', TCG_CT_CONST_I32)
+CONST('O', TCG_CT_CONST_ZERO)
CONST('T', TCG_CT_CONST_TST)
CONST('W', TCG_CT_CONST_WSZ)
CONST('Z', TCG_CT_CONST_U32)
diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc
index 9a54ef7..1bf50f1 100644
--- a/tcg/i386/tcg-target.c.inc
+++ b/tcg/i386/tcg-target.c.inc
@@ -133,6 +133,7 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot)
#define TCG_CT_CONST_I32 0x400
#define TCG_CT_CONST_WSZ 0x800
#define TCG_CT_CONST_TST 0x1000
+#define TCG_CT_CONST_ZERO 0x2000
/* Registers used with L constraint, which are the first argument
registers on x86_64, and two random call clobbered registers on
@@ -226,6 +227,9 @@ static bool tcg_target_const_match(int64_t val, int ct,
if ((ct & TCG_CT_CONST_WSZ) && val == (type == TCG_TYPE_I32 ? 32 : 64)) {
return 1;
}
+ if ((ct & TCG_CT_CONST_ZERO) && val == 0) {
+ return 1;
+ }
return 0;
}
@@ -409,6 +413,18 @@ static bool tcg_target_const_match(int64_t val, int ct,
#define OPC_UD2 (0x0b | P_EXT)
#define OPC_VPBLENDD (0x02 | P_EXT3A | P_DATA16)
#define OPC_VPBLENDVB (0x4c | P_EXT3A | P_DATA16)
+#define OPC_VPBLENDMB (0x66 | P_EXT38 | P_DATA16 | P_EVEX)
+#define OPC_VPBLENDMW (0x66 | P_EXT38 | P_DATA16 | P_VEXW | P_EVEX)
+#define OPC_VPBLENDMD (0x64 | P_EXT38 | P_DATA16 | P_EVEX)
+#define OPC_VPBLENDMQ (0x64 | P_EXT38 | P_DATA16 | P_VEXW | P_EVEX)
+#define OPC_VPCMPB (0x3f | P_EXT3A | P_DATA16 | P_EVEX)
+#define OPC_VPCMPUB (0x3e | P_EXT3A | P_DATA16 | P_EVEX)
+#define OPC_VPCMPW (0x3f | P_EXT3A | P_DATA16 | P_VEXW | P_EVEX)
+#define OPC_VPCMPUW (0x3e | P_EXT3A | P_DATA16 | P_VEXW | P_EVEX)
+#define OPC_VPCMPD (0x1f | P_EXT3A | P_DATA16 | P_EVEX)
+#define OPC_VPCMPUD (0x1e | P_EXT3A | P_DATA16 | P_EVEX)
+#define OPC_VPCMPQ (0x1f | P_EXT3A | P_DATA16 | P_VEXW | P_EVEX)
+#define OPC_VPCMPUQ (0x1e | P_EXT3A | P_DATA16 | P_VEXW | P_EVEX)
#define OPC_VPINSRB (0x20 | P_EXT3A | P_DATA16)
#define OPC_VPINSRW (0xc4 | P_EXT | P_DATA16)
#define OPC_VBROADCASTSS (0x18 | P_EXT38 | P_DATA16)
@@ -417,6 +433,10 @@ static bool tcg_target_const_match(int64_t val, int ct,
#define OPC_VPBROADCASTW (0x79 | P_EXT38 | P_DATA16)
#define OPC_VPBROADCASTD (0x58 | P_EXT38 | P_DATA16)
#define OPC_VPBROADCASTQ (0x59 | P_EXT38 | P_DATA16)
+#define OPC_VPMOVM2B (0x28 | P_EXT38 | P_SIMDF3 | P_EVEX)
+#define OPC_VPMOVM2W (0x28 | P_EXT38 | P_SIMDF3 | P_VEXW | P_EVEX)
+#define OPC_VPMOVM2D (0x38 | P_EXT38 | P_SIMDF3 | P_EVEX)
+#define OPC_VPMOVM2Q (0x38 | P_EXT38 | P_SIMDF3 | P_VEXW | P_EVEX)
#define OPC_VPERMQ (0x00 | P_EXT3A | P_DATA16 | P_VEXW)
#define OPC_VPERM2I128 (0x46 | P_EXT3A | P_DATA16 | P_VEXL)
#define OPC_VPROLVD (0x15 | P_EXT38 | P_DATA16 | P_EVEX)
@@ -442,6 +462,14 @@ static bool tcg_target_const_match(int64_t val, int ct,
#define OPC_VPSRLVD (0x45 | P_EXT38 | P_DATA16)
#define OPC_VPSRLVQ (0x45 | P_EXT38 | P_DATA16 | P_VEXW)
#define OPC_VPTERNLOGQ (0x25 | P_EXT3A | P_DATA16 | P_VEXW | P_EVEX)
+#define OPC_VPTESTMB (0x26 | P_EXT38 | P_DATA16 | P_EVEX)
+#define OPC_VPTESTMW (0x26 | P_EXT38 | P_DATA16 | P_VEXW | P_EVEX)
+#define OPC_VPTESTMD (0x27 | P_EXT38 | P_DATA16 | P_EVEX)
+#define OPC_VPTESTMQ (0x27 | P_EXT38 | P_DATA16 | P_VEXW | P_EVEX)
+#define OPC_VPTESTNMB (0x26 | P_EXT38 | P_SIMDF3 | P_EVEX)
+#define OPC_VPTESTNMW (0x26 | P_EXT38 | P_SIMDF3 | P_VEXW | P_EVEX)
+#define OPC_VPTESTNMD (0x27 | P_EXT38 | P_SIMDF3 | P_EVEX)
+#define OPC_VPTESTNMQ (0x27 | P_EXT38 | P_SIMDF3 | P_VEXW | P_EVEX)
#define OPC_VZEROUPPER (0x77 | P_EXT)
#define OPC_XCHG_ax_r32 (0x90)
#define OPC_XCHG_EvGv (0x87)
@@ -658,7 +686,7 @@ static void tcg_out_vex_opc(TCGContext *s, int opc, int r, int v,
}
static void tcg_out_evex_opc(TCGContext *s, int opc, int r, int v,
- int rm, int index)
+ int rm, int index, int aaa, bool z)
{
/* The entire 4-byte evex prefix; with R' and V' set. */
uint32_t p = 0x08041062;
@@ -695,7 +723,9 @@ static void tcg_out_evex_opc(TCGContext *s, int opc, int r, int v,
p = deposit32(p, 16, 2, pp);
p = deposit32(p, 19, 4, ~v);
p = deposit32(p, 23, 1, (opc & P_VEXW) != 0);
+ p = deposit32(p, 24, 3, aaa);
p = deposit32(p, 29, 2, (opc & P_VEXL) != 0);
+ p = deposit32(p, 31, 1, z);
tcg_out32(s, p);
tcg_out8(s, opc);
@@ -704,13 +734,32 @@ static void tcg_out_evex_opc(TCGContext *s, int opc, int r, int v,
static void tcg_out_vex_modrm(TCGContext *s, int opc, int r, int v, int rm)
{
if (opc & P_EVEX) {
- tcg_out_evex_opc(s, opc, r, v, rm, 0);
+ tcg_out_evex_opc(s, opc, r, v, rm, 0, 0, false);
} else {
tcg_out_vex_opc(s, opc, r, v, rm, 0);
}
tcg_out8(s, 0xc0 | (LOWREGMASK(r) << 3) | LOWREGMASK(rm));
}
+static void tcg_out_vex_modrm_type(TCGContext *s, int opc,
+ int r, int v, int rm, TCGType type)
+{
+ if (type == TCG_TYPE_V256) {
+ opc |= P_VEXL;
+ }
+ tcg_out_vex_modrm(s, opc, r, v, rm);
+}
+
+static void tcg_out_evex_modrm_type(TCGContext *s, int opc, int r, int v,
+ int rm, int aaa, bool z, TCGType type)
+{
+ if (type == TCG_TYPE_V256) {
+ opc |= P_VEXL;
+ }
+ tcg_out_evex_opc(s, opc, r, v, rm, 0, aaa, z);
+ tcg_out8(s, 0xc0 | (LOWREGMASK(r) << 3) | LOWREGMASK(rm));
+}
+
/* Output an opcode with a full "rm + (index<<shift) + offset" address mode.
We handle either RM and INDEX missing with a negative value. In 64-bit
mode for absolute addresses, ~RM is the size of the immediate operand
@@ -904,8 +953,7 @@ static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
TCGReg r, TCGReg a)
{
if (have_avx2) {
- int vex_l = (type == TCG_TYPE_V256 ? P_VEXL : 0);
- tcg_out_vex_modrm(s, avx2_dup_insn[vece] + vex_l, r, 0, a);
+ tcg_out_vex_modrm_type(s, avx2_dup_insn[vece], r, 0, a, type);
} else {
switch (vece) {
case MO_8:
@@ -3021,6 +3069,214 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
#undef OP_32_64
}
+static int const umin_insn[4] = {
+ OPC_PMINUB, OPC_PMINUW, OPC_PMINUD, OPC_VPMINUQ
+};
+
+static int const umax_insn[4] = {
+ OPC_PMAXUB, OPC_PMAXUW, OPC_PMAXUD, OPC_VPMAXUQ
+};
+
+static bool tcg_out_cmp_vec_noinv(TCGContext *s, TCGType type, unsigned vece,
+ TCGReg v0, TCGReg v1, TCGReg v2, TCGCond cond)
+{
+ static int const cmpeq_insn[4] = {
+ OPC_PCMPEQB, OPC_PCMPEQW, OPC_PCMPEQD, OPC_PCMPEQQ
+ };
+ static int const cmpgt_insn[4] = {
+ OPC_PCMPGTB, OPC_PCMPGTW, OPC_PCMPGTD, OPC_PCMPGTQ
+ };
+
+ enum {
+ NEED_INV = 1,
+ NEED_SWAP = 2,
+ NEED_UMIN = 4,
+ NEED_UMAX = 8,
+ INVALID = 16,
+ };
+ static const uint8_t cond_fixup[16] = {
+ [0 ... 15] = INVALID,
+ [TCG_COND_EQ] = 0,
+ [TCG_COND_GT] = 0,
+ [TCG_COND_NE] = NEED_INV,
+ [TCG_COND_LE] = NEED_INV,
+ [TCG_COND_LT] = NEED_SWAP,
+ [TCG_COND_GE] = NEED_SWAP | NEED_INV,
+ [TCG_COND_LEU] = NEED_UMIN,
+ [TCG_COND_GTU] = NEED_UMIN | NEED_INV,
+ [TCG_COND_GEU] = NEED_UMAX,
+ [TCG_COND_LTU] = NEED_UMAX | NEED_INV,
+ };
+ int fixup = cond_fixup[cond];
+
+ assert(!(fixup & INVALID));
+
+ if (fixup & NEED_INV) {
+ cond = tcg_invert_cond(cond);
+ }
+
+ if (fixup & NEED_SWAP) {
+ TCGReg swap = v1;
+ v1 = v2;
+ v2 = swap;
+ cond = tcg_swap_cond(cond);
+ }
+
+ if (fixup & (NEED_UMIN | NEED_UMAX)) {
+ int op = (fixup & NEED_UMIN ? umin_insn[vece] : umax_insn[vece]);
+
+ /* avx2 does not have 64-bit min/max; adjusted during expand. */
+ assert(vece <= MO_32);
+
+ tcg_out_vex_modrm_type(s, op, TCG_TMP_VEC, v1, v2, type);
+ v2 = TCG_TMP_VEC;
+ cond = TCG_COND_EQ;
+ }
+
+ switch (cond) {
+ case TCG_COND_EQ:
+ tcg_out_vex_modrm_type(s, cmpeq_insn[vece], v0, v1, v2, type);
+ break;
+ case TCG_COND_GT:
+ tcg_out_vex_modrm_type(s, cmpgt_insn[vece], v0, v1, v2, type);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ return fixup & NEED_INV;
+}
+
+static void tcg_out_cmp_vec_k1(TCGContext *s, TCGType type, unsigned vece,
+ TCGReg v1, TCGReg v2, TCGCond cond)
+{
+ static const int cmpm_insn[2][4] = {
+ { OPC_VPCMPB, OPC_VPCMPW, OPC_VPCMPD, OPC_VPCMPQ },
+ { OPC_VPCMPUB, OPC_VPCMPUW, OPC_VPCMPUD, OPC_VPCMPUQ }
+ };
+ static const int testm_insn[4] = {
+ OPC_VPTESTMB, OPC_VPTESTMW, OPC_VPTESTMD, OPC_VPTESTMQ
+ };
+ static const int testnm_insn[4] = {
+ OPC_VPTESTNMB, OPC_VPTESTNMW, OPC_VPTESTNMD, OPC_VPTESTNMQ
+ };
+
+ static const int cond_ext[16] = {
+ [TCG_COND_EQ] = 0,
+ [TCG_COND_NE] = 4,
+ [TCG_COND_LT] = 1,
+ [TCG_COND_LTU] = 1,
+ [TCG_COND_LE] = 2,
+ [TCG_COND_LEU] = 2,
+ [TCG_COND_NEVER] = 3,
+ [TCG_COND_GE] = 5,
+ [TCG_COND_GEU] = 5,
+ [TCG_COND_GT] = 6,
+ [TCG_COND_GTU] = 6,
+ [TCG_COND_ALWAYS] = 7,
+ };
+
+ switch (cond) {
+ case TCG_COND_TSTNE:
+ tcg_out_vex_modrm_type(s, testm_insn[vece], /* k1 */ 1, v1, v2, type);
+ break;
+ case TCG_COND_TSTEQ:
+ tcg_out_vex_modrm_type(s, testnm_insn[vece], /* k1 */ 1, v1, v2, type);
+ break;
+ default:
+ tcg_out_vex_modrm_type(s, cmpm_insn[is_unsigned_cond(cond)][vece],
+ /* k1 */ 1, v1, v2, type);
+ tcg_out8(s, cond_ext[cond]);
+ break;
+ }
+}
+
+static void tcg_out_k1_to_vec(TCGContext *s, TCGType type,
+ unsigned vece, TCGReg dest)
+{
+ static const int movm_insn[] = {
+ OPC_VPMOVM2B, OPC_VPMOVM2W, OPC_VPMOVM2D, OPC_VPMOVM2Q
+ };
+ tcg_out_vex_modrm_type(s, movm_insn[vece], dest, 0, /* k1 */ 1, type);
+}
+
+static void tcg_out_cmp_vec(TCGContext *s, TCGType type, unsigned vece,
+ TCGReg v0, TCGReg v1, TCGReg v2, TCGCond cond)
+{
+ /*
+ * With avx512, we have a complete set of comparisons into mask.
+ * Unless there's a single insn expansion for the comparision,
+ * expand via a mask in k1.
+ */
+ if ((vece <= MO_16 ? have_avx512bw : have_avx512dq)
+ && cond != TCG_COND_EQ
+ && cond != TCG_COND_LT
+ && cond != TCG_COND_GT) {
+ tcg_out_cmp_vec_k1(s, type, vece, v1, v2, cond);
+ tcg_out_k1_to_vec(s, type, vece, v0);
+ return;
+ }
+
+ if (tcg_out_cmp_vec_noinv(s, type, vece, v0, v1, v2, cond)) {
+ tcg_out_dupi_vec(s, type, vece, TCG_TMP_VEC, -1);
+ tcg_out_vex_modrm_type(s, OPC_PXOR, v0, v0, TCG_TMP_VEC, type);
+ }
+}
+
+static void tcg_out_cmpsel_vec_k1(TCGContext *s, TCGType type, unsigned vece,
+ TCGReg v0, TCGReg c1, TCGReg c2,
+ TCGReg v3, TCGReg v4, TCGCond cond)
+{
+ static const int vpblendm_insn[] = {
+ OPC_VPBLENDMB, OPC_VPBLENDMW, OPC_VPBLENDMD, OPC_VPBLENDMQ
+ };
+ bool z = false;
+
+ /* Swap to place constant in V4 to take advantage of zero-masking. */
+ if (!v3) {
+ z = true;
+ v3 = v4;
+ cond = tcg_invert_cond(cond);
+ }
+
+ tcg_out_cmp_vec_k1(s, type, vece, c1, c2, cond);
+ tcg_out_evex_modrm_type(s, vpblendm_insn[vece], v0, v4, v3,
+ /* k1 */1, z, type);
+}
+
+static void tcg_out_cmpsel_vec(TCGContext *s, TCGType type, unsigned vece,
+ TCGReg v0, TCGReg c1, TCGReg c2,
+ TCGReg v3, TCGReg v4, TCGCond cond)
+{
+ bool inv;
+
+ if (vece <= MO_16 ? have_avx512bw : have_avx512vl) {
+ tcg_out_cmpsel_vec_k1(s, type, vece, v0, c1, c2, v3, v4, cond);
+ return;
+ }
+
+ inv = tcg_out_cmp_vec_noinv(s, type, vece, TCG_TMP_VEC, c1, c2, cond);
+
+ /*
+ * Since XMM0 is 16, the only way we get 0 into V3
+ * is via the constant zero constraint.
+ */
+ if (!v3) {
+ if (inv) {
+ tcg_out_vex_modrm_type(s, OPC_PAND, v0, TCG_TMP_VEC, v4, type);
+ } else {
+ tcg_out_vex_modrm_type(s, OPC_PANDN, v0, TCG_TMP_VEC, v4, type);
+ }
+ } else {
+ if (inv) {
+ TCGReg swap = v3;
+ v3 = v4;
+ v4 = swap;
+ }
+ tcg_out_vex_modrm_type(s, OPC_VPBLENDVB, v0, v4, v3, type);
+ tcg_out8(s, (TCG_TMP_VEC - TCG_REG_XMM0) << 4);
+ }
+}
+
static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
unsigned vecl, unsigned vece,
const TCGArg args[TCG_MAX_OP_ARGS],
@@ -3050,12 +3306,6 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
static int const shift_imm_insn[4] = {
OPC_UD2, OPC_PSHIFTW_Ib, OPC_PSHIFTD_Ib, OPC_PSHIFTQ_Ib
};
- static int const cmpeq_insn[4] = {
- OPC_PCMPEQB, OPC_PCMPEQW, OPC_PCMPEQD, OPC_PCMPEQQ
- };
- static int const cmpgt_insn[4] = {
- OPC_PCMPGTB, OPC_PCMPGTW, OPC_PCMPGTD, OPC_PCMPGTQ
- };
static int const punpckl_insn[4] = {
OPC_PUNPCKLBW, OPC_PUNPCKLWD, OPC_PUNPCKLDQ, OPC_PUNPCKLQDQ
};
@@ -3074,12 +3324,6 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
static int const smax_insn[4] = {
OPC_PMAXSB, OPC_PMAXSW, OPC_PMAXSD, OPC_VPMAXSQ
};
- static int const umin_insn[4] = {
- OPC_PMINUB, OPC_PMINUW, OPC_PMINUD, OPC_VPMINUQ
- };
- static int const umax_insn[4] = {
- OPC_PMAXUB, OPC_PMAXUW, OPC_PMAXUD, OPC_VPMAXUQ
- };
static int const rotlv_insn[4] = {
OPC_UD2, OPC_UD2, OPC_VPROLVD, OPC_VPROLVQ
};
@@ -3231,29 +3475,21 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
goto gen_simd;
gen_simd:
tcg_debug_assert(insn != OPC_UD2);
- if (type == TCG_TYPE_V256) {
- insn |= P_VEXL;
- }
- tcg_out_vex_modrm(s, insn, a0, a1, a2);
+ tcg_out_vex_modrm_type(s, insn, a0, a1, a2, type);
break;
case INDEX_op_cmp_vec:
- sub = args[3];
- if (sub == TCG_COND_EQ) {
- insn = cmpeq_insn[vece];
- } else if (sub == TCG_COND_GT) {
- insn = cmpgt_insn[vece];
- } else {
- g_assert_not_reached();
- }
- goto gen_simd;
+ tcg_out_cmp_vec(s, type, vece, a0, a1, a2, args[3]);
+ break;
+
+ case INDEX_op_cmpsel_vec:
+ tcg_out_cmpsel_vec(s, type, vece, a0, a1, a2,
+ args[3], args[4], args[5]);
+ break;
case INDEX_op_andc_vec:
insn = OPC_PANDN;
- if (type == TCG_TYPE_V256) {
- insn |= P_VEXL;
- }
- tcg_out_vex_modrm(s, insn, a0, a2, a1);
+ tcg_out_vex_modrm_type(s, insn, a0, a2, a1, type);
break;
case INDEX_op_shli_vec:
@@ -3281,10 +3517,7 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
goto gen_shift;
gen_shift:
tcg_debug_assert(vece != MO_8);
- if (type == TCG_TYPE_V256) {
- insn |= P_VEXL;
- }
- tcg_out_vex_modrm(s, insn, sub, a0, a1);
+ tcg_out_vex_modrm_type(s, insn, sub, a0, a1, type);
tcg_out8(s, a2);
break;
@@ -3361,22 +3594,10 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
gen_simd_imm8:
tcg_debug_assert(insn != OPC_UD2);
- if (type == TCG_TYPE_V256) {
- insn |= P_VEXL;
- }
- tcg_out_vex_modrm(s, insn, a0, a1, a2);
+ tcg_out_vex_modrm_type(s, insn, a0, a1, a2, type);
tcg_out8(s, sub);
break;
- case INDEX_op_x86_vpblendvb_vec:
- insn = OPC_VPBLENDVB;
- if (type == TCG_TYPE_V256) {
- insn |= P_VEXL;
- }
- tcg_out_vex_modrm(s, insn, a0, a1, a2);
- tcg_out8(s, args[3] << 4);
- break;
-
case INDEX_op_x86_psrldq_vec:
tcg_out_vex_modrm(s, OPC_GRP14, 3, a0, a1);
tcg_out8(s, a2);
@@ -3642,8 +3863,9 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
return C_O1_I3(x, 0, x, x);
case INDEX_op_bitsel_vec:
- case INDEX_op_x86_vpblendvb_vec:
return C_O1_I3(x, x, x, x);
+ case INDEX_op_cmpsel_vec:
+ return C_O1_I4(x, x, x, xO, x);
default:
g_assert_not_reached();
@@ -3979,145 +4201,59 @@ static void expand_vec_mul(TCGType type, unsigned vece,
}
}
-static bool expand_vec_cmp_noinv(TCGType type, unsigned vece, TCGv_vec v0,
- TCGv_vec v1, TCGv_vec v2, TCGCond cond)
+static TCGCond expand_vec_cond(TCGType type, unsigned vece,
+ TCGArg *a1, TCGArg *a2, TCGCond cond)
{
- enum {
- NEED_INV = 1,
- NEED_SWAP = 2,
- NEED_BIAS = 4,
- NEED_UMIN = 8,
- NEED_UMAX = 16,
- };
- TCGv_vec t1, t2, t3;
- uint8_t fixup;
-
- switch (cond) {
- case TCG_COND_EQ:
- case TCG_COND_GT:
- fixup = 0;
- break;
- case TCG_COND_NE:
- case TCG_COND_LE:
- fixup = NEED_INV;
- break;
- case TCG_COND_LT:
- fixup = NEED_SWAP;
- break;
- case TCG_COND_GE:
- fixup = NEED_SWAP | NEED_INV;
- break;
- case TCG_COND_LEU:
- if (tcg_can_emit_vec_op(INDEX_op_umin_vec, type, vece)) {
- fixup = NEED_UMIN;
- } else {
- fixup = NEED_BIAS | NEED_INV;
- }
- break;
- case TCG_COND_GTU:
- if (tcg_can_emit_vec_op(INDEX_op_umin_vec, type, vece)) {
- fixup = NEED_UMIN | NEED_INV;
- } else {
- fixup = NEED_BIAS;
- }
- break;
- case TCG_COND_GEU:
- if (tcg_can_emit_vec_op(INDEX_op_umax_vec, type, vece)) {
- fixup = NEED_UMAX;
- } else {
- fixup = NEED_BIAS | NEED_SWAP | NEED_INV;
- }
- break;
- case TCG_COND_LTU:
- if (tcg_can_emit_vec_op(INDEX_op_umax_vec, type, vece)) {
- fixup = NEED_UMAX | NEED_INV;
- } else {
- fixup = NEED_BIAS | NEED_SWAP;
- }
- break;
- default:
- g_assert_not_reached();
- }
-
- if (fixup & NEED_INV) {
- cond = tcg_invert_cond(cond);
- }
- if (fixup & NEED_SWAP) {
- t1 = v1, v1 = v2, v2 = t1;
- cond = tcg_swap_cond(cond);
- }
+ /*
+ * Without AVX512, there are no 64-bit unsigned comparisons.
+ * We must bias the inputs so that they become signed.
+ * All other swapping and inversion are handled during code generation.
+ */
+ if (vece == MO_64 && !have_avx512dq && is_unsigned_cond(cond)) {
+ TCGv_vec v1 = temp_tcgv_vec(arg_temp(*a1));
+ TCGv_vec v2 = temp_tcgv_vec(arg_temp(*a2));
+ TCGv_vec t1 = tcg_temp_new_vec(type);
+ TCGv_vec t2 = tcg_temp_new_vec(type);
+ TCGv_vec t3 = tcg_constant_vec(type, vece, 1ull << ((8 << vece) - 1));
- t1 = t2 = NULL;
- if (fixup & (NEED_UMIN | NEED_UMAX)) {
- t1 = tcg_temp_new_vec(type);
- if (fixup & NEED_UMIN) {
- tcg_gen_umin_vec(vece, t1, v1, v2);
- } else {
- tcg_gen_umax_vec(vece, t1, v1, v2);
- }
- v2 = t1;
- cond = TCG_COND_EQ;
- } else if (fixup & NEED_BIAS) {
- t1 = tcg_temp_new_vec(type);
- t2 = tcg_temp_new_vec(type);
- t3 = tcg_constant_vec(type, vece, 1ull << ((8 << vece) - 1));
tcg_gen_sub_vec(vece, t1, v1, t3);
tcg_gen_sub_vec(vece, t2, v2, t3);
- v1 = t1;
- v2 = t2;
+ *a1 = tcgv_vec_arg(t1);
+ *a2 = tcgv_vec_arg(t2);
cond = tcg_signed_cond(cond);
}
-
- tcg_debug_assert(cond == TCG_COND_EQ || cond == TCG_COND_GT);
- /* Expand directly; do not recurse. */
- vec_gen_4(INDEX_op_cmp_vec, type, vece,
- tcgv_vec_arg(v0), tcgv_vec_arg(v1), tcgv_vec_arg(v2), cond);
-
- if (t1) {
- tcg_temp_free_vec(t1);
- if (t2) {
- tcg_temp_free_vec(t2);
- }
- }
- return fixup & NEED_INV;
+ return cond;
}
-static void expand_vec_cmp(TCGType type, unsigned vece, TCGv_vec v0,
- TCGv_vec v1, TCGv_vec v2, TCGCond cond)
+static void expand_vec_cmp(TCGType type, unsigned vece, TCGArg a0,
+ TCGArg a1, TCGArg a2, TCGCond cond)
{
- if (expand_vec_cmp_noinv(type, vece, v0, v1, v2, cond)) {
- tcg_gen_not_vec(vece, v0, v0);
- }
+ cond = expand_vec_cond(type, vece, &a1, &a2, cond);
+ /* Expand directly; do not recurse. */
+ vec_gen_4(INDEX_op_cmp_vec, type, vece, a0, a1, a2, cond);
}
-static void expand_vec_cmpsel(TCGType type, unsigned vece, TCGv_vec v0,
- TCGv_vec c1, TCGv_vec c2,
- TCGv_vec v3, TCGv_vec v4, TCGCond cond)
+static void expand_vec_cmpsel(TCGType type, unsigned vece, TCGArg a0,
+ TCGArg a1, TCGArg a2,
+ TCGArg a3, TCGArg a4, TCGCond cond)
{
- TCGv_vec t = tcg_temp_new_vec(type);
-
- if (expand_vec_cmp_noinv(type, vece, t, c1, c2, cond)) {
- /* Invert the sense of the compare by swapping arguments. */
- TCGv_vec x;
- x = v3, v3 = v4, v4 = x;
- }
- vec_gen_4(INDEX_op_x86_vpblendvb_vec, type, vece,
- tcgv_vec_arg(v0), tcgv_vec_arg(v4),
- tcgv_vec_arg(v3), tcgv_vec_arg(t));
- tcg_temp_free_vec(t);
+ cond = expand_vec_cond(type, vece, &a1, &a2, cond);
+ /* Expand directly; do not recurse. */
+ vec_gen_6(INDEX_op_cmpsel_vec, type, vece, a0, a1, a2, a3, a4, cond);
}
void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece,
TCGArg a0, ...)
{
va_list va;
- TCGArg a2;
- TCGv_vec v0, v1, v2, v3, v4;
+ TCGArg a1, a2, a3, a4, a5;
+ TCGv_vec v0, v1, v2;
va_start(va, a0);
- v0 = temp_tcgv_vec(arg_temp(a0));
- v1 = temp_tcgv_vec(arg_temp(va_arg(va, TCGArg)));
+ a1 = va_arg(va, TCGArg);
a2 = va_arg(va, TCGArg);
+ v0 = temp_tcgv_vec(arg_temp(a0));
+ v1 = temp_tcgv_vec(arg_temp(a1));
switch (opc) {
case INDEX_op_shli_vec:
@@ -4153,15 +4289,15 @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece,
break;
case INDEX_op_cmp_vec:
- v2 = temp_tcgv_vec(arg_temp(a2));
- expand_vec_cmp(type, vece, v0, v1, v2, va_arg(va, TCGArg));
+ a3 = va_arg(va, TCGArg);
+ expand_vec_cmp(type, vece, a0, a1, a2, a3);
break;
case INDEX_op_cmpsel_vec:
- v2 = temp_tcgv_vec(arg_temp(a2));
- v3 = temp_tcgv_vec(arg_temp(va_arg(va, TCGArg)));
- v4 = temp_tcgv_vec(arg_temp(va_arg(va, TCGArg)));
- expand_vec_cmpsel(type, vece, v0, v1, v2, v3, v4, va_arg(va, TCGArg));
+ a3 = va_arg(va, TCGArg);
+ a4 = va_arg(va, TCGArg);
+ a5 = va_arg(va, TCGArg);
+ expand_vec_cmpsel(type, vece, a0, a1, a2, a3, a4, a5);
break;
default:
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
index 2f67a97..c68ac02 100644
--- a/tcg/i386/tcg-target.h
+++ b/tcg/i386/tcg-target.h
@@ -223,8 +223,8 @@ typedef enum {
#define TCG_TARGET_HAS_sat_vec 1
#define TCG_TARGET_HAS_minmax_vec 1
#define TCG_TARGET_HAS_bitsel_vec have_avx512vl
-#define TCG_TARGET_HAS_cmpsel_vec -1
-#define TCG_TARGET_HAS_tst_vec 0
+#define TCG_TARGET_HAS_cmpsel_vec 1
+#define TCG_TARGET_HAS_tst_vec have_avx512bw
#define TCG_TARGET_deposit_i32_valid(ofs, len) \
(((ofs) == 0 && ((len) == 8 || (len) == 16)) || \
diff --git a/tcg/i386/tcg-target.opc.h b/tcg/i386/tcg-target.opc.h
index b5f403e..4ffc084 100644
--- a/tcg/i386/tcg-target.opc.h
+++ b/tcg/i386/tcg-target.opc.h
@@ -25,7 +25,6 @@
*/
DEF(x86_shufps_vec, 1, 2, 1, IMPLVEC)
-DEF(x86_vpblendvb_vec, 1, 3, 0, IMPLVEC)
DEF(x86_blend_vec, 1, 2, 1, IMPLVEC)
DEF(x86_packss_vec, 1, 2, 0, IMPLVEC)
DEF(x86_packus_vec, 1, 2, 0, IMPLVEC)
diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc
index 5b7ed5c..973601a 100644
--- a/tcg/loongarch64/tcg-target.c.inc
+++ b/tcg/loongarch64/tcg-target.c.inc
@@ -650,7 +650,6 @@ static int tcg_out_setcond_int(TCGContext *s, TCGCond cond, TCGReg ret,
default:
g_assert_not_reached();
- break;
}
return ret | flags;
diff --git a/tcg/optimize.c b/tcg/optimize.c
index ba16ec2..e9ef16b 100644
--- a/tcg/optimize.c
+++ b/tcg/optimize.c
@@ -1851,6 +1851,11 @@ static bool fold_movcond(OptContext *ctx, TCGOp *op)
{
int i;
+ /* If true and false values are the same, eliminate the cmp. */
+ if (args_are_copies(op->args[3], op->args[4])) {
+ return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[3]);
+ }
+
/*
* Canonicalize the "false" input reg to match the destination reg so
* that the tcg backend can implement a "move if true" operation.
@@ -2417,6 +2422,36 @@ static bool fold_setcond2(OptContext *ctx, TCGOp *op)
return tcg_opt_gen_movi(ctx, op, op->args[0], i);
}
+static bool fold_cmp_vec(OptContext *ctx, TCGOp *op)
+{
+ /* Canonicalize the comparison to put immediate second. */
+ if (swap_commutative(NO_DEST, &op->args[1], &op->args[2])) {
+ op->args[3] = tcg_swap_cond(op->args[3]);
+ }
+ return false;
+}
+
+static bool fold_cmpsel_vec(OptContext *ctx, TCGOp *op)
+{
+ /* If true and false values are the same, eliminate the cmp. */
+ if (args_are_copies(op->args[3], op->args[4])) {
+ return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[3]);
+ }
+
+ /* Canonicalize the comparison to put immediate second. */
+ if (swap_commutative(NO_DEST, &op->args[1], &op->args[2])) {
+ op->args[5] = tcg_swap_cond(op->args[5]);
+ }
+ /*
+ * Canonicalize the "false" input reg to match the destination,
+ * so that the tcg backend can implement "move if true".
+ */
+ if (swap_commutative(op->args[0], &op->args[4], &op->args[3])) {
+ op->args[5] = tcg_invert_cond(op->args[5]);
+ }
+ return false;
+}
+
static bool fold_sextract(OptContext *ctx, TCGOp *op)
{
uint64_t z_mask, s_mask, s_mask_old;
@@ -2702,6 +2737,61 @@ static bool fold_xor(OptContext *ctx, TCGOp *op)
return fold_masks(ctx, op);
}
+static bool fold_bitsel_vec(OptContext *ctx, TCGOp *op)
+{
+ /* If true and false values are the same, eliminate the cmp. */
+ if (args_are_copies(op->args[2], op->args[3])) {
+ return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[2]);
+ }
+
+ if (arg_is_const(op->args[2]) && arg_is_const(op->args[3])) {
+ uint64_t tv = arg_info(op->args[2])->val;
+ uint64_t fv = arg_info(op->args[3])->val;
+
+ if (tv == -1 && fv == 0) {
+ return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[1]);
+ }
+ if (tv == 0 && fv == -1) {
+ if (TCG_TARGET_HAS_not_vec) {
+ op->opc = INDEX_op_not_vec;
+ return fold_not(ctx, op);
+ } else {
+ op->opc = INDEX_op_xor_vec;
+ op->args[2] = arg_new_constant(ctx, -1);
+ return fold_xor(ctx, op);
+ }
+ }
+ }
+ if (arg_is_const(op->args[2])) {
+ uint64_t tv = arg_info(op->args[2])->val;
+ if (tv == -1) {
+ op->opc = INDEX_op_or_vec;
+ op->args[2] = op->args[3];
+ return fold_or(ctx, op);
+ }
+ if (tv == 0 && TCG_TARGET_HAS_andc_vec) {
+ op->opc = INDEX_op_andc_vec;
+ op->args[2] = op->args[1];
+ op->args[1] = op->args[3];
+ return fold_andc(ctx, op);
+ }
+ }
+ if (arg_is_const(op->args[3])) {
+ uint64_t fv = arg_info(op->args[3])->val;
+ if (fv == 0) {
+ op->opc = INDEX_op_and_vec;
+ return fold_and(ctx, op);
+ }
+ if (fv == -1 && TCG_TARGET_HAS_orc_vec) {
+ op->opc = INDEX_op_orc_vec;
+ op->args[2] = op->args[1];
+ op->args[1] = op->args[3];
+ return fold_orc(ctx, op);
+ }
+ }
+ return false;
+}
+
/* Propagate constants and copies, fold constant expressions. */
void tcg_optimize(TCGContext *s)
{
@@ -2923,6 +3013,15 @@ void tcg_optimize(TCGContext *s)
case INDEX_op_setcond2_i32:
done = fold_setcond2(&ctx, op);
break;
+ case INDEX_op_cmp_vec:
+ done = fold_cmp_vec(&ctx, op);
+ break;
+ case INDEX_op_cmpsel_vec:
+ done = fold_cmpsel_vec(&ctx, op);
+ break;
+ case INDEX_op_bitsel_vec:
+ done = fold_bitsel_vec(&ctx, op);
+ break;
CASE_OP_32_64(sextract):
done = fold_sextract(&ctx, op);
break;
diff --git a/tcg/ppc/tcg-target-con-set.h b/tcg/ppc/tcg-target-con-set.h
index 9f99bde..453abde 100644
--- a/tcg/ppc/tcg-target-con-set.h
+++ b/tcg/ppc/tcg-target-con-set.h
@@ -33,6 +33,7 @@ C_O1_I2(r, r, rU)
C_O1_I2(r, r, rZW)
C_O1_I2(v, v, v)
C_O1_I3(v, v, v, v)
+C_O1_I4(v, v, v, vZM, v)
C_O1_I4(r, r, rC, rZ, rZ)
C_O1_I4(r, r, r, ri, ri)
C_O2_I1(r, r, r)
diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc
index 7f3829b..9a11c26 100644
--- a/tcg/ppc/tcg-target.c.inc
+++ b/tcg/ppc/tcg-target.c.inc
@@ -325,9 +325,11 @@ static bool tcg_target_const_match(int64_t sval, int ct,
if ((uval & ~0xffff) == 0 || (uval & ~0xffff0000ull) == 0) {
return 1;
}
- if (TCG_TARGET_REG_BITS == 32 || type == TCG_TYPE_I32
- ? mask_operand(uval, &mb, &me)
- : mask64_operand(uval << clz64(uval), &mb, &me)) {
+ if (uval == (uint32_t)uval && mask_operand(uval, &mb, &me)) {
+ return 1;
+ }
+ if (TCG_TARGET_REG_BITS == 64 &&
+ mask64_operand(uval << clz64(uval), &mb, &me)) {
return 1;
}
return 0;
@@ -909,7 +911,9 @@ static void tcg_out_rld(TCGContext *s, int op, TCGReg ra, TCGReg rs,
static void tcg_out_rlw_rc(TCGContext *s, int op, TCGReg ra, TCGReg rs,
int sh, int mb, int me, bool rc)
{
- tcg_out32(s, op | RA(ra) | RS(rs) | SH(sh) | MB(mb) | ME(me) | rc);
+ tcg_debug_assert((mb & 0x1f) == mb);
+ tcg_debug_assert((me & 0x1f) == me);
+ tcg_out32(s, op | RA(ra) | RS(rs) | SH(sh & 0x1f) | MB(mb) | ME(me) | rc);
}
static void tcg_out_rlw(TCGContext *s, int op, TCGReg ra, TCGReg rs,
@@ -1749,8 +1753,6 @@ static void tcg_out_test(TCGContext *s, TCGReg dest, TCGReg arg1, TCGArg arg2,
if (type == TCG_TYPE_I32) {
arg2 = (uint32_t)arg2;
- } else if (arg2 == (uint32_t)arg2) {
- type = TCG_TYPE_I32;
}
if ((arg2 & ~0xffff) == 0) {
@@ -1761,12 +1763,11 @@ static void tcg_out_test(TCGContext *s, TCGReg dest, TCGReg arg1, TCGArg arg2,
tcg_out32(s, ANDIS | SAI(arg1, dest, arg2 >> 16));
return;
}
- if (TCG_TARGET_REG_BITS == 32 || type == TCG_TYPE_I32) {
- if (mask_operand(arg2, &mb, &me)) {
- tcg_out_rlw_rc(s, RLWINM, dest, arg1, 0, mb, me, rc);
- return;
- }
- } else {
+ if (arg2 == (uint32_t)arg2 && mask_operand(arg2, &mb, &me)) {
+ tcg_out_rlw_rc(s, RLWINM, dest, arg1, 0, mb, me, rc);
+ return;
+ }
+ if (TCG_TARGET_REG_BITS == 64) {
int sh = clz64(arg2);
if (mask64_operand(arg2 << sh, &mb, &me)) {
tcg_out_rld_rc(s, RLDICR, dest, arg1, sh, me, rc);
@@ -2618,8 +2619,8 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h,
if (TCG_TARGET_REG_BITS == 64 && addr_type == TCG_TYPE_I32) {
/* Zero-extend the guest address for use in the host address. */
- tcg_out_ext32u(s, TCG_REG_R0, addrlo);
- h->index = TCG_REG_R0;
+ tcg_out_ext32u(s, TCG_REG_TMP2, addrlo);
+ h->index = TCG_REG_TMP2;
} else {
h->index = addrlo;
}
@@ -2705,9 +2706,9 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg datalo, TCGReg datahi,
uint32_t insn = qemu_stx_opc[opc & (MO_BSWAP | MO_SIZE)];
if (!have_isa_2_06 && insn == STDBRX) {
tcg_out32(s, STWBRX | SAB(datalo, h.base, h.index));
- tcg_out32(s, ADDI | TAI(TCG_REG_TMP1, h.index, 4));
+ tcg_out32(s, ADDI | TAI(TCG_REG_TMP2, h.index, 4));
tcg_out_shri64(s, TCG_REG_R0, datalo, 32);
- tcg_out32(s, STWBRX | SAB(TCG_REG_R0, h.base, TCG_REG_TMP1));
+ tcg_out32(s, STWBRX | SAB(TCG_REG_R0, h.base, TCG_REG_TMP2));
} else {
tcg_out32(s, insn | SAB(datalo, h.base, h.index));
}
@@ -3568,12 +3569,14 @@ int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece)
case INDEX_op_usadd_vec:
case INDEX_op_ussub_vec:
return vece <= MO_32;
- case INDEX_op_cmp_vec:
case INDEX_op_shli_vec:
case INDEX_op_shri_vec:
case INDEX_op_sari_vec:
case INDEX_op_rotli_vec:
return vece <= MO_32 || have_isa_2_07 ? -1 : 0;
+ case INDEX_op_cmp_vec:
+ case INDEX_op_cmpsel_vec:
+ return vece <= MO_32 || have_isa_2_07 ? 1 : 0;
case INDEX_op_neg_vec:
return vece >= MO_32 && have_isa_3_00;
case INDEX_op_mul_vec:
@@ -3714,6 +3717,149 @@ static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
return true;
}
+static void tcg_out_not_vec(TCGContext *s, TCGReg a0, TCGReg a1)
+{
+ tcg_out32(s, VNOR | VRT(a0) | VRA(a1) | VRB(a1));
+}
+
+static void tcg_out_or_vec(TCGContext *s, TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out32(s, VOR | VRT(a0) | VRA(a1) | VRB(a2));
+}
+
+static void tcg_out_orc_vec(TCGContext *s, TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out32(s, VORC | VRT(a0) | VRA(a1) | VRB(a2));
+}
+
+static void tcg_out_and_vec(TCGContext *s, TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out32(s, VAND | VRT(a0) | VRA(a1) | VRB(a2));
+}
+
+static void tcg_out_andc_vec(TCGContext *s, TCGReg a0, TCGReg a1, TCGReg a2)
+{
+ tcg_out32(s, VANDC | VRT(a0) | VRA(a1) | VRB(a2));
+}
+
+static void tcg_out_bitsel_vec(TCGContext *s, TCGReg d,
+ TCGReg c, TCGReg t, TCGReg f)
+{
+ if (TCG_TARGET_HAS_bitsel_vec) {
+ tcg_out32(s, XXSEL | VRT(d) | VRC(c) | VRB(t) | VRA(f));
+ } else {
+ tcg_out_and_vec(s, TCG_VEC_TMP2, t, c);
+ tcg_out_andc_vec(s, d, f, c);
+ tcg_out_or_vec(s, d, d, TCG_VEC_TMP2);
+ }
+}
+
+static bool tcg_out_cmp_vec_noinv(TCGContext *s, unsigned vece, TCGReg a0,
+ TCGReg a1, TCGReg a2, TCGCond cond)
+{
+ static const uint32_t
+ eq_op[4] = { VCMPEQUB, VCMPEQUH, VCMPEQUW, VCMPEQUD },
+ ne_op[4] = { VCMPNEB, VCMPNEH, VCMPNEW, 0 },
+ gts_op[4] = { VCMPGTSB, VCMPGTSH, VCMPGTSW, VCMPGTSD },
+ gtu_op[4] = { VCMPGTUB, VCMPGTUH, VCMPGTUW, VCMPGTUD };
+ uint32_t insn;
+
+ bool need_swap = false, need_inv = false;
+
+ tcg_debug_assert(vece <= MO_32 || have_isa_2_07);
+
+ switch (cond) {
+ case TCG_COND_EQ:
+ case TCG_COND_GT:
+ case TCG_COND_GTU:
+ break;
+ case TCG_COND_NE:
+ if (have_isa_3_00 && vece <= MO_32) {
+ break;
+ }
+ /* fall through */
+ case TCG_COND_LE:
+ case TCG_COND_LEU:
+ need_inv = true;
+ break;
+ case TCG_COND_LT:
+ case TCG_COND_LTU:
+ need_swap = true;
+ break;
+ case TCG_COND_GE:
+ case TCG_COND_GEU:
+ need_swap = need_inv = true;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (need_inv) {
+ cond = tcg_invert_cond(cond);
+ }
+ if (need_swap) {
+ TCGReg swap = a1;
+ a1 = a2;
+ a2 = swap;
+ cond = tcg_swap_cond(cond);
+ }
+
+ switch (cond) {
+ case TCG_COND_EQ:
+ insn = eq_op[vece];
+ break;
+ case TCG_COND_NE:
+ insn = ne_op[vece];
+ break;
+ case TCG_COND_GT:
+ insn = gts_op[vece];
+ break;
+ case TCG_COND_GTU:
+ insn = gtu_op[vece];
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ tcg_out32(s, insn | VRT(a0) | VRA(a1) | VRB(a2));
+
+ return need_inv;
+}
+
+static void tcg_out_cmp_vec(TCGContext *s, unsigned vece, TCGReg a0,
+ TCGReg a1, TCGReg a2, TCGCond cond)
+{
+ if (tcg_out_cmp_vec_noinv(s, vece, a0, a1, a2, cond)) {
+ tcg_out_not_vec(s, a0, a0);
+ }
+}
+
+static void tcg_out_cmpsel_vec(TCGContext *s, unsigned vece, TCGReg a0,
+ TCGReg c1, TCGReg c2, TCGArg v3, int const_v3,
+ TCGReg v4, TCGCond cond)
+{
+ bool inv = tcg_out_cmp_vec_noinv(s, vece, TCG_VEC_TMP1, c1, c2, cond);
+
+ if (!const_v3) {
+ if (inv) {
+ tcg_out_bitsel_vec(s, a0, TCG_VEC_TMP1, v4, v3);
+ } else {
+ tcg_out_bitsel_vec(s, a0, TCG_VEC_TMP1, v3, v4);
+ }
+ } else if (v3) {
+ if (inv) {
+ tcg_out_orc_vec(s, a0, v4, TCG_VEC_TMP1);
+ } else {
+ tcg_out_or_vec(s, a0, v4, TCG_VEC_TMP1);
+ }
+ } else {
+ if (inv) {
+ tcg_out_and_vec(s, a0, v4, TCG_VEC_TMP1);
+ } else {
+ tcg_out_andc_vec(s, a0, v4, TCG_VEC_TMP1);
+ }
+ }
+}
+
static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
unsigned vecl, unsigned vece,
const TCGArg args[TCG_MAX_OP_ARGS],
@@ -3724,10 +3870,6 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
sub_op[4] = { VSUBUBM, VSUBUHM, VSUBUWM, VSUBUDM },
mul_op[4] = { 0, 0, VMULUWM, VMULLD },
neg_op[4] = { 0, 0, VNEGW, VNEGD },
- eq_op[4] = { VCMPEQUB, VCMPEQUH, VCMPEQUW, VCMPEQUD },
- ne_op[4] = { VCMPNEB, VCMPNEH, VCMPNEW, 0 },
- gts_op[4] = { VCMPGTSB, VCMPGTSH, VCMPGTSW, VCMPGTSD },
- gtu_op[4] = { VCMPGTUB, VCMPGTUH, VCMPGTUW, VCMPGTUD },
ssadd_op[4] = { VADDSBS, VADDSHS, VADDSWS, 0 },
usadd_op[4] = { VADDUBS, VADDUHS, VADDUWS, 0 },
sssub_op[4] = { VSUBSBS, VSUBSHS, VSUBSWS, 0 },
@@ -3809,24 +3951,23 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
insn = sarv_op[vece];
break;
case INDEX_op_and_vec:
- insn = VAND;
- break;
+ tcg_out_and_vec(s, a0, a1, a2);
+ return;
case INDEX_op_or_vec:
- insn = VOR;
- break;
+ tcg_out_or_vec(s, a0, a1, a2);
+ return;
case INDEX_op_xor_vec:
insn = VXOR;
break;
case INDEX_op_andc_vec:
- insn = VANDC;
- break;
+ tcg_out_andc_vec(s, a0, a1, a2);
+ return;
case INDEX_op_not_vec:
- insn = VNOR;
- a2 = a1;
- break;
+ tcg_out_not_vec(s, a0, a1);
+ return;
case INDEX_op_orc_vec:
- insn = VORC;
- break;
+ tcg_out_orc_vec(s, a0, a1, a2);
+ return;
case INDEX_op_nand_vec:
insn = VNAND;
break;
@@ -3838,26 +3979,14 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
break;
case INDEX_op_cmp_vec:
- switch (args[3]) {
- case TCG_COND_EQ:
- insn = eq_op[vece];
- break;
- case TCG_COND_NE:
- insn = ne_op[vece];
- break;
- case TCG_COND_GT:
- insn = gts_op[vece];
- break;
- case TCG_COND_GTU:
- insn = gtu_op[vece];
- break;
- default:
- g_assert_not_reached();
- }
- break;
-
+ tcg_out_cmp_vec(s, vece, a0, a1, a2, args[3]);
+ return;
+ case INDEX_op_cmpsel_vec:
+ tcg_out_cmpsel_vec(s, vece, a0, a1, a2,
+ args[3], const_args[3], args[4], args[5]);
+ return;
case INDEX_op_bitsel_vec:
- tcg_out32(s, XXSEL | VRT(a0) | VRC(a1) | VRB(a2) | VRA(args[3]));
+ tcg_out_bitsel_vec(s, a0, a1, a2, args[3]);
return;
case INDEX_op_dup2_vec:
@@ -3922,56 +4051,6 @@ static void expand_vec_shi(TCGType type, unsigned vece, TCGv_vec v0,
tcgv_vec_arg(v1), tcgv_vec_arg(t1));
}
-static void expand_vec_cmp(TCGType type, unsigned vece, TCGv_vec v0,
- TCGv_vec v1, TCGv_vec v2, TCGCond cond)
-{
- bool need_swap = false, need_inv = false;
-
- tcg_debug_assert(vece <= MO_32 || have_isa_2_07);
-
- switch (cond) {
- case TCG_COND_EQ:
- case TCG_COND_GT:
- case TCG_COND_GTU:
- break;
- case TCG_COND_NE:
- if (have_isa_3_00 && vece <= MO_32) {
- break;
- }
- /* fall through */
- case TCG_COND_LE:
- case TCG_COND_LEU:
- need_inv = true;
- break;
- case TCG_COND_LT:
- case TCG_COND_LTU:
- need_swap = true;
- break;
- case TCG_COND_GE:
- case TCG_COND_GEU:
- need_swap = need_inv = true;
- break;
- default:
- g_assert_not_reached();
- }
-
- if (need_inv) {
- cond = tcg_invert_cond(cond);
- }
- if (need_swap) {
- TCGv_vec t1;
- t1 = v1, v1 = v2, v2 = t1;
- cond = tcg_swap_cond(cond);
- }
-
- vec_gen_4(INDEX_op_cmp_vec, type, vece, tcgv_vec_arg(v0),
- tcgv_vec_arg(v1), tcgv_vec_arg(v2), cond);
-
- if (need_inv) {
- tcg_gen_not_vec(vece, v0, v0);
- }
-}
-
static void expand_vec_mul(TCGType type, unsigned vece, TCGv_vec v0,
TCGv_vec v1, TCGv_vec v2)
{
@@ -4046,10 +4125,6 @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece,
case INDEX_op_rotli_vec:
expand_vec_shi(type, vece, v0, v1, a2, INDEX_op_rotlv_vec);
break;
- case INDEX_op_cmp_vec:
- v2 = temp_tcgv_vec(arg_temp(a2));
- expand_vec_cmp(type, vece, v0, v1, v2, va_arg(va, TCGArg));
- break;
case INDEX_op_mul_vec:
v2 = temp_tcgv_vec(arg_temp(a2));
expand_vec_mul(type, vece, v0, v1, v2);
@@ -4277,6 +4352,8 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
case INDEX_op_bitsel_vec:
case INDEX_op_ppc_msum_vec:
return C_O1_I3(v, v, v, v);
+ case INDEX_op_cmpsel_vec:
+ return C_O1_I4(v, v, v, vZM, v);
default:
g_assert_not_reached();
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
index e154fb1..0b2171d 100644
--- a/tcg/ppc/tcg-target.h
+++ b/tcg/ppc/tcg-target.h
@@ -172,7 +172,7 @@ typedef enum {
#define TCG_TARGET_HAS_sat_vec 1
#define TCG_TARGET_HAS_minmax_vec 1
#define TCG_TARGET_HAS_bitsel_vec have_vsx
-#define TCG_TARGET_HAS_cmpsel_vec 0
+#define TCG_TARGET_HAS_cmpsel_vec 1
#define TCG_TARGET_HAS_tst_vec 0
#define TCG_TARGET_DEFAULT_MO (0)
diff --git a/tcg/riscv/tcg-target-con-set.h b/tcg/riscv/tcg-target-con-set.h
index aac5cee..3c4ef44 100644
--- a/tcg/riscv/tcg-target-con-set.h
+++ b/tcg/riscv/tcg-target-con-set.h
@@ -21,3 +21,12 @@ C_O1_I2(r, rZ, rZ)
C_N1_I2(r, r, rM)
C_O1_I4(r, r, rI, rM, rM)
C_O2_I4(r, r, rZ, rZ, rM, rM)
+C_O0_I2(v, r)
+C_O1_I1(v, r)
+C_O1_I1(v, v)
+C_O1_I2(v, v, r)
+C_O1_I2(v, v, v)
+C_O1_I2(v, vK, v)
+C_O1_I2(v, v, vK)
+C_O1_I2(v, v, vL)
+C_O1_I4(v, v, vL, vK, vK)
diff --git a/tcg/riscv/tcg-target-con-str.h b/tcg/riscv/tcg-target-con-str.h
index d5c419d..089efe9 100644
--- a/tcg/riscv/tcg-target-con-str.h
+++ b/tcg/riscv/tcg-target-con-str.h
@@ -9,6 +9,7 @@
* REGS(letter, register_mask)
*/
REGS('r', ALL_GENERAL_REGS)
+REGS('v', ALL_VECTOR_REGS)
/*
* Define constraint letters for constants:
@@ -16,6 +17,8 @@ REGS('r', ALL_GENERAL_REGS)
*/
CONST('I', TCG_CT_CONST_S12)
CONST('J', TCG_CT_CONST_J12)
+CONST('K', TCG_CT_CONST_S5)
+CONST('L', TCG_CT_CONST_CMP_VI)
CONST('N', TCG_CT_CONST_N12)
CONST('M', TCG_CT_CONST_M12)
CONST('Z', TCG_CT_CONST_ZERO)
diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc
index d334857..f8331e4 100644
--- a/tcg/riscv/tcg-target.c.inc
+++ b/tcg/riscv/tcg-target.c.inc
@@ -32,38 +32,14 @@
#ifdef CONFIG_DEBUG_TCG
static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
- "zero",
- "ra",
- "sp",
- "gp",
- "tp",
- "t0",
- "t1",
- "t2",
- "s0",
- "s1",
- "a0",
- "a1",
- "a2",
- "a3",
- "a4",
- "a5",
- "a6",
- "a7",
- "s2",
- "s3",
- "s4",
- "s5",
- "s6",
- "s7",
- "s8",
- "s9",
- "s10",
- "s11",
- "t3",
- "t4",
- "t5",
- "t6"
+ "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
+ "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
+ "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
+ "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6",
+ "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
+ "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
+ "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
+ "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
};
#endif
@@ -100,6 +76,16 @@ static const int tcg_target_reg_alloc_order[] = {
TCG_REG_A5,
TCG_REG_A6,
TCG_REG_A7,
+
+ /* Vector registers and TCG_REG_V0 reserved for mask. */
+ TCG_REG_V1, TCG_REG_V2, TCG_REG_V3, TCG_REG_V4,
+ TCG_REG_V5, TCG_REG_V6, TCG_REG_V7, TCG_REG_V8,
+ TCG_REG_V9, TCG_REG_V10, TCG_REG_V11, TCG_REG_V12,
+ TCG_REG_V13, TCG_REG_V14, TCG_REG_V15, TCG_REG_V16,
+ TCG_REG_V17, TCG_REG_V18, TCG_REG_V19, TCG_REG_V20,
+ TCG_REG_V21, TCG_REG_V22, TCG_REG_V23, TCG_REG_V24,
+ TCG_REG_V25, TCG_REG_V26, TCG_REG_V27, TCG_REG_V28,
+ TCG_REG_V29, TCG_REG_V30, TCG_REG_V31,
};
static const int tcg_target_call_iarg_regs[] = {
@@ -120,62 +106,50 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot)
return TCG_REG_A0 + slot;
}
-#define TCG_CT_CONST_ZERO 0x100
-#define TCG_CT_CONST_S12 0x200
-#define TCG_CT_CONST_N12 0x400
-#define TCG_CT_CONST_M12 0x800
-#define TCG_CT_CONST_J12 0x1000
+#define TCG_CT_CONST_ZERO 0x100
+#define TCG_CT_CONST_S12 0x200
+#define TCG_CT_CONST_N12 0x400
+#define TCG_CT_CONST_M12 0x800
+#define TCG_CT_CONST_J12 0x1000
+#define TCG_CT_CONST_S5 0x2000
+#define TCG_CT_CONST_CMP_VI 0x4000
#define ALL_GENERAL_REGS MAKE_64BIT_MASK(0, 32)
+#define ALL_VECTOR_REGS MAKE_64BIT_MASK(32, 32)
+#define ALL_DVECTOR_REG_GROUPS 0x5555555500000000
+#define ALL_QVECTOR_REG_GROUPS 0x1111111100000000
#define sextreg sextract64
-/* test if a constant matches the constraint */
-static bool tcg_target_const_match(int64_t val, int ct,
- TCGType type, TCGCond cond, int vece)
-{
- if (ct & TCG_CT_CONST) {
- return 1;
- }
- if ((ct & TCG_CT_CONST_ZERO) && val == 0) {
- return 1;
- }
- /*
- * Sign extended from 12 bits: [-0x800, 0x7ff].
- * Used for most arithmetic, as this is the isa field.
- */
- if ((ct & TCG_CT_CONST_S12) && val >= -0x800 && val <= 0x7ff) {
- return 1;
- }
- /*
- * Sign extended from 12 bits, negated: [-0x7ff, 0x800].
- * Used for subtraction, where a constant must be handled by ADDI.
- */
- if ((ct & TCG_CT_CONST_N12) && val >= -0x7ff && val <= 0x800) {
- return 1;
- }
- /*
- * Sign extended from 12 bits, +/- matching: [-0x7ff, 0x7ff].
- * Used by addsub2 and movcond, which may need the negative value,
- * and requires the modified constant to be representable.
- */
- if ((ct & TCG_CT_CONST_M12) && val >= -0x7ff && val <= 0x7ff) {
- return 1;
- }
- /*
- * Inverse of sign extended from 12 bits: ~[-0x800, 0x7ff].
- * Used to map ANDN back to ANDI, etc.
- */
- if ((ct & TCG_CT_CONST_J12) && ~val >= -0x800 && ~val <= 0x7ff) {
- return 1;
- }
- return 0;
-}
-
/*
* RISC-V Base ISA opcodes (IM)
*/
+#define V_OPIVV (0x0 << 12)
+#define V_OPFVV (0x1 << 12)
+#define V_OPMVV (0x2 << 12)
+#define V_OPIVI (0x3 << 12)
+#define V_OPIVX (0x4 << 12)
+#define V_OPFVF (0x5 << 12)
+#define V_OPMVX (0x6 << 12)
+#define V_OPCFG (0x7 << 12)
+
+/* NF <= 7 && NF >= 0 */
+#define V_NF(x) (x << 29)
+#define V_UNIT_STRIDE (0x0 << 20)
+#define V_UNIT_STRIDE_WHOLE_REG (0x8 << 20)
+
+typedef enum {
+ VLMUL_M1 = 0, /* LMUL=1 */
+ VLMUL_M2, /* LMUL=2 */
+ VLMUL_M4, /* LMUL=4 */
+ VLMUL_M8, /* LMUL=8 */
+ VLMUL_RESERVED,
+ VLMUL_MF8, /* LMUL=1/8 */
+ VLMUL_MF4, /* LMUL=1/4 */
+ VLMUL_MF2, /* LMUL=1/2 */
+} RISCVVlmul;
+
typedef enum {
OPC_ADD = 0x33,
OPC_ADDI = 0x13,
@@ -271,8 +245,199 @@ typedef enum {
/* Zicond: integer conditional operations */
OPC_CZERO_EQZ = 0x0e005033,
OPC_CZERO_NEZ = 0x0e007033,
+
+ /* V: Vector extension 1.0 */
+ OPC_VSETVLI = 0x57 | V_OPCFG,
+ OPC_VSETIVLI = 0xc0000057 | V_OPCFG,
+ OPC_VSETVL = 0x80000057 | V_OPCFG,
+
+ OPC_VLE8_V = 0x7 | V_UNIT_STRIDE,
+ OPC_VLE16_V = 0x5007 | V_UNIT_STRIDE,
+ OPC_VLE32_V = 0x6007 | V_UNIT_STRIDE,
+ OPC_VLE64_V = 0x7007 | V_UNIT_STRIDE,
+ OPC_VSE8_V = 0x27 | V_UNIT_STRIDE,
+ OPC_VSE16_V = 0x5027 | V_UNIT_STRIDE,
+ OPC_VSE32_V = 0x6027 | V_UNIT_STRIDE,
+ OPC_VSE64_V = 0x7027 | V_UNIT_STRIDE,
+
+ OPC_VL1RE64_V = 0x2007007 | V_UNIT_STRIDE_WHOLE_REG | V_NF(0),
+ OPC_VL2RE64_V = 0x2007007 | V_UNIT_STRIDE_WHOLE_REG | V_NF(1),
+ OPC_VL4RE64_V = 0x2007007 | V_UNIT_STRIDE_WHOLE_REG | V_NF(3),
+ OPC_VL8RE64_V = 0x2007007 | V_UNIT_STRIDE_WHOLE_REG | V_NF(7),
+
+ OPC_VS1R_V = 0x2000027 | V_UNIT_STRIDE_WHOLE_REG | V_NF(0),
+ OPC_VS2R_V = 0x2000027 | V_UNIT_STRIDE_WHOLE_REG | V_NF(1),
+ OPC_VS4R_V = 0x2000027 | V_UNIT_STRIDE_WHOLE_REG | V_NF(3),
+ OPC_VS8R_V = 0x2000027 | V_UNIT_STRIDE_WHOLE_REG | V_NF(7),
+
+ OPC_VMERGE_VIM = 0x5c000057 | V_OPIVI,
+ OPC_VMERGE_VVM = 0x5c000057 | V_OPIVV,
+
+ OPC_VADD_VV = 0x57 | V_OPIVV,
+ OPC_VADD_VI = 0x57 | V_OPIVI,
+ OPC_VSUB_VV = 0x8000057 | V_OPIVV,
+ OPC_VRSUB_VI = 0xc000057 | V_OPIVI,
+ OPC_VAND_VV = 0x24000057 | V_OPIVV,
+ OPC_VAND_VI = 0x24000057 | V_OPIVI,
+ OPC_VOR_VV = 0x28000057 | V_OPIVV,
+ OPC_VOR_VI = 0x28000057 | V_OPIVI,
+ OPC_VXOR_VV = 0x2c000057 | V_OPIVV,
+ OPC_VXOR_VI = 0x2c000057 | V_OPIVI,
+
+ OPC_VMUL_VV = 0x94000057 | V_OPMVV,
+ OPC_VSADD_VV = 0x84000057 | V_OPIVV,
+ OPC_VSADD_VI = 0x84000057 | V_OPIVI,
+ OPC_VSSUB_VV = 0x8c000057 | V_OPIVV,
+ OPC_VSSUB_VI = 0x8c000057 | V_OPIVI,
+ OPC_VSADDU_VV = 0x80000057 | V_OPIVV,
+ OPC_VSADDU_VI = 0x80000057 | V_OPIVI,
+ OPC_VSSUBU_VV = 0x88000057 | V_OPIVV,
+ OPC_VSSUBU_VI = 0x88000057 | V_OPIVI,
+
+ OPC_VMAX_VV = 0x1c000057 | V_OPIVV,
+ OPC_VMAX_VI = 0x1c000057 | V_OPIVI,
+ OPC_VMAXU_VV = 0x18000057 | V_OPIVV,
+ OPC_VMAXU_VI = 0x18000057 | V_OPIVI,
+ OPC_VMIN_VV = 0x14000057 | V_OPIVV,
+ OPC_VMIN_VI = 0x14000057 | V_OPIVI,
+ OPC_VMINU_VV = 0x10000057 | V_OPIVV,
+ OPC_VMINU_VI = 0x10000057 | V_OPIVI,
+
+ OPC_VMSEQ_VV = 0x60000057 | V_OPIVV,
+ OPC_VMSEQ_VI = 0x60000057 | V_OPIVI,
+ OPC_VMSEQ_VX = 0x60000057 | V_OPIVX,
+ OPC_VMSNE_VV = 0x64000057 | V_OPIVV,
+ OPC_VMSNE_VI = 0x64000057 | V_OPIVI,
+ OPC_VMSNE_VX = 0x64000057 | V_OPIVX,
+
+ OPC_VMSLTU_VV = 0x68000057 | V_OPIVV,
+ OPC_VMSLTU_VX = 0x68000057 | V_OPIVX,
+ OPC_VMSLT_VV = 0x6c000057 | V_OPIVV,
+ OPC_VMSLT_VX = 0x6c000057 | V_OPIVX,
+ OPC_VMSLEU_VV = 0x70000057 | V_OPIVV,
+ OPC_VMSLEU_VX = 0x70000057 | V_OPIVX,
+ OPC_VMSLE_VV = 0x74000057 | V_OPIVV,
+ OPC_VMSLE_VX = 0x74000057 | V_OPIVX,
+
+ OPC_VMSLEU_VI = 0x70000057 | V_OPIVI,
+ OPC_VMSLE_VI = 0x74000057 | V_OPIVI,
+ OPC_VMSGTU_VI = 0x78000057 | V_OPIVI,
+ OPC_VMSGTU_VX = 0x78000057 | V_OPIVX,
+ OPC_VMSGT_VI = 0x7c000057 | V_OPIVI,
+ OPC_VMSGT_VX = 0x7c000057 | V_OPIVX,
+
+ OPC_VSLL_VV = 0x94000057 | V_OPIVV,
+ OPC_VSLL_VI = 0x94000057 | V_OPIVI,
+ OPC_VSLL_VX = 0x94000057 | V_OPIVX,
+ OPC_VSRL_VV = 0xa0000057 | V_OPIVV,
+ OPC_VSRL_VI = 0xa0000057 | V_OPIVI,
+ OPC_VSRL_VX = 0xa0000057 | V_OPIVX,
+ OPC_VSRA_VV = 0xa4000057 | V_OPIVV,
+ OPC_VSRA_VI = 0xa4000057 | V_OPIVI,
+ OPC_VSRA_VX = 0xa4000057 | V_OPIVX,
+
+ OPC_VMV_V_V = 0x5e000057 | V_OPIVV,
+ OPC_VMV_V_I = 0x5e000057 | V_OPIVI,
+ OPC_VMV_V_X = 0x5e000057 | V_OPIVX,
+
+ OPC_VMVNR_V = 0x9e000057 | V_OPIVI,
} RISCVInsn;
+static const struct {
+ RISCVInsn op;
+ bool swap;
+} tcg_cmpcond_to_rvv_vv[] = {
+ [TCG_COND_EQ] = { OPC_VMSEQ_VV, false },
+ [TCG_COND_NE] = { OPC_VMSNE_VV, false },
+ [TCG_COND_LT] = { OPC_VMSLT_VV, false },
+ [TCG_COND_GE] = { OPC_VMSLE_VV, true },
+ [TCG_COND_GT] = { OPC_VMSLT_VV, true },
+ [TCG_COND_LE] = { OPC_VMSLE_VV, false },
+ [TCG_COND_LTU] = { OPC_VMSLTU_VV, false },
+ [TCG_COND_GEU] = { OPC_VMSLEU_VV, true },
+ [TCG_COND_GTU] = { OPC_VMSLTU_VV, true },
+ [TCG_COND_LEU] = { OPC_VMSLEU_VV, false }
+};
+
+static const struct {
+ RISCVInsn op;
+ int min;
+ int max;
+ bool adjust;
+} tcg_cmpcond_to_rvv_vi[] = {
+ [TCG_COND_EQ] = { OPC_VMSEQ_VI, -16, 15, false },
+ [TCG_COND_NE] = { OPC_VMSNE_VI, -16, 15, false },
+ [TCG_COND_GT] = { OPC_VMSGT_VI, -16, 15, false },
+ [TCG_COND_LE] = { OPC_VMSLE_VI, -16, 15, false },
+ [TCG_COND_LT] = { OPC_VMSLE_VI, -15, 16, true },
+ [TCG_COND_GE] = { OPC_VMSGT_VI, -15, 16, true },
+ [TCG_COND_LEU] = { OPC_VMSLEU_VI, 0, 15, false },
+ [TCG_COND_GTU] = { OPC_VMSGTU_VI, 0, 15, false },
+ [TCG_COND_LTU] = { OPC_VMSLEU_VI, 1, 16, true },
+ [TCG_COND_GEU] = { OPC_VMSGTU_VI, 1, 16, true },
+};
+
+/* test if a constant matches the constraint */
+static bool tcg_target_const_match(int64_t val, int ct,
+ TCGType type, TCGCond cond, int vece)
+{
+ if (ct & TCG_CT_CONST) {
+ return 1;
+ }
+ if ((ct & TCG_CT_CONST_ZERO) && val == 0) {
+ return 1;
+ }
+ if (type >= TCG_TYPE_V64) {
+ /* Val is replicated by VECE; extract the highest element. */
+ val >>= (-8 << vece) & 63;
+ }
+ /*
+ * Sign extended from 12 bits: [-0x800, 0x7ff].
+ * Used for most arithmetic, as this is the isa field.
+ */
+ if ((ct & TCG_CT_CONST_S12) && val >= -0x800 && val <= 0x7ff) {
+ return 1;
+ }
+ /*
+ * Sign extended from 12 bits, negated: [-0x7ff, 0x800].
+ * Used for subtraction, where a constant must be handled by ADDI.
+ */
+ if ((ct & TCG_CT_CONST_N12) && val >= -0x7ff && val <= 0x800) {
+ return 1;
+ }
+ /*
+ * Sign extended from 12 bits, +/- matching: [-0x7ff, 0x7ff].
+ * Used by addsub2 and movcond, which may need the negative value,
+ * and requires the modified constant to be representable.
+ */
+ if ((ct & TCG_CT_CONST_M12) && val >= -0x7ff && val <= 0x7ff) {
+ return 1;
+ }
+ /*
+ * Inverse of sign extended from 12 bits: ~[-0x800, 0x7ff].
+ * Used to map ANDN back to ANDI, etc.
+ */
+ if ((ct & TCG_CT_CONST_J12) && ~val >= -0x800 && ~val <= 0x7ff) {
+ return 1;
+ }
+ /*
+ * Sign extended from 5 bits: [-0x10, 0x0f].
+ * Used for vector-immediate.
+ */
+ if ((ct & TCG_CT_CONST_S5) && val >= -0x10 && val <= 0x0f) {
+ return 1;
+ }
+ /*
+ * Used for vector compare OPIVI instructions.
+ */
+ if ((ct & TCG_CT_CONST_CMP_VI) &&
+ val >= tcg_cmpcond_to_rvv_vi[cond].min &&
+ val <= tcg_cmpcond_to_rvv_vi[cond].max) {
+ return true;
+ }
+ return 0;
+}
+
/*
* RISC-V immediate and instruction encoders (excludes 16-bit RVC)
*/
@@ -363,6 +528,45 @@ static int32_t encode_uj(RISCVInsn opc, TCGReg rd, uint32_t imm)
return opc | (rd & 0x1f) << 7 | encode_ujimm20(imm);
}
+
+/* Type-OPIVI */
+
+static int32_t encode_vi(RISCVInsn opc, TCGReg rd, int32_t imm,
+ TCGReg vs2, bool vm)
+{
+ return opc | (rd & 0x1f) << 7 | (imm & 0x1f) << 15 |
+ (vs2 & 0x1f) << 20 | (vm << 25);
+}
+
+/* Type-OPIVV/OPMVV/OPIVX/OPMVX, Vector load and store */
+
+static int32_t encode_v(RISCVInsn opc, TCGReg d, TCGReg s1,
+ TCGReg s2, bool vm)
+{
+ return opc | (d & 0x1f) << 7 | (s1 & 0x1f) << 15 |
+ (s2 & 0x1f) << 20 | (vm << 25);
+}
+
+/* Vector vtype */
+
+static uint32_t encode_vtype(bool vta, bool vma,
+ MemOp vsew, RISCVVlmul vlmul)
+{
+ return vma << 7 | vta << 6 | vsew << 3 | vlmul;
+}
+
+static int32_t encode_vset(RISCVInsn opc, TCGReg rd,
+ TCGArg rs1, uint32_t vtype)
+{
+ return opc | (rd & 0x1f) << 7 | (rs1 & 0x1f) << 15 | (vtype & 0x7ff) << 20;
+}
+
+static int32_t encode_vseti(RISCVInsn opc, TCGReg rd,
+ uint32_t uimm, uint32_t vtype)
+{
+ return opc | (rd & 0x1f) << 7 | (uimm & 0x1f) << 15 | (vtype & 0x3ff) << 20;
+}
+
/*
* RISC-V instruction emitters
*/
@@ -476,6 +680,91 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
}
/*
+ * RISC-V vector instruction emitters
+ */
+
+/*
+ * Vector registers uses the same 5 lower bits as GPR registers,
+ * and vm=0 (vm = false) means vector masking ENABLED.
+ * With RVV 1.0, vs2 is the first operand, while rs1/imm is the
+ * second operand.
+ */
+static void tcg_out_opc_vv(TCGContext *s, RISCVInsn opc,
+ TCGReg vd, TCGReg vs2, TCGReg vs1)
+{
+ tcg_out32(s, encode_v(opc, vd, vs1, vs2, true));
+}
+
+static void tcg_out_opc_vx(TCGContext *s, RISCVInsn opc,
+ TCGReg vd, TCGReg vs2, TCGReg rs1)
+{
+ tcg_out32(s, encode_v(opc, vd, rs1, vs2, true));
+}
+
+static void tcg_out_opc_vi(TCGContext *s, RISCVInsn opc,
+ TCGReg vd, TCGReg vs2, int32_t imm)
+{
+ tcg_out32(s, encode_vi(opc, vd, imm, vs2, true));
+}
+
+static void tcg_out_opc_vv_vi(TCGContext *s, RISCVInsn o_vv, RISCVInsn o_vi,
+ TCGReg vd, TCGReg vs2, TCGArg vi1, int c_vi1)
+{
+ if (c_vi1) {
+ tcg_out_opc_vi(s, o_vi, vd, vs2, vi1);
+ } else {
+ tcg_out_opc_vv(s, o_vv, vd, vs2, vi1);
+ }
+}
+
+static void tcg_out_opc_vim_mask(TCGContext *s, RISCVInsn opc, TCGReg vd,
+ TCGReg vs2, int32_t imm)
+{
+ tcg_out32(s, encode_vi(opc, vd, imm, vs2, false));
+}
+
+static void tcg_out_opc_vvm_mask(TCGContext *s, RISCVInsn opc, TCGReg vd,
+ TCGReg vs2, TCGReg vs1)
+{
+ tcg_out32(s, encode_v(opc, vd, vs1, vs2, false));
+}
+
+typedef struct VsetCache {
+ uint32_t movi_insn;
+ uint32_t vset_insn;
+} VsetCache;
+
+static VsetCache riscv_vset_cache[3][4];
+
+static void set_vtype(TCGContext *s, TCGType type, MemOp vsew)
+{
+ const VsetCache *p = &riscv_vset_cache[type - TCG_TYPE_V64][vsew];
+
+ s->riscv_cur_type = type;
+ s->riscv_cur_vsew = vsew;
+
+ if (p->movi_insn) {
+ tcg_out32(s, p->movi_insn);
+ }
+ tcg_out32(s, p->vset_insn);
+}
+
+static MemOp set_vtype_len(TCGContext *s, TCGType type)
+{
+ if (type != s->riscv_cur_type) {
+ set_vtype(s, type, MO_64);
+ }
+ return s->riscv_cur_vsew;
+}
+
+static void set_vtype_len_sew(TCGContext *s, TCGType type, MemOp vsew)
+{
+ if (type != s->riscv_cur_type || vsew != s->riscv_cur_vsew) {
+ set_vtype(s, type, vsew);
+ }
+}
+
+/*
* TCG intrinsics
*/
@@ -489,6 +778,15 @@ static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg)
case TCG_TYPE_I64:
tcg_out_opc_imm(s, OPC_ADDI, ret, arg, 0);
break;
+ case TCG_TYPE_V64:
+ case TCG_TYPE_V128:
+ case TCG_TYPE_V256:
+ {
+ int lmul = type - riscv_lg2_vlenb;
+ int nf = 1 << MAX(lmul, 0);
+ tcg_out_opc_vi(s, OPC_VMVNR_V, ret, arg, nf - 1);
+ }
+ break;
default:
g_assert_not_reached();
}
@@ -681,18 +979,101 @@ static void tcg_out_ldst(TCGContext *s, RISCVInsn opc, TCGReg data,
}
}
+static void tcg_out_vec_ldst(TCGContext *s, RISCVInsn opc, TCGReg data,
+ TCGReg addr, intptr_t offset)
+{
+ tcg_debug_assert(data >= TCG_REG_V0);
+ tcg_debug_assert(addr < TCG_REG_V0);
+
+ if (offset) {
+ tcg_debug_assert(addr != TCG_REG_ZERO);
+ if (offset == sextreg(offset, 0, 12)) {
+ tcg_out_opc_imm(s, OPC_ADDI, TCG_REG_TMP0, addr, offset);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP0, offset);
+ tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP0, TCG_REG_TMP0, addr);
+ }
+ addr = TCG_REG_TMP0;
+ }
+ tcg_out32(s, encode_v(opc, data, addr, 0, true));
+}
+
static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg arg,
TCGReg arg1, intptr_t arg2)
{
- RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_LW : OPC_LD;
- tcg_out_ldst(s, insn, arg, arg1, arg2);
+ RISCVInsn insn;
+
+ switch (type) {
+ case TCG_TYPE_I32:
+ tcg_out_ldst(s, OPC_LW, arg, arg1, arg2);
+ break;
+ case TCG_TYPE_I64:
+ tcg_out_ldst(s, OPC_LD, arg, arg1, arg2);
+ break;
+ case TCG_TYPE_V64:
+ case TCG_TYPE_V128:
+ case TCG_TYPE_V256:
+ if (type >= riscv_lg2_vlenb) {
+ static const RISCVInsn whole_reg_ld[] = {
+ OPC_VL1RE64_V, OPC_VL2RE64_V, OPC_VL4RE64_V, OPC_VL8RE64_V
+ };
+ unsigned idx = type - riscv_lg2_vlenb;
+
+ tcg_debug_assert(idx < ARRAY_SIZE(whole_reg_ld));
+ insn = whole_reg_ld[idx];
+ } else {
+ static const RISCVInsn unit_stride_ld[] = {
+ OPC_VLE8_V, OPC_VLE16_V, OPC_VLE32_V, OPC_VLE64_V
+ };
+ MemOp prev_vsew = set_vtype_len(s, type);
+
+ tcg_debug_assert(prev_vsew < ARRAY_SIZE(unit_stride_ld));
+ insn = unit_stride_ld[prev_vsew];
+ }
+ tcg_out_vec_ldst(s, insn, arg, arg1, arg2);
+ break;
+ default:
+ g_assert_not_reached();
+ }
}
static void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg,
TCGReg arg1, intptr_t arg2)
{
- RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_SW : OPC_SD;
- tcg_out_ldst(s, insn, arg, arg1, arg2);
+ RISCVInsn insn;
+
+ switch (type) {
+ case TCG_TYPE_I32:
+ tcg_out_ldst(s, OPC_SW, arg, arg1, arg2);
+ break;
+ case TCG_TYPE_I64:
+ tcg_out_ldst(s, OPC_SD, arg, arg1, arg2);
+ break;
+ case TCG_TYPE_V64:
+ case TCG_TYPE_V128:
+ case TCG_TYPE_V256:
+ if (type >= riscv_lg2_vlenb) {
+ static const RISCVInsn whole_reg_st[] = {
+ OPC_VS1R_V, OPC_VS2R_V, OPC_VS4R_V, OPC_VS8R_V
+ };
+ unsigned idx = type - riscv_lg2_vlenb;
+
+ tcg_debug_assert(idx < ARRAY_SIZE(whole_reg_st));
+ insn = whole_reg_st[idx];
+ } else {
+ static const RISCVInsn unit_stride_st[] = {
+ OPC_VSE8_V, OPC_VSE16_V, OPC_VSE32_V, OPC_VSE64_V
+ };
+ MemOp prev_vsew = set_vtype_len(s, type);
+
+ tcg_debug_assert(prev_vsew < ARRAY_SIZE(unit_stride_st));
+ insn = unit_stride_st[prev_vsew];
+ }
+ tcg_out_vec_ldst(s, insn, arg, arg1, arg2);
+ break;
+ default:
+ g_assert_not_reached();
+ }
}
static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
@@ -766,6 +1147,40 @@ static void tcg_out_addsub2(TCGContext *s,
}
}
+static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
+ TCGReg dst, TCGReg src)
+{
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_opc_vx(s, OPC_VMV_V_X, dst, 0, src);
+ return true;
+}
+
+static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
+ TCGReg dst, TCGReg base, intptr_t offset)
+{
+ tcg_out_ld(s, TCG_TYPE_REG, TCG_REG_TMP0, base, offset);
+ return tcg_out_dup_vec(s, type, vece, dst, TCG_REG_TMP0);
+}
+
+static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
+ TCGReg dst, int64_t arg)
+{
+ /* Arg is replicated by VECE; extract the highest element. */
+ arg >>= (-8 << vece) & 63;
+
+ if (arg >= -16 && arg < 16) {
+ if (arg == 0 || arg == -1) {
+ set_vtype_len(s, type);
+ } else {
+ set_vtype_len_sew(s, type, vece);
+ }
+ tcg_out_opc_vi(s, OPC_VMV_V_I, dst, 0, arg);
+ return;
+ }
+ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP0, arg);
+ tcg_out_dup_vec(s, type, vece, dst, TCG_REG_TMP0);
+}
+
static const struct {
RISCVInsn op;
bool swap;
@@ -1104,12 +1519,72 @@ static void tcg_out_cltz(TCGContext *s, TCGType type, RISCVInsn insn,
}
}
+static void tcg_out_cmpsel(TCGContext *s, TCGType type, unsigned vece,
+ TCGCond cond, TCGReg ret,
+ TCGReg cmp1, TCGReg cmp2, bool c_cmp2,
+ TCGReg val1, bool c_val1,
+ TCGReg val2, bool c_val2)
+{
+ set_vtype_len_sew(s, type, vece);
+
+ /* Use only vmerge_vim if possible, by inverting the test. */
+ if (c_val2 && !c_val1) {
+ TCGArg temp = val1;
+ cond = tcg_invert_cond(cond);
+ val1 = val2;
+ val2 = temp;
+ c_val1 = true;
+ c_val2 = false;
+ }
+
+ /* Perform the comparison into V0 mask. */
+ if (c_cmp2) {
+ tcg_out_opc_vi(s, tcg_cmpcond_to_rvv_vi[cond].op, TCG_REG_V0, cmp1,
+ cmp2 - tcg_cmpcond_to_rvv_vi[cond].adjust);
+ } else if (tcg_cmpcond_to_rvv_vv[cond].swap) {
+ tcg_out_opc_vv(s, tcg_cmpcond_to_rvv_vv[cond].op,
+ TCG_REG_V0, cmp2, cmp1);
+ } else {
+ tcg_out_opc_vv(s, tcg_cmpcond_to_rvv_vv[cond].op,
+ TCG_REG_V0, cmp1, cmp2);
+ }
+ if (c_val1) {
+ if (c_val2) {
+ tcg_out_opc_vi(s, OPC_VMV_V_I, ret, 0, val2);
+ val2 = ret;
+ }
+ /* vd[i] == v0.mask[i] ? imm : vs2[i] */
+ tcg_out_opc_vim_mask(s, OPC_VMERGE_VIM, ret, val2, val1);
+ } else {
+ /* vd[i] == v0.mask[i] ? vs1[i] : vs2[i] */
+ tcg_out_opc_vvm_mask(s, OPC_VMERGE_VVM, ret, val2, val1);
+ }
+}
+
+static void tcg_out_vshifti(TCGContext *s, RISCVInsn opc_vi, RISCVInsn opc_vx,
+ TCGReg dst, TCGReg src, unsigned imm)
+{
+ if (imm < 32) {
+ tcg_out_opc_vi(s, opc_vi, dst, src, imm);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_TMP0, imm);
+ tcg_out_opc_vx(s, opc_vx, dst, src, TCG_REG_TMP0);
+ }
+}
+
+static void init_setting_vtype(TCGContext *s)
+{
+ s->riscv_cur_type = TCG_TYPE_COUNT;
+}
+
static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail)
{
TCGReg link = tail ? TCG_REG_ZERO : TCG_REG_RA;
ptrdiff_t offset = tcg_pcrel_diff(s, arg);
int ret;
+ init_setting_vtype(s);
+
tcg_debug_assert((offset & 1) == 0);
if (offset == sextreg(offset, 0, 20)) {
/* short jump: -2097150 to 2097152 */
@@ -1247,6 +1722,8 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, TCGReg *pbase,
ldst->oi = oi;
ldst->addrlo_reg = addr_reg;
+ init_setting_vtype(s);
+
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP0, TCG_AREG0, mask_ofs);
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_AREG0, table_ofs);
@@ -1308,6 +1785,8 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, TCGReg *pbase,
ldst->oi = oi;
ldst->addrlo_reg = addr_reg;
+ init_setting_vtype(s);
+
/* We are expecting alignment max 7, so we can always use andi. */
tcg_debug_assert(a_mask == sextreg(a_mask, 0, 12));
tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_TMP1, addr_reg, a_mask);
@@ -1881,6 +2360,223 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
}
}
+static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
+ unsigned vecl, unsigned vece,
+ const TCGArg args[TCG_MAX_OP_ARGS],
+ const int const_args[TCG_MAX_OP_ARGS])
+{
+ TCGType type = vecl + TCG_TYPE_V64;
+ TCGArg a0, a1, a2;
+ int c2;
+
+ a0 = args[0];
+ a1 = args[1];
+ a2 = args[2];
+ c2 = const_args[2];
+
+ switch (opc) {
+ case INDEX_op_dupm_vec:
+ tcg_out_dupm_vec(s, type, vece, a0, a1, a2);
+ break;
+ case INDEX_op_ld_vec:
+ tcg_out_ld(s, type, a0, a1, a2);
+ break;
+ case INDEX_op_st_vec:
+ tcg_out_st(s, type, a0, a1, a2);
+ break;
+ case INDEX_op_add_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_opc_vv_vi(s, OPC_VADD_VV, OPC_VADD_VI, a0, a1, a2, c2);
+ break;
+ case INDEX_op_sub_vec:
+ set_vtype_len_sew(s, type, vece);
+ if (const_args[1]) {
+ tcg_out_opc_vi(s, OPC_VRSUB_VI, a0, a2, a1);
+ } else {
+ tcg_out_opc_vv(s, OPC_VSUB_VV, a0, a1, a2);
+ }
+ break;
+ case INDEX_op_and_vec:
+ set_vtype_len(s, type);
+ tcg_out_opc_vv_vi(s, OPC_VAND_VV, OPC_VAND_VI, a0, a1, a2, c2);
+ break;
+ case INDEX_op_or_vec:
+ set_vtype_len(s, type);
+ tcg_out_opc_vv_vi(s, OPC_VOR_VV, OPC_VOR_VI, a0, a1, a2, c2);
+ break;
+ case INDEX_op_xor_vec:
+ set_vtype_len(s, type);
+ tcg_out_opc_vv_vi(s, OPC_VXOR_VV, OPC_VXOR_VI, a0, a1, a2, c2);
+ break;
+ case INDEX_op_not_vec:
+ set_vtype_len(s, type);
+ tcg_out_opc_vi(s, OPC_VXOR_VI, a0, a1, -1);
+ break;
+ case INDEX_op_neg_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_opc_vi(s, OPC_VRSUB_VI, a0, a1, 0);
+ break;
+ case INDEX_op_mul_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_opc_vv(s, OPC_VMUL_VV, a0, a1, a2);
+ break;
+ case INDEX_op_ssadd_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_opc_vv_vi(s, OPC_VSADD_VV, OPC_VSADD_VI, a0, a1, a2, c2);
+ break;
+ case INDEX_op_sssub_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_opc_vv_vi(s, OPC_VSSUB_VV, OPC_VSSUB_VI, a0, a1, a2, c2);
+ break;
+ case INDEX_op_usadd_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_opc_vv_vi(s, OPC_VSADDU_VV, OPC_VSADDU_VI, a0, a1, a2, c2);
+ break;
+ case INDEX_op_ussub_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_opc_vv_vi(s, OPC_VSSUBU_VV, OPC_VSSUBU_VI, a0, a1, a2, c2);
+ break;
+ case INDEX_op_smax_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_opc_vv_vi(s, OPC_VMAX_VV, OPC_VMAX_VI, a0, a1, a2, c2);
+ break;
+ case INDEX_op_smin_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_opc_vv_vi(s, OPC_VMIN_VV, OPC_VMIN_VI, a0, a1, a2, c2);
+ break;
+ case INDEX_op_umax_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_opc_vv_vi(s, OPC_VMAXU_VV, OPC_VMAXU_VI, a0, a1, a2, c2);
+ break;
+ case INDEX_op_umin_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_opc_vv_vi(s, OPC_VMINU_VV, OPC_VMINU_VI, a0, a1, a2, c2);
+ break;
+ case INDEX_op_shls_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_opc_vx(s, OPC_VSLL_VX, a0, a1, a2);
+ break;
+ case INDEX_op_shrs_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_opc_vx(s, OPC_VSRL_VX, a0, a1, a2);
+ break;
+ case INDEX_op_sars_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_opc_vx(s, OPC_VSRA_VX, a0, a1, a2);
+ break;
+ case INDEX_op_shlv_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_opc_vv(s, OPC_VSLL_VV, a0, a1, a2);
+ break;
+ case INDEX_op_shrv_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_opc_vv(s, OPC_VSRL_VV, a0, a1, a2);
+ break;
+ case INDEX_op_sarv_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_opc_vv(s, OPC_VSRA_VV, a0, a1, a2);
+ break;
+ case INDEX_op_shli_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_vshifti(s, OPC_VSLL_VI, OPC_VSLL_VX, a0, a1, a2);
+ break;
+ case INDEX_op_shri_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_vshifti(s, OPC_VSRL_VI, OPC_VSRL_VX, a0, a1, a2);
+ break;
+ case INDEX_op_sari_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_vshifti(s, OPC_VSRA_VI, OPC_VSRA_VX, a0, a1, a2);
+ break;
+ case INDEX_op_rotli_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_vshifti(s, OPC_VSLL_VI, OPC_VSLL_VX, TCG_REG_V0, a1, a2);
+ tcg_out_vshifti(s, OPC_VSRL_VI, OPC_VSRL_VX, a0, a1,
+ -a2 & ((8 << vece) - 1));
+ tcg_out_opc_vv(s, OPC_VOR_VV, a0, a0, TCG_REG_V0);
+ break;
+ case INDEX_op_rotls_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_opc_vx(s, OPC_VSLL_VX, TCG_REG_V0, a1, a2);
+ tcg_out_opc_reg(s, OPC_SUBW, TCG_REG_TMP0, TCG_REG_ZERO, a2);
+ tcg_out_opc_vx(s, OPC_VSRL_VX, a0, a1, TCG_REG_TMP0);
+ tcg_out_opc_vv(s, OPC_VOR_VV, a0, a0, TCG_REG_V0);
+ break;
+ case INDEX_op_rotlv_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_opc_vi(s, OPC_VRSUB_VI, TCG_REG_V0, a2, 0);
+ tcg_out_opc_vv(s, OPC_VSRL_VV, TCG_REG_V0, a1, TCG_REG_V0);
+ tcg_out_opc_vv(s, OPC_VSLL_VV, a0, a1, a2);
+ tcg_out_opc_vv(s, OPC_VOR_VV, a0, a0, TCG_REG_V0);
+ break;
+ case INDEX_op_rotrv_vec:
+ set_vtype_len_sew(s, type, vece);
+ tcg_out_opc_vi(s, OPC_VRSUB_VI, TCG_REG_V0, a2, 0);
+ tcg_out_opc_vv(s, OPC_VSLL_VV, TCG_REG_V0, a1, TCG_REG_V0);
+ tcg_out_opc_vv(s, OPC_VSRL_VV, a0, a1, a2);
+ tcg_out_opc_vv(s, OPC_VOR_VV, a0, a0, TCG_REG_V0);
+ break;
+ case INDEX_op_cmp_vec:
+ tcg_out_cmpsel(s, type, vece, args[3], a0, a1, a2, c2,
+ -1, true, 0, true);
+ break;
+ case INDEX_op_cmpsel_vec:
+ tcg_out_cmpsel(s, type, vece, args[5], a0, a1, a2, c2,
+ args[3], const_args[3], args[4], const_args[4]);
+ break;
+ case INDEX_op_mov_vec: /* Always emitted via tcg_out_mov. */
+ case INDEX_op_dup_vec: /* Always emitted via tcg_out_dup_vec. */
+ default:
+ g_assert_not_reached();
+ }
+}
+
+void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece,
+ TCGArg a0, ...)
+{
+ g_assert_not_reached();
+}
+
+int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece)
+{
+ switch (opc) {
+ case INDEX_op_add_vec:
+ case INDEX_op_sub_vec:
+ case INDEX_op_and_vec:
+ case INDEX_op_or_vec:
+ case INDEX_op_xor_vec:
+ case INDEX_op_not_vec:
+ case INDEX_op_neg_vec:
+ case INDEX_op_mul_vec:
+ case INDEX_op_ssadd_vec:
+ case INDEX_op_sssub_vec:
+ case INDEX_op_usadd_vec:
+ case INDEX_op_ussub_vec:
+ case INDEX_op_smax_vec:
+ case INDEX_op_smin_vec:
+ case INDEX_op_umax_vec:
+ case INDEX_op_umin_vec:
+ case INDEX_op_shls_vec:
+ case INDEX_op_shrs_vec:
+ case INDEX_op_sars_vec:
+ case INDEX_op_shlv_vec:
+ case INDEX_op_shrv_vec:
+ case INDEX_op_sarv_vec:
+ case INDEX_op_shri_vec:
+ case INDEX_op_shli_vec:
+ case INDEX_op_sari_vec:
+ case INDEX_op_rotls_vec:
+ case INDEX_op_rotlv_vec:
+ case INDEX_op_rotrv_vec:
+ case INDEX_op_rotli_vec:
+ case INDEX_op_cmp_vec:
+ case INDEX_op_cmpsel_vec:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
{
switch (op) {
@@ -2020,6 +2716,50 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
case INDEX_op_qemu_st_a64_i64:
return C_O0_I2(rZ, r);
+ case INDEX_op_st_vec:
+ return C_O0_I2(v, r);
+ case INDEX_op_dup_vec:
+ case INDEX_op_dupm_vec:
+ case INDEX_op_ld_vec:
+ return C_O1_I1(v, r);
+ case INDEX_op_neg_vec:
+ case INDEX_op_not_vec:
+ case INDEX_op_shli_vec:
+ case INDEX_op_shri_vec:
+ case INDEX_op_sari_vec:
+ case INDEX_op_rotli_vec:
+ return C_O1_I1(v, v);
+ case INDEX_op_add_vec:
+ case INDEX_op_and_vec:
+ case INDEX_op_or_vec:
+ case INDEX_op_xor_vec:
+ case INDEX_op_ssadd_vec:
+ case INDEX_op_sssub_vec:
+ case INDEX_op_usadd_vec:
+ case INDEX_op_ussub_vec:
+ case INDEX_op_smax_vec:
+ case INDEX_op_smin_vec:
+ case INDEX_op_umax_vec:
+ case INDEX_op_umin_vec:
+ return C_O1_I2(v, v, vK);
+ case INDEX_op_sub_vec:
+ return C_O1_I2(v, vK, v);
+ case INDEX_op_mul_vec:
+ case INDEX_op_shlv_vec:
+ case INDEX_op_shrv_vec:
+ case INDEX_op_sarv_vec:
+ case INDEX_op_rotlv_vec:
+ case INDEX_op_rotrv_vec:
+ return C_O1_I2(v, v, v);
+ case INDEX_op_shls_vec:
+ case INDEX_op_shrs_vec:
+ case INDEX_op_sars_vec:
+ case INDEX_op_rotls_vec:
+ return C_O1_I2(v, v, r);
+ case INDEX_op_cmp_vec:
+ return C_O1_I2(v, v, vL);
+ case INDEX_op_cmpsel_vec:
+ return C_O1_I4(v, v, vL, vK, vK);
default:
g_assert_not_reached();
}
@@ -2093,7 +2833,65 @@ static void tcg_target_qemu_prologue(TCGContext *s)
static void tcg_out_tb_start(TCGContext *s)
{
- /* nothing to do */
+ init_setting_vtype(s);
+}
+
+static bool vtype_check(unsigned vtype)
+{
+ unsigned long tmp;
+
+ /* vsetvl tmp, zero, vtype */
+ asm(".insn r 0x57, 7, 0x40, %0, zero, %1" : "=r"(tmp) : "r"(vtype));
+ return tmp != 0;
+}
+
+static void probe_frac_lmul_1(TCGType type, MemOp vsew)
+{
+ VsetCache *p = &riscv_vset_cache[type - TCG_TYPE_V64][vsew];
+ unsigned avl = tcg_type_size(type) >> vsew;
+ int lmul = type - riscv_lg2_vlenb;
+ unsigned vtype = encode_vtype(true, true, vsew, lmul & 7);
+ bool lmul_eq_avl = true;
+
+ /* Guaranteed by Zve64x. */
+ assert(lmul < 3);
+
+ /*
+ * For LMUL < -3, the host vector size is so large that TYPE
+ * is smaller than the minimum 1/8 fraction.
+ *
+ * For other fractional LMUL settings, implementations must
+ * support SEW settings between SEW_MIN and LMUL * ELEN, inclusive.
+ * So if ELEN = 64, LMUL = 1/2, then SEW will support e8, e16, e32,
+ * but e64 may not be supported. In other words, the hardware only
+ * guarantees SEW_MIN <= SEW <= LMUL * ELEN. Check.
+ */
+ if (lmul < 0 && (lmul < -3 || !vtype_check(vtype))) {
+ vtype = encode_vtype(true, true, vsew, VLMUL_M1);
+ lmul_eq_avl = false;
+ }
+
+ if (avl < 32) {
+ p->vset_insn = encode_vseti(OPC_VSETIVLI, TCG_REG_ZERO, avl, vtype);
+ } else if (lmul_eq_avl) {
+ /* rd != 0 and rs1 == 0 uses vlmax */
+ p->vset_insn = encode_vset(OPC_VSETVLI, TCG_REG_TMP0, TCG_REG_ZERO, vtype);
+ } else {
+ p->movi_insn = encode_i(OPC_ADDI, TCG_REG_TMP0, TCG_REG_ZERO, avl);
+ p->vset_insn = encode_vset(OPC_VSETVLI, TCG_REG_ZERO, TCG_REG_TMP0, vtype);
+ }
+}
+
+static void probe_frac_lmul(void)
+{
+ /* Match riscv_lg2_vlenb to TCG_TYPE_V64. */
+ QEMU_BUILD_BUG_ON(TCG_TYPE_V64 != 3);
+
+ for (TCGType t = TCG_TYPE_V64; t <= TCG_TYPE_V256; t++) {
+ for (MemOp e = MO_8; e <= MO_64; e++) {
+ probe_frac_lmul_1(t, e);
+ }
+ }
}
static void tcg_target_init(TCGContext *s)
@@ -2101,7 +2899,7 @@ static void tcg_target_init(TCGContext *s)
tcg_target_available_regs[TCG_TYPE_I32] = 0xffffffff;
tcg_target_available_regs[TCG_TYPE_I64] = 0xffffffff;
- tcg_target_call_clobber_regs = -1u;
+ tcg_target_call_clobber_regs = -1;
tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S0);
tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S1);
tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_S2);
@@ -2123,6 +2921,32 @@ static void tcg_target_init(TCGContext *s)
tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP);
tcg_regset_set_reg(s->reserved_regs, TCG_REG_GP);
tcg_regset_set_reg(s->reserved_regs, TCG_REG_TP);
+
+ if (cpuinfo & CPUINFO_ZVE64X) {
+ switch (riscv_lg2_vlenb) {
+ case TCG_TYPE_V64:
+ tcg_target_available_regs[TCG_TYPE_V64] = ALL_VECTOR_REGS;
+ tcg_target_available_regs[TCG_TYPE_V128] = ALL_DVECTOR_REG_GROUPS;
+ tcg_target_available_regs[TCG_TYPE_V256] = ALL_QVECTOR_REG_GROUPS;
+ s->reserved_regs |= (~ALL_QVECTOR_REG_GROUPS & ALL_VECTOR_REGS);
+ break;
+ case TCG_TYPE_V128:
+ tcg_target_available_regs[TCG_TYPE_V64] = ALL_VECTOR_REGS;
+ tcg_target_available_regs[TCG_TYPE_V128] = ALL_VECTOR_REGS;
+ tcg_target_available_regs[TCG_TYPE_V256] = ALL_DVECTOR_REG_GROUPS;
+ s->reserved_regs |= (~ALL_DVECTOR_REG_GROUPS & ALL_VECTOR_REGS);
+ break;
+ default:
+ /* Guaranteed by Zve64x. */
+ tcg_debug_assert(riscv_lg2_vlenb >= TCG_TYPE_V256);
+ tcg_target_available_regs[TCG_TYPE_V64] = ALL_VECTOR_REGS;
+ tcg_target_available_regs[TCG_TYPE_V128] = ALL_VECTOR_REGS;
+ tcg_target_available_regs[TCG_TYPE_V256] = ALL_VECTOR_REGS;
+ break;
+ }
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_V0);
+ probe_frac_lmul();
+ }
}
typedef struct {
diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h
index 1a347ea..334c37c 100644
--- a/tcg/riscv/tcg-target.h
+++ b/tcg/riscv/tcg-target.h
@@ -28,42 +28,28 @@
#include "host/cpuinfo.h"
#define TCG_TARGET_INSN_UNIT_SIZE 4
-#define TCG_TARGET_NB_REGS 32
+#define TCG_TARGET_NB_REGS 64
#define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1)
typedef enum {
- TCG_REG_ZERO,
- TCG_REG_RA,
- TCG_REG_SP,
- TCG_REG_GP,
- TCG_REG_TP,
- TCG_REG_T0,
- TCG_REG_T1,
- TCG_REG_T2,
- TCG_REG_S0,
- TCG_REG_S1,
- TCG_REG_A0,
- TCG_REG_A1,
- TCG_REG_A2,
- TCG_REG_A3,
- TCG_REG_A4,
- TCG_REG_A5,
- TCG_REG_A6,
- TCG_REG_A7,
- TCG_REG_S2,
- TCG_REG_S3,
- TCG_REG_S4,
- TCG_REG_S5,
- TCG_REG_S6,
- TCG_REG_S7,
- TCG_REG_S8,
- TCG_REG_S9,
- TCG_REG_S10,
- TCG_REG_S11,
- TCG_REG_T3,
- TCG_REG_T4,
- TCG_REG_T5,
- TCG_REG_T6,
+ TCG_REG_ZERO, TCG_REG_RA, TCG_REG_SP, TCG_REG_GP,
+ TCG_REG_TP, TCG_REG_T0, TCG_REG_T1, TCG_REG_T2,
+ TCG_REG_S0, TCG_REG_S1, TCG_REG_A0, TCG_REG_A1,
+ TCG_REG_A2, TCG_REG_A3, TCG_REG_A4, TCG_REG_A5,
+ TCG_REG_A6, TCG_REG_A7, TCG_REG_S2, TCG_REG_S3,
+ TCG_REG_S4, TCG_REG_S5, TCG_REG_S6, TCG_REG_S7,
+ TCG_REG_S8, TCG_REG_S9, TCG_REG_S10, TCG_REG_S11,
+ TCG_REG_T3, TCG_REG_T4, TCG_REG_T5, TCG_REG_T6,
+
+ /* RISC-V V Extension registers */
+ TCG_REG_V0, TCG_REG_V1, TCG_REG_V2, TCG_REG_V3,
+ TCG_REG_V4, TCG_REG_V5, TCG_REG_V6, TCG_REG_V7,
+ TCG_REG_V8, TCG_REG_V9, TCG_REG_V10, TCG_REG_V11,
+ TCG_REG_V12, TCG_REG_V13, TCG_REG_V14, TCG_REG_V15,
+ TCG_REG_V16, TCG_REG_V17, TCG_REG_V18, TCG_REG_V19,
+ TCG_REG_V20, TCG_REG_V21, TCG_REG_V22, TCG_REG_V23,
+ TCG_REG_V24, TCG_REG_V25, TCG_REG_V26, TCG_REG_V27,
+ TCG_REG_V28, TCG_REG_V29, TCG_REG_V30, TCG_REG_V31,
/* aliases */
TCG_AREG0 = TCG_REG_S0,
@@ -156,6 +142,32 @@ typedef enum {
#define TCG_TARGET_HAS_tst 0
+/* vector instructions */
+#define TCG_TARGET_HAS_v64 (cpuinfo & CPUINFO_ZVE64X)
+#define TCG_TARGET_HAS_v128 (cpuinfo & CPUINFO_ZVE64X)
+#define TCG_TARGET_HAS_v256 (cpuinfo & CPUINFO_ZVE64X)
+#define TCG_TARGET_HAS_andc_vec 0
+#define TCG_TARGET_HAS_orc_vec 0
+#define TCG_TARGET_HAS_nand_vec 0
+#define TCG_TARGET_HAS_nor_vec 0
+#define TCG_TARGET_HAS_eqv_vec 0
+#define TCG_TARGET_HAS_not_vec 1
+#define TCG_TARGET_HAS_neg_vec 1
+#define TCG_TARGET_HAS_abs_vec 0
+#define TCG_TARGET_HAS_roti_vec 1
+#define TCG_TARGET_HAS_rots_vec 1
+#define TCG_TARGET_HAS_rotv_vec 1
+#define TCG_TARGET_HAS_shi_vec 1
+#define TCG_TARGET_HAS_shs_vec 1
+#define TCG_TARGET_HAS_shv_vec 1
+#define TCG_TARGET_HAS_mul_vec 1
+#define TCG_TARGET_HAS_sat_vec 1
+#define TCG_TARGET_HAS_minmax_vec 1
+#define TCG_TARGET_HAS_bitsel_vec 0
+#define TCG_TARGET_HAS_cmpsel_vec 1
+
+#define TCG_TARGET_HAS_tst_vec 0
+
#define TCG_TARGET_DEFAULT_MO (0)
#define TCG_TARGET_NEED_LDST_LABELS
diff --git a/tcg/riscv/tcg-target.opc.h b/tcg/riscv/tcg-target.opc.h
new file mode 100644
index 0000000..b80b39e
--- /dev/null
+++ b/tcg/riscv/tcg-target.opc.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) C-SKY Microsystems Co., Ltd.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version.
+ *
+ * See the COPYING file in the top-level directory for details.
+ *
+ * Target-specific opcodes for host vector expansion. These will be
+ * emitted by tcg_expand_vec_op. For those familiar with GCC internals,
+ * consider these to be UNSPEC with names.
+ */
diff --git a/tcg/s390x/tcg-target-con-set.h b/tcg/s390x/tcg-target-con-set.h
index f75955e..370e4b1 100644
--- a/tcg/s390x/tcg-target-con-set.h
+++ b/tcg/s390x/tcg-target-con-set.h
@@ -38,6 +38,8 @@ C_O1_I2(r, rZ, r)
C_O1_I2(v, v, r)
C_O1_I2(v, v, v)
C_O1_I3(v, v, v, v)
+C_O1_I4(v, v, v, vZ, v)
+C_O1_I4(v, v, v, vZM, v)
C_O1_I4(r, r, ri, rI, r)
C_O1_I4(r, r, rC, rI, r)
C_O2_I1(o, m, r)
diff --git a/tcg/s390x/tcg-target-con-str.h b/tcg/s390x/tcg-target-con-str.h
index 745f6c0d..3e574e0 100644
--- a/tcg/s390x/tcg-target-con-str.h
+++ b/tcg/s390x/tcg-target-con-str.h
@@ -20,6 +20,7 @@ CONST('C', TCG_CT_CONST_CMP)
CONST('I', TCG_CT_CONST_S16)
CONST('J', TCG_CT_CONST_S32)
CONST('K', TCG_CT_CONST_P32)
+CONST('M', TCG_CT_CONST_M1)
CONST('N', TCG_CT_CONST_INV)
CONST('R', TCG_CT_CONST_INVRISBG)
CONST('U', TCG_CT_CONST_U32)
diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc
index ad58732..27bccc1 100644
--- a/tcg/s390x/tcg-target.c.inc
+++ b/tcg/s390x/tcg-target.c.inc
@@ -36,6 +36,7 @@
#define TCG_CT_CONST_INV (1 << 13)
#define TCG_CT_CONST_INVRISBG (1 << 14)
#define TCG_CT_CONST_CMP (1 << 15)
+#define TCG_CT_CONST_M1 (1 << 16)
#define ALL_GENERAL_REGS MAKE_64BIT_MASK(0, 16)
#define ALL_VECTOR_REGS MAKE_64BIT_MASK(32, 32)
@@ -46,6 +47,7 @@
/* A scratch register that may be be used throughout the backend. */
#define TCG_TMP0 TCG_REG_R1
+#define TCG_VEC_TMP0 TCG_REG_V31
#define TCG_GUEST_BASE_REG TCG_REG_R13
@@ -563,6 +565,20 @@ static bool tcg_target_const_match(int64_t val, int ct,
}
if (ct & TCG_CT_CONST_CMP) {
+ if (is_tst_cond(cond)) {
+ if (is_const_p16(uval) >= 0) {
+ return true; /* TMxx */
+ }
+ if (risbg_mask(uval)) {
+ return true; /* RISBG */
+ }
+ return false;
+ }
+
+ if (type == TCG_TYPE_I32) {
+ return true;
+ }
+
switch (cond) {
case TCG_COND_EQ:
case TCG_COND_NE:
@@ -582,13 +598,7 @@ static bool tcg_target_const_match(int64_t val, int ct,
break;
case TCG_COND_TSTNE:
case TCG_COND_TSTEQ:
- if (is_const_p16(uval) >= 0) {
- return true; /* TMxx */
- }
- if (risbg_mask(uval)) {
- return true; /* RISBG */
- }
- break;
+ /* checked above, fallthru */
default:
g_assert_not_reached();
}
@@ -606,6 +616,9 @@ static bool tcg_target_const_match(int64_t val, int ct,
if ((ct & TCG_CT_CONST_ZERO) && val == 0) {
return true;
}
+ if ((ct & TCG_CT_CONST_M1) && val == -1) {
+ return true;
+ }
if (ct & TCG_CT_CONST_INV) {
val = ~val;
@@ -2841,6 +2854,94 @@ static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece,
tcg_out_insn(s, VRX, VLREP, dst, TCG_TMP0, TCG_REG_NONE, 0, MO_64);
}
+static bool tcg_out_cmp_vec_noinv(TCGContext *s, unsigned vece, TCGReg a0,
+ TCGReg a1, TCGReg a2, TCGCond cond)
+{
+ bool need_swap = false, need_inv = false;
+
+ switch (cond) {
+ case TCG_COND_EQ:
+ case TCG_COND_GT:
+ case TCG_COND_GTU:
+ break;
+ case TCG_COND_NE:
+ case TCG_COND_LE:
+ case TCG_COND_LEU:
+ need_inv = true;
+ break;
+ case TCG_COND_LT:
+ case TCG_COND_LTU:
+ need_swap = true;
+ break;
+ case TCG_COND_GE:
+ case TCG_COND_GEU:
+ need_swap = need_inv = true;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (need_inv) {
+ cond = tcg_invert_cond(cond);
+ }
+ if (need_swap) {
+ TCGReg swap = a1;
+ a1 = a2;
+ a2 = swap;
+ cond = tcg_swap_cond(cond);
+ }
+
+ switch (cond) {
+ case TCG_COND_EQ:
+ tcg_out_insn(s, VRRc, VCEQ, a0, a1, a2, vece);
+ break;
+ case TCG_COND_GT:
+ tcg_out_insn(s, VRRc, VCH, a0, a1, a2, vece);
+ break;
+ case TCG_COND_GTU:
+ tcg_out_insn(s, VRRc, VCHL, a0, a1, a2, vece);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ return need_inv;
+}
+
+static void tcg_out_cmp_vec(TCGContext *s, unsigned vece, TCGReg a0,
+ TCGReg a1, TCGReg a2, TCGCond cond)
+{
+ if (tcg_out_cmp_vec_noinv(s, vece, a0, a1, a2, cond)) {
+ tcg_out_insn(s, VRRc, VNO, a0, a0, a0, 0);
+ }
+}
+
+static void tcg_out_cmpsel_vec(TCGContext *s, unsigned vece, TCGReg a0,
+ TCGReg c1, TCGReg c2, TCGArg v3,
+ int const_v3, TCGReg v4, TCGCond cond)
+{
+ bool inv = tcg_out_cmp_vec_noinv(s, vece, TCG_VEC_TMP0, c1, c2, cond);
+
+ if (!const_v3) {
+ if (inv) {
+ tcg_out_insn(s, VRRe, VSEL, a0, v4, v3, TCG_VEC_TMP0);
+ } else {
+ tcg_out_insn(s, VRRe, VSEL, a0, v3, v4, TCG_VEC_TMP0);
+ }
+ } else if (v3) {
+ if (inv) {
+ tcg_out_insn(s, VRRc, VOC, a0, v4, TCG_VEC_TMP0, 0);
+ } else {
+ tcg_out_insn(s, VRRc, VO, a0, v4, TCG_VEC_TMP0, 0);
+ }
+ } else {
+ if (inv) {
+ tcg_out_insn(s, VRRc, VN, a0, v4, TCG_VEC_TMP0, 0);
+ } else {
+ tcg_out_insn(s, VRRc, VNC, a0, v4, TCG_VEC_TMP0, 0);
+ }
+ }
+}
+
static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
unsigned vecl, unsigned vece,
const TCGArg args[TCG_MAX_OP_ARGS],
@@ -2959,19 +3060,11 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
break;
case INDEX_op_cmp_vec:
- switch ((TCGCond)args[3]) {
- case TCG_COND_EQ:
- tcg_out_insn(s, VRRc, VCEQ, a0, a1, a2, vece);
- break;
- case TCG_COND_GT:
- tcg_out_insn(s, VRRc, VCH, a0, a1, a2, vece);
- break;
- case TCG_COND_GTU:
- tcg_out_insn(s, VRRc, VCHL, a0, a1, a2, vece);
- break;
- default:
- g_assert_not_reached();
- }
+ tcg_out_cmp_vec(s, vece, a0, a1, a2, args[3]);
+ break;
+ case INDEX_op_cmpsel_vec:
+ tcg_out_cmpsel_vec(s, vece, a0, a1, a2, args[3], const_args[3],
+ args[4], args[5]);
break;
case INDEX_op_s390_vuph_vec:
@@ -3024,9 +3117,9 @@ int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece)
case INDEX_op_umax_vec:
case INDEX_op_umin_vec:
case INDEX_op_xor_vec:
- return 1;
case INDEX_op_cmp_vec:
case INDEX_op_cmpsel_vec:
+ return 1;
case INDEX_op_rotrv_vec:
return -1;
case INDEX_op_mul_vec:
@@ -3039,71 +3132,6 @@ int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece)
}
}
-static bool expand_vec_cmp_noinv(TCGType type, unsigned vece, TCGv_vec v0,
- TCGv_vec v1, TCGv_vec v2, TCGCond cond)
-{
- bool need_swap = false, need_inv = false;
-
- switch (cond) {
- case TCG_COND_EQ:
- case TCG_COND_GT:
- case TCG_COND_GTU:
- break;
- case TCG_COND_NE:
- case TCG_COND_LE:
- case TCG_COND_LEU:
- need_inv = true;
- break;
- case TCG_COND_LT:
- case TCG_COND_LTU:
- need_swap = true;
- break;
- case TCG_COND_GE:
- case TCG_COND_GEU:
- need_swap = need_inv = true;
- break;
- default:
- g_assert_not_reached();
- }
-
- if (need_inv) {
- cond = tcg_invert_cond(cond);
- }
- if (need_swap) {
- TCGv_vec t1;
- t1 = v1, v1 = v2, v2 = t1;
- cond = tcg_swap_cond(cond);
- }
-
- vec_gen_4(INDEX_op_cmp_vec, type, vece, tcgv_vec_arg(v0),
- tcgv_vec_arg(v1), tcgv_vec_arg(v2), cond);
-
- return need_inv;
-}
-
-static void expand_vec_cmp(TCGType type, unsigned vece, TCGv_vec v0,
- TCGv_vec v1, TCGv_vec v2, TCGCond cond)
-{
- if (expand_vec_cmp_noinv(type, vece, v0, v1, v2, cond)) {
- tcg_gen_not_vec(vece, v0, v0);
- }
-}
-
-static void expand_vec_cmpsel(TCGType type, unsigned vece, TCGv_vec v0,
- TCGv_vec c1, TCGv_vec c2,
- TCGv_vec v3, TCGv_vec v4, TCGCond cond)
-{
- TCGv_vec t = tcg_temp_new_vec(type);
-
- if (expand_vec_cmp_noinv(type, vece, t, c1, c2, cond)) {
- /* Invert the sense of the compare by swapping arguments. */
- tcg_gen_bitsel_vec(vece, v0, t, v4, v3);
- } else {
- tcg_gen_bitsel_vec(vece, v0, t, v3, v4);
- }
- tcg_temp_free_vec(t);
-}
-
static void expand_vec_sat(TCGType type, unsigned vece, TCGv_vec v0,
TCGv_vec v1, TCGv_vec v2, TCGOpcode add_sub_opc)
{
@@ -3145,7 +3173,7 @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece,
TCGArg a0, ...)
{
va_list va;
- TCGv_vec v0, v1, v2, v3, v4, t0;
+ TCGv_vec v0, v1, v2, t0;
va_start(va, a0);
v0 = temp_tcgv_vec(arg_temp(a0));
@@ -3153,16 +3181,6 @@ void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece,
v2 = temp_tcgv_vec(arg_temp(va_arg(va, TCGArg)));
switch (opc) {
- case INDEX_op_cmp_vec:
- expand_vec_cmp(type, vece, v0, v1, v2, va_arg(va, TCGArg));
- break;
-
- case INDEX_op_cmpsel_vec:
- v3 = temp_tcgv_vec(arg_temp(va_arg(va, TCGArg)));
- v4 = temp_tcgv_vec(arg_temp(va_arg(va, TCGArg)));
- expand_vec_cmpsel(type, vece, v0, v1, v2, v3, v4, va_arg(va, TCGArg));
- break;
-
case INDEX_op_rotrv_vec:
t0 = tcg_temp_new_vec(type);
tcg_gen_neg_vec(vece, t0, v2);
@@ -3221,9 +3239,9 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
case INDEX_op_rotl_i64:
case INDEX_op_rotr_i32:
case INDEX_op_rotr_i64:
+ return C_O1_I2(r, r, ri);
case INDEX_op_setcond_i32:
case INDEX_op_negsetcond_i32:
- return C_O1_I2(r, r, ri);
case INDEX_op_setcond_i64:
case INDEX_op_negsetcond_i64:
return C_O1_I2(r, r, rC);
@@ -3397,6 +3415,10 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op)
return C_O1_I2(v, v, r);
case INDEX_op_bitsel_vec:
return C_O1_I3(v, v, v, v);
+ case INDEX_op_cmpsel_vec:
+ return (TCG_TARGET_HAS_orc_vec
+ ? C_O1_I4(v, v, v, vZM, v)
+ : C_O1_I4(v, v, v, vZ, v));
default:
g_assert_not_reached();
@@ -3521,6 +3543,7 @@ static void tcg_target_init(TCGContext *s)
s->reserved_regs = 0;
tcg_regset_set_reg(s->reserved_regs, TCG_TMP0);
+ tcg_regset_set_reg(s->reserved_regs, TCG_VEC_TMP0);
/* XXX many insns can't be used with R0, so we better avoid it for now */
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0);
tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK);
diff --git a/tcg/s390x/tcg-target.h b/tcg/s390x/tcg-target.h
index 62ce9d7..86aeca1 100644
--- a/tcg/s390x/tcg-target.h
+++ b/tcg/s390x/tcg-target.h
@@ -162,7 +162,7 @@ extern uint64_t s390_facilities[3];
#define TCG_TARGET_HAS_sat_vec 0
#define TCG_TARGET_HAS_minmax_vec 1
#define TCG_TARGET_HAS_bitsel_vec 1
-#define TCG_TARGET_HAS_cmpsel_vec 0
+#define TCG_TARGET_HAS_cmpsel_vec 1
#define TCG_TARGET_HAS_tst_vec 0
/* used for function call generation */
diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc
index 176c987..32f9ec2 100644
--- a/tcg/sparc64/tcg-target.c.inc
+++ b/tcg/sparc64/tcg-target.c.inc
@@ -1133,7 +1133,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h,
* Otherwise, test for at least natural alignment and defer
* everything else to the helper functions.
*/
- if (s_bits != get_alignment_bits(opc)) {
+ if (s_bits != memop_alignment_bits(opc)) {
tcg_debug_assert(check_fit_tl(a_mask, 13));
tcg_out_arithi(s, TCG_REG_G0, addr_reg, a_mask, ARITH_ANDCC);
diff --git a/tcg/tcg-internal.h b/tcg/tcg-internal.h
index 9b0d982..8099248 100644
--- a/tcg/tcg-internal.h
+++ b/tcg/tcg-internal.h
@@ -92,15 +92,17 @@ TCGTemp *tcg_temp_new_internal(TCGType type, TCGTempKind kind);
*/
TCGTemp *tcg_constant_internal(TCGType type, int64_t val);
-void tcg_gen_op1(TCGOpcode, TCGArg);
-void tcg_gen_op2(TCGOpcode, TCGArg, TCGArg);
-void tcg_gen_op3(TCGOpcode, TCGArg, TCGArg, TCGArg);
-void tcg_gen_op4(TCGOpcode, TCGArg, TCGArg, TCGArg, TCGArg);
-void tcg_gen_op5(TCGOpcode, TCGArg, TCGArg, TCGArg, TCGArg, TCGArg);
-void tcg_gen_op6(TCGOpcode, TCGArg, TCGArg, TCGArg, TCGArg, TCGArg, TCGArg);
+TCGOp *tcg_gen_op1(TCGOpcode, TCGArg);
+TCGOp *tcg_gen_op2(TCGOpcode, TCGArg, TCGArg);
+TCGOp *tcg_gen_op3(TCGOpcode, TCGArg, TCGArg, TCGArg);
+TCGOp *tcg_gen_op4(TCGOpcode, TCGArg, TCGArg, TCGArg, TCGArg);
+TCGOp *tcg_gen_op5(TCGOpcode, TCGArg, TCGArg, TCGArg, TCGArg, TCGArg);
+TCGOp *tcg_gen_op6(TCGOpcode, TCGArg, TCGArg, TCGArg, TCGArg, TCGArg, TCGArg);
void vec_gen_2(TCGOpcode, TCGType, unsigned, TCGArg, TCGArg);
void vec_gen_3(TCGOpcode, TCGType, unsigned, TCGArg, TCGArg, TCGArg);
void vec_gen_4(TCGOpcode, TCGType, unsigned, TCGArg, TCGArg, TCGArg, TCGArg);
+void vec_gen_6(TCGOpcode opc, TCGType type, unsigned vece, TCGArg r,
+ TCGArg a, TCGArg b, TCGArg c, TCGArg d, TCGArg e);
#endif /* TCG_INTERNAL_H */
diff --git a/tcg/tcg-op-gvec.c b/tcg/tcg-op-gvec.c
index 0308732..78ee1ce 100644
--- a/tcg/tcg-op-gvec.c
+++ b/tcg/tcg-op-gvec.c
@@ -3939,7 +3939,7 @@ void tcg_gen_gvec_cmps(TCGCond cond, unsigned vece, uint32_t dofs,
uint32_t i;
tcg_gen_extrl_i64_i32(t1, c);
- for (i = 0; i < oprsz; i += 8) {
+ for (i = 0; i < oprsz; i += 4) {
tcg_gen_ld_i32(t0, tcg_env, aofs + i);
tcg_gen_negsetcond_i32(cond, t0, t0, t1);
tcg_gen_st_i32(t0, tcg_env, dofs + i);
diff --git a/tcg/tcg-op-ldst.c b/tcg/tcg-op-ldst.c
index 8510160..a318011 100644
--- a/tcg/tcg-op-ldst.c
+++ b/tcg/tcg-op-ldst.c
@@ -45,7 +45,7 @@ static void check_max_alignment(unsigned a_bits)
static MemOp tcg_canonicalize_memop(MemOp op, bool is64, bool st)
{
- unsigned a_bits = get_alignment_bits(op);
+ unsigned a_bits = memop_alignment_bits(op);
check_max_alignment(a_bits);
@@ -148,11 +148,11 @@ static TCGv_i64 plugin_maybe_preserve_addr(TCGTemp *addr)
return NULL;
}
+#ifdef CONFIG_PLUGIN
static void
plugin_gen_mem_callbacks(TCGv_i64 copy_addr, TCGTemp *orig_addr, MemOpIdx oi,
enum qemu_plugin_mem_rw rw)
{
-#ifdef CONFIG_PLUGIN
if (tcg_ctx->plugin_insn != NULL) {
qemu_plugin_meminfo_t info = make_plugin_meminfo(oi, rw);
@@ -172,6 +172,54 @@ plugin_gen_mem_callbacks(TCGv_i64 copy_addr, TCGTemp *orig_addr, MemOpIdx oi,
}
}
}
+}
+#endif
+
+static void
+plugin_gen_mem_callbacks_i32(TCGv_i32 val,
+ TCGv_i64 copy_addr, TCGTemp *orig_addr,
+ MemOpIdx oi, enum qemu_plugin_mem_rw rw)
+{
+#ifdef CONFIG_PLUGIN
+ if (tcg_ctx->plugin_insn != NULL) {
+ tcg_gen_st_i32(val, tcg_env,
+ offsetof(CPUState, neg.plugin_mem_value_low) -
+ sizeof(CPUState) + (HOST_BIG_ENDIAN * 4));
+ plugin_gen_mem_callbacks(copy_addr, orig_addr, oi, rw);
+ }
+#endif
+}
+
+static void
+plugin_gen_mem_callbacks_i64(TCGv_i64 val,
+ TCGv_i64 copy_addr, TCGTemp *orig_addr,
+ MemOpIdx oi, enum qemu_plugin_mem_rw rw)
+{
+#ifdef CONFIG_PLUGIN
+ if (tcg_ctx->plugin_insn != NULL) {
+ tcg_gen_st_i64(val, tcg_env,
+ offsetof(CPUState, neg.plugin_mem_value_low) -
+ sizeof(CPUState));
+ plugin_gen_mem_callbacks(copy_addr, orig_addr, oi, rw);
+ }
+#endif
+}
+
+static void
+plugin_gen_mem_callbacks_i128(TCGv_i128 val,
+ TCGv_i64 copy_addr, TCGTemp *orig_addr,
+ MemOpIdx oi, enum qemu_plugin_mem_rw rw)
+{
+#ifdef CONFIG_PLUGIN
+ if (tcg_ctx->plugin_insn != NULL) {
+ tcg_gen_st_i64(TCGV128_LOW(val), tcg_env,
+ offsetof(CPUState, neg.plugin_mem_value_low) -
+ sizeof(CPUState));
+ tcg_gen_st_i64(TCGV128_HIGH(val), tcg_env,
+ offsetof(CPUState, neg.plugin_mem_value_high) -
+ sizeof(CPUState));
+ plugin_gen_mem_callbacks(copy_addr, orig_addr, oi, rw);
+ }
#endif
}
@@ -203,7 +251,8 @@ static void tcg_gen_qemu_ld_i32_int(TCGv_i32 val, TCGTemp *addr,
opc = INDEX_op_qemu_ld_a64_i32;
}
gen_ldst(opc, tcgv_i32_temp(val), NULL, addr, oi);
- plugin_gen_mem_callbacks(copy_addr, addr, orig_oi, QEMU_PLUGIN_MEM_R);
+ plugin_gen_mem_callbacks_i32(val, copy_addr, addr, orig_oi,
+ QEMU_PLUGIN_MEM_R);
if ((orig_memop ^ memop) & MO_BSWAP) {
switch (orig_memop & MO_SIZE) {
@@ -271,7 +320,7 @@ static void tcg_gen_qemu_st_i32_int(TCGv_i32 val, TCGTemp *addr,
}
}
gen_ldst(opc, tcgv_i32_temp(val), NULL, addr, oi);
- plugin_gen_mem_callbacks(NULL, addr, orig_oi, QEMU_PLUGIN_MEM_W);
+ plugin_gen_mem_callbacks_i32(val, NULL, addr, orig_oi, QEMU_PLUGIN_MEM_W);
if (swap) {
tcg_temp_free_i32(swap);
@@ -324,7 +373,8 @@ static void tcg_gen_qemu_ld_i64_int(TCGv_i64 val, TCGTemp *addr,
opc = INDEX_op_qemu_ld_a64_i64;
}
gen_ldst_i64(opc, val, addr, oi);
- plugin_gen_mem_callbacks(copy_addr, addr, orig_oi, QEMU_PLUGIN_MEM_R);
+ plugin_gen_mem_callbacks_i64(val, copy_addr, addr, orig_oi,
+ QEMU_PLUGIN_MEM_R);
if ((orig_memop ^ memop) & MO_BSWAP) {
int flags = (orig_memop & MO_SIGN
@@ -396,7 +446,7 @@ static void tcg_gen_qemu_st_i64_int(TCGv_i64 val, TCGTemp *addr,
opc = INDEX_op_qemu_st_a64_i64;
}
gen_ldst_i64(opc, val, addr, oi);
- plugin_gen_mem_callbacks(NULL, addr, orig_oi, QEMU_PLUGIN_MEM_W);
+ plugin_gen_mem_callbacks_i64(val, NULL, addr, orig_oi, QEMU_PLUGIN_MEM_W);
if (swap) {
tcg_temp_free_i64(swap);
@@ -509,7 +559,7 @@ static void tcg_gen_qemu_ld_i128_int(TCGv_i128 val, TCGTemp *addr,
TCGv_i64 ext_addr = NULL;
TCGOpcode opc;
- check_max_alignment(get_alignment_bits(memop));
+ check_max_alignment(memop_alignment_bits(memop));
tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
/* In serial mode, reduce atomicity. */
@@ -606,7 +656,8 @@ static void tcg_gen_qemu_ld_i128_int(TCGv_i128 val, TCGTemp *addr,
tcg_constant_i32(orig_oi));
}
- plugin_gen_mem_callbacks(ext_addr, addr, orig_oi, QEMU_PLUGIN_MEM_R);
+ plugin_gen_mem_callbacks_i128(val, ext_addr, addr, orig_oi,
+ QEMU_PLUGIN_MEM_R);
}
void tcg_gen_qemu_ld_i128_chk(TCGv_i128 val, TCGTemp *addr, TCGArg idx,
@@ -625,7 +676,7 @@ static void tcg_gen_qemu_st_i128_int(TCGv_i128 val, TCGTemp *addr,
TCGv_i64 ext_addr = NULL;
TCGOpcode opc;
- check_max_alignment(get_alignment_bits(memop));
+ check_max_alignment(memop_alignment_bits(memop));
tcg_gen_req_mo(TCG_MO_ST_LD | TCG_MO_ST_ST);
/* In serial mode, reduce atomicity. */
@@ -722,7 +773,8 @@ static void tcg_gen_qemu_st_i128_int(TCGv_i128 val, TCGTemp *addr,
tcg_constant_i32(orig_oi));
}
- plugin_gen_mem_callbacks(ext_addr, addr, orig_oi, QEMU_PLUGIN_MEM_W);
+ plugin_gen_mem_callbacks_i128(val, ext_addr, addr, orig_oi,
+ QEMU_PLUGIN_MEM_W);
}
void tcg_gen_qemu_st_i128_chk(TCGv_i128 val, TCGTemp *addr, TCGArg idx,
diff --git a/tcg/tcg-op-vec.c b/tcg/tcg-op-vec.c
index 84af210..d4bb4ae 100644
--- a/tcg/tcg-op-vec.c
+++ b/tcg/tcg-op-vec.c
@@ -172,8 +172,8 @@ void vec_gen_4(TCGOpcode opc, TCGType type, unsigned vece,
op->args[3] = c;
}
-static void vec_gen_6(TCGOpcode opc, TCGType type, unsigned vece, TCGArg r,
- TCGArg a, TCGArg b, TCGArg c, TCGArg d, TCGArg e)
+void vec_gen_6(TCGOpcode opc, TCGType type, unsigned vece, TCGArg r,
+ TCGArg a, TCGArg b, TCGArg c, TCGArg d, TCGArg e)
{
TCGOp *op = tcg_emit_op(opc, 6);
TCGOP_VECL(op) = type - TCG_TYPE_V64;
diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
index eff3728..4a7e705 100644
--- a/tcg/tcg-op.c
+++ b/tcg/tcg-op.c
@@ -37,38 +37,43 @@
*/
#define NI __attribute__((noinline))
-void NI tcg_gen_op1(TCGOpcode opc, TCGArg a1)
+TCGOp * NI tcg_gen_op1(TCGOpcode opc, TCGArg a1)
{
TCGOp *op = tcg_emit_op(opc, 1);
op->args[0] = a1;
+ return op;
}
-void NI tcg_gen_op2(TCGOpcode opc, TCGArg a1, TCGArg a2)
+TCGOp * NI tcg_gen_op2(TCGOpcode opc, TCGArg a1, TCGArg a2)
{
TCGOp *op = tcg_emit_op(opc, 2);
op->args[0] = a1;
op->args[1] = a2;
+ return op;
}
-void NI tcg_gen_op3(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3)
+TCGOp * NI tcg_gen_op3(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3)
{
TCGOp *op = tcg_emit_op(opc, 3);
op->args[0] = a1;
op->args[1] = a2;
op->args[2] = a3;
+ return op;
}
-void NI tcg_gen_op4(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3, TCGArg a4)
+TCGOp * NI tcg_gen_op4(TCGOpcode opc, TCGArg a1, TCGArg a2,
+ TCGArg a3, TCGArg a4)
{
TCGOp *op = tcg_emit_op(opc, 4);
op->args[0] = a1;
op->args[1] = a2;
op->args[2] = a3;
op->args[3] = a4;
+ return op;
}
-void NI tcg_gen_op5(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3,
- TCGArg a4, TCGArg a5)
+TCGOp * NI tcg_gen_op5(TCGOpcode opc, TCGArg a1, TCGArg a2,
+ TCGArg a3, TCGArg a4, TCGArg a5)
{
TCGOp *op = tcg_emit_op(opc, 5);
op->args[0] = a1;
@@ -76,10 +81,11 @@ void NI tcg_gen_op5(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3,
op->args[2] = a3;
op->args[3] = a4;
op->args[4] = a5;
+ return op;
}
-void NI tcg_gen_op6(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3,
- TCGArg a4, TCGArg a5, TCGArg a6)
+TCGOp * NI tcg_gen_op6(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3,
+ TCGArg a4, TCGArg a5, TCGArg a6)
{
TCGOp *op = tcg_emit_op(opc, 6);
op->args[0] = a1;
@@ -88,6 +94,7 @@ void NI tcg_gen_op6(TCGOpcode opc, TCGArg a1, TCGArg a2, TCGArg a3,
op->args[3] = a4;
op->args[4] = a5;
op->args[5] = a6;
+ return op;
}
/*
@@ -110,9 +117,9 @@ static void DNI tcg_gen_op1_i64(TCGOpcode opc, TCGv_i64 a1)
tcg_gen_op1(opc, tcgv_i64_arg(a1));
}
-static void DNI tcg_gen_op1i(TCGOpcode opc, TCGArg a1)
+static TCGOp * DNI tcg_gen_op1i(TCGOpcode opc, TCGArg a1)
{
- tcg_gen_op1(opc, a1);
+ return tcg_gen_op1(opc, a1);
}
static void DNI tcg_gen_op2_i32(TCGOpcode opc, TCGv_i32 a1, TCGv_i32 a2)
@@ -189,16 +196,16 @@ static void DNI tcg_gen_op4i_i64(TCGOpcode opc, TCGv_i64 a1, TCGv_i64 a2,
tcgv_i64_arg(a3), a4);
}
-static void DNI tcg_gen_op4ii_i32(TCGOpcode opc, TCGv_i32 a1, TCGv_i32 a2,
- TCGArg a3, TCGArg a4)
+static TCGOp * DNI tcg_gen_op4ii_i32(TCGOpcode opc, TCGv_i32 a1, TCGv_i32 a2,
+ TCGArg a3, TCGArg a4)
{
- tcg_gen_op4(opc, tcgv_i32_arg(a1), tcgv_i32_arg(a2), a3, a4);
+ return tcg_gen_op4(opc, tcgv_i32_arg(a1), tcgv_i32_arg(a2), a3, a4);
}
-static void DNI tcg_gen_op4ii_i64(TCGOpcode opc, TCGv_i64 a1, TCGv_i64 a2,
- TCGArg a3, TCGArg a4)
+static TCGOp * DNI tcg_gen_op4ii_i64(TCGOpcode opc, TCGv_i64 a1, TCGv_i64 a2,
+ TCGArg a3, TCGArg a4)
{
- tcg_gen_op4(opc, tcgv_i64_arg(a1), tcgv_i64_arg(a2), a3, a4);
+ return tcg_gen_op4(opc, tcgv_i64_arg(a1), tcgv_i64_arg(a2), a3, a4);
}
static void DNI tcg_gen_op5_i32(TCGOpcode opc, TCGv_i32 a1, TCGv_i32 a2,
@@ -263,12 +270,12 @@ static void DNI tcg_gen_op6i_i64(TCGOpcode opc, TCGv_i64 a1, TCGv_i64 a2,
tcgv_i64_arg(a3), tcgv_i64_arg(a4), tcgv_i64_arg(a5), a6);
}
-static void DNI tcg_gen_op6ii_i32(TCGOpcode opc, TCGv_i32 a1, TCGv_i32 a2,
- TCGv_i32 a3, TCGv_i32 a4,
- TCGArg a5, TCGArg a6)
+static TCGOp * DNI tcg_gen_op6ii_i32(TCGOpcode opc, TCGv_i32 a1, TCGv_i32 a2,
+ TCGv_i32 a3, TCGv_i32 a4,
+ TCGArg a5, TCGArg a6)
{
- tcg_gen_op6(opc, tcgv_i32_arg(a1), tcgv_i32_arg(a2),
- tcgv_i32_arg(a3), tcgv_i32_arg(a4), a5, a6);
+ return tcg_gen_op6(opc, tcgv_i32_arg(a1), tcgv_i32_arg(a2),
+ tcgv_i32_arg(a3), tcgv_i32_arg(a4), a5, a6);
}
/* Generic ops. */
@@ -279,18 +286,17 @@ void gen_set_label(TCGLabel *l)
tcg_gen_op1(INDEX_op_set_label, label_arg(l));
}
-static void add_last_as_label_use(TCGLabel *l)
+static void add_as_label_use(TCGLabel *l, TCGOp *op)
{
TCGLabelUse *u = tcg_malloc(sizeof(TCGLabelUse));
- u->op = tcg_last_op();
+ u->op = op;
QSIMPLEQ_INSERT_TAIL(&l->branches, u, next);
}
void tcg_gen_br(TCGLabel *l)
{
- tcg_gen_op1(INDEX_op_br, label_arg(l));
- add_last_as_label_use(l);
+ add_as_label_use(l, tcg_gen_op1(INDEX_op_br, label_arg(l)));
}
void tcg_gen_mb(TCGBar mb_type)
@@ -507,8 +513,9 @@ void tcg_gen_brcond_i32(TCGCond cond, TCGv_i32 arg1, TCGv_i32 arg2, TCGLabel *l)
if (cond == TCG_COND_ALWAYS) {
tcg_gen_br(l);
} else if (cond != TCG_COND_NEVER) {
- tcg_gen_op4ii_i32(INDEX_op_brcond_i32, arg1, arg2, cond, label_arg(l));
- add_last_as_label_use(l);
+ TCGOp *op = tcg_gen_op4ii_i32(INDEX_op_brcond_i32,
+ arg1, arg2, cond, label_arg(l));
+ add_as_label_use(l, op);
}
}
@@ -1927,15 +1934,16 @@ void tcg_gen_brcond_i64(TCGCond cond, TCGv_i64 arg1, TCGv_i64 arg2, TCGLabel *l)
if (cond == TCG_COND_ALWAYS) {
tcg_gen_br(l);
} else if (cond != TCG_COND_NEVER) {
+ TCGOp *op;
if (TCG_TARGET_REG_BITS == 32) {
- tcg_gen_op6ii_i32(INDEX_op_brcond2_i32, TCGV_LOW(arg1),
- TCGV_HIGH(arg1), TCGV_LOW(arg2),
- TCGV_HIGH(arg2), cond, label_arg(l));
+ op = tcg_gen_op6ii_i32(INDEX_op_brcond2_i32, TCGV_LOW(arg1),
+ TCGV_HIGH(arg1), TCGV_LOW(arg2),
+ TCGV_HIGH(arg2), cond, label_arg(l));
} else {
- tcg_gen_op4ii_i64(INDEX_op_brcond_i64, arg1, arg2, cond,
- label_arg(l));
+ op = tcg_gen_op4ii_i64(INDEX_op_brcond_i64, arg1, arg2, cond,
+ label_arg(l));
}
- add_last_as_label_use(l);
+ add_as_label_use(l, op);
}
}
@@ -1946,12 +1954,12 @@ void tcg_gen_brcondi_i64(TCGCond cond, TCGv_i64 arg1, int64_t arg2, TCGLabel *l)
} else if (cond == TCG_COND_ALWAYS) {
tcg_gen_br(l);
} else if (cond != TCG_COND_NEVER) {
- tcg_gen_op6ii_i32(INDEX_op_brcond2_i32,
- TCGV_LOW(arg1), TCGV_HIGH(arg1),
- tcg_constant_i32(arg2),
- tcg_constant_i32(arg2 >> 32),
- cond, label_arg(l));
- add_last_as_label_use(l);
+ TCGOp *op = tcg_gen_op6ii_i32(INDEX_op_brcond2_i32,
+ TCGV_LOW(arg1), TCGV_HIGH(arg1),
+ tcg_constant_i32(arg2),
+ tcg_constant_i32(arg2 >> 32),
+ cond, label_arg(l));
+ add_as_label_use(l, op);
}
}
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 34e3056..0babae1 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -1399,7 +1399,6 @@ TranslationBlock *tcg_tb_alloc(TCGContext *s)
goto retry;
}
qatomic_set(&s->code_gen_ptr, next);
- s->data_gen_ptr = NULL;
return tb;
}
@@ -5506,7 +5505,7 @@ static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op)
static TCGAtomAlign atom_and_align_for_opc(TCGContext *s, MemOp opc,
MemOp host_atom, bool allow_two_ops)
{
- MemOp align = get_alignment_bits(opc);
+ MemOp align = memop_alignment_bits(opc);
MemOp size = opc & MO_SIZE;
MemOp half = size ? size - 1 : 0;
MemOp atom = opc & MO_ATOM_MASK;
@@ -6172,6 +6171,7 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start)
*/
s->code_buf = tcg_splitwx_to_rw(tb->tc.ptr);
s->code_ptr = s->code_buf;
+ s->data_gen_ptr = NULL;
#ifdef TCG_TARGET_NEED_LDST_LABELS
QSIMPLEQ_INIT(&s->ldst_labels);
diff --git a/tests/Makefile.include b/tests/Makefile.include
index d39d5dd..010369b 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -3,28 +3,30 @@
.PHONY: check-help
check-help:
@echo "Regression testing targets:"
- @echo " $(MAKE) check Run block, qapi-schema, unit, softfloat, qtest and decodetree tests"
- @echo " $(MAKE) bench Run speed tests"
+ @echo " $(MAKE) check Run block, qapi-schema, unit, softfloat, qtest and decodetree tests"
+ @echo " $(MAKE) bench Run speed tests"
@echo
@echo "Individual test suites:"
- @echo " $(MAKE) check-qtest-TARGET Run qtest tests for given target"
- @echo " $(MAKE) check-qtest Run qtest tests"
- @echo " $(MAKE) check-unit Run qobject tests"
- @echo " $(MAKE) check-qapi-schema Run QAPI schema tests"
- @echo " $(MAKE) check-block Run block tests"
+ @echo " $(MAKE) check-qtest-TARGET Run qtest tests for given target"
+ @echo " $(MAKE) check-qtest Run qtest tests"
+ @echo " $(MAKE) check-functional Run python-based functional tests"
+ @echo " $(MAKE) check-functional-TARGET Run functional tests for a given target"
+ @echo " $(MAKE) check-unit Run qobject tests"
+ @echo " $(MAKE) check-qapi-schema Run QAPI schema tests"
+ @echo " $(MAKE) check-block Run block tests"
ifneq ($(filter $(all-check-targets), check-softfloat),)
- @echo " $(MAKE) check-tcg Run TCG tests"
- @echo " $(MAKE) check-softfloat Run FPU emulation tests"
+ @echo " $(MAKE) check-tcg Run TCG tests"
+ @echo " $(MAKE) check-softfloat Run FPU emulation tests"
endif
- @echo " $(MAKE) check-avocado Run avocado (integration) tests for currently configured targets"
+ @echo " $(MAKE) check-avocado Run avocado (integration) tests for currently configured targets"
@echo
- @echo " $(MAKE) check-report.junit.xml Generates an aggregated XML test report"
- @echo " $(MAKE) check-venv Creates a Python venv for tests"
- @echo " $(MAKE) check-clean Clean the tests and related data"
+ @echo " $(MAKE) check-report.junit.xml Generates an aggregated XML test report"
+ @echo " $(MAKE) check-venv Creates a Python venv for tests"
+ @echo " $(MAKE) check-clean Clean the tests and related data"
@echo
@echo "The following are useful for CI builds"
- @echo " $(MAKE) check-build Build most test binaries"
- @echo " $(MAKE) get-vm-images Downloads all images used by avocado tests, according to configured targets (~350 MB each, 1.5 GB max)"
+ @echo " $(MAKE) check-build Build most test binaries"
+ @echo " $(MAKE) get-vm-images Downloads all images used by avocado tests, according to configured targets (~350 MB each, 1.5 GB max)"
@echo
@echo
@echo "The variable SPEED can be set to control the gtester speed setting."
@@ -97,7 +99,7 @@ endif
# Controls the output generated by Avocado when running tests.
# Any number of command separated loggers are accepted. For more
# information please refer to "avocado --help".
-AVOCADO_SHOW=app
+AVOCADO_SHOW?=app
ifndef AVOCADO_TAGS
AVOCADO_CMDLINE_TAGS=$(patsubst %-softmmu,-t arch:%, \
$(filter %-softmmu,$(TARGETS)))
@@ -141,7 +143,7 @@ check-avocado: check-venv $(TESTS_RESULTS_DIR) get-vm-images
--show=$(AVOCADO_SHOW) run --job-results-dir=$(TESTS_RESULTS_DIR) \
$(if $(AVOCADO_TAGS),, --filter-by-tags-include-empty \
--filter-by-tags-include-empty-key) \
- $(AVOCADO_CMDLINE_TAGS) \
+ $(AVOCADO_CMDLINE_TAGS) --max-parallel-tasks=1 \
$(if $(GITLAB_CI),,--failfast) $(AVOCADO_TESTS), \
"AVOCADO", "tests/avocado")
@@ -152,6 +154,16 @@ check-acceptance-deprecated-warning:
check-acceptance: check-acceptance-deprecated-warning | check-avocado
+FUNCTIONAL_TARGETS=$(patsubst %-softmmu,check-functional-%, $(filter %-softmmu,$(TARGETS)))
+.PHONY: $(FUNCTIONAL_TARGETS)
+$(FUNCTIONAL_TARGETS):
+ @$(MAKE) SPEED=thorough $(subst -functional,-func,$@)
+
+.PHONY: check-functional
+check-functional:
+ @$(NINJA) precache-functional
+ @QEMU_TEST_NO_DOWNLOAD=1 $(MAKE) SPEED=thorough check-func check-func-quick
+
# Consolidated targets
.PHONY: check check-clean get-vm-images
diff --git a/tests/avocado/avocado_qemu/__init__.py b/tests/avocado/avocado_qemu/__init__.py
index 304c428..93c3460 100644
--- a/tests/avocado/avocado_qemu/__init__.py
+++ b/tests/avocado/avocado_qemu/__init__.py
@@ -10,7 +10,6 @@
import logging
import os
-import shutil
import subprocess
import sys
import tempfile
@@ -18,7 +17,7 @@ import time
import uuid
import avocado
-from avocado.utils import cloudinit, datadrainer, process, ssh, vmimage
+from avocado.utils import ssh
from avocado.utils.path import find_command
from qemu.machine import QEMUMachine
@@ -32,14 +31,6 @@ from qemu.utils import (get_info_usernet_hostfwd_port, kvm_available,
#: and build tree, it will not be accurate.
BUILD_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
-if os.path.islink(os.path.dirname(os.path.dirname(__file__))):
- # The link to the avocado tests dir in the source code directory
- lnk = os.path.dirname(os.path.dirname(__file__))
- #: The QEMU root source directory
- SOURCE_DIR = os.path.dirname(os.path.dirname(os.readlink(lnk)))
-else:
- SOURCE_DIR = BUILD_DIR
-
def has_cmd(name, args=None):
"""
@@ -144,6 +135,13 @@ def _console_interaction(test, success_message, failure_message,
vm.console_socket.sendall(send_string.encode())
if not keep_sending:
send_string = None # send only once
+
+ # Only consume console output if waiting for something
+ if success_message is None and failure_message is None:
+ if send_string is None:
+ break
+ continue
+
try:
msg = console.readline().decode().strip()
except UnicodeDecodeError:
@@ -309,16 +307,6 @@ class QemuSystemTest(QemuBaseTest):
if netdevhelp.find('\n' + netdevname + '\n') < 0:
self.cancel('no support for user networking')
- def require_multiprocess(self):
- """
- Test for the presence of the x-pci-proxy-dev which is required
- to support multiprocess.
- """
- devhelp = run_cmd([self.qemu_bin,
- '-M', 'none', '-device', 'help'])[0];
- if devhelp.find('x-pci-proxy-dev') < 0:
- self.cancel('no support for multiprocess device emulation')
-
def _new_vm(self, name, *args):
self._sd = tempfile.TemporaryDirectory(prefix="qemu_")
vm = QEMUMachine(self.qemu_bin, base_temp_dir=self.workdir,
@@ -386,23 +374,6 @@ class QemuSystemTest(QemuBaseTest):
super().tearDown()
-class QemuUserTest(QemuBaseTest):
- """Facilitates user-mode emulation tests."""
-
- def setUp(self):
- self._ldpath = []
- super().setUp('qemu-')
-
- def add_ldpath(self, ldpath):
- self._ldpath.append(os.path.abspath(ldpath))
-
- def run(self, bin_path, args=[]):
- qemu_args = " ".join(["-L %s" % ldpath for ldpath in self._ldpath])
- bin_args = " ".join(args)
- return process.run("%s %s %s %s" % (self.qemu_bin, qemu_args,
- bin_path, bin_args))
-
-
class LinuxSSHMixIn:
"""Contains utility methods for interacting with a guest via SSH."""
@@ -451,231 +422,3 @@ class LinuxSSHMixIn:
break
else:
self.fail('"%s" output does not contain "%s"' % (cmd, exp))
-
-class LinuxDistro:
- """Represents a Linux distribution
-
- Holds information of known distros.
- """
- #: A collection of known distros and their respective image checksum
- KNOWN_DISTROS = {
- 'fedora': {
- '31': {
- 'x86_64':
- {'checksum': ('e3c1b309d9203604922d6e255c2c5d09'
- '8a309c2d46215d8fc026954f3c5c27a0'),
- 'pxeboot_url': ('https://archives.fedoraproject.org/'
- 'pub/archive/fedora/linux/releases/31/'
- 'Everything/x86_64/os/images/pxeboot/'),
- 'kernel_params': ('root=UUID=b1438b9b-2cab-4065-a99a-'
- '08a96687f73c ro no_timer_check '
- 'net.ifnames=0 console=tty1 '
- 'console=ttyS0,115200n8'),
- },
- 'aarch64':
- {'checksum': ('1e18d9c0cf734940c4b5d5ec592facae'
- 'd2af0ad0329383d5639c997fdf16fe49'),
- 'pxeboot_url': 'https://archives.fedoraproject.org/'
- 'pub/archive/fedora/linux/releases/31/'
- 'Everything/aarch64/os/images/pxeboot/',
- 'kernel_params': ('root=UUID=b6950a44-9f3c-4076-a9c2-'
- '355e8475b0a7 ro earlyprintk=pl011,0x9000000'
- ' ignore_loglevel no_timer_check'
- ' printk.time=1 rd_NO_PLYMOUTH'
- ' console=ttyAMA0'),
- },
- 'ppc64':
- {'checksum': ('7c3528b85a3df4b2306e892199a9e1e4'
- '3f991c506f2cc390dc4efa2026ad2f58')},
- 's390x':
- {'checksum': ('4caaab5a434fd4d1079149a072fdc789'
- '1e354f834d355069ca982fdcaf5a122d')},
- },
- '32': {
- 'aarch64':
- {'checksum': ('b367755c664a2d7a26955bbfff985855'
- 'adfa2ca15e908baf15b4b176d68d3967'),
- 'pxeboot_url': ('http://dl.fedoraproject.org/pub/fedora/linux/'
- 'releases/32/Server/aarch64/os/images/'
- 'pxeboot/'),
- 'kernel_params': ('root=UUID=3df75b65-be8d-4db4-8655-'
- '14d95c0e90c5 ro no_timer_check net.ifnames=0'
- ' console=tty1 console=ttyS0,115200n8'),
- },
- },
- '33': {
- 'aarch64':
- {'checksum': ('e7f75cdfd523fe5ac2ca9eeece68edc1'
- 'a81f386a17f969c1d1c7c87031008a6b'),
- 'pxeboot_url': ('http://dl.fedoraproject.org/pub/fedora/linux/'
- 'releases/33/Server/aarch64/os/images/'
- 'pxeboot/'),
- 'kernel_params': ('root=UUID=d20b3ffa-6397-4a63-a734-'
- '1126a0208f8a ro no_timer_check net.ifnames=0'
- ' console=tty1 console=ttyS0,115200n8'
- ' console=tty0'),
- },
- },
- }
- }
-
- def __init__(self, name, version, arch):
- self.name = name
- self.version = version
- self.arch = arch
- try:
- info = self.KNOWN_DISTROS.get(name).get(version).get(arch)
- except AttributeError:
- # Unknown distro
- info = None
- self._info = info or {}
-
- @property
- def checksum(self):
- """Gets the cloud-image file checksum"""
- return self._info.get('checksum', None)
-
- @checksum.setter
- def checksum(self, value):
- self._info['checksum'] = value
-
- @property
- def pxeboot_url(self):
- """Gets the repository url where pxeboot files can be found"""
- return self._info.get('pxeboot_url', None)
-
- @property
- def default_kernel_params(self):
- """Gets the default kernel parameters"""
- return self._info.get('kernel_params', None)
-
-
-class LinuxTest(LinuxSSHMixIn, QemuSystemTest):
- """Facilitates having a cloud-image Linux based available.
-
- For tests that intend to interact with guests, this is a better choice
- to start with than the more vanilla `QemuSystemTest` class.
- """
-
- distro = None
- username = 'root'
- password = 'password'
- smp = '2'
- memory = '1024'
-
- def _set_distro(self):
- distro_name = self.params.get(
- 'distro',
- default=self._get_unique_tag_val('distro'))
- if not distro_name:
- distro_name = 'fedora'
-
- distro_version = self.params.get(
- 'distro_version',
- default=self._get_unique_tag_val('distro_version'))
- if not distro_version:
- distro_version = '31'
-
- self.distro = LinuxDistro(distro_name, distro_version, self.arch)
-
- # The distro checksum behaves differently than distro name and
- # version. First, it does not respect a tag with the same
- # name, given that it's not expected to be used for filtering
- # (distro name versions are the natural choice). Second, the
- # order of precedence is: parameter, attribute and then value
- # from KNOWN_DISTROS.
- distro_checksum = self.params.get('distro_checksum',
- default=None)
- if distro_checksum:
- self.distro.checksum = distro_checksum
-
- def setUp(self, ssh_pubkey=None, network_device_type='virtio-net'):
- super().setUp()
- self.require_netdev('user')
- self._set_distro()
- self.vm.add_args('-smp', self.smp)
- self.vm.add_args('-m', self.memory)
- # The following network device allows for SSH connections
- self.vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22',
- '-device', '%s,netdev=vnet' % network_device_type)
- self.set_up_boot()
- if ssh_pubkey is None:
- ssh_pubkey, self.ssh_key = self.set_up_existing_ssh_keys()
- self.set_up_cloudinit(ssh_pubkey)
-
- def set_up_existing_ssh_keys(self):
- ssh_public_key = os.path.join(SOURCE_DIR, 'tests', 'keys', 'id_rsa.pub')
- source_private_key = os.path.join(SOURCE_DIR, 'tests', 'keys', 'id_rsa')
- ssh_dir = os.path.join(self.workdir, '.ssh')
- os.mkdir(ssh_dir, mode=0o700)
- ssh_private_key = os.path.join(ssh_dir,
- os.path.basename(source_private_key))
- shutil.copyfile(source_private_key, ssh_private_key)
- os.chmod(ssh_private_key, 0o600)
- return (ssh_public_key, ssh_private_key)
-
- def download_boot(self):
- # Set the qemu-img binary.
- # If none is available, the test will cancel.
- vmimage.QEMU_IMG = super().get_qemu_img()
-
- self.log.info('Downloading/preparing boot image')
- # Fedora 31 only provides ppc64le images
- image_arch = self.arch
- if self.distro.name == 'fedora':
- if image_arch == 'ppc64':
- image_arch = 'ppc64le'
-
- try:
- boot = vmimage.get(
- self.distro.name, arch=image_arch, version=self.distro.version,
- checksum=self.distro.checksum,
- algorithm='sha256',
- cache_dir=self.cache_dirs[0],
- snapshot_dir=self.workdir)
- except:
- self.cancel('Failed to download/prepare boot image')
- return boot.path
-
- def prepare_cloudinit(self, ssh_pubkey=None):
- self.log.info('Preparing cloudinit image')
- try:
- cloudinit_iso = os.path.join(self.workdir, 'cloudinit.iso')
- pubkey_content = None
- if ssh_pubkey:
- with open(ssh_pubkey) as pubkey:
- pubkey_content = pubkey.read()
- cloudinit.iso(cloudinit_iso, self.name,
- username=self.username,
- password=self.password,
- # QEMU's hard coded usermode router address
- phone_home_host='10.0.2.2',
- phone_home_port=self.phone_server.server_port,
- authorized_key=pubkey_content)
- except Exception:
- self.cancel('Failed to prepare the cloudinit image')
- return cloudinit_iso
-
- def set_up_boot(self):
- path = self.download_boot()
- self.vm.add_args('-drive', 'file=%s' % path)
-
- def set_up_cloudinit(self, ssh_pubkey=None):
- self.phone_server = cloudinit.PhoneHomeServer(('0.0.0.0', 0),
- self.name)
- cloudinit_iso = self.prepare_cloudinit(ssh_pubkey)
- self.vm.add_args('-drive', 'file=%s,format=raw' % cloudinit_iso)
-
- def launch_and_wait(self, set_up_ssh_connection=True):
- self.vm.set_console()
- self.vm.launch()
- console_drainer = datadrainer.LineLogger(self.vm.console_socket.fileno(),
- logger=self.log.getChild('console'))
- console_drainer.start()
- self.log.info('VM launched, waiting for boot confirmation from guest')
- while not self.phone_server.instance_phoned_back:
- self.phone_server.handle_request()
-
- if set_up_ssh_connection:
- self.log.info('Setting up the SSH connection')
- self.ssh_connect(self.username, self.ssh_key)
diff --git a/tests/avocado/avocado_qemu/linuxtest.py b/tests/avocado/avocado_qemu/linuxtest.py
new file mode 100644
index 0000000..66fb9f1
--- /dev/null
+++ b/tests/avocado/avocado_qemu/linuxtest.py
@@ -0,0 +1,253 @@
+# Test class and utilities for functional Linux-based tests
+#
+# Copyright (c) 2018 Red Hat, Inc.
+#
+# Author:
+# Cleber Rosa <crosa@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+import os
+import shutil
+
+from avocado.utils import cloudinit, datadrainer, process, vmimage
+
+from avocado_qemu import LinuxSSHMixIn
+from avocado_qemu import QemuSystemTest
+
+if os.path.islink(os.path.dirname(os.path.dirname(__file__))):
+ # The link to the avocado tests dir in the source code directory
+ lnk = os.path.dirname(os.path.dirname(__file__))
+ #: The QEMU root source directory
+ SOURCE_DIR = os.path.dirname(os.path.dirname(os.readlink(lnk)))
+else:
+ SOURCE_DIR = BUILD_DIR
+
+class LinuxDistro:
+ """Represents a Linux distribution
+
+ Holds information of known distros.
+ """
+ #: A collection of known distros and their respective image checksum
+ KNOWN_DISTROS = {
+ 'fedora': {
+ '31': {
+ 'x86_64':
+ {'checksum': ('e3c1b309d9203604922d6e255c2c5d09'
+ '8a309c2d46215d8fc026954f3c5c27a0'),
+ 'pxeboot_url': ('https://archives.fedoraproject.org/'
+ 'pub/archive/fedora/linux/releases/31/'
+ 'Everything/x86_64/os/images/pxeboot/'),
+ 'kernel_params': ('root=UUID=b1438b9b-2cab-4065-a99a-'
+ '08a96687f73c ro no_timer_check '
+ 'net.ifnames=0 console=tty1 '
+ 'console=ttyS0,115200n8'),
+ },
+ 'aarch64':
+ {'checksum': ('1e18d9c0cf734940c4b5d5ec592facae'
+ 'd2af0ad0329383d5639c997fdf16fe49'),
+ 'pxeboot_url': 'https://archives.fedoraproject.org/'
+ 'pub/archive/fedora/linux/releases/31/'
+ 'Everything/aarch64/os/images/pxeboot/',
+ 'kernel_params': ('root=UUID=b6950a44-9f3c-4076-a9c2-'
+ '355e8475b0a7 ro earlyprintk=pl011,0x9000000'
+ ' ignore_loglevel no_timer_check'
+ ' printk.time=1 rd_NO_PLYMOUTH'
+ ' console=ttyAMA0'),
+ },
+ 'ppc64':
+ {'checksum': ('7c3528b85a3df4b2306e892199a9e1e4'
+ '3f991c506f2cc390dc4efa2026ad2f58')},
+ 's390x':
+ {'checksum': ('4caaab5a434fd4d1079149a072fdc789'
+ '1e354f834d355069ca982fdcaf5a122d')},
+ },
+ '32': {
+ 'aarch64':
+ {'checksum': ('b367755c664a2d7a26955bbfff985855'
+ 'adfa2ca15e908baf15b4b176d68d3967'),
+ 'pxeboot_url': ('http://dl.fedoraproject.org/pub/fedora/linux/'
+ 'releases/32/Server/aarch64/os/images/'
+ 'pxeboot/'),
+ 'kernel_params': ('root=UUID=3df75b65-be8d-4db4-8655-'
+ '14d95c0e90c5 ro no_timer_check net.ifnames=0'
+ ' console=tty1 console=ttyS0,115200n8'),
+ },
+ },
+ '33': {
+ 'aarch64':
+ {'checksum': ('e7f75cdfd523fe5ac2ca9eeece68edc1'
+ 'a81f386a17f969c1d1c7c87031008a6b'),
+ 'pxeboot_url': ('http://dl.fedoraproject.org/pub/fedora/linux/'
+ 'releases/33/Server/aarch64/os/images/'
+ 'pxeboot/'),
+ 'kernel_params': ('root=UUID=d20b3ffa-6397-4a63-a734-'
+ '1126a0208f8a ro no_timer_check net.ifnames=0'
+ ' console=tty1 console=ttyS0,115200n8'
+ ' console=tty0'),
+ },
+ },
+ }
+ }
+
+ def __init__(self, name, version, arch):
+ self.name = name
+ self.version = version
+ self.arch = arch
+ try:
+ info = self.KNOWN_DISTROS.get(name).get(version).get(arch)
+ except AttributeError:
+ # Unknown distro
+ info = None
+ self._info = info or {}
+
+ @property
+ def checksum(self):
+ """Gets the cloud-image file checksum"""
+ return self._info.get('checksum', None)
+
+ @checksum.setter
+ def checksum(self, value):
+ self._info['checksum'] = value
+
+ @property
+ def pxeboot_url(self):
+ """Gets the repository url where pxeboot files can be found"""
+ return self._info.get('pxeboot_url', None)
+
+ @property
+ def default_kernel_params(self):
+ """Gets the default kernel parameters"""
+ return self._info.get('kernel_params', None)
+
+
+class LinuxTest(LinuxSSHMixIn, QemuSystemTest):
+ """Facilitates having a cloud-image Linux based available.
+
+ For tests that intend to interact with guests, this is a better choice
+ to start with than the more vanilla `QemuSystemTest` class.
+ """
+
+ distro = None
+ username = 'root'
+ password = 'password'
+ smp = '2'
+ memory = '1024'
+
+ def _set_distro(self):
+ distro_name = self.params.get(
+ 'distro',
+ default=self._get_unique_tag_val('distro'))
+ if not distro_name:
+ distro_name = 'fedora'
+
+ distro_version = self.params.get(
+ 'distro_version',
+ default=self._get_unique_tag_val('distro_version'))
+ if not distro_version:
+ distro_version = '31'
+
+ self.distro = LinuxDistro(distro_name, distro_version, self.arch)
+
+ # The distro checksum behaves differently than distro name and
+ # version. First, it does not respect a tag with the same
+ # name, given that it's not expected to be used for filtering
+ # (distro name versions are the natural choice). Second, the
+ # order of precedence is: parameter, attribute and then value
+ # from KNOWN_DISTROS.
+ distro_checksum = self.params.get('distro_checksum',
+ default=None)
+ if distro_checksum:
+ self.distro.checksum = distro_checksum
+
+ def setUp(self, ssh_pubkey=None, network_device_type='virtio-net'):
+ super().setUp()
+ self.require_netdev('user')
+ self._set_distro()
+ self.vm.add_args('-smp', self.smp)
+ self.vm.add_args('-m', self.memory)
+ # The following network device allows for SSH connections
+ self.vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22',
+ '-device', '%s,netdev=vnet' % network_device_type)
+ self.set_up_boot()
+ if ssh_pubkey is None:
+ ssh_pubkey, self.ssh_key = self.set_up_existing_ssh_keys()
+ self.set_up_cloudinit(ssh_pubkey)
+
+ def set_up_existing_ssh_keys(self):
+ ssh_public_key = os.path.join(SOURCE_DIR, 'tests', 'keys', 'id_rsa.pub')
+ source_private_key = os.path.join(SOURCE_DIR, 'tests', 'keys', 'id_rsa')
+ ssh_dir = os.path.join(self.workdir, '.ssh')
+ os.mkdir(ssh_dir, mode=0o700)
+ ssh_private_key = os.path.join(ssh_dir,
+ os.path.basename(source_private_key))
+ shutil.copyfile(source_private_key, ssh_private_key)
+ os.chmod(ssh_private_key, 0o600)
+ return (ssh_public_key, ssh_private_key)
+
+ def download_boot(self):
+ # Set the qemu-img binary.
+ # If none is available, the test will cancel.
+ vmimage.QEMU_IMG = super().get_qemu_img()
+
+ self.log.info('Downloading/preparing boot image')
+ # Fedora 31 only provides ppc64le images
+ image_arch = self.arch
+ if self.distro.name == 'fedora':
+ if image_arch == 'ppc64':
+ image_arch = 'ppc64le'
+
+ try:
+ boot = vmimage.get(
+ self.distro.name, arch=image_arch, version=self.distro.version,
+ checksum=self.distro.checksum,
+ algorithm='sha256',
+ cache_dir=self.cache_dirs[0],
+ snapshot_dir=self.workdir)
+ except:
+ self.cancel('Failed to download/prepare boot image')
+ return boot.path
+
+ def prepare_cloudinit(self, ssh_pubkey=None):
+ self.log.info('Preparing cloudinit image')
+ try:
+ cloudinit_iso = os.path.join(self.workdir, 'cloudinit.iso')
+ pubkey_content = None
+ if ssh_pubkey:
+ with open(ssh_pubkey) as pubkey:
+ pubkey_content = pubkey.read()
+ cloudinit.iso(cloudinit_iso, self.name,
+ username=self.username,
+ password=self.password,
+ # QEMU's hard coded usermode router address
+ phone_home_host='10.0.2.2',
+ phone_home_port=self.phone_server.server_port,
+ authorized_key=pubkey_content)
+ except Exception:
+ self.cancel('Failed to prepare the cloudinit image')
+ return cloudinit_iso
+
+ def set_up_boot(self):
+ path = self.download_boot()
+ self.vm.add_args('-drive', 'file=%s' % path)
+
+ def set_up_cloudinit(self, ssh_pubkey=None):
+ self.phone_server = cloudinit.PhoneHomeServer(('0.0.0.0', 0),
+ self.name)
+ cloudinit_iso = self.prepare_cloudinit(ssh_pubkey)
+ self.vm.add_args('-drive', 'file=%s,format=raw' % cloudinit_iso)
+
+ def launch_and_wait(self, set_up_ssh_connection=True):
+ self.vm.set_console()
+ self.vm.launch()
+ console_drainer = datadrainer.LineLogger(self.vm.console_socket.fileno(),
+ logger=self.log.getChild('console'))
+ console_drainer.start()
+ self.log.info('VM launched, waiting for boot confirmation from guest')
+ while not self.phone_server.instance_phoned_back:
+ self.phone_server.handle_request()
+
+ if set_up_ssh_connection:
+ self.log.info('Setting up the SSH connection')
+ self.ssh_connect(self.username, self.ssh_key)
diff --git a/tests/avocado/boot_linux.py b/tests/avocado/boot_linux.py
index cdce4cb..a029ef4 100644
--- a/tests/avocado/boot_linux.py
+++ b/tests/avocado/boot_linux.py
@@ -10,7 +10,8 @@
import os
-from avocado_qemu import LinuxTest, BUILD_DIR
+from avocado_qemu.linuxtest import LinuxTest
+from avocado_qemu import BUILD_DIR
from avocado import skipUnless
diff --git a/tests/avocado/boot_linux_console.py b/tests/avocado/boot_linux_console.py
index c35fc5e..23d1b35 100644
--- a/tests/avocado/boot_linux_console.py
+++ b/tests/avocado/boot_linux_console.py
@@ -116,221 +116,6 @@ class BootLinuxConsole(LinuxKernelTest):
console_pattern = 'Kernel command line: %s' % kernel_command_line
self.wait_for_console_pattern(console_pattern)
- def test_mips_malta(self):
- """
- :avocado: tags=arch:mips
- :avocado: tags=machine:malta
- :avocado: tags=endian:big
- """
- deb_url = ('http://snapshot.debian.org/archive/debian/'
- '20130217T032700Z/pool/main/l/linux-2.6/'
- 'linux-image-2.6.32-5-4kc-malta_2.6.32-48_mips.deb')
- deb_hash = 'a8cfc28ad8f45f54811fc6cf74fc43ffcfe0ba04'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinux-2.6.32-5-4kc-malta')
-
- self.vm.set_console()
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
- self.vm.add_args('-kernel', kernel_path,
- '-append', kernel_command_line)
- self.vm.launch()
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.wait_for_console_pattern(console_pattern)
-
- def test_mips64el_malta(self):
- """
- This test requires the ar tool to extract "data.tar.gz" from
- the Debian package.
-
- The kernel can be rebuilt using this Debian kernel source [1] and
- following the instructions on [2].
-
- [1] http://snapshot.debian.org/package/linux-2.6/2.6.32-48/
- #linux-source-2.6.32_2.6.32-48
- [2] https://kernel-team.pages.debian.net/kernel-handbook/
- ch-common-tasks.html#s-common-official
-
- :avocado: tags=arch:mips64el
- :avocado: tags=machine:malta
- """
- deb_url = ('http://snapshot.debian.org/archive/debian/'
- '20130217T032700Z/pool/main/l/linux-2.6/'
- 'linux-image-2.6.32-5-5kc-malta_2.6.32-48_mipsel.deb')
- deb_hash = '1aaec92083bf22fda31e0d27fa8d9a388e5fc3d5'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinux-2.6.32-5-5kc-malta')
-
- self.vm.set_console()
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
- self.vm.add_args('-kernel', kernel_path,
- '-append', kernel_command_line)
- self.vm.launch()
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.wait_for_console_pattern(console_pattern)
-
- def test_mips64el_fuloong2e(self):
- """
- :avocado: tags=arch:mips64el
- :avocado: tags=machine:fuloong2e
- :avocado: tags=endian:little
- """
- deb_url = ('http://archive.debian.org/debian/pool/main/l/linux/'
- 'linux-image-3.16.0-6-loongson-2e_3.16.56-1+deb8u1_mipsel.deb')
- deb_hash = 'd04d446045deecf7b755ef576551de0c4184dd44'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinux-3.16.0-6-loongson-2e')
-
- self.vm.set_console()
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
- self.vm.add_args('-kernel', kernel_path,
- '-append', kernel_command_line)
- self.vm.launch()
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.wait_for_console_pattern(console_pattern)
-
- def test_mips_malta_cpio(self):
- """
- :avocado: tags=arch:mips
- :avocado: tags=machine:malta
- :avocado: tags=endian:big
- """
- deb_url = ('http://snapshot.debian.org/archive/debian/'
- '20160601T041800Z/pool/main/l/linux/'
- 'linux-image-4.5.0-2-4kc-malta_4.5.5-1_mips.deb')
- deb_hash = 'a3c84f3e88b54e06107d65a410d1d1e8e0f340f8'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinux-4.5.0-2-4kc-malta')
- initrd_url = ('https://github.com/groeck/linux-build-test/raw/'
- '8584a59ed9e5eb5ee7ca91f6d74bbb06619205b8/rootfs/'
- 'mips/rootfs.cpio.gz')
- initrd_hash = 'bf806e17009360a866bf537f6de66590de349a99'
- initrd_path_gz = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
- initrd_path = self.workdir + "rootfs.cpio"
- archive.gzip_uncompress(initrd_path_gz, initrd_path)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE
- + 'console=ttyS0 console=tty '
- + 'rdinit=/sbin/init noreboot')
- self.vm.add_args('-kernel', kernel_path,
- '-initrd', initrd_path,
- '-append', kernel_command_line,
- '-no-reboot')
- self.vm.launch()
- self.wait_for_console_pattern('Boot successful.')
-
- exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
- 'BogoMIPS')
- exec_command_and_wait_for_pattern(self, 'uname -a',
- 'Debian')
- exec_command_and_wait_for_pattern(self, 'reboot',
- 'reboot: Restarting system')
- # Wait for VM to shut down gracefully
- self.vm.wait()
-
- @skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
- def test_mips64el_malta_5KEc_cpio(self):
- """
- :avocado: tags=arch:mips64el
- :avocado: tags=machine:malta
- :avocado: tags=endian:little
- :avocado: tags=cpu:5KEc
- """
- kernel_url = ('https://github.com/philmd/qemu-testing-blob/'
- 'raw/9ad2df38/mips/malta/mips64el/'
- 'vmlinux-3.19.3.mtoman.20150408')
- kernel_hash = '00d1d268fb9f7d8beda1de6bebcc46e884d71754'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- initrd_url = ('https://github.com/groeck/linux-build-test/'
- 'raw/8584a59e/rootfs/'
- 'mipsel64/rootfs.mipsel64r1.cpio.gz')
- initrd_hash = '1dbb8a396e916847325284dbe2151167'
- initrd_path_gz = self.fetch_asset(initrd_url, algorithm='md5',
- asset_hash=initrd_hash)
- initrd_path = self.workdir + "rootfs.cpio"
- archive.gzip_uncompress(initrd_path_gz, initrd_path)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE
- + 'console=ttyS0 console=tty '
- + 'rdinit=/sbin/init noreboot')
- self.vm.add_args('-kernel', kernel_path,
- '-initrd', initrd_path,
- '-append', kernel_command_line,
- '-no-reboot')
- self.vm.launch()
- wait_for_console_pattern(self, 'Boot successful.')
-
- exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
- 'MIPS 5KE')
- exec_command_and_wait_for_pattern(self, 'uname -a',
- '3.19.3.mtoman.20150408')
- exec_command_and_wait_for_pattern(self, 'reboot',
- 'reboot: Restarting system')
- # Wait for VM to shut down gracefully
- self.vm.wait()
-
- def do_test_mips_malta32el_nanomips(self, kernel_url, kernel_hash):
- kernel_path_xz = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- kernel_path = self.workdir + "kernel"
- with lzma.open(kernel_path_xz, 'rb') as f_in:
- with open(kernel_path, 'wb') as f_out:
- shutil.copyfileobj(f_in, f_out)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE
- + 'mem=256m@@0x0 '
- + 'console=ttyS0')
- self.vm.add_args('-no-reboot',
- '-kernel', kernel_path,
- '-append', kernel_command_line)
- self.vm.launch()
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.wait_for_console_pattern(console_pattern)
-
- def test_mips_malta32el_nanomips_4k(self):
- """
- :avocado: tags=arch:mipsel
- :avocado: tags=machine:malta
- :avocado: tags=endian:little
- :avocado: tags=cpu:I7200
- """
- kernel_url = ('https://mipsdistros.mips.com/LinuxDistro/nanomips/'
- 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/'
- 'generic_nano32r6el_page4k.xz')
- kernel_hash = '477456aafd2a0f1ddc9482727f20fe9575565dd6'
- self.do_test_mips_malta32el_nanomips(kernel_url, kernel_hash)
-
- def test_mips_malta32el_nanomips_16k_up(self):
- """
- :avocado: tags=arch:mipsel
- :avocado: tags=machine:malta
- :avocado: tags=endian:little
- :avocado: tags=cpu:I7200
- """
- kernel_url = ('https://mipsdistros.mips.com/LinuxDistro/nanomips/'
- 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/'
- 'generic_nano32r6el_page16k_up.xz')
- kernel_hash = 'e882868f944c71c816e832e2303b7874d044a7bc'
- self.do_test_mips_malta32el_nanomips(kernel_url, kernel_hash)
-
- def test_mips_malta32el_nanomips_64k_dbg(self):
- """
- :avocado: tags=arch:mipsel
- :avocado: tags=machine:malta
- :avocado: tags=endian:little
- :avocado: tags=cpu:I7200
- """
- kernel_url = ('https://mipsdistros.mips.com/LinuxDistro/nanomips/'
- 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/'
- 'generic_nano32r6el_page64k_dbg.xz')
- kernel_hash = '18d1c68f2e23429e266ca39ba5349ccd0aeb7180'
- self.do_test_mips_malta32el_nanomips(kernel_url, kernel_hash)
-
def test_aarch64_xlnx_versal_virt(self):
"""
:avocado: tags=arch:aarch64
@@ -399,14 +184,16 @@ class BootLinuxConsole(LinuxKernelTest):
'fe371d32e50ca682391e1e70ab98c2942aeffb01/spi.bin')
spi_hash = '65523a1835949b6f4553be96dec1b6a38fb05501'
spi_path = self.fetch_asset(spi_url, asset_hash=spi_hash)
+ spi_path_rw = os.path.join(self.workdir, os.path.basename(spi_path))
+ shutil.copy(spi_path, spi_path_rw)
- file_truncate(spi_path, 16 << 20) # Spansion S25FL128SDPBHICO is 16 MiB
+ file_truncate(spi_path_rw, 16 << 20) # Spansion S25FL128SDPBHICO is 16 MiB
self.vm.set_console()
kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE
self.vm.add_args('-kernel', uboot_path,
'-append', kernel_command_line,
- '-drive', 'file=' + spi_path + ',if=mtd,format=raw',
+ '-drive', 'file=' + spi_path_rw + ',if=mtd,format=raw',
'-no-reboot')
self.vm.launch()
self.wait_for_console_pattern('Enter \'help\' for a list')
@@ -416,188 +203,6 @@ class BootLinuxConsole(LinuxKernelTest):
exec_command_and_wait_for_pattern(self, 'ping -c 3 10.0.2.2',
'3 packets transmitted, 3 packets received, 0% packet loss')
- def do_test_arm_raspi2(self, uart_id):
- """
- :avocado: tags=accel:tcg
-
- The kernel can be rebuilt using the kernel source referenced
- and following the instructions on the on:
- https://www.raspberrypi.org/documentation/linux/kernel/building.md
- """
- serial_kernel_cmdline = {
- 0: 'earlycon=pl011,0x3f201000 console=ttyAMA0',
- }
- deb_url = ('http://archive.raspberrypi.org/debian/'
- 'pool/main/r/raspberrypi-firmware/'
- 'raspberrypi-kernel_1.20190215-1_armhf.deb')
- deb_hash = 'cd284220b32128c5084037553db3c482426f3972'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path, '/boot/kernel7.img')
- dtb_path = self.extract_from_deb(deb_path, '/boot/bcm2709-rpi-2-b.dtb')
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- serial_kernel_cmdline[uart_id] +
- ' root=/dev/mmcblk0p2 rootwait ' +
- 'dwc_otg.fiq_fsm_enable=0')
- self.vm.add_args('-kernel', kernel_path,
- '-dtb', dtb_path,
- '-append', kernel_command_line,
- '-device', 'usb-kbd')
- self.vm.launch()
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.wait_for_console_pattern(console_pattern)
- console_pattern = 'Product: QEMU USB Keyboard'
- self.wait_for_console_pattern(console_pattern)
-
- def test_arm_raspi2_uart0(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:raspi2b
- :avocado: tags=device:pl011
- :avocado: tags=accel:tcg
- """
- self.do_test_arm_raspi2(0)
-
- def test_arm_raspi2_initrd(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:raspi2b
- """
- deb_url = ('http://archive.raspberrypi.org/debian/'
- 'pool/main/r/raspberrypi-firmware/'
- 'raspberrypi-kernel_1.20190215-1_armhf.deb')
- deb_hash = 'cd284220b32128c5084037553db3c482426f3972'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path, '/boot/kernel7.img')
- dtb_path = self.extract_from_deb(deb_path, '/boot/bcm2709-rpi-2-b.dtb')
-
- initrd_url = ('https://github.com/groeck/linux-build-test/raw/'
- '2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
- 'arm/rootfs-armv7a.cpio.gz')
- initrd_hash = '604b2e45cdf35045846b8bbfbf2129b1891bdc9c'
- initrd_path_gz = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
- initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
- archive.gzip_uncompress(initrd_path_gz, initrd_path)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'earlycon=pl011,0x3f201000 console=ttyAMA0 '
- 'panic=-1 noreboot ' +
- 'dwc_otg.fiq_fsm_enable=0')
- self.vm.add_args('-kernel', kernel_path,
- '-dtb', dtb_path,
- '-initrd', initrd_path,
- '-append', kernel_command_line,
- '-no-reboot')
- self.vm.launch()
- self.wait_for_console_pattern('Boot successful.')
-
- exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
- 'BCM2835')
- exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
- '/soc/cprman@7e101000')
- exec_command_and_wait_for_pattern(self, 'halt', 'reboot: System halted')
- # Wait for VM to shut down gracefully
- self.vm.wait()
-
- def test_arm_raspi4(self):
- """
- :avocado: tags=arch:aarch64
- :avocado: tags=machine:raspi4b
- :avocado: tags=device:pl011
- :avocado: tags=accel:tcg
- :avocado: tags=rpi4b
-
- The kernel can be rebuilt using the kernel source referenced
- and following the instructions on the on:
- https://www.raspberrypi.org/documentation/linux/kernel/building.md
- """
-
- deb_url = ('http://archive.raspberrypi.org/debian/'
- 'pool/main/r/raspberrypi-firmware/'
- 'raspberrypi-kernel_1.20230106-1_arm64.deb')
- deb_hash = '08dc55696535b18a6d4fe6fa10d4c0d905cbb2ed'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path, '/boot/kernel8.img')
- dtb_path = self.extract_from_deb(deb_path, '/boot/bcm2711-rpi-4-b.dtb')
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'earlycon=pl011,mmio32,0xfe201000 ' +
- 'console=ttyAMA0,115200 ' +
- 'root=/dev/mmcblk1p2 rootwait ' +
- 'dwc_otg.fiq_fsm_enable=0')
- self.vm.add_args('-kernel', kernel_path,
- '-dtb', dtb_path,
- '-append', kernel_command_line)
- # When PCI is supported we can add a USB controller:
- # '-device', 'qemu-xhci,bus=pcie.1,id=xhci',
- # '-device', 'usb-kbd,bus=xhci.0',
- self.vm.launch()
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.wait_for_console_pattern(console_pattern)
- # When USB is enabled we can look for this
- # console_pattern = 'Product: QEMU USB Keyboard'
- # self.wait_for_console_pattern(console_pattern)
- console_pattern = 'Waiting for root device'
- self.wait_for_console_pattern(console_pattern)
-
-
- def test_arm_raspi4_initrd(self):
- """
- :avocado: tags=arch:aarch64
- :avocado: tags=machine:raspi4b
- :avocado: tags=device:pl011
- :avocado: tags=accel:tcg
- :avocado: tags=rpi4b
-
- The kernel can be rebuilt using the kernel source referenced
- and following the instructions on the on:
- https://www.raspberrypi.org/documentation/linux/kernel/building.md
- """
- deb_url = ('http://archive.raspberrypi.org/debian/'
- 'pool/main/r/raspberrypi-firmware/'
- 'raspberrypi-kernel_1.20230106-1_arm64.deb')
- deb_hash = '08dc55696535b18a6d4fe6fa10d4c0d905cbb2ed'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path, '/boot/kernel8.img')
- dtb_path = self.extract_from_deb(deb_path, '/boot/bcm2711-rpi-4-b.dtb')
-
- initrd_url = ('https://github.com/groeck/linux-build-test/raw/'
- '86b2be1384d41c8c388e63078a847f1e1c4cb1de/rootfs/'
- 'arm64/rootfs.cpio.gz')
- initrd_hash = 'f3d4f9fa92a49aa542f1b44d34be77bbf8ca5b9d'
- initrd_path_gz = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
- initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
- archive.gzip_uncompress(initrd_path_gz, initrd_path)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'earlycon=pl011,mmio32,0xfe201000 ' +
- 'console=ttyAMA0,115200 ' +
- 'panic=-1 noreboot ' +
- 'dwc_otg.fiq_fsm_enable=0')
- self.vm.add_args('-kernel', kernel_path,
- '-dtb', dtb_path,
- '-initrd', initrd_path,
- '-append', kernel_command_line,
- '-no-reboot')
- # When PCI is supported we can add a USB controller:
- # '-device', 'qemu-xhci,bus=pcie.1,id=xhci',
- # '-device', 'usb-kbd,bus=xhci.0',
- self.vm.launch()
- self.wait_for_console_pattern('Boot successful.')
-
- exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
- 'BCM2835')
- exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
- 'cprman@7e101000')
- exec_command_and_wait_for_pattern(self, 'halt', 'reboot: System halted')
- # TODO: Raspberry Pi4 doesn't shut down properly with recent kernels
- # Wait for VM to shut down gracefully
- #self.vm.wait()
-
def test_arm_exynos4210_initrd(self):
"""
:avocado: tags=arch:arm
@@ -1277,114 +882,6 @@ class BootLinuxConsole(LinuxKernelTest):
# Wait for user-space
wait_for_console_pattern(self, 'Starting root file system check')
- def test_aarch64_raspi3_atf(self):
- """
- :avocado: tags=accel:tcg
- :avocado: tags=arch:aarch64
- :avocado: tags=machine:raspi3b
- :avocado: tags=cpu:cortex-a53
- :avocado: tags=device:pl011
- :avocado: tags=atf
- """
- zip_url = ('https://github.com/pbatard/RPi3/releases/download/'
- 'v1.15/RPi3_UEFI_Firmware_v1.15.zip')
- zip_hash = '74b3bd0de92683cadb14e008a7575e1d0c3cafb9'
- zip_path = self.fetch_asset(zip_url, asset_hash=zip_hash)
-
- archive.extract(zip_path, self.workdir)
- efi_fd = os.path.join(self.workdir, 'RPI_EFI.fd')
-
- self.vm.set_console(console_index=1)
- self.vm.add_args('-nodefaults',
- '-device', 'loader,file=%s,force-raw=true' % efi_fd)
- self.vm.launch()
- self.wait_for_console_pattern('version UEFI Firmware v1.15')
-
- def test_s390x_s390_ccw_virtio(self):
- """
- :avocado: tags=arch:s390x
- :avocado: tags=machine:s390-ccw-virtio
- """
- kernel_url = ('https://archives.fedoraproject.org/pub/archive'
- '/fedora-secondary/releases/29/Everything/s390x/os/images'
- '/kernel.img')
- kernel_hash = 'e8e8439103ef8053418ef062644ffd46a7919313'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
-
- self.vm.set_console()
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=sclp0'
- self.vm.add_args('-nodefaults',
- '-kernel', kernel_path,
- '-append', kernel_command_line)
- self.vm.launch()
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.wait_for_console_pattern(console_pattern)
-
- def test_alpha_clipper(self):
- """
- :avocado: tags=arch:alpha
- :avocado: tags=machine:clipper
- """
- kernel_url = ('http://archive.debian.org/debian/dists/lenny/main/'
- 'installer-alpha/20090123lenny10/images/cdrom/vmlinuz')
- kernel_hash = '3a943149335529e2ed3e74d0d787b85fb5671ba3'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
-
- uncompressed_kernel = archive.uncompress(kernel_path, self.workdir)
-
- self.vm.set_console()
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
- self.vm.add_args('-nodefaults',
- '-kernel', uncompressed_kernel,
- '-append', kernel_command_line)
- self.vm.launch()
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.wait_for_console_pattern(console_pattern)
-
- def test_m68k_q800(self):
- """
- :avocado: tags=arch:m68k
- :avocado: tags=machine:q800
- """
- deb_url = ('https://snapshot.debian.org/archive/debian-ports'
- '/20191021T083923Z/pool-m68k/main'
- '/l/linux/kernel-image-5.3.0-1-m68k-di_5.3.7-1_m68k.udeb')
- deb_hash = '044954bb9be4160a3ce81f8bc1b5e856b75cccd1'
- deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinux-5.3.0-1-m68k')
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyS0 vga=off')
- self.vm.add_args('-kernel', kernel_path,
- '-append', kernel_command_line)
- self.vm.launch()
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.wait_for_console_pattern(console_pattern)
- console_pattern = 'No filesystem could mount root'
- self.wait_for_console_pattern(console_pattern)
-
- def do_test_advcal_2018(self, day, tar_hash, kernel_name, console=0):
- tar_url = ('https://qemu-advcal.gitlab.io'
- '/qac-best-of-multiarch/download/day' + day + '.tar.xz')
- file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- archive.extract(file_path, self.workdir)
- self.vm.set_console(console_index=console)
- self.vm.add_args('-kernel',
- self.workdir + '/day' + day + '/' + kernel_name)
- self.vm.launch()
- self.wait_for_console_pattern('QEMU advent calendar')
-
- def test_arm_vexpressa9(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:vexpress-a9
- """
- tar_hash = '32b7677ce8b6f1471fb0059865f451169934245b'
- self.vm.add_args('-dtb', self.workdir + '/day16/vexpress-v2p-ca9.dtb')
- self.do_test_advcal_2018('16', tar_hash, 'winter.zImage')
-
def test_arm_ast2600_debian(self):
"""
:avocado: tags=arch:arm
@@ -1410,138 +907,3 @@ class BootLinuxConsole(LinuxKernelTest):
self.wait_for_console_pattern("SMP: Total of 2 processors activated")
self.wait_for_console_pattern("No filesystem could mount root")
- def test_m68k_mcf5208evb(self):
- """
- :avocado: tags=arch:m68k
- :avocado: tags=machine:mcf5208evb
- """
- tar_hash = 'ac688fd00561a2b6ce1359f9ff6aa2b98c9a570c'
- self.do_test_advcal_2018('07', tar_hash, 'sanity-clause.elf')
-
- def test_or1k_sim(self):
- """
- :avocado: tags=arch:or1k
- :avocado: tags=machine:or1k-sim
- """
- tar_hash = '20334cdaf386108c530ff0badaecc955693027dd'
- self.do_test_advcal_2018('20', tar_hash, 'vmlinux')
-
- def test_ppc64_e500(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:ppce500
- :avocado: tags=cpu:e5500
- :avocado: tags=accel:tcg
- """
- self.require_accelerator("tcg")
- tar_hash = '6951d86d644b302898da2fd701739c9406527fe1'
- self.do_test_advcal_2018('19', tar_hash, 'uImage')
-
- def do_test_ppc64_powernv(self, proc):
- self.require_accelerator("tcg")
- images_url = ('https://github.com/open-power/op-build/releases/download/v2.7/')
-
- kernel_url = images_url + 'zImage.epapr'
- kernel_hash = '0ab237df661727e5392cee97460e8674057a883c5f74381a128fa772588d45cd'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash,
- algorithm='sha256')
- self.vm.set_console()
- self.vm.add_args('-kernel', kernel_path,
- '-append', 'console=tty0 console=hvc0',
- '-device', 'pcie-pci-bridge,id=bridge1,bus=pcie.1,addr=0x0',
- '-device', 'nvme,bus=pcie.2,addr=0x0,serial=1234',
- '-device', 'e1000e,bus=bridge1,addr=0x3',
- '-device', 'nec-usb-xhci,bus=bridge1,addr=0x2')
- self.vm.launch()
-
- self.wait_for_console_pattern("CPU: " + proc + " generation processor")
- self.wait_for_console_pattern("zImage starting: loaded")
- self.wait_for_console_pattern("Run /init as init process")
- # Device detection output driven by udev probing is sometimes cut off
- # from console output, suspect S14silence-console init script.
-
- def test_ppc_powernv8(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:powernv8
- :avocado: tags=accel:tcg
- """
- self.do_test_ppc64_powernv('P8')
-
- def test_ppc_powernv9(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:powernv9
- :avocado: tags=accel:tcg
- """
- self.do_test_ppc64_powernv('P9')
-
- def test_ppc_powernv10(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:powernv10
- :avocado: tags=accel:tcg
- """
- self.do_test_ppc64_powernv('P10')
-
- def test_ppc_g3beige(self):
- """
- :avocado: tags=arch:ppc
- :avocado: tags=machine:g3beige
- :avocado: tags=accel:tcg
- """
- # TODO: g3beige works with kvm_pr but we don't have a
- # reliable way ATM (e.g. looking at /proc/modules) to detect
- # whether we're running kvm_hv or kvm_pr. For now let's
- # disable this test if we don't have TCG support.
- self.require_accelerator("tcg")
- tar_hash = 'e0b872a5eb8fdc5bed19bd43ffe863900ebcedfc'
- self.vm.add_args('-M', 'graphics=off')
- self.do_test_advcal_2018('15', tar_hash, 'invaders.elf')
-
- def test_ppc_mac99(self):
- """
- :avocado: tags=arch:ppc
- :avocado: tags=machine:mac99
- :avocado: tags=accel:tcg
- """
- # TODO: mac99 works with kvm_pr but we don't have a
- # reliable way ATM (e.g. looking at /proc/modules) to detect
- # whether we're running kvm_hv or kvm_pr. For now let's
- # disable this test if we don't have TCG support.
- self.require_accelerator("tcg")
- tar_hash = 'e0b872a5eb8fdc5bed19bd43ffe863900ebcedfc'
- self.vm.add_args('-M', 'graphics=off')
- self.do_test_advcal_2018('15', tar_hash, 'invaders.elf')
-
- # This test has a 6-10% failure rate on various hosts that look
- # like issues with a buggy kernel. As a result we don't want it
- # gating releases on Gitlab.
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
-
- def test_sh4_r2d(self):
- """
- :avocado: tags=arch:sh4
- :avocado: tags=machine:r2d
- :avocado: tags=flaky
- """
- tar_hash = 'fe06a4fd8ccbf2e27928d64472939d47829d4c7e'
- self.vm.add_args('-append', 'console=ttySC1')
- self.do_test_advcal_2018('09', tar_hash, 'zImage', console=1)
-
- def test_sparc_ss20(self):
- """
- :avocado: tags=arch:sparc
- :avocado: tags=machine:SS-20
- """
- tar_hash = 'b18550d5d61c7615d989a06edace051017726a9f'
- self.do_test_advcal_2018('11', tar_hash, 'zImage.elf')
-
- def test_xtensa_lx60(self):
- """
- :avocado: tags=arch:xtensa
- :avocado: tags=machine:lx60
- :avocado: tags=cpu:dc233c
- """
- tar_hash = '49e88d9933742f0164b60839886c9739cb7a0d34'
- self.do_test_advcal_2018('02', tar_hash, 'santas-sleigh-ride.elf')
diff --git a/tests/avocado/boot_xen.py b/tests/avocado/boot_xen.py
index fc2faee..490a127 100644
--- a/tests/avocado/boot_xen.py
+++ b/tests/avocado/boot_xen.py
@@ -17,59 +17,52 @@ from avocado_qemu import wait_for_console_pattern
from boot_linux_console import LinuxKernelTest
-class BootXenBase(LinuxKernelTest):
+class BootXen(LinuxKernelTest):
"""
Boots a Xen hypervisor with a Linux DomU kernel.
+
+ :avocado: tags=arch:aarch64
+ :avocado: tags=accel:tcg
+ :avocado: tags=cpu:cortex-a57
+ :avocado: tags=machine:virt
"""
timeout = 90
XEN_COMMON_COMMAND_LINE = 'dom0_mem=128M loglvl=all guest_loglvl=all'
- def fetch_guest_kernel(self):
+ def setUp(self):
+ super(BootXen, self).setUp()
+
# Using my own built kernel - which works
kernel_url = ('https://fileserver.linaro.org/'
's/JSsewXGZ6mqxPr5/download?path=%2F&files='
'linux-5.9.9-arm64-ajb')
kernel_sha1 = '4f92bc4b9f88d5ab792fa7a43a68555d344e1b83'
- kernel_path = self.fetch_asset(kernel_url,
- asset_hash=kernel_sha1)
-
- return kernel_path
+ self.kernel_path = self.fetch_asset(kernel_url,
+ asset_hash=kernel_sha1)
def launch_xen(self, xen_path):
"""
Launch Xen with a dom0 guest kernel
"""
self.log.info("launch with xen_path: %s", xen_path)
- kernel_path = self.fetch_guest_kernel()
self.vm.set_console()
- xen_command_line = self.XEN_COMMON_COMMAND_LINE
self.vm.add_args('-machine', 'virtualization=on',
'-m', '768',
'-kernel', xen_path,
- '-append', xen_command_line,
+ '-append', self.XEN_COMMON_COMMAND_LINE,
'-device',
'guest-loader,addr=0x47000000,kernel=%s,bootargs=console=hvc0'
- % (kernel_path))
+ % (self.kernel_path))
self.vm.launch()
console_pattern = 'VFS: Cannot open root device'
wait_for_console_pattern(self, console_pattern, "Panic on CPU 0:")
-
-class BootXen(BootXenBase):
-
def test_arm64_xen_411_and_dom0(self):
- """
- :avocado: tags=arch:aarch64
- :avocado: tags=accel:tcg
- :avocado: tags=cpu:cortex-a57
- :avocado: tags=machine:virt
- """
-
# archive of file from https://deb.debian.org/debian/pool/main/x/xen/
xen_url = ('https://fileserver.linaro.org/s/JSsewXGZ6mqxPr5/'
'download?path=%2F&files='
@@ -81,13 +74,6 @@ class BootXen(BootXenBase):
self.launch_xen(xen_path)
def test_arm64_xen_414_and_dom0(self):
- """
- :avocado: tags=arch:aarch64
- :avocado: tags=accel:tcg
- :avocado: tags=cpu:cortex-a57
- :avocado: tags=machine:virt
- """
-
# archive of file from https://deb.debian.org/debian/pool/main/x/xen/
xen_url = ('https://fileserver.linaro.org/s/JSsewXGZ6mqxPr5/'
'download?path=%2F&files='
@@ -99,13 +85,6 @@ class BootXen(BootXenBase):
self.launch_xen(xen_path)
def test_arm64_xen_415_and_dom0(self):
- """
- :avocado: tags=arch:aarch64
- :avocado: tags=accel:tcg
- :avocado: tags=cpu:cortex-a57
- :avocado: tags=machine:virt
- """
-
xen_url = ('https://fileserver.linaro.org/'
's/JSsewXGZ6mqxPr5/download'
'?path=%2F&files=xen-upstream-4.15-unstable.deb')
diff --git a/tests/avocado/hotplug_blk.py b/tests/avocado/hotplug_blk.py
index 5dc30f6..d55ded1 100644
--- a/tests/avocado/hotplug_blk.py
+++ b/tests/avocado/hotplug_blk.py
@@ -9,7 +9,7 @@
import time
-from avocado_qemu import LinuxTest
+from avocado_qemu.linuxtest import LinuxTest
class HotPlug(LinuxTest):
diff --git a/tests/avocado/hotplug_cpu.py b/tests/avocado/hotplug_cpu.py
index 292bb43..342c838 100644
--- a/tests/avocado/hotplug_cpu.py
+++ b/tests/avocado/hotplug_cpu.py
@@ -8,7 +8,7 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from avocado_qemu import LinuxTest
+from avocado_qemu.linuxtest import LinuxTest
class HotPlugCPU(LinuxTest):
diff --git a/tests/avocado/intel_iommu.py b/tests/avocado/intel_iommu.py
index 09e694b..992583f 100644
--- a/tests/avocado/intel_iommu.py
+++ b/tests/avocado/intel_iommu.py
@@ -10,10 +10,9 @@
import os
from avocado import skipUnless
-from avocado_qemu import LinuxTest
+from avocado_qemu.linuxtest import LinuxTest
@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
-
class IntelIOMMU(LinuxTest):
"""
:avocado: tags=arch:x86_64
diff --git a/tests/avocado/load_bflt.py b/tests/avocado/load_bflt.py
deleted file mode 100644
index bb50cec..0000000
--- a/tests/avocado/load_bflt.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# Test the bFLT loader format
-#
-# Copyright (C) 2019 Philippe Mathieu-DaudƩ <f4bug@amsat.org>
-#
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-import os
-import bz2
-import subprocess
-
-from avocado import skipUnless
-from avocado_qemu import QemuUserTest
-from avocado_qemu import has_cmd
-
-
-class LoadBFLT(QemuUserTest):
-
- def extract_cpio(self, cpio_path):
- """
- Extracts a cpio archive into the test workdir
-
- :param cpio_path: path to the cpio archive
- """
- cwd = os.getcwd()
- os.chdir(self.workdir)
- with bz2.open(cpio_path, 'rb') as archive_cpio:
- subprocess.run(['cpio', '-i'], input=archive_cpio.read(),
- stderr=subprocess.DEVNULL)
- os.chdir(cwd)
-
- @skipUnless(*has_cmd('cpio'))
- @skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
- def test_stm32(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=linux_user
- :avocado: tags=quick
- """
- # See https://elinux.org/STM32#User_Space
- rootfs_url = ('https://elinux.org/images/5/51/'
- 'Stm32_mini_rootfs.cpio.bz2')
- rootfs_hash = '9f065e6ba40cce7411ba757f924f30fcc57951e6'
- rootfs_path_bz2 = self.fetch_asset(rootfs_url, asset_hash=rootfs_hash)
- busybox_path = os.path.join(self.workdir, "/bin/busybox")
-
- self.extract_cpio(rootfs_path_bz2)
-
- res = self.run(busybox_path)
- ver = 'BusyBox v1.24.0.git (2015-02-03 22:17:13 CET) multi-call binary.'
- self.assertIn(ver, res.stdout_text)
-
- res = self.run(busybox_path, ['uname', '-a'])
- unm = 'armv7l GNU/Linux'
- self.assertIn(unm, res.stdout_text)
diff --git a/tests/avocado/machine_aarch64_sbsaref.py b/tests/avocado/machine_aarch64_sbsaref.py
deleted file mode 100644
index e920bbf..0000000
--- a/tests/avocado/machine_aarch64_sbsaref.py
+++ /dev/null
@@ -1,236 +0,0 @@
-# Functional test that boots a Linux kernel and checks the console
-#
-# SPDX-FileCopyrightText: 2023-2024 Linaro Ltd.
-# SPDX-FileContributor: Philippe Mathieu-DaudƩ <philmd@linaro.org>
-# SPDX-FileContributor: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
-#
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-import os
-
-from avocado import skipUnless
-from avocado.utils import archive
-
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
-from avocado_qemu import interrupt_interactive_console_until_pattern
-
-
-class Aarch64SbsarefMachine(QemuSystemTest):
- """
- :avocado: tags=arch:aarch64
- :avocado: tags=machine:sbsa-ref
- :avocado: tags=accel:tcg
-
- As firmware runs at a higher privilege level than the hypervisor we
- can only run these tests under TCG emulation.
- """
-
- timeout = 180
-
- def fetch_firmware(self):
- """
- Flash volumes generated using:
-
- Toolchain from Debian:
- aarch64-linux-gnu-gcc (Debian 12.2.0-14) 12.2.0
-
- Used components:
-
- - Trusted Firmware v2.11.0
- - Tianocore EDK2 4d4f569924
- - Tianocore EDK2-platforms 3f08401
-
- """
-
- # Secure BootRom (TF-A code)
- fs0_xz_url = (
- "https://artifacts.codelinaro.org/artifactory/linaro-419-sbsa-ref/"
- "20240619-148232/edk2/SBSA_FLASH0.fd.xz"
- )
- fs0_xz_hash = "0c954842a590988f526984de22e21ae0ab9cb351a0c99a8a58e928f0c7359cf7"
- tar_xz_path = self.fetch_asset(fs0_xz_url, asset_hash=fs0_xz_hash,
- algorithm='sha256')
- archive.extract(tar_xz_path, self.workdir)
- fs0_path = os.path.join(self.workdir, "SBSA_FLASH0.fd")
-
- # Non-secure rom (UEFI and EFI variables)
- fs1_xz_url = (
- "https://artifacts.codelinaro.org/artifactory/linaro-419-sbsa-ref/"
- "20240619-148232/edk2/SBSA_FLASH1.fd.xz"
- )
- fs1_xz_hash = "c6ec39374c4d79bb9e9cdeeb6db44732d90bb4a334cec92002b3f4b9cac4b5ee"
- tar_xz_path = self.fetch_asset(fs1_xz_url, asset_hash=fs1_xz_hash,
- algorithm='sha256')
- archive.extract(tar_xz_path, self.workdir)
- fs1_path = os.path.join(self.workdir, "SBSA_FLASH1.fd")
-
- for path in [fs0_path, fs1_path]:
- with open(path, "ab+") as fd:
- fd.truncate(256 << 20) # Expand volumes to 256MiB
-
- self.vm.set_console()
- self.vm.add_args(
- "-drive",
- f"if=pflash,file={fs0_path},format=raw",
- "-drive",
- f"if=pflash,file={fs1_path},format=raw",
- "-machine",
- "sbsa-ref",
- )
-
- def test_sbsaref_edk2_firmware(self):
- """
- :avocado: tags=cpu:cortex-a57
- """
-
- self.fetch_firmware()
- self.vm.launch()
-
- # TF-A boot sequence:
- #
- # https://github.com/ARM-software/arm-trusted-firmware/blob/v2.8.0/\
- # docs/design/trusted-board-boot.rst#trusted-board-boot-sequence
- # https://trustedfirmware-a.readthedocs.io/en/v2.8/\
- # design/firmware-design.html#cold-boot
-
- # AP Trusted ROM
- wait_for_console_pattern(self, "Booting Trusted Firmware")
- wait_for_console_pattern(self, "BL1: v2.11.0(release):")
- wait_for_console_pattern(self, "BL1: Booting BL2")
-
- # Trusted Boot Firmware
- wait_for_console_pattern(self, "BL2: v2.11.0(release)")
- wait_for_console_pattern(self, "Booting BL31")
-
- # EL3 Runtime Software
- wait_for_console_pattern(self, "BL31: v2.11.0(release)")
-
- # Non-trusted Firmware
- wait_for_console_pattern(self, "UEFI firmware (version 1.0")
- interrupt_interactive_console_until_pattern(self, "QEMU SBSA-REF Machine")
-
- # This tests the whole boot chain from EFI to Userspace
- # We only boot a whole OS for the current top level CPU and GIC
- # Other test profiles should use more minimal boots
- def boot_alpine_linux(self, cpu):
- self.fetch_firmware()
-
- iso_url = (
- "https://dl-cdn.alpinelinux.org/"
- "alpine/v3.17/releases/aarch64/alpine-standard-3.17.2-aarch64.iso"
- )
-
- iso_hash = "5a36304ecf039292082d92b48152a9ec21009d3a62f459de623e19c4bd9dc027"
- iso_path = self.fetch_asset(iso_url, algorithm="sha256", asset_hash=iso_hash)
-
- self.vm.set_console()
- self.vm.add_args(
- "-cpu",
- cpu,
- "-drive",
- f"file={iso_path},format=raw",
- )
-
- self.vm.launch()
- wait_for_console_pattern(self, "Welcome to Alpine Linux 3.17")
-
- def test_sbsaref_alpine_linux_cortex_a57(self):
- """
- :avocado: tags=cpu:cortex-a57
- :avocado: tags=os:linux
- """
- self.boot_alpine_linux("cortex-a57")
-
- def test_sbsaref_alpine_linux_neoverse_n1(self):
- """
- :avocado: tags=cpu:neoverse-n1
- :avocado: tags=os:linux
- """
- self.boot_alpine_linux("neoverse-n1")
-
- def test_sbsaref_alpine_linux_max_pauth_off(self):
- """
- :avocado: tags=cpu:max
- :avocado: tags=os:linux
- """
- self.boot_alpine_linux("max,pauth=off")
-
- def test_sbsaref_alpine_linux_max_pauth_impdef(self):
- """
- :avocado: tags=cpu:max
- :avocado: tags=os:linux
- """
- self.boot_alpine_linux("max,pauth-impdef=on")
-
- @skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
- def test_sbsaref_alpine_linux_max(self):
- """
- :avocado: tags=cpu:max
- :avocado: tags=os:linux
- """
- self.boot_alpine_linux("max")
-
-
- # This tests the whole boot chain from EFI to Userspace
- # We only boot a whole OS for the current top level CPU and GIC
- # Other test profiles should use more minimal boots
- def boot_openbsd73(self, cpu):
- self.fetch_firmware()
-
- img_url = (
- "https://cdn.openbsd.org/pub/OpenBSD/7.3/arm64/miniroot73.img"
- )
-
- img_hash = "7fc2c75401d6f01fbfa25f4953f72ad7d7c18650056d30755c44b9c129b707e5"
- img_path = self.fetch_asset(img_url, algorithm="sha256", asset_hash=img_hash)
-
- self.vm.set_console()
- self.vm.add_args(
- "-cpu",
- cpu,
- "-drive",
- f"file={img_path},format=raw",
- )
-
- self.vm.launch()
- wait_for_console_pattern(self,
- "Welcome to the OpenBSD/arm64"
- " 7.3 installation program.")
-
- def test_sbsaref_openbsd73_cortex_a57(self):
- """
- :avocado: tags=cpu:cortex-a57
- :avocado: tags=os:openbsd
- """
- self.boot_openbsd73("cortex-a57")
-
- def test_sbsaref_openbsd73_neoverse_n1(self):
- """
- :avocado: tags=cpu:neoverse-n1
- :avocado: tags=os:openbsd
- """
- self.boot_openbsd73("neoverse-n1")
-
- def test_sbsaref_openbsd73_max_pauth_off(self):
- """
- :avocado: tags=cpu:max
- :avocado: tags=os:openbsd
- """
- self.boot_openbsd73("max,pauth=off")
-
- @skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
- def test_sbsaref_openbsd73_max_pauth_impdef(self):
- """
- :avocado: tags=cpu:max
- :avocado: tags=os:openbsd
- """
- self.boot_openbsd73("max,pauth-impdef=on")
-
- @skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
- def test_sbsaref_openbsd73_max(self):
- """
- :avocado: tags=cpu:max
- :avocado: tags=os:openbsd
- """
- self.boot_openbsd73("max")
diff --git a/tests/avocado/machine_arm_n8x0.py b/tests/avocado/machine_arm_n8x0.py
deleted file mode 100644
index 12e9a68..0000000
--- a/tests/avocado/machine_arm_n8x0.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# Functional test that boots a Linux kernel and checks the console
-#
-# Copyright (c) 2020 Red Hat, Inc.
-#
-# Author:
-# Thomas Huth <thuth@redhat.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-import os
-
-from avocado import skipUnless
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
-
-class N8x0Machine(QemuSystemTest):
- """Boots the Linux kernel and checks that the console is operational"""
-
- timeout = 90
-
- def __do_test_n8x0(self):
- kernel_url = ('http://stskeeps.subnetmask.net/meego-n8x0/'
- 'meego-arm-n8x0-1.0.80.20100712.1431-'
- 'vmlinuz-2.6.35~rc4-129.1-n8x0')
- kernel_hash = 'e9d5ab8d7548923a0061b6fbf601465e479ed269'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
-
- self.vm.set_console(console_index=1)
- self.vm.add_args('-kernel', kernel_path,
- '-append', 'printk.time=0 console=ttyS1')
- self.vm.launch()
- wait_for_console_pattern(self, 'TSC2005 driver initializing')
-
- @skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
- def test_n800(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:n800
- """
- self.__do_test_n8x0()
-
- @skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
- def test_n810(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:n810
- """
- self.__do_test_n8x0()
diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py
index f66ad38..241ef18 100644
--- a/tests/avocado/machine_aspeed.py
+++ b/tests/avocado/machine_aspeed.py
@@ -19,258 +19,6 @@ from avocado_qemu import interrupt_interactive_console_until_pattern
from avocado_qemu import has_cmd
from avocado.utils import archive
from avocado import skipUnless
-from avocado import skipUnless
-
-
-class AST1030Machine(QemuSystemTest):
- """Boots the zephyr os and checks that the console is operational"""
-
- timeout = 10
-
- def test_ast1030_zephyros_1_04(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:ast1030-evb
- :avocado: tags=os:zephyr
- """
- tar_url = ('https://github.com/AspeedTech-BMC'
- '/zephyr/releases/download/v00.01.04/ast1030-evb-demo.zip')
- tar_hash = '4c6a8ce3a8ba76ef1a65dae419ae3409343c4b20'
- tar_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- archive.extract(tar_path, self.workdir)
- kernel_file = self.workdir + "/ast1030-evb-demo/zephyr.elf"
- self.vm.set_console()
- self.vm.add_args('-kernel', kernel_file,
- '-nographic')
- self.vm.launch()
- wait_for_console_pattern(self, "Booting Zephyr OS")
- exec_command_and_wait_for_pattern(self, "help",
- "Available commands")
-
- def test_ast1030_zephyros_1_07(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:ast1030-evb
- :avocado: tags=os:zephyr
- """
- tar_url = ('https://github.com/AspeedTech-BMC'
- '/zephyr/releases/download/v00.01.07/ast1030-evb-demo.zip')
- tar_hash = '40ac87eabdcd3b3454ce5aad11fedc72a33ecda2'
- tar_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- archive.extract(tar_path, self.workdir)
- kernel_file = self.workdir + "/ast1030-evb-demo/zephyr.bin"
- self.vm.set_console()
- self.vm.add_args('-kernel', kernel_file,
- '-nographic')
- self.vm.launch()
- wait_for_console_pattern(self, "Booting Zephyr OS")
- for shell_cmd in [
- 'kernel stacks',
- 'otp info conf',
- 'otp info scu',
- 'hwinfo devid',
- 'crypto aes256_cbc_vault',
- 'random get',
- 'jtag JTAG1 sw_xfer high TMS',
- 'adc ADC0 resolution 12',
- 'adc ADC0 read 42',
- 'adc ADC1 read 69',
- 'i2c scan I2C_0',
- 'i3c attach I3C_0',
- 'hash test',
- 'kernel uptime',
- 'kernel reboot warm',
- 'kernel uptime',
- 'kernel reboot cold',
- 'kernel uptime',
- ]: exec_command_and_wait_for_pattern(self, shell_cmd, "uart:~$")
-
-class AST2x00Machine(QemuSystemTest):
-
- timeout = 90
-
- def wait_for_console_pattern(self, success_message, vm=None):
- wait_for_console_pattern(self, success_message,
- failure_message='Kernel panic - not syncing',
- vm=vm)
-
- def do_test_arm_aspeed(self, image):
- self.vm.set_console()
- self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
- '-net', 'nic')
- self.vm.launch()
-
- self.wait_for_console_pattern("U-Boot 2016.07")
- self.wait_for_console_pattern("## Loading kernel from FIT Image at 20080000")
- self.wait_for_console_pattern("Starting kernel ...")
- self.wait_for_console_pattern("Booting Linux on physical CPU 0x0")
- wait_for_console_pattern(self,
- "aspeed-smc 1e620000.spi: read control register: 203b0641")
- self.wait_for_console_pattern("ftgmac100 1e660000.ethernet eth0: irq ")
- self.wait_for_console_pattern("systemd[1]: Set hostname to")
-
- def test_arm_ast2400_palmetto_openbmc_v2_9_0(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:palmetto-bmc
- """
-
- image_url = ('https://github.com/openbmc/openbmc/releases/download/2.9.0/'
- 'obmc-phosphor-image-palmetto.static.mtd')
- image_hash = ('3e13bbbc28e424865dc42f35ad672b10f2e82cdb11846bb28fa625b48beafd0d')
- image_path = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
-
- self.do_test_arm_aspeed(image_path)
-
- def test_arm_ast2500_romulus_openbmc_v2_9_0(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:romulus-bmc
- """
-
- image_url = ('https://github.com/openbmc/openbmc/releases/download/2.9.0/'
- 'obmc-phosphor-image-romulus.static.mtd')
- image_hash = ('820341076803f1955bc31e647a512c79f9add4f5233d0697678bab4604c7bb25')
- image_path = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
-
- self.do_test_arm_aspeed(image_path)
-
- def do_test_arm_aspeed_buildroot_start(self, image, cpu_id, pattern='Aspeed EVB'):
- self.require_netdev('user')
-
- self.vm.set_console()
- self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
- '-net', 'nic', '-net', 'user')
- self.vm.launch()
-
- self.wait_for_console_pattern('U-Boot 2019.04')
- self.wait_for_console_pattern('## Loading kernel from FIT Image')
- self.wait_for_console_pattern('Starting kernel ...')
- self.wait_for_console_pattern('Booting Linux on physical CPU ' + cpu_id)
- self.wait_for_console_pattern('lease of 10.0.2.15')
- # the line before login:
- self.wait_for_console_pattern(pattern)
- time.sleep(0.1)
- exec_command(self, 'root')
- time.sleep(0.1)
- exec_command(self, "passw0rd")
-
- def do_test_arm_aspeed_buildroot_poweroff(self):
- exec_command_and_wait_for_pattern(self, 'poweroff',
- 'reboot: System halted');
-
- def test_arm_ast2500_evb_buildroot(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:ast2500-evb
- """
-
- image_url = ('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
- 'images/ast2500-evb/buildroot-2023.11/flash.img')
- image_hash = ('c23db6160cf77d0258397eb2051162c8473a56c441417c52a91ba217186e715f')
- image_path = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
-
- self.vm.add_args('-device',
- 'tmp105,bus=aspeed.i2c.bus.3,address=0x4d,id=tmp-test');
- self.do_test_arm_aspeed_buildroot_start(image_path, '0x0', 'Aspeed AST2500 EVB')
-
- exec_command_and_wait_for_pattern(self,
- 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-3/device/new_device',
- 'i2c i2c-3: new_device: Instantiated device lm75 at 0x4d');
- exec_command_and_wait_for_pattern(self,
- 'cat /sys/class/hwmon/hwmon1/temp1_input', '0')
- self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test',
- property='temperature', value=18000);
- exec_command_and_wait_for_pattern(self,
- 'cat /sys/class/hwmon/hwmon1/temp1_input', '18000')
-
- self.do_test_arm_aspeed_buildroot_poweroff()
-
- def test_arm_ast2600_evb_buildroot(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:ast2600-evb
- """
-
- image_url = ('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
- 'images/ast2600-evb/buildroot-2023.11/flash.img')
- image_hash = ('b62808daef48b438d0728ee07662290490ecfa65987bb91294cafb1bb7ad1a68')
- image_path = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
-
- self.vm.add_args('-device',
- 'tmp105,bus=aspeed.i2c.bus.3,address=0x4d,id=tmp-test');
- self.vm.add_args('-device',
- 'ds1338,bus=aspeed.i2c.bus.3,address=0x32');
- self.vm.add_args('-device',
- 'i2c-echo,bus=aspeed.i2c.bus.3,address=0x42');
- self.do_test_arm_aspeed_buildroot_start(image_path, '0xf00', 'Aspeed AST2600 EVB')
-
- exec_command_and_wait_for_pattern(self,
- 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-3/device/new_device',
- 'i2c i2c-3: new_device: Instantiated device lm75 at 0x4d');
- exec_command_and_wait_for_pattern(self,
- 'cat /sys/class/hwmon/hwmon1/temp1_input', '0')
- self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test',
- property='temperature', value=18000);
- exec_command_and_wait_for_pattern(self,
- 'cat /sys/class/hwmon/hwmon1/temp1_input', '18000')
-
- exec_command_and_wait_for_pattern(self,
- 'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-3/device/new_device',
- 'i2c i2c-3: new_device: Instantiated device ds1307 at 0x32');
- year = time.strftime("%Y")
- exec_command_and_wait_for_pattern(self, 'hwclock -f /dev/rtc1', year);
-
- exec_command_and_wait_for_pattern(self,
- 'echo slave-24c02 0x1064 > /sys/bus/i2c/devices/i2c-3/new_device',
- 'i2c i2c-3: new_device: Instantiated device slave-24c02 at 0x64');
- exec_command(self, 'i2cset -y 3 0x42 0x64 0x00 0xaa i');
- time.sleep(0.1)
- exec_command_and_wait_for_pattern(self,
- 'hexdump /sys/bus/i2c/devices/3-1064/slave-eeprom',
- '0000000 ffaa ffff ffff ffff ffff ffff ffff ffff');
- self.do_test_arm_aspeed_buildroot_poweroff()
-
- @skipUnless(*has_cmd('swtpm'))
- def test_arm_ast2600_evb_buildroot_tpm(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:ast2600-evb
- """
-
- image_url = ('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
- 'images/ast2600-evb/buildroot-2023.02-tpm/flash.img')
- image_hash = ('a46009ae8a5403a0826d607215e731a8c68d27c14c41e55331706b8f9c7bd997')
- image_path = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
-
- # force creation of VM object, which also defines self._sd
- vm = self.vm
-
- socket = os.path.join(self._sd.name, 'swtpm-socket')
-
- subprocess.run(['swtpm', 'socket', '-d', '--tpm2',
- '--tpmstate', f'dir={self.vm.temp_dir}',
- '--ctrl', f'type=unixio,path={socket}'])
-
- self.vm.add_args('-chardev', f'socket,id=chrtpm,path={socket}')
- self.vm.add_args('-tpmdev', 'emulator,id=tpm0,chardev=chrtpm')
- self.vm.add_args('-device',
- 'tpm-tis-i2c,tpmdev=tpm0,bus=aspeed.i2c.bus.12,address=0x2e')
- self.do_test_arm_aspeed_buildroot_start(image_path, '0xf00', 'Aspeed AST2600 EVB')
-
- exec_command_and_wait_for_pattern(self,
- 'echo tpm_tis_i2c 0x2e > /sys/bus/i2c/devices/i2c-12/new_device',
- 'tpm_tis_i2c 12-002e: 2.0 TPM (device-id 0x1, rev-id 1)');
- exec_command_and_wait_for_pattern(self,
- 'cat /sys/class/tpm/tpm0/pcr-sha256/0',
- 'B804724EA13F52A9072BA87FE8FDCC497DFC9DF9AA15B9088694639C431688E0');
-
- self.do_test_arm_aspeed_buildroot_poweroff()
class AST2x00MachineSDK(QemuSystemTest, LinuxSSHMixIn):
@@ -323,7 +71,6 @@ class AST2x00MachineSDK(QemuSystemTest, LinuxSSHMixIn):
self.wait_for_console_pattern('Starting kernel ...')
@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
-
def test_arm_ast2500_evb_sdk(self):
"""
:avocado: tags=arch:arm
@@ -343,7 +90,6 @@ class AST2x00MachineSDK(QemuSystemTest, LinuxSSHMixIn):
self.wait_for_console_pattern('nodistro.0 ast2500-default ttyS4')
@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
-
def test_arm_ast2600_evb_sdk(self):
"""
:avocado: tags=arch:arm
@@ -435,7 +181,22 @@ class AST2x00MachineSDK(QemuSystemTest, LinuxSSHMixIn):
f'loader,addr=0x430000000,cpu-num={i}')
self.vm.add_args('-smp', str(num_cpu))
+ self.vm.add_args('-device',
+ 'tmp105,bus=aspeed.i2c.bus.1,address=0x4d,id=tmp-test')
self.do_test_aarch64_aspeed_sdk_start(image_dir + 'image-bmc')
self.wait_for_console_pattern('nodistro.0 ast2700-default ttyS12')
+
self.ssh_connect('root', '0penBmc', False)
+ self.ssh_command('dmesg -c > /dev/null')
+
+ self.ssh_command_output_contains(
+ 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-1/device/new_device '
+ '&& dmesg -c',
+ 'i2c i2c-1: new_device: Instantiated device lm75 at 0x4d');
+ self.ssh_command_output_contains(
+ 'cat /sys/class/hwmon/hwmon20/temp1_input', '0')
+ self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test',
+ property='temperature', value=18000)
+ self.ssh_command_output_contains(
+ 'cat /sys/class/hwmon/hwmon20/temp1_input', '18000')
diff --git a/tests/avocado/machine_microblaze.py b/tests/avocado/machine_microblaze.py
deleted file mode 100644
index 807709c..0000000
--- a/tests/avocado/machine_microblaze.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# Functional test that boots a microblaze Linux kernel and checks the console
-#
-# Copyright (c) 2018, 2021 Red Hat, Inc.
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-import time
-from avocado_qemu import exec_command, exec_command_and_wait_for_pattern
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
-from avocado.utils import archive
-
-class MicroblazeMachine(QemuSystemTest):
-
- timeout = 90
-
- def test_microblaze_s3adsp1800(self):
- """
- :avocado: tags=arch:microblaze
- :avocado: tags=machine:petalogix-s3adsp1800
- """
-
- tar_url = ('https://qemu-advcal.gitlab.io'
- '/qac-best-of-multiarch/download/day17.tar.xz')
- tar_hash = '08bf3e3bfb6b6c7ce1e54ab65d54e189f2caf13f'
- file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- archive.extract(file_path, self.workdir)
- self.vm.set_console()
- self.vm.add_args('-kernel', self.workdir + '/day17/ballerina.bin')
- self.vm.launch()
- wait_for_console_pattern(self, 'This architecture does not have '
- 'kernel memory protection')
- # Note:
- # The kernel sometimes gets stuck after the "This architecture ..."
- # message, that's why we don't test for a later string here. This
- # needs some investigation by a microblaze wizard one day...
-
- def test_microblazeel_s3adsp1800(self):
- """
- :avocado: tags=arch:microblazeel
- :avocado: tags=machine:petalogix-s3adsp1800
- """
-
- self.require_netdev('user')
- tar_url = ('http://www.qemu-advent-calendar.org/2023/download/'
- 'day13.tar.gz')
- tar_hash = '6623d5fff5f84cfa8f34e286f32eff6a26546f44'
- file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- archive.extract(file_path, self.workdir)
- self.vm.set_console()
- self.vm.add_args('-kernel', self.workdir + '/day13/xmaton.bin')
- self.vm.add_args('-nic', 'user,tftp=' + self.workdir + '/day13/')
- self.vm.launch()
- wait_for_console_pattern(self, 'QEMU Advent Calendar 2023')
- time.sleep(0.1)
- exec_command(self, 'root')
- time.sleep(0.1)
- exec_command_and_wait_for_pattern(self,
- 'tftp -g -r xmaton.png 10.0.2.2 ; md5sum xmaton.png',
- '821cd3cab8efd16ad6ee5acc3642a8ea')
diff --git a/tests/avocado/machine_mips_fuloong2e.py b/tests/avocado/machine_mips_fuloong2e.py
deleted file mode 100644
index 89291f4..0000000
--- a/tests/avocado/machine_mips_fuloong2e.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# Functional tests for the Lemote Fuloong-2E machine.
-#
-# Copyright (c) 2019 Philippe Mathieu-DaudƩ <f4bug@amsat.org>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or later.
-# See the COPYING file in the top-level directory.
-#
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-import os
-
-from avocado import skipUnless
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
-
-class MipsFuloong2e(QemuSystemTest):
-
- timeout = 60
-
- @skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
- @skipUnless(os.getenv('RESCUE_YL_PATH'), 'RESCUE_YL_PATH not available')
- def test_linux_kernel_isa_serial(self):
- """
- :avocado: tags=arch:mips64el
- :avocado: tags=machine:fuloong2e
- :avocado: tags=endian:little
- :avocado: tags=device:bonito64
- :avocado: tags=device:via686b
- """
- # Recovery system for the Yeeloong laptop
- # (enough to test the fuloong2e southbridge, accessing its ISA bus)
- # http://dev.lemote.com/files/resource/download/rescue/rescue-yl
- kernel_hash = 'ec4d1bd89a8439c41033ca63db60160cc6d6f09a'
- kernel_path = self.fetch_asset('file://' + os.getenv('RESCUE_YL_PATH'),
- asset_hash=kernel_hash)
-
- self.vm.set_console()
- self.vm.add_args('-kernel', kernel_path)
- self.vm.launch()
- wait_for_console_pattern(self, 'Linux version 2.6.27.7lemote')
- cpu_revision = 'CPU revision is: 00006302 (ICT Loongson-2)'
- wait_for_console_pattern(self, cpu_revision)
diff --git a/tests/avocado/machine_mips_loongson3v.py b/tests/avocado/machine_mips_loongson3v.py
deleted file mode 100644
index 5194cf1..0000000
--- a/tests/avocado/machine_mips_loongson3v.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# Functional tests for the Generic Loongson-3 Platform.
-#
-# Copyright (c) 2021 Jiaxun Yang <jiaxun.yang@flygoat.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.
-#
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-import os
-import time
-
-from avocado import skipUnless
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
-
-class MipsLoongson3v(QemuSystemTest):
- timeout = 60
-
- @skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
- def test_pmon_serial_console(self):
- """
- :avocado: tags=arch:mips64el
- :avocado: tags=endian:little
- :avocado: tags=machine:loongson3-virt
- :avocado: tags=cpu:Loongson-3A1000
- :avocado: tags=device:liointc
- :avocado: tags=device:goldfish_rtc
- """
-
- pmon_hash = '7c8b45dd81ccfc55ff28f5aa267a41c3'
- pmon_path = self.fetch_asset('https://github.com/loongson-community/pmon/'
- 'releases/download/20210112/pmon-3avirt.bin',
- asset_hash=pmon_hash, algorithm='md5')
-
- self.vm.set_console()
- self.vm.add_args('-bios', pmon_path)
- self.vm.launch()
- wait_for_console_pattern(self, 'CPU GODSON3 BogoMIPS:')
diff --git a/tests/avocado/machine_mips_malta.py b/tests/avocado/machine_mips_malta.py
deleted file mode 100644
index 8cf84bd..0000000
--- a/tests/avocado/machine_mips_malta.py
+++ /dev/null
@@ -1,164 +0,0 @@
-# Functional tests for the MIPS Malta board
-#
-# Copyright (c) Philippe Mathieu-DaudƩ <f4bug@amsat.org>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or later.
-# See the COPYING file in the top-level directory.
-#
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-import os
-import gzip
-import logging
-
-from avocado import skipUnless
-from avocado import skipUnless
-from avocado.utils import archive
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import exec_command_and_wait_for_pattern
-from avocado_qemu import interrupt_interactive_console_until_pattern
-from avocado_qemu import wait_for_console_pattern
-
-
-NUMPY_AVAILABLE = True
-try:
- import numpy as np
-except ImportError:
- NUMPY_AVAILABLE = False
-
-CV2_AVAILABLE = True
-try:
- import cv2
-except ImportError:
- CV2_AVAILABLE = False
-
-
-@skipUnless(NUMPY_AVAILABLE, 'Python NumPy not installed')
-@skipUnless(CV2_AVAILABLE, 'Python OpenCV not installed')
-class MaltaMachineFramebuffer(QemuSystemTest):
-
- timeout = 30
-
- KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
-
- def do_test_i6400_framebuffer_logo(self, cpu_cores_count):
- """
- Boot Linux kernel and check Tux logo is displayed on the framebuffer.
- """
- screendump_path = os.path.join(self.workdir, 'screendump.pbm')
-
- kernel_url = ('https://github.com/philmd/qemu-testing-blob/raw/'
- 'a5966ca4b5/mips/malta/mips64el/'
- 'vmlinux-4.7.0-rc1.I6400.gz')
- kernel_hash = '096f50c377ec5072e6a366943324622c312045f6'
- kernel_path_gz = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- kernel_path = self.workdir + "vmlinux"
- archive.gzip_uncompress(kernel_path_gz, kernel_path)
-
- tuxlogo_url = ('https://github.com/torvalds/linux/raw/v2.6.12/'
- 'drivers/video/logo/logo_linux_vga16.ppm')
- tuxlogo_hash = '3991c2ddbd1ddaecda7601f8aafbcf5b02dc86af'
- tuxlogo_path = self.fetch_asset(tuxlogo_url, asset_hash=tuxlogo_hash)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'clocksource=GIC console=tty0 console=ttyS0')
- self.vm.add_args('-kernel', kernel_path,
- '-smp', '%u' % cpu_cores_count,
- '-vga', 'std',
- '-append', kernel_command_line)
- self.vm.launch()
- framebuffer_ready = 'Console: switching to colour frame buffer device'
- wait_for_console_pattern(self, framebuffer_ready,
- failure_message='Kernel panic - not syncing')
- self.vm.cmd('human-monitor-command', command_line='stop')
- self.vm.cmd('human-monitor-command',
- command_line='screendump %s' % screendump_path)
- logger = logging.getLogger('framebuffer')
-
- match_threshold = 0.95
- screendump_bgr = cv2.imread(screendump_path, cv2.IMREAD_COLOR)
- tuxlogo_bgr = cv2.imread(tuxlogo_path, cv2.IMREAD_COLOR)
- result = cv2.matchTemplate(screendump_bgr, tuxlogo_bgr,
- cv2.TM_CCOEFF_NORMED)
- loc = np.where(result >= match_threshold)
- tuxlogo_count = 0
- h, w = tuxlogo_bgr.shape[:2]
- debug_png = os.getenv('AVOCADO_CV2_SCREENDUMP_PNG_PATH')
- for tuxlogo_count, pt in enumerate(zip(*loc[::-1]), start=1):
- logger.debug('found Tux at position (x, y) = %s', pt)
- cv2.rectangle(screendump_bgr, pt,
- (pt[0] + w, pt[1] + h), (0, 0, 255), 2)
- if debug_png:
- cv2.imwrite(debug_png, screendump_bgr)
- self.assertGreaterEqual(tuxlogo_count, cpu_cores_count)
-
- def test_mips_malta_i6400_framebuffer_logo_1core(self):
- """
- :avocado: tags=arch:mips64el
- :avocado: tags=machine:malta
- :avocado: tags=cpu:I6400
- """
- self.do_test_i6400_framebuffer_logo(1)
-
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
-
- def test_mips_malta_i6400_framebuffer_logo_7cores(self):
- """
- :avocado: tags=arch:mips64el
- :avocado: tags=machine:malta
- :avocado: tags=cpu:I6400
- :avocado: tags=mips:smp
- :avocado: tags=flaky
- """
- self.do_test_i6400_framebuffer_logo(7)
-
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
-
- def test_mips_malta_i6400_framebuffer_logo_8cores(self):
- """
- :avocado: tags=arch:mips64el
- :avocado: tags=machine:malta
- :avocado: tags=cpu:I6400
- :avocado: tags=mips:smp
- :avocado: tags=flaky
- """
- self.do_test_i6400_framebuffer_logo(8)
-
-class MaltaMachine(QemuSystemTest):
-
- def do_test_yamon(self):
- rom_url = ('https://s3-eu-west-1.amazonaws.com/'
- 'downloads-mips/mips-downloads/'
- 'YAMON/yamon-bin-02.22.zip')
- rom_hash = '8da7ecddbc5312704b8b324341ee238189bde480'
- zip_path = self.fetch_asset(rom_url, asset_hash=rom_hash)
-
- archive.extract(zip_path, self.workdir)
- yamon_path = os.path.join(self.workdir, 'yamon-02.22.bin')
-
- self.vm.set_console()
- self.vm.add_args('-bios', yamon_path)
- self.vm.launch()
-
- prompt = 'YAMON>'
- pattern = 'YAMON ROM Monitor'
- interrupt_interactive_console_until_pattern(self, pattern, prompt)
- wait_for_console_pattern(self, prompt)
- self.vm.shutdown()
-
- def test_mipsel_malta_yamon(self):
- """
- :avocado: tags=arch:mipsel
- :avocado: tags=machine:malta
- :avocado: tags=endian:little
- """
- self.do_test_yamon()
-
- def test_mips64el_malta_yamon(self):
- """
- :avocado: tags=arch:mips64el
- :avocado: tags=machine:malta
- :avocado: tags=endian:little
- """
- self.do_test_yamon()
diff --git a/tests/avocado/machine_sparc64_sun4u.py b/tests/avocado/machine_sparc64_sun4u.py
deleted file mode 100644
index d333c0a..0000000
--- a/tests/avocado/machine_sparc64_sun4u.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# Functional test that boots a Linux kernel and checks the console
-#
-# Copyright (c) 2020 Red Hat, Inc.
-#
-# Author:
-# Thomas Huth <thuth@redhat.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-import os
-
-from avocado_qemu import wait_for_console_pattern
-from avocado.utils import archive
-from boot_linux_console import LinuxKernelTest
-
-class Sun4uMachine(LinuxKernelTest):
- """Boots the Linux kernel and checks that the console is operational"""
-
- timeout = 90
-
- def test_sparc64_sun4u(self):
- """
- :avocado: tags=arch:sparc64
- :avocado: tags=machine:sun4u
- """
- tar_url = ('https://qemu-advcal.gitlab.io'
- '/qac-best-of-multiarch/download/day23.tar.xz')
- tar_hash = '142db83cd974ffadc4f75c8a5cad5bcc5722c240'
- file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- archive.extract(file_path, self.workdir)
- self.vm.set_console()
- self.vm.add_args('-kernel', self.workdir + '/day23/vmlinux',
- '-append', self.KERNEL_COMMON_COMMAND_LINE)
- self.vm.launch()
- wait_for_console_pattern(self, 'Starting logging: OK')
diff --git a/tests/avocado/machine_sparc_leon3.py b/tests/avocado/machine_sparc_leon3.py
deleted file mode 100644
index e61b223..0000000
--- a/tests/avocado/machine_sparc_leon3.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# Functional test that boots a Leon3 machine and checks its serial console.
-#
-# Copyright (c) Philippe Mathieu-DaudƩ <f4bug@amsat.org>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
-from avocado import skip
-
-
-class Leon3Machine(QemuSystemTest):
-
- timeout = 60
-
- @skip("Test currently broken")
- # A Window Underflow exception occurs before booting the kernel,
- # and QEMU exit calling cpu_abort(), which makes this test to fail.
- def test_leon3_helenos_uimage(self):
- """
- :avocado: tags=arch:sparc
- :avocado: tags=machine:leon3_generic
- :avocado: tags=binfmt:uimage
- """
- kernel_url = ('http://www.helenos.org/releases/'
- 'HelenOS-0.6.0-sparc32-leon3.bin')
- kernel_hash = 'a88c9cfdb8430c66650e5290a08765f9bf049a30'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
-
- self.vm.set_console()
- self.vm.add_args('-kernel', kernel_path)
-
- self.vm.launch()
-
- wait_for_console_pattern(self, 'Copyright (c) 2001-2014 HelenOS project')
- wait_for_console_pattern(self, 'Booting the kernel ...')
diff --git a/tests/avocado/multiprocess.py b/tests/avocado/multiprocess.py
deleted file mode 100644
index ee7490a..0000000
--- a/tests/avocado/multiprocess.py
+++ /dev/null
@@ -1,102 +0,0 @@
-# Test for multiprocess qemu
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-
-import os
-import socket
-
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
-from avocado_qemu import exec_command
-from avocado_qemu import exec_command_and_wait_for_pattern
-
-class Multiprocess(QemuSystemTest):
- """
- :avocado: tags=multiprocess
- """
- KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
-
- def do_test(self, kernel_url, kernel_hash, initrd_url, initrd_hash,
- kernel_command_line, machine_type):
- """Main test method"""
- self.require_accelerator('kvm')
- self.require_multiprocess()
-
- # Create socketpair to connect proxy and remote processes
- proxy_sock, remote_sock = socket.socketpair(socket.AF_UNIX,
- socket.SOCK_STREAM)
- os.set_inheritable(proxy_sock.fileno(), True)
- os.set_inheritable(remote_sock.fileno(), True)
-
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- initrd_path = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
-
- # Create remote process
- remote_vm = self.get_vm()
- remote_vm.add_args('-machine', 'x-remote')
- remote_vm.add_args('-nodefaults')
- remote_vm.add_args('-device', 'lsi53c895a,id=lsi1')
- remote_vm.add_args('-object', 'x-remote-object,id=robj1,'
- 'devid=lsi1,fd='+str(remote_sock.fileno()))
- remote_vm.launch()
-
- # Create proxy process
- self.vm.set_console()
- self.vm.add_args('-machine', machine_type)
- self.vm.add_args('-accel', 'kvm')
- self.vm.add_args('-cpu', 'host')
- self.vm.add_args('-object',
- 'memory-backend-memfd,id=sysmem-file,size=2G')
- self.vm.add_args('--numa', 'node,memdev=sysmem-file')
- self.vm.add_args('-m', '2048')
- self.vm.add_args('-kernel', kernel_path,
- '-initrd', initrd_path,
- '-append', kernel_command_line)
- self.vm.add_args('-device',
- 'x-pci-proxy-dev,'
- 'id=lsi1,fd='+str(proxy_sock.fileno()))
- self.vm.launch()
- wait_for_console_pattern(self, 'as init process',
- 'Kernel panic - not syncing')
- exec_command(self, 'mount -t sysfs sysfs /sys')
- exec_command_and_wait_for_pattern(self,
- 'cat /sys/bus/pci/devices/*/uevent',
- 'PCI_ID=1000:0012')
-
- def test_multiprocess_x86_64(self):
- """
- :avocado: tags=arch:x86_64
- """
- kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
- '/linux/releases/31/Everything/x86_64/os/images'
- '/pxeboot/vmlinuz')
- kernel_hash = '5b6f6876e1b5bda314f93893271da0d5777b1f3c'
- initrd_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
- '/linux/releases/31/Everything/x86_64/os/images'
- '/pxeboot/initrd.img')
- initrd_hash = 'dd0340a1b39bd28f88532babd4581c67649ec5b1'
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyS0 rdinit=/bin/bash')
- machine_type = 'pc'
- self.do_test(kernel_url, kernel_hash, initrd_url, initrd_hash,
- kernel_command_line, machine_type)
-
- def test_multiprocess_aarch64(self):
- """
- :avocado: tags=arch:aarch64
- """
- kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
- '/linux/releases/31/Everything/aarch64/os/images'
- '/pxeboot/vmlinuz')
- kernel_hash = '3505f2751e2833c681de78cee8dda1e49cabd2e8'
- initrd_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
- '/linux/releases/31/Everything/aarch64/os/images'
- '/pxeboot/initrd.img')
- initrd_hash = '519a1962daf17d67fc3a9c89d45affcb399607db'
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'rdinit=/bin/bash console=ttyAMA0')
- machine_type = 'virt,gic-version=3'
- self.do_test(kernel_url, kernel_hash, initrd_url, initrd_hash,
- kernel_command_line, machine_type)
diff --git a/tests/avocado/ppc_amiga.py b/tests/avocado/ppc_amiga.py
deleted file mode 100644
index b6f866f..0000000
--- a/tests/avocado/ppc_amiga.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# Test AmigaNG boards
-#
-# Copyright (c) 2023 BALATON Zoltan
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-from avocado.utils import archive
-from avocado.utils import process
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
-
-class AmigaOneMachine(QemuSystemTest):
-
- timeout = 90
-
- def test_ppc_amigaone(self):
- """
- :avocado: tags=arch:ppc
- :avocado: tags=machine:amigaone
- :avocado: tags=device:articia
- :avocado: tags=accel:tcg
- """
- self.require_accelerator("tcg")
- tar_name = 'A1Firmware_Floppy_05-Mar-2005.zip'
- tar_url = ('https://www.hyperion-entertainment.com/index.php/'
- 'downloads?view=download&format=raw&file=25')
- tar_hash = 'c52e59bc73e31d8bcc3cc2106778f7ac84f6c755'
- zip_file = self.fetch_asset(tar_name, locations=tar_url,
- asset_hash=tar_hash)
- archive.extract(zip_file, self.workdir)
- cmd = f"tail -c 524288 {self.workdir}/floppy_edition/updater.image >{self.workdir}/u-boot-amigaone.bin"
- process.run(cmd, shell=True)
-
- self.vm.set_console()
- self.vm.add_args('-bios', self.workdir + '/u-boot-amigaone.bin')
- self.vm.launch()
- wait_for_console_pattern(self, 'FLASH:')
diff --git a/tests/avocado/replay_kernel.py b/tests/avocado/replay_kernel.py
index 232d287..e22c200 100644
--- a/tests/avocado/replay_kernel.py
+++ b/tests/avocado/replay_kernel.py
@@ -13,6 +13,7 @@ import lzma
import shutil
import logging
import time
+import subprocess
from avocado import skip
from avocado import skipUnless
@@ -31,7 +32,7 @@ class ReplayKernelBase(LinuxKernelTest):
terminates.
"""
- timeout = 120
+ timeout = 180
KERNEL_COMMON_COMMAND_LINE = 'printk.time=1 panic=-1 '
def run_vm(self, kernel_path, kernel_command_line, console_pattern,
@@ -63,6 +64,8 @@ class ReplayKernelBase(LinuxKernelTest):
vm.shutdown()
logger.info('finished the recording with log size %s bytes'
% os.path.getsize(replay_path))
+ self.run_replay_dump(replay_path)
+ logger.info('successfully tested replay-dump.py')
else:
vm.wait()
logger.info('successfully finished the replay')
@@ -70,6 +73,14 @@ class ReplayKernelBase(LinuxKernelTest):
logger.info('elapsed time %.2f sec' % elapsed)
return elapsed
+ def run_replay_dump(self, replay_path):
+ try:
+ subprocess.check_call(["./scripts/replay-dump.py",
+ "-f", replay_path],
+ stdout=subprocess.DEVNULL)
+ except subprocess.CalledProcessError:
+ self.fail('replay-dump.py failed')
+
def run_rr(self, kernel_path, kernel_command_line, console_pattern,
shift=7, args=None):
replay_path = os.path.join(self.workdir, 'replay.bin')
@@ -99,7 +110,7 @@ class ReplayKernelNormal(ReplayKernelBase):
self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
# See https://gitlab.com/qemu-project/qemu/-/issues/2094
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test sometimes gets stuck')
+ @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'pc machine is unstable with replay')
def test_x86_64_pc(self):
"""
:avocado: tags=arch:x86_64
@@ -117,6 +128,22 @@ class ReplayKernelNormal(ReplayKernelBase):
self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
+ def test_x86_64_q35(self):
+ """
+ :avocado: tags=arch:x86_64
+ :avocado: tags=machine:q35
+ """
+ kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
+ '/linux/releases/29/Everything/x86_64/os/images/pxeboot'
+ '/vmlinuz')
+ kernel_hash = '23bebd2680757891cf7adedb033532163a792495'
+ kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
+
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
+ console_pattern = 'VFS: Cannot open root device'
+
+ self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5)
+
def test_mips_malta(self):
"""
:avocado: tags=arch:mips
diff --git a/tests/avocado/replay_linux.py b/tests/avocado/replay_linux.py
index f3a43dc..5916922 100644
--- a/tests/avocado/replay_linux.py
+++ b/tests/avocado/replay_linux.py
@@ -19,7 +19,7 @@ from avocado.utils import network
from avocado.utils import vmimage
from avocado.utils import datadrainer
from avocado.utils.path import find_command
-from avocado_qemu import LinuxTest
+from avocado_qemu.linuxtest import LinuxTest
class ReplayLinux(LinuxTest):
"""
@@ -94,6 +94,8 @@ class ReplayLinux(LinuxTest):
vm.shutdown()
logger.info('finished the recording with log size %s bytes'
% os.path.getsize(replay_path))
+ self.run_replay_dump(replay_path)
+ logger.info('successfully tested replay-dump.py')
else:
vm.event_wait('SHUTDOWN', self.timeout)
vm.wait()
@@ -108,6 +110,14 @@ class ReplayLinux(LinuxTest):
logger = logging.getLogger('replay')
logger.info('replay overhead {:.2%}'.format(t2 / t1 - 1))
+ def run_replay_dump(self, replay_path):
+ try:
+ subprocess.check_call(["./scripts/replay-dump.py",
+ "-f", replay_path],
+ stdout=subprocess.DEVNULL)
+ except subprocess.CalledProcessError:
+ self.fail('replay-dump.py failed')
+
@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
class ReplayLinuxX8664(ReplayLinux):
"""
diff --git a/tests/avocado/reverse_debugging.py b/tests/avocado/reverse_debugging.py
index 92855a0..f24287c 100644
--- a/tests/avocado/reverse_debugging.py
+++ b/tests/avocado/reverse_debugging.py
@@ -207,7 +207,6 @@ class ReverseDebugging_X86_64(ReverseDebugging):
# unidentified gitlab timeout problem
@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
-
def test_x86_64_pc(self):
"""
:avocado: tags=arch:x86_64
@@ -225,7 +224,6 @@ class ReverseDebugging_AArch64(ReverseDebugging):
# unidentified gitlab timeout problem
@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
-
def test_aarch64_virt(self):
"""
:avocado: tags=arch:aarch64
@@ -250,7 +248,6 @@ class ReverseDebugging_ppc64(ReverseDebugging):
# unidentified gitlab timeout problem
@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
-
def test_ppc64_pseries(self):
"""
:avocado: tags=arch:ppc64
@@ -265,7 +262,6 @@ class ReverseDebugging_ppc64(ReverseDebugging):
# See https://gitlab.com/qemu-project/qemu/-/issues/1992
@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
-
def test_ppc64_powernv(self):
"""
:avocado: tags=arch:ppc64
diff --git a/tests/avocado/smmu.py b/tests/avocado/smmu.py
index 4ebfa71..83fd79e 100644
--- a/tests/avocado/smmu.py
+++ b/tests/avocado/smmu.py
@@ -10,10 +10,10 @@
import os
from avocado import skipUnless
-from avocado_qemu import LinuxTest, BUILD_DIR
+from avocado_qemu import BUILD_DIR
+from avocado_qemu.linuxtest import LinuxTest
@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
-
class SMMU(LinuxTest):
"""
:avocado: tags=accel:kvm
diff --git a/tests/avocado/tcg_plugins.py b/tests/avocado/tcg_plugins.py
index 15fd87b..a6ff457 100644
--- a/tests/avocado/tcg_plugins.py
+++ b/tests/avocado/tcg_plugins.py
@@ -77,7 +77,7 @@ class PluginKernelNormal(PluginKernelBase):
suffix=".log")
self.run_vm(kernel_path, kernel_command_line,
- "tests/plugin/libinsn.so", plugin_log.name,
+ "tests/tcg/plugins/libinsn.so", plugin_log.name,
console_pattern)
with plugin_log as lf, \
@@ -107,7 +107,7 @@ class PluginKernelNormal(PluginKernelBase):
suffix=".log")
self.run_vm(kernel_path, kernel_command_line,
- "tests/plugin/libinsn.so", plugin_log.name,
+ "tests/tcg/plugins/libinsn.so", plugin_log.name,
console_pattern,
args=('-icount', 'shift=1'))
@@ -120,36 +120,3 @@ class PluginKernelNormal(PluginKernelBase):
else:
count = int(m.group("count"))
self.log.info(f"Counted: {count} instructions")
-
- def test_aarch64_virt_mem_icount(self):
- """
- :avocado: tags=accel:tcg
- :avocado: tags=arch:aarch64
- :avocado: tags=machine:virt
- :avocado: tags=cpu:cortex-a53
- """
- kernel_path = self._grab_aarch64_kernel()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyAMA0')
- console_pattern = 'Kernel panic - not syncing: VFS:'
-
- plugin_log = tempfile.NamedTemporaryFile(mode="r+t", prefix="plugin",
- suffix=".log")
-
- self.run_vm(kernel_path, kernel_command_line,
- "tests/plugin/libmem.so,inline=true,callback=true", plugin_log.name,
- console_pattern,
- args=('-icount', 'shift=1'))
-
- with plugin_log as lf, \
- mmap.mmap(lf.fileno(), 0, access=mmap.ACCESS_READ) as s:
- m = re.findall(br"mem accesses: (?P<count>\d+)", s)
- if m is None or len(m) != 2:
- self.fail("no memory access counts found")
- else:
- inline = int(m[0])
- callback = int(m[1])
- if inline != callback:
- self.fail("mismatched access counts")
- else:
- self.log.info(f"Counted {inline} memory accesses")
diff --git a/tests/avocado/tesseract_utils.py b/tests/avocado/tesseract_utils.py
deleted file mode 100644
index 476f528..0000000
--- a/tests/avocado/tesseract_utils.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# ...
-#
-# Copyright (c) 2019 Philippe Mathieu-DaudƩ <f4bug@amsat.org>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-import re
-import logging
-
-from avocado.utils import process
-from avocado.utils.path import find_command, CmdNotFoundError
-
-def tesseract_available(expected_version):
- try:
- find_command('tesseract')
- except CmdNotFoundError:
- return False
- res = process.run('tesseract --version')
- try:
- version = res.stdout_text.split()[1]
- except IndexError:
- version = res.stderr_text.split()[1]
- return int(version.split('.')[0]) >= expected_version
-
- match = re.match(r'tesseract\s(\d)', res)
- if match is None:
- return False
- # now this is guaranteed to be a digit
- return int(match.groups()[0]) >= expected_version
-
-
-def tesseract_ocr(image_path, tesseract_args='', tesseract_version=3):
- console_logger = logging.getLogger('tesseract')
- console_logger.debug(image_path)
- if tesseract_version == 4:
- tesseract_args += ' --oem 1'
- proc = process.run("tesseract {} {} stdout".format(tesseract_args,
- image_path))
- lines = []
- for line in proc.stdout_text.split('\n'):
- sline = line.strip()
- if len(sline):
- console_logger.debug(sline)
- lines += [sline]
- return lines
diff --git a/tests/avocado/tuxrun_baselines.py b/tests/avocado/tuxrun_baselines.py
index 736e4aa..3806484 100644
--- a/tests/avocado/tuxrun_baselines.py
+++ b/tests/avocado/tuxrun_baselines.py
@@ -182,63 +182,6 @@ class TuxRunBaselineTest(QemuSystemTest):
self.vm.launch()
self.run_tuxtest_tests(haltmsg)
- def ppc64_common_tuxrun(self, sums, prefix):
- # add device args to command line.
- self.require_netdev('user')
- self.vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22',
- '-device', 'virtio-net,netdev=vnet')
- self.vm.add_args('-netdev', '{"type":"user","id":"hostnet0"}',
- '-device', '{"driver":"virtio-net-pci","netdev":'
- '"hostnet0","id":"net0","mac":"52:54:00:4c:e3:86",'
- '"bus":"pci.0","addr":"0x9"}')
- self.vm.add_args('-device', '{"driver":"qemu-xhci","p2":15,"p3":15,'
- '"id":"usb","bus":"pci.0","addr":"0x2"}')
- self.vm.add_args('-device', '{"driver":"virtio-scsi-pci","id":"scsi0"'
- ',"bus":"pci.0","addr":"0x3"}')
- self.vm.add_args('-device', '{"driver":"virtio-serial-pci","id":'
- '"virtio-serial0","bus":"pci.0","addr":"0x4"}')
- self.vm.add_args('-device', '{"driver":"scsi-cd","bus":"scsi0.0"'
- ',"channel":0,"scsi-id":0,"lun":0,"device_id":'
- '"drive-scsi0-0-0-0","id":"scsi0-0-0-0"}')
- self.vm.add_args('-device', '{"driver":"virtio-balloon-pci",'
- '"id":"balloon0","bus":"pci.0","addr":"0x6"}')
- self.vm.add_args('-audiodev', '{"id":"audio1","driver":"none"}')
- self.vm.add_args('-device', '{"driver":"usb-tablet","id":"input0"'
- ',"bus":"usb.0","port":"1"}')
- self.vm.add_args('-device', '{"driver":"usb-kbd","id":"input1"'
- ',"bus":"usb.0","port":"2"}')
- self.vm.add_args('-device', '{"driver":"VGA","id":"video0",'
- '"vgamem_mb":16,"bus":"pci.0","addr":"0x7"}')
- self.vm.add_args('-object', '{"qom-type":"rng-random","id":"objrng0"'
- ',"filename":"/dev/urandom"}',
- '-device', '{"driver":"virtio-rng-pci","rng":"objrng0"'
- ',"id":"rng0","bus":"pci.0","addr":"0x8"}')
- self.vm.add_args('-object', '{"qom-type":"cryptodev-backend-builtin",'
- '"id":"objcrypto0","queues":1}',
- '-device', '{"driver":"virtio-crypto-pci",'
- '"cryptodev":"objcrypto0","id":"crypto0","bus"'
- ':"pci.0","addr":"0xa"}')
- self.vm.add_args('-device', '{"driver":"spapr-pci-host-bridge"'
- ',"index":1,"id":"pci.1"}')
- self.vm.add_args('-device', '{"driver":"spapr-vscsi","id":"scsi1"'
- ',"reg":12288}')
- self.vm.add_args('-m', '2G,slots=32,maxmem=4G',
- '-object', 'memory-backend-ram,id=ram1,size=1G',
- '-device', 'pc-dimm,id=dimm1,memdev=ram1')
-
- # Create a temporary qcow2 and launch the test-case
- with tempfile.NamedTemporaryFile(prefix=prefix,
- suffix='.qcow2') as qcow2:
- process.run(self.qemu_img + ' create -f qcow2 ' +
- qcow2.name + ' 1G')
-
- self.vm.add_args('-drive', 'file=' + qcow2.name +
- ',format=qcow2,if=none,id='
- 'drive-virtio-disk1',
- '-device', 'virtio-blk-pci,bus=pci.0,'
- 'addr=0xb,drive=drive-virtio-disk1,id=virtio-disk1'
- ',bootindex=2')
- self.common_tuxrun(csums=sums, drive="scsi-hd")
#
# The tests themselves. The configuration is derived from how
@@ -279,342 +222,3 @@ class TuxRunBaselineTest(QemuSystemTest):
"rootfs.ext4.zst" :
"e6ffd8813c8a335bc15728f2835f90539c84be7f8f5f691a8b01451b47fb4bd7"}
self.common_tuxrun(csums=sums)
-
- def test_armv5(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=cpu:arm926
- :avocado: tags=machine:versatilepb
- :avocado: tags=tuxboot:armv5
- :avocado: tags=image:zImage
- :avocado: tags=console:ttyAMA0
- :avocado: tags=shutdown:nowait
- """
- sums = { "rootfs.ext4.zst" :
- "17177afa74e7294da0642861f08c88ca3c836764299a54bf6d1ce276cb9712a5",
- "versatile-pb.dtb" :
- "0bc0c0b0858cefd3c32b385c0d66d97142ded29472a496f4f490e42fc7615b25",
- "zImage" :
- "c95af2f27647c12265d75e9df44c22ff5228c59855f54aaa70f41ec2842e3a4d" }
-
- self.common_tuxrun(csums=sums,
- drive="virtio-blk-pci",
- dt="versatile-pb.dtb")
-
- def test_armv7(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=cpu:cortex-a15
- :avocado: tags=machine:virt
- :avocado: tags=tuxboot:armv7
- :avocado: tags=image:zImage
- :avocado: tags=console:ttyAMA0
- :avocado: tags=shutdown:nowait
- """
- sums = { "rootfs.ext4.zst" :
- "ab1fbbeaddda1ffdd45c9405a28cd5370c20f23a7cbc809cc90dc9f243a8eb5a",
- "zImage" :
- "4c7a22e9f15875bec06bd2a29d822496571eb297d4f22694099ffcdb19077572" }
-
- self.common_tuxrun(csums=sums)
-
- def test_armv7be(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=cpu:cortex-a15
- :avocado: tags=endian:big
- :avocado: tags=machine:virt
- :avocado: tags=tuxboot:armv7be
- :avocado: tags=image:zImage
- :avocado: tags=console:ttyAMA0
- :avocado: tags=shutdown:nowait
- """
- sums = {"rootfs.ext4.zst" :
- "42ed46dd2d59986206c5b1f6cf35eab58fe3fd20c96b41aaa16b32f3f90a9835",
- "zImage" :
- "7facc62082b57af12015b08f7fdbaf2f123ba07a478367853ae12b219afc9f2f" }
-
- self.common_tuxrun(csums=sums)
-
- def test_i386(self):
- """
- :avocado: tags=arch:i386
- :avocado: tags=cpu:coreduo
- :avocado: tags=machine:q35
- :avocado: tags=tuxboot:i386
- :avocado: tags=image:bzImage
- :avocado: tags=shutdown:nowait
- """
- sums = {"bzImage" :
- "a3e5b32a354729e65910f5a1ffcda7c14a6c12a55e8213fb86e277f1b76ed956",
- "rootfs.ext4.zst" :
- "f15e66b2bf673a210ec2a4b2e744a80530b36289e04f5388aab812b97f69754a" }
-
- self.common_tuxrun(csums=sums, drive="virtio-blk-pci")
-
- def test_mips32(self):
- """
- :avocado: tags=arch:mips
- :avocado: tags=machine:malta
- :avocado: tags=cpu:mips32r6-generic
- :avocado: tags=endian:big
- :avocado: tags=tuxboot:mips32
- :avocado: tags=image:vmlinux
- :avocado: tags=root:sda
- :avocado: tags=shutdown:nowait
- """
- sums = { "rootfs.ext4.zst" :
- "fc3da0b4c2f38d74c6d705123bb0f633c76ed953128f9d0859378c328a6d11a0",
- "vmlinux" :
- "bfd2172f8b17fb32970ca0c8c58f59c5a4ca38aa5855d920be3a69b5d16e52f0" }
-
- self.common_tuxrun(csums=sums, drive="driver=ide-hd,bus=ide.0,unit=0")
-
- def test_mips32el(self):
- """
- :avocado: tags=arch:mipsel
- :avocado: tags=machine:malta
- :avocado: tags=cpu:mips32r6-generic
- :avocado: tags=tuxboot:mips32el
- :avocado: tags=image:vmlinux
- :avocado: tags=root:sda
- :avocado: tags=shutdown:nowait
- """
- sums = { "rootfs.ext4.zst" :
- "e799768e289fd69209c21f4dacffa11baea7543d5db101e8ce27e3bc2c41d90e",
- "vmlinux" :
- "8573867c68a8443db8de6d08bb33fb291c189ca2ca671471d3973a3e712096a3" }
-
- self.common_tuxrun(csums=sums, drive="driver=ide-hd,bus=ide.0,unit=0")
-
- def test_mips64(self):
- """
- :avocado: tags=arch:mips64
- :avocado: tags=machine:malta
- :avocado: tags=tuxboot:mips64
- :avocado: tags=endian:big
- :avocado: tags=image:vmlinux
- :avocado: tags=root:sda
- :avocado: tags=shutdown:nowait
- """
- sums = { "rootfs.ext4.zst" :
- "69d91eeb04df3d8d172922c6993bb37d4deeb6496def75d8580f6f9de3e431da",
- "vmlinux" :
- "09010e51e4b8bcbbd2494786ffb48eca78f228e96e5c5438344b0eac4029dc61" }
-
- self.common_tuxrun(csums=sums, drive="driver=ide-hd,bus=ide.0,unit=0")
-
- def test_mips64el(self):
- """
- :avocado: tags=arch:mips64el
- :avocado: tags=machine:malta
- :avocado: tags=tuxboot:mips64el
- :avocado: tags=image:vmlinux
- :avocado: tags=root:sda
- :avocado: tags=shutdown:nowait
- """
- sums = { "rootfs.ext4.zst" :
- "fba585368f5915b1498ed081863474b2d7ec4e97cdd46d21bdcb2f9698f83de4",
- "vmlinux" :
- "d4e08965e2155c4cccce7c5f34d18fe34c636cda2f2c9844387d614950155266" }
-
- self.common_tuxrun(csums=sums, drive="driver=ide-hd,bus=ide.0,unit=0")
-
- def test_ppc32(self):
- """
- :avocado: tags=arch:ppc
- :avocado: tags=machine:ppce500
- :avocado: tags=cpu:e500mc
- :avocado: tags=tuxboot:ppc32
- :avocado: tags=image:uImage
- :avocado: tags=shutdown:nowait
- """
- sums = { "rootfs.ext4.zst" :
- "8885b9d999cc24d679542a02e9b6aaf48f718f2050ece6b8347074b6ee41dd09",
- "uImage" :
- "1a68f74b860fda022fb12e03c5efece8c2b8b590d96cca37a8481a3ae0b3f81f" }
-
- self.common_tuxrun(csums=sums, drive="virtio-blk-pci")
-
- def test_ppc64(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:pseries
- :avocado: tags=cpu:POWER10
- :avocado: tags=endian:big
- :avocado: tags=console:hvc0
- :avocado: tags=tuxboot:ppc64
- :avocado: tags=image:vmlinux
- :avocado: tags=extradev:driver=spapr-vscsi
- :avocado: tags=root:sda
- """
- sums = { "rootfs.ext4.zst" :
- "1d953e81a4379e537fc8e41e05a0a59d9b453eef97aa03d47866c6c45b00bdff",
- "vmlinux" :
- "f22a9b9e924174a4c199f4c7e5d91a2339fcfe51c6eafd0907dc3e09b64ab728" }
- self.ppc64_common_tuxrun(sums, prefix='tuxrun_ppc64_')
-
- def test_ppc64le(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:pseries
- :avocado: tags=cpu:POWER10
- :avocado: tags=console:hvc0
- :avocado: tags=tuxboot:ppc64le
- :avocado: tags=image:vmlinux
- :avocado: tags=extradev:driver=spapr-vscsi
- :avocado: tags=root:sda
- """
- sums = { "rootfs.ext4.zst" :
- "b442678c93fb8abe1f7d3bfa20556488de6b475c22c8fed363f42cf81a0a3906",
- "vmlinux" :
- "979eb61b445a010fb13e2b927126991f8ceef9c590fa2be0996c00e293e80cf2" }
- self.ppc64_common_tuxrun(sums, prefix='tuxrun_ppc64le_')
-
- def test_riscv32(self):
- """
- :avocado: tags=arch:riscv32
- :avocado: tags=machine:virt
- :avocado: tags=tuxboot:riscv32
- """
- sums = { "Image" :
- "89599407d7334de629a40e7ad6503c73670359eb5f5ae9d686353a3d6deccbd5",
- "fw_jump.elf" :
- "f2ef28a0b77826f79d085d3e4aa686f1159b315eff9099a37046b18936676985",
- "rootfs.ext4.zst" :
- "7168d296d0283238ea73cd5a775b3dd608e55e04c7b92b76ecce31bb13108cba" }
-
- self.common_tuxrun(csums=sums)
-
- def test_riscv64(self):
- """
- :avocado: tags=arch:riscv64
- :avocado: tags=machine:virt
- :avocado: tags=tuxboot:riscv64
- """
- sums = { "Image" :
- "cd634badc65e52fb63465ec99e309c0de0369f0841b7d9486f9729e119bac25e",
- "fw_jump.elf" :
- "6e3373abcab4305fe151b564a4c71110d833c21f2c0a1753b7935459e36aedcf",
- "rootfs.ext4.zst" :
- "b18e3a3bdf27be03da0b285e84cb71bf09eca071c3a087b42884b6982ed679eb" }
-
- self.common_tuxrun(csums=sums)
-
- def test_riscv32_maxcpu(self):
- """
- :avocado: tags=arch:riscv32
- :avocado: tags=machine:virt
- :avocado: tags=cpu:max
- :avocado: tags=tuxboot:riscv32
- """
- sums = { "Image" :
- "89599407d7334de629a40e7ad6503c73670359eb5f5ae9d686353a3d6deccbd5",
- "fw_jump.elf" :
- "f2ef28a0b77826f79d085d3e4aa686f1159b315eff9099a37046b18936676985",
- "rootfs.ext4.zst" :
- "7168d296d0283238ea73cd5a775b3dd608e55e04c7b92b76ecce31bb13108cba" }
-
- self.common_tuxrun(csums=sums)
-
- def test_riscv64_maxcpu(self):
- """
- :avocado: tags=arch:riscv64
- :avocado: tags=machine:virt
- :avocado: tags=cpu:max
- :avocado: tags=tuxboot:riscv64
- """
- sums = { "Image" :
- "cd634badc65e52fb63465ec99e309c0de0369f0841b7d9486f9729e119bac25e",
- "fw_jump.elf" :
- "6e3373abcab4305fe151b564a4c71110d833c21f2c0a1753b7935459e36aedcf",
- "rootfs.ext4.zst" :
- "b18e3a3bdf27be03da0b285e84cb71bf09eca071c3a087b42884b6982ed679eb" }
-
- self.common_tuxrun(csums=sums)
-
- def test_s390(self):
- """
- :avocado: tags=arch:s390x
- :avocado: tags=endian:big
- :avocado: tags=tuxboot:s390
- :avocado: tags=image:bzImage
- :avocado: tags=shutdown:nowait
- """
- sums = { "bzImage" :
- "0414e98dd1c3dafff8496c9cd9c28a5f8d04553bb5ba37e906a812b48d442ef0",
- "rootfs.ext4.zst" :
- "88c37c32276677f873a25ab9ec6247895b8e3e6f8259134de2a616080b8ab3fc" }
-
- self.common_tuxrun(csums=sums,
- drive="virtio-blk-ccw",
- haltmsg="Requesting system halt")
-
- # Note: some segfaults caused by unaligned userspace access
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
- def test_sh4(self):
- """
- :avocado: tags=arch:sh4
- :avocado: tags=machine:r2d
- :avocado: tags=cpu:sh7785
- :avocado: tags=tuxboot:sh4
- :avocado: tags=image:zImage
- :avocado: tags=root:sda
- :avocado: tags=console:ttySC1
- :avocado: tags=flaky
- """
- sums = { "rootfs.ext4.zst" :
- "3592a7a3d5a641e8b9821449e77bc43c9904a56c30d45da0694349cfd86743fd",
- "zImage" :
- "29d9b2aba604a0f53a5dc3b5d0f2b8e35d497de1129f8ee5139eb6fdf0db692f" }
-
- # The test is currently too unstable to do much in userspace
- # so we skip common_tuxrun and do a minimal boot and shutdown.
- (kernel, disk, dtb) = self.fetch_tuxrun_assets(csums=sums)
-
- # the console comes on the second serial port
- self.prepare_run(kernel, disk,
- "driver=ide-hd,bus=ide.0,unit=0",
- console_index=1)
- self.vm.launch()
-
- self.wait_for_console_pattern("Welcome to TuxTest")
- time.sleep(0.1)
- exec_command(self, 'root')
- time.sleep(0.1)
- exec_command_and_wait_for_pattern(self, 'halt',
- "reboot: System halted")
-
- def test_sparc64(self):
- """
- :avocado: tags=arch:sparc64
- :avocado: tags=tuxboot:sparc64
- :avocado: tags=image:vmlinux
- :avocado: tags=root:sda
- :avocado: tags=shutdown:nowait
- """
-
- sums = { "rootfs.ext4.zst" :
- "ad2f1dc436ab51583543d25d2c210cab478645d47078d30d129a66ab0e281d76",
- "vmlinux" :
- "e34313e4325ff21deaa3d38a502aa09a373ef62b9bd4d7f8f29388b688225c55" }
-
- self.common_tuxrun(csums=sums, drive="driver=ide-hd,bus=ide.0,unit=0")
-
- def test_x86_64(self):
- """
- :avocado: tags=arch:x86_64
- :avocado: tags=machine:q35
- :avocado: tags=cpu:Nehalem
- :avocado: tags=tuxboot:x86_64
- :avocado: tags=image:bzImage
- :avocado: tags=root:sda
- :avocado: tags=shutdown:nowait
- """
- sums = { "bzImage" :
- "2bc7480a669ee9b6b82500a236aba0c54233debe98cb968268fa230f52f03461",
- "rootfs.ext4.zst" :
- "b72ac729769b8f51c6dffb221113c9a063c774dbe1d66af30eb593c4e9999b4b" }
-
- self.common_tuxrun(csums=sums,
- drive="driver=ide-hd,bus=ide.0,unit=0")
diff --git a/tests/avocado/virtiofs_submounts.py.data/cleanup.sh b/tests/avocado/virtiofs_submounts.py.data/cleanup.sh
deleted file mode 100644
index 2a6579a..0000000
--- a/tests/avocado/virtiofs_submounts.py.data/cleanup.sh
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/bash
-
-function print_usage()
-{
- if [ -n "$2" ]; then
- echo "Error: $2"
- echo
- fi
- echo "Usage: $1 <scratch dir>"
-}
-
-scratch_dir=$1
-if [ -z "$scratch_dir" ]; then
- print_usage "$0" 'Scratch dir not given' >&2
- exit 1
-fi
-
-cd "$scratch_dir/share" || exit 1
-mps=(mnt*)
-mp_i=0
-for mp in "${mps[@]}"; do
- mp_i=$((mp_i + 1))
- printf "Unmounting %i/%i...\r" "$mp_i" "${#mps[@]}"
-
- sudo umount -R "$mp"
- rm -rf "$mp"
-done
-echo
-
-rm some-file
-cd ..
-rmdir share
-
-imgs=(fs*.img)
-img_i=0
-for img in "${imgs[@]}"; do
- img_i=$((img_i + 1))
- printf "Detaching and deleting %i/%i...\r" "$img_i" "${#imgs[@]}"
-
- dev=$(losetup -j "$img" | sed -e 's/:.*//')
- sudo losetup -d "$dev"
- rm -f "$img"
-done
-echo
-
-echo 'Done.'
diff --git a/tests/avocado/virtiofs_submounts.py.data/guest-cleanup.sh b/tests/avocado/virtiofs_submounts.py.data/guest-cleanup.sh
deleted file mode 100644
index 729cb2d..0000000
--- a/tests/avocado/virtiofs_submounts.py.data/guest-cleanup.sh
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/bash
-
-function print_usage()
-{
- if [ -n "$2" ]; then
- echo "Error: $2"
- echo
- fi
- echo "Usage: $1 <scratch dir>"
-}
-
-scratch_dir=$1
-if [ -z "$scratch_dir" ]; then
- print_usage "$0" 'Scratch dir not given' >&2
- exit 1
-fi
-
-cd "$scratch_dir/share" || exit 1
-
-mps=(mnt*)
-mp_i=0
-for mp in "${mps[@]}"; do
- mp_i=$((mp_i + 1))
- printf "Unmounting %i/%i...\r" "$mp_i" "${#mps[@]}"
-
- sudo umount -R "$mp"
-done
-echo
-
-echo 'Done.'
diff --git a/tests/avocado/virtiofs_submounts.py.data/guest.sh b/tests/avocado/virtiofs_submounts.py.data/guest.sh
deleted file mode 100644
index 59ba40f..0000000
--- a/tests/avocado/virtiofs_submounts.py.data/guest.sh
+++ /dev/null
@@ -1,138 +0,0 @@
-#!/bin/bash
-
-function print_usage()
-{
- if [ -n "$2" ]; then
- echo "Error: $2"
- echo
- fi
- echo "Usage: $1 <shared dir>"
- echo '(The shared directory is the "share" directory in the scratch' \
- 'directory)'
-}
-
-shared_dir=$1
-if [ -z "$shared_dir" ]; then
- print_usage "$0" 'Shared dir not given' >&2
- exit 1
-fi
-
-cd "$shared_dir"
-
-# FIXME: This should not be necessary, but it is. In order for all
-# submounts to be proper mount points, we need to visit them.
-# (Before we visit them, they will not be auto-mounted, and so just
-# appear as normal directories, with the catch that their st_ino will
-# be the st_ino of the filesystem they host, while the st_dev will
-# still be the st_dev of the parent.)
-# `find` does not work, because it will refuse to touch the mount
-# points as long as they are not mounted; their st_dev being shared
-# with the parent and st_ino just being the root node's inode ID
-# will practically ensure that this node exists elsewhere on the
-# filesystem, and `find` is required to recognize loops and not to
-# follow them.
-# Thus, we have to manually visit all nodes first.
-
-mnt_i=0
-
-function recursively_visit()
-{
- pushd "$1" >/dev/null
- for entry in *; do
- if [[ "$entry" == mnt* ]]; then
- mnt_i=$((mnt_i + 1))
- printf "Triggering auto-mount $mnt_i...\r"
- fi
-
- if [ -d "$entry" ]; then
- recursively_visit "$entry"
- fi
- done
- popd >/dev/null
-}
-
-recursively_visit .
-echo
-
-
-if [ -n "$(find -name not-mounted)" ]; then
- echo "Error: not-mounted files visible on mount points:" >&2
- find -name not-mounted >&2
- exit 1
-fi
-
-if [ ! -f some-file -o "$(cat some-file)" != 'root' ]; then
- echo "Error: Bad file in the share root" >&2
- exit 1
-fi
-
-shopt -s nullglob
-
-function check_submounts()
-{
- local base_path=$1
-
- for mp in mnt*; do
- printf "Checking submount %i...\r" "$((${#devs[@]} + 1))"
-
- mp_i=$(echo "$mp" | sed -e 's/mnt//')
- dev=$(stat -c '%D' "$mp")
-
- if [ -n "${devs[mp_i]}" ]; then
- echo "Error: $mp encountered twice" >&2
- exit 1
- fi
- devs[mp_i]=$dev
-
- pushd "$mp" >/dev/null
- path="$base_path$mp"
- while true; do
- expected_content="$(printf '%s\n%s\n' "$mp_i" "$path")"
- if [ ! -f some-file ]; then
- echo "Error: $PWD/some-file does not exist" >&2
- exit 1
- fi
-
- if [ "$(cat some-file)" != "$expected_content" ]; then
- echo "Error: Bad content in $PWD/some-file:" >&2
- echo '--- found ---'
- cat some-file
- echo '--- expected ---'
- echo "$expected_content"
- exit 1
- fi
- if [ "$(stat -c '%D' some-file)" != "$dev" ]; then
- echo "Error: $PWD/some-file has the wrong device ID" >&2
- exit 1
- fi
-
- if [ -d sub ]; then
- if [ "$(stat -c '%D' sub)" != "$dev" ]; then
- echo "Error: $PWD/some-file has the wrong device ID" >&2
- exit 1
- fi
- cd sub
- path="$path/sub"
- else
- if [ -n "$(echo mnt*)" ]; then
- check_submounts "$path/"
- fi
- break
- fi
- done
- popd >/dev/null
- done
-}
-
-root_dev=$(stat -c '%D' some-file)
-devs=()
-check_submounts ''
-echo
-
-reused_devs=$(echo "$root_dev ${devs[@]}" | tr ' ' '\n' | sort | uniq -d)
-if [ -n "$reused_devs" ]; then
- echo "Error: Reused device IDs: $reused_devs" >&2
- exit 1
-fi
-
-echo "Test passed for ${#devs[@]} submounts."
diff --git a/tests/avocado/virtiofs_submounts.py.data/host.sh b/tests/avocado/virtiofs_submounts.py.data/host.sh
deleted file mode 100644
index d8a9afe..0000000
--- a/tests/avocado/virtiofs_submounts.py.data/host.sh
+++ /dev/null
@@ -1,127 +0,0 @@
-#!/bin/bash
-
-mount_count=128
-
-function print_usage()
-{
- if [ -n "$2" ]; then
- echo "Error: $2"
- echo
- fi
- echo "Usage: $1 <scratch dir> [seed]"
- echo "(If no seed is given, it will be randomly generated.)"
-}
-
-scratch_dir=$1
-if [ -z "$scratch_dir" ]; then
- print_usage "$0" 'No scratch dir given' >&2
- exit 1
-fi
-
-if [ ! -d "$scratch_dir" ]; then
- print_usage "$0" "$scratch_dir is not a directory" >&2
- exit 1
-fi
-
-seed=$2
-if [ -z "$seed" ]; then
- seed=$RANDOM
-fi
-RANDOM=$seed
-
-echo "Seed: $seed"
-
-set -e
-shopt -s nullglob
-
-cd "$scratch_dir"
-if [ -d share ]; then
- echo 'Error: This directory seems to be in use already' >&2
- exit 1
-fi
-
-for ((i = 0; i < $mount_count; i++)); do
- printf "Setting up fs %i/%i...\r" "$((i + 1))" "$mount_count"
-
- rm -f fs$i.img
- truncate -s 512M fs$i.img
- mkfs.xfs -q fs$i.img
- devs[i]=$(sudo losetup -f --show fs$i.img)
-done
-echo
-
-top_level_mounts=$((RANDOM % mount_count + 1))
-
-mkdir -p share
-echo 'root' > share/some-file
-
-for ((i = 0; i < $top_level_mounts; i++)); do
- printf "Mounting fs %i/%i...\r" "$((i + 1))" "$mount_count"
-
- mkdir -p share/mnt$i
- touch share/mnt$i/not-mounted
- sudo mount "${devs[i]}" share/mnt$i
- sudo chown "$(id -u):$(id -g)" share/mnt$i
-
- pushd share/mnt$i >/dev/null
- path=mnt$i
- nesting=$((RANDOM % 4))
- for ((j = 0; j < $nesting; j++)); do
- cat > some-file <<EOF
-$i
-$path
-EOF
- mkdir sub
- cd sub
- path="$path/sub"
- done
-cat > some-file <<EOF
-$i
-$path
-EOF
- popd >/dev/null
-done
-
-for ((; i < $mount_count; i++)); do
- printf "Mounting fs %i/%i...\r" "$((i + 1))" "$mount_count"
-
- mp_i=$((i % top_level_mounts))
-
- pushd share/mnt$mp_i >/dev/null
- path=mnt$mp_i
- while true; do
- sub_mp="$(echo mnt*)"
- if cd sub 2>/dev/null; then
- path="$path/sub"
- elif [ -n "$sub_mp" ] && cd "$sub_mp" 2>/dev/null; then
- path="$path/$sub_mp"
- else
- break
- fi
- done
- mkdir mnt$i
- touch mnt$i/not-mounted
- sudo mount "${devs[i]}" mnt$i
- sudo chown "$(id -u):$(id -g)" mnt$i
-
- cd mnt$i
- path="$path/mnt$i"
- nesting=$((RANDOM % 4))
- for ((j = 0; j < $nesting; j++)); do
- cat > some-file <<EOF
-$i
-$path
-EOF
- mkdir sub
- cd sub
- path="$path/sub"
- done
- cat > some-file <<EOF
-$i
-$path
-EOF
- popd >/dev/null
-done
-echo
-
-echo 'Done.'
diff --git a/tests/bench/benchmark-crypto-akcipher.c b/tests/bench/benchmark-crypto-akcipher.c
index 5e68cb0..0a6e5db 100644
--- a/tests/bench/benchmark-crypto-akcipher.c
+++ b/tests/bench/benchmark-crypto-akcipher.c
@@ -16,19 +16,19 @@
#include "crypto/akcipher.h"
#include "standard-headers/linux/virtio_crypto.h"
-#include "test_akcipher_keys.inc"
+#include "test_akcipher_keys.c.inc"
static QCryptoAkCipher *create_rsa_akcipher(const uint8_t *priv_key,
size_t keylen,
- QCryptoRSAPaddingAlgorithm padding,
- QCryptoHashAlgorithm hash)
+ QCryptoRSAPaddingAlgo padding,
+ QCryptoHashAlgo hash)
{
QCryptoAkCipherOptions opt;
- opt.alg = QCRYPTO_AKCIPHER_ALG_RSA;
+ opt.alg = QCRYPTO_AK_CIPHER_ALGO_RSA;
opt.u.rsa.padding_alg = padding;
opt.u.rsa.hash_alg = hash;
- return qcrypto_akcipher_new(&opt, QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
+ return qcrypto_akcipher_new(&opt, QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE,
priv_key, keylen, &error_abort);
}
@@ -39,8 +39,8 @@ static void test_rsa_speed(const uint8_t *priv_key, size_t keylen,
#define SHA1_DGST_LEN 20
#define SIGN_TIMES 10000
#define VERIFY_TIMES 100000
-#define PADDING QCRYPTO_RSA_PADDING_ALG_PKCS1
-#define HASH QCRYPTO_HASH_ALG_SHA1
+#define PADDING QCRYPTO_RSA_PADDING_ALGO_PKCS1
+#define HASH QCRYPTO_HASH_ALGO_SHA1
g_autoptr(QCryptoAkCipher) rsa =
create_rsa_akcipher(priv_key, keylen, PADDING, HASH);
@@ -53,8 +53,8 @@ static void test_rsa_speed(const uint8_t *priv_key, size_t keylen,
signature = g_new0(uint8_t, key_size / BYTE);
g_test_message("benchmark rsa%zu (%s-%s) sign...", key_size,
- QCryptoRSAPaddingAlgorithm_str(PADDING),
- QCryptoHashAlgorithm_str(HASH));
+ QCryptoRSAPaddingAlgo_str(PADDING),
+ QCryptoHashAlgo_str(HASH));
g_test_timer_start();
for (count = 0; count < SIGN_TIMES; ++count) {
g_assert(qcrypto_akcipher_sign(rsa, dgst, SHA1_DGST_LEN,
@@ -64,14 +64,14 @@ static void test_rsa_speed(const uint8_t *priv_key, size_t keylen,
g_test_timer_elapsed();
g_test_message("rsa%zu (%s-%s) sign %zu times in %.2f seconds,"
" %.2f times/sec ",
- key_size, QCryptoRSAPaddingAlgorithm_str(PADDING),
- QCryptoHashAlgorithm_str(HASH),
+ key_size, QCryptoRSAPaddingAlgo_str(PADDING),
+ QCryptoHashAlgo_str(HASH),
count, g_test_timer_last(),
(double)count / g_test_timer_last());
g_test_message("benchmark rsa%zu (%s-%s) verification...", key_size,
- QCryptoRSAPaddingAlgorithm_str(PADDING),
- QCryptoHashAlgorithm_str(HASH));
+ QCryptoRSAPaddingAlgo_str(PADDING),
+ QCryptoHashAlgo_str(HASH));
g_test_timer_start();
for (count = 0; count < VERIFY_TIMES; ++count) {
g_assert(qcrypto_akcipher_verify(rsa, signature, key_size / BYTE,
@@ -81,8 +81,8 @@ static void test_rsa_speed(const uint8_t *priv_key, size_t keylen,
g_test_timer_elapsed();
g_test_message("rsa%zu (%s-%s) verify %zu times in %.2f seconds,"
" %.2f times/sec ",
- key_size, QCryptoRSAPaddingAlgorithm_str(PADDING),
- QCryptoHashAlgorithm_str(HASH),
+ key_size, QCryptoRSAPaddingAlgo_str(PADDING),
+ QCryptoHashAlgo_str(HASH),
count, g_test_timer_last(),
(double)count / g_test_timer_last());
}
diff --git a/tests/bench/benchmark-crypto-cipher.c b/tests/bench/benchmark-crypto-cipher.c
index c04f0a0..889a29b 100644
--- a/tests/bench/benchmark-crypto-cipher.c
+++ b/tests/bench/benchmark-crypto-cipher.c
@@ -17,7 +17,7 @@
static void test_cipher_speed(size_t chunk_size,
QCryptoCipherMode mode,
- QCryptoCipherAlgorithm alg)
+ QCryptoCipherAlgo alg)
{
QCryptoCipher *cipher;
Error *err = NULL;
@@ -71,7 +71,7 @@ static void test_cipher_speed(size_t chunk_size,
g_test_timer_elapsed();
g_test_message("enc(%s-%s) chunk %zu bytes %.2f MB/sec ",
- QCryptoCipherAlgorithm_str(alg),
+ QCryptoCipherAlgo_str(alg),
QCryptoCipherMode_str(mode),
chunk_size, (double)total / MiB / g_test_timer_last());
@@ -88,7 +88,7 @@ static void test_cipher_speed(size_t chunk_size,
g_test_timer_elapsed();
g_test_message("dec(%s-%s) chunk %zu bytes %.2f MB/sec ",
- QCryptoCipherAlgorithm_str(alg),
+ QCryptoCipherAlgo_str(alg),
QCryptoCipherMode_str(mode),
chunk_size, (double)total / MiB / g_test_timer_last());
@@ -105,7 +105,7 @@ static void test_cipher_speed_ecb_aes_128(const void *opaque)
size_t chunk_size = (size_t)opaque;
test_cipher_speed(chunk_size,
QCRYPTO_CIPHER_MODE_ECB,
- QCRYPTO_CIPHER_ALG_AES_128);
+ QCRYPTO_CIPHER_ALGO_AES_128);
}
static void test_cipher_speed_ecb_aes_256(const void *opaque)
@@ -113,7 +113,7 @@ static void test_cipher_speed_ecb_aes_256(const void *opaque)
size_t chunk_size = (size_t)opaque;
test_cipher_speed(chunk_size,
QCRYPTO_CIPHER_MODE_ECB,
- QCRYPTO_CIPHER_ALG_AES_256);
+ QCRYPTO_CIPHER_ALGO_AES_256);
}
static void test_cipher_speed_cbc_aes_128(const void *opaque)
@@ -121,7 +121,7 @@ static void test_cipher_speed_cbc_aes_128(const void *opaque)
size_t chunk_size = (size_t)opaque;
test_cipher_speed(chunk_size,
QCRYPTO_CIPHER_MODE_CBC,
- QCRYPTO_CIPHER_ALG_AES_128);
+ QCRYPTO_CIPHER_ALGO_AES_128);
}
static void test_cipher_speed_cbc_aes_256(const void *opaque)
@@ -129,7 +129,7 @@ static void test_cipher_speed_cbc_aes_256(const void *opaque)
size_t chunk_size = (size_t)opaque;
test_cipher_speed(chunk_size,
QCRYPTO_CIPHER_MODE_CBC,
- QCRYPTO_CIPHER_ALG_AES_256);
+ QCRYPTO_CIPHER_ALGO_AES_256);
}
static void test_cipher_speed_ctr_aes_128(const void *opaque)
@@ -137,7 +137,7 @@ static void test_cipher_speed_ctr_aes_128(const void *opaque)
size_t chunk_size = (size_t)opaque;
test_cipher_speed(chunk_size,
QCRYPTO_CIPHER_MODE_CTR,
- QCRYPTO_CIPHER_ALG_AES_128);
+ QCRYPTO_CIPHER_ALGO_AES_128);
}
static void test_cipher_speed_ctr_aes_256(const void *opaque)
@@ -145,7 +145,7 @@ static void test_cipher_speed_ctr_aes_256(const void *opaque)
size_t chunk_size = (size_t)opaque;
test_cipher_speed(chunk_size,
QCRYPTO_CIPHER_MODE_CTR,
- QCRYPTO_CIPHER_ALG_AES_256);
+ QCRYPTO_CIPHER_ALGO_AES_256);
}
static void test_cipher_speed_xts_aes_128(const void *opaque)
@@ -153,7 +153,7 @@ static void test_cipher_speed_xts_aes_128(const void *opaque)
size_t chunk_size = (size_t)opaque;
test_cipher_speed(chunk_size,
QCRYPTO_CIPHER_MODE_XTS,
- QCRYPTO_CIPHER_ALG_AES_128);
+ QCRYPTO_CIPHER_ALGO_AES_128);
}
static void test_cipher_speed_xts_aes_256(const void *opaque)
@@ -161,7 +161,7 @@ static void test_cipher_speed_xts_aes_256(const void *opaque)
size_t chunk_size = (size_t)opaque;
test_cipher_speed(chunk_size,
QCRYPTO_CIPHER_MODE_XTS,
- QCRYPTO_CIPHER_ALG_AES_256);
+ QCRYPTO_CIPHER_ALGO_AES_256);
}
diff --git a/tests/bench/benchmark-crypto-hash.c b/tests/bench/benchmark-crypto-hash.c
index 927b00b..252098a 100644
--- a/tests/bench/benchmark-crypto-hash.c
+++ b/tests/bench/benchmark-crypto-hash.c
@@ -17,7 +17,7 @@
typedef struct QCryptoHashOpts {
size_t chunk_size;
- QCryptoHashAlgorithm alg;
+ QCryptoHashAlgo alg;
} QCryptoHashOpts;
static void test_hash_speed(const void *opaque)
@@ -49,7 +49,7 @@ static void test_hash_speed(const void *opaque)
g_test_timer_elapsed();
g_test_message("hash(%s): chunk %zu bytes %.2f MB/sec",
- QCryptoHashAlgorithm_str(opts->alg),
+ QCryptoHashAlgo_str(opts->alg),
opts->chunk_size, total / g_test_timer_last());
g_free(out);
@@ -65,14 +65,14 @@ int main(int argc, char **argv)
#define TEST_ONE(a, c) \
QCryptoHashOpts opts ## a ## c = { \
- .alg = QCRYPTO_HASH_ALG_ ## a, .chunk_size = c, \
+ .alg = QCRYPTO_HASH_ALGO_ ## a, .chunk_size = c, \
}; \
memset(name, 0 , sizeof(name)); \
snprintf(name, sizeof(name), \
"/crypto/benchmark/hash/%s/bufsize-%d", \
- QCryptoHashAlgorithm_str(QCRYPTO_HASH_ALG_ ## a), \
+ QCryptoHashAlgo_str(QCRYPTO_HASH_ALGO_ ## a), \
c); \
- if (qcrypto_hash_supports(QCRYPTO_HASH_ALG_ ## a)) \
+ if (qcrypto_hash_supports(QCRYPTO_HASH_ALGO_ ## a)) \
g_test_add_data_func(name, \
&opts ## a ## c, \
test_hash_speed);
diff --git a/tests/bench/benchmark-crypto-hmac.c b/tests/bench/benchmark-crypto-hmac.c
index 5cca636..d51de98 100644
--- a/tests/bench/benchmark-crypto-hmac.c
+++ b/tests/bench/benchmark-crypto-hmac.c
@@ -28,7 +28,7 @@ static void test_hmac_speed(const void *opaque)
Error *err = NULL;
int ret;
- if (!qcrypto_hmac_supports(QCRYPTO_HASH_ALG_SHA256)) {
+ if (!qcrypto_hmac_supports(QCRYPTO_HASH_ALGO_SHA256)) {
return;
}
@@ -40,7 +40,7 @@ static void test_hmac_speed(const void *opaque)
g_test_timer_start();
do {
- hmac = qcrypto_hmac_new(QCRYPTO_HASH_ALG_SHA256,
+ hmac = qcrypto_hmac_new(QCRYPTO_HASH_ALGO_SHA256,
(const uint8_t *)KEY, strlen(KEY), &err);
g_assert(err == NULL);
g_assert(hmac != NULL);
@@ -56,7 +56,7 @@ static void test_hmac_speed(const void *opaque)
total /= MiB;
g_test_message("hmac(%s): chunk %zu bytes %.2f MB/sec",
- QCryptoHashAlgorithm_str(QCRYPTO_HASH_ALG_SHA256),
+ QCryptoHashAlgo_str(QCRYPTO_HASH_ALGO_SHA256),
chunk_size, total / g_test_timer_last());
g_free(out);
diff --git a/tests/bench/test_akcipher_keys.inc b/tests/bench/test_akcipher_keys.c.inc
index df3eccb..df3eccb 100644
--- a/tests/bench/test_akcipher_keys.inc
+++ b/tests/bench/test_akcipher_keys.c.inc
diff --git a/tests/data/acpi/aarch64/virt/DSDT b/tests/data/acpi/aarch64/virt/DSDT
index c475039..36d3e5d 100644
--- a/tests/data/acpi/aarch64/virt/DSDT
+++ b/tests/data/acpi/aarch64/virt/DSDT
Binary files differ
diff --git a/tests/data/acpi/aarch64/virt/DSDT.acpihmatvirt b/tests/data/acpi/aarch64/virt/DSDT.acpihmatvirt
index aee6ba0..e6154d0 100644
--- a/tests/data/acpi/aarch64/virt/DSDT.acpihmatvirt
+++ b/tests/data/acpi/aarch64/virt/DSDT.acpihmatvirt
Binary files differ
diff --git a/tests/data/acpi/aarch64/virt/DSDT.memhp b/tests/data/acpi/aarch64/virt/DSDT.memhp
index bae36cd..33f011d 100644
--- a/tests/data/acpi/aarch64/virt/DSDT.memhp
+++ b/tests/data/acpi/aarch64/virt/DSDT.memhp
Binary files differ
diff --git a/tests/data/acpi/aarch64/virt/DSDT.pxb b/tests/data/acpi/aarch64/virt/DSDT.pxb
index fbd78f4..c0fdc6e 100644
--- a/tests/data/acpi/aarch64/virt/DSDT.pxb
+++ b/tests/data/acpi/aarch64/virt/DSDT.pxb
Binary files differ
diff --git a/tests/data/acpi/aarch64/virt/DSDT.topology b/tests/data/acpi/aarch64/virt/DSDT.topology
index 501314c..029d03e 100644
--- a/tests/data/acpi/aarch64/virt/DSDT.topology
+++ b/tests/data/acpi/aarch64/virt/DSDT.topology
Binary files differ
diff --git a/tests/data/acpi/aarch64/virt/SSDT.memhp b/tests/data/acpi/aarch64/virt/SSDT.memhp
index fb3dcde..1deb1d2 100644
--- a/tests/data/acpi/aarch64/virt/SSDT.memhp
+++ b/tests/data/acpi/aarch64/virt/SSDT.memhp
Binary files differ
diff --git a/tests/data/acpi/riscv64/virt/APIC b/tests/data/acpi/riscv64/virt/APIC
new file mode 100644
index 0000000..66a25df
--- /dev/null
+++ b/tests/data/acpi/riscv64/virt/APIC
Binary files differ
diff --git a/tests/data/acpi/riscv64/virt/DSDT b/tests/data/acpi/riscv64/virt/DSDT
new file mode 100644
index 0000000..6a33f56
--- /dev/null
+++ b/tests/data/acpi/riscv64/virt/DSDT
Binary files differ
diff --git a/tests/data/acpi/riscv64/virt/FACP b/tests/data/acpi/riscv64/virt/FACP
new file mode 100644
index 0000000..a5276b6
--- /dev/null
+++ b/tests/data/acpi/riscv64/virt/FACP
Binary files differ
diff --git a/tests/data/acpi/riscv64/virt/MCFG b/tests/data/acpi/riscv64/virt/MCFG
new file mode 100644
index 0000000..37eb923
--- /dev/null
+++ b/tests/data/acpi/riscv64/virt/MCFG
Binary files differ
diff --git a/tests/data/acpi/riscv64/virt/RHCT b/tests/data/acpi/riscv64/virt/RHCT
new file mode 100644
index 0000000..4f23173
--- /dev/null
+++ b/tests/data/acpi/riscv64/virt/RHCT
Binary files differ
diff --git a/tests/data/acpi/riscv64/virt/SPCR b/tests/data/acpi/riscv64/virt/SPCR
new file mode 100644
index 0000000..4da9daf
--- /dev/null
+++ b/tests/data/acpi/riscv64/virt/SPCR
Binary files differ
diff --git a/tests/data/acpi/riscv64/virt/SRAT.numamem b/tests/data/acpi/riscv64/virt/SRAT.numamem
new file mode 100644
index 0000000..2b64673
--- /dev/null
+++ b/tests/data/acpi/riscv64/virt/SRAT.numamem
Binary files differ
diff --git a/tests/data/acpi/x86/microvm/DSDT.pcie b/tests/data/acpi/x86/microvm/DSDT.pcie
index 765f14e..8eacd21 100644
--- a/tests/data/acpi/x86/microvm/DSDT.pcie
+++ b/tests/data/acpi/x86/microvm/DSDT.pcie
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT b/tests/data/acpi/x86/pc/DSDT
index c93ad6b..9222523 100644
--- a/tests/data/acpi/x86/pc/DSDT
+++ b/tests/data/acpi/x86/pc/DSDT
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.acpierst b/tests/data/acpi/x86/pc/DSDT.acpierst
index f643fa2..25b3995 100644
--- a/tests/data/acpi/x86/pc/DSDT.acpierst
+++ b/tests/data/acpi/x86/pc/DSDT.acpierst
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.acpihmat b/tests/data/acpi/x86/pc/DSDT.acpihmat
index 9d3695f..73a9ce5 100644
--- a/tests/data/acpi/x86/pc/DSDT.acpihmat
+++ b/tests/data/acpi/x86/pc/DSDT.acpihmat
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.bridge b/tests/data/acpi/x86/pc/DSDT.bridge
index 840b45f..4cef454 100644
--- a/tests/data/acpi/x86/pc/DSDT.bridge
+++ b/tests/data/acpi/x86/pc/DSDT.bridge
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.cphp b/tests/data/acpi/x86/pc/DSDT.cphp
index dbc0141..1dc9283 100644
--- a/tests/data/acpi/x86/pc/DSDT.cphp
+++ b/tests/data/acpi/x86/pc/DSDT.cphp
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.dimmpxm b/tests/data/acpi/x86/pc/DSDT.dimmpxm
index 1294f65..9f71d2e 100644
--- a/tests/data/acpi/x86/pc/DSDT.dimmpxm
+++ b/tests/data/acpi/x86/pc/DSDT.dimmpxm
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.hpbridge b/tests/data/acpi/x86/pc/DSDT.hpbridge
index 8012b5e..db42059 100644
--- a/tests/data/acpi/x86/pc/DSDT.hpbridge
+++ b/tests/data/acpi/x86/pc/DSDT.hpbridge
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.hpbrroot b/tests/data/acpi/x86/pc/DSDT.hpbrroot
index 4fa0c6f..31b6adb 100644
--- a/tests/data/acpi/x86/pc/DSDT.hpbrroot
+++ b/tests/data/acpi/x86/pc/DSDT.hpbrroot
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.ipmikcs b/tests/data/acpi/x86/pc/DSDT.ipmikcs
index 0a891ba..c2a0330 100644
--- a/tests/data/acpi/x86/pc/DSDT.ipmikcs
+++ b/tests/data/acpi/x86/pc/DSDT.ipmikcs
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.memhp b/tests/data/acpi/x86/pc/DSDT.memhp
index 9b442a6..c15a9fa 100644
--- a/tests/data/acpi/x86/pc/DSDT.memhp
+++ b/tests/data/acpi/x86/pc/DSDT.memhp
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.nohpet b/tests/data/acpi/x86/pc/DSDT.nohpet
index 1754c68..dd29f5c 100644
--- a/tests/data/acpi/x86/pc/DSDT.nohpet
+++ b/tests/data/acpi/x86/pc/DSDT.nohpet
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.numamem b/tests/data/acpi/x86/pc/DSDT.numamem
index 9fc731d..8a6b56f 100644
--- a/tests/data/acpi/x86/pc/DSDT.numamem
+++ b/tests/data/acpi/x86/pc/DSDT.numamem
Binary files differ
diff --git a/tests/data/acpi/x86/pc/DSDT.roothp b/tests/data/acpi/x86/pc/DSDT.roothp
index e654c83..a16b0d9 100644
--- a/tests/data/acpi/x86/pc/DSDT.roothp
+++ b/tests/data/acpi/x86/pc/DSDT.roothp
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.cxl b/tests/data/acpi/x86/q35/DSDT.cxl
index afcdc0d..f561750 100644
--- a/tests/data/acpi/x86/q35/DSDT.cxl
+++ b/tests/data/acpi/x86/q35/DSDT.cxl
Binary files differ
diff --git a/tests/data/acpi/x86/q35/DSDT.viot b/tests/data/acpi/x86/q35/DSDT.viot
index 64e81f5..8d98dd8 100644
--- a/tests/data/acpi/x86/q35/DSDT.viot
+++ b/tests/data/acpi/x86/q35/DSDT.viot
Binary files differ
diff --git a/tests/data/qobject/qdict.txt b/tests/data/qobject/qdict.txt
index e2edc88..888f343 100644
--- a/tests/data/qobject/qdict.txt
+++ b/tests/data/qobject/qdict.txt
@@ -3487,12 +3487,6 @@ cred-internals.h: 559
CREDITS: 603
crime.c: 2833
crime.h: 5271
-cris: 4096
-cris_defs_asm.h: 3805
-crisksyms.c: 472
-cris_supp_reg.h: 198
-crisv10.c: 129158
-crisv10.h: 4289
crm_regs.h: 1700
cr_pll.c: 4842
crt0_ram.S: 2152
diff --git a/tests/docker/Makefile.include b/tests/docker/Makefile.include
index 708e3a7..fead7d3 100644
--- a/tests/docker/Makefile.include
+++ b/tests/docker/Makefile.include
@@ -92,10 +92,10 @@ endif
docker-image-alpine: NOUSER=1
debian-toolchain-run = \
- $(if $(NOCACHE), \
+ $(if $(NOCACHE)$(NOFETCH), \
$(call quiet-command, \
$(DOCKER_SCRIPT) build -t qemu/$1 -f $< \
- $(if $V,,--quiet) --no-cache \
+ $(if $V,,--quiet) $(if $(NOCACHE),--no-cache) \
--registry $(DOCKER_REGISTRY) --extra-files \
$(DOCKER_FILES_DIR)/$1.d/build-toolchain.sh, \
"BUILD", $1), \
@@ -117,7 +117,6 @@ docker-image-debian-microblaze-cross: $(DOCKER_FILES_DIR)/debian-toolchain.docke
# These images may be good enough for building tests but not for test builds
DOCKER_PARTIAL_IMAGES += debian-microblaze-cross
DOCKER_PARTIAL_IMAGES += debian-xtensa-cross
-DOCKER_PARTIAL_IMAGES += fedora-cris-cross
# images that are only used to build other images
DOCKER_VIRTUAL_IMAGES := debian-bootstrap debian-toolchain
@@ -178,6 +177,7 @@ docker:
@echo ' NETWORK=$$BACKEND Enable virtual network interface with $$BACKEND.'
@echo ' NOUSER=1 Define to disable adding current user to containers passwd.'
@echo ' NOCACHE=1 Ignore cache when build images.'
+ @echo ' NOFETCH=1 Do not fetch from the registry.'
@echo ' EXECUTABLE=<path> Include executable in image.'
@echo ' EXTRA_FILES="<path> [... <path>]"'
@echo ' Include extra files in image.'
diff --git a/tests/docker/dockerfiles/alpine.docker b/tests/docker/dockerfiles/alpine.docker
index b079a83..54b9721 100644
--- a/tests/docker/dockerfiles/alpine.docker
+++ b/tests/docker/dockerfiles/alpine.docker
@@ -40,6 +40,7 @@ RUN apk update && \
glib-static \
gnutls-dev \
gtk+3.0-dev \
+ gtk-vnc-dev \
json-c-dev \
libaio-dev \
libbpf-dev \
diff --git a/tests/docker/dockerfiles/debian-all-test-cross.docker b/tests/docker/dockerfiles/debian-all-test-cross.docker
index 6cc38a3..8ab244e 100644
--- a/tests/docker/dockerfiles/debian-all-test-cross.docker
+++ b/tests/docker/dockerfiles/debian-all-test-cross.docker
@@ -62,7 +62,8 @@ RUN DEBIAN_FRONTEND=noninteractive eatmydata \
gcc-s390x-linux-gnu \
libc6-dev-s390x-cross \
gcc-sparc64-linux-gnu \
- libc6-dev-sparc64-cross
+ libc6-dev-sparc64-cross && \
+ dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt
ENV QEMU_CONFIGURE_OPTS --disable-system --disable-docs --disable-tools
diff --git a/tests/docker/dockerfiles/debian-amd64-cross.docker b/tests/docker/dockerfiles/debian-amd64-cross.docker
index 8058695..136c3a7 100644
--- a/tests/docker/dockerfiles/debian-amd64-cross.docker
+++ b/tests/docker/dockerfiles/debian-amd64-cross.docker
@@ -30,6 +30,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
git \
hostname \
libglib2.0-dev \
+ libgtk-vnc-2.0-dev \
libpcre2-dev \
libsndio-dev \
libspice-protocol-dev \
diff --git a/tests/docker/dockerfiles/debian-arm64-cross.docker b/tests/docker/dockerfiles/debian-arm64-cross.docker
index 15457d7..233f6ee 100644
--- a/tests/docker/dockerfiles/debian-arm64-cross.docker
+++ b/tests/docker/dockerfiles/debian-arm64-cross.docker
@@ -30,6 +30,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
git \
hostname \
libglib2.0-dev \
+ libgtk-vnc-2.0-dev \
libpcre2-dev \
libsndio-dev \
libspice-protocol-dev \
diff --git a/tests/docker/dockerfiles/debian-armel-cross.docker b/tests/docker/dockerfiles/debian-armel-cross.docker
deleted file mode 100644
index c26ffc2..0000000
--- a/tests/docker/dockerfiles/debian-armel-cross.docker
+++ /dev/null
@@ -1,178 +0,0 @@
-# THIS FILE WAS AUTO-GENERATED
-#
-# $ lcitool dockerfile --layers all --cross-arch armv6l debian-11 qemu
-#
-# https://gitlab.com/libvirt/libvirt-ci
-
-FROM docker.io/library/debian:11-slim
-
-RUN export DEBIAN_FRONTEND=noninteractive && \
- apt-get update && \
- apt-get install -y eatmydata && \
- eatmydata apt-get dist-upgrade -y && \
- eatmydata apt-get install --no-install-recommends -y \
- bash \
- bc \
- bison \
- bsdextrautils \
- bzip2 \
- ca-certificates \
- ccache \
- dbus \
- debianutils \
- diffutils \
- exuberant-ctags \
- findutils \
- flex \
- gcc \
- gcovr \
- gettext \
- git \
- hostname \
- libglib2.0-dev \
- libpcre2-dev \
- libsndio-dev \
- libspice-protocol-dev \
- llvm \
- locales \
- make \
- meson \
- mtools \
- ncat \
- ninja-build \
- openssh-client \
- pkgconf \
- python3 \
- python3-numpy \
- python3-opencv \
- python3-pillow \
- python3-pip \
- python3-setuptools \
- python3-sphinx \
- python3-sphinx-rtd-theme \
- python3-venv \
- python3-wheel \
- python3-yaml \
- rpm2cpio \
- sed \
- socat \
- sparse \
- tar \
- tesseract-ocr \
- tesseract-ocr-eng \
- xorriso \
- zstd && \
- eatmydata apt-get autoremove -y && \
- eatmydata apt-get autoclean -y && \
- sed -Ei 's,^# (en_US\.UTF-8 .*)$,\1,' /etc/locale.gen && \
- dpkg-reconfigure locales && \
- rm -f /usr/lib*/python3*/EXTERNALLY-MANAGED
-
-RUN /usr/bin/pip3 install tomli
-
-ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers"
-ENV LANG "en_US.UTF-8"
-ENV MAKE "/usr/bin/make"
-ENV NINJA "/usr/bin/ninja"
-ENV PYTHON "/usr/bin/python3"
-
-RUN export DEBIAN_FRONTEND=noninteractive && \
- dpkg --add-architecture armel && \
- eatmydata apt-get update && \
- eatmydata apt-get dist-upgrade -y && \
- eatmydata apt-get install --no-install-recommends -y dpkg-dev && \
- eatmydata apt-get install --no-install-recommends -y \
- gcc-arm-linux-gnueabi \
- libaio-dev:armel \
- libasan6:armel \
- libasound2-dev:armel \
- libattr1-dev:armel \
- libbpf-dev:armel \
- libbrlapi-dev:armel \
- libbz2-dev:armel \
- libc6-dev:armel \
- libcacard-dev:armel \
- libcap-ng-dev:armel \
- libcapstone-dev:armel \
- libcmocka-dev:armel \
- libcurl4-gnutls-dev:armel \
- libdaxctl-dev:armel \
- libdrm-dev:armel \
- libepoxy-dev:armel \
- libfdt-dev:armel \
- libffi-dev:armel \
- libfuse3-dev:armel \
- libgbm-dev:armel \
- libgcrypt20-dev:armel \
- libglib2.0-dev:armel \
- libglusterfs-dev:armel \
- libgnutls28-dev:armel \
- libgtk-3-dev:armel \
- libibverbs-dev:armel \
- libiscsi-dev:armel \
- libjemalloc-dev:armel \
- libjpeg62-turbo-dev:armel \
- libjson-c-dev:armel \
- liblttng-ust-dev:armel \
- liblzo2-dev:armel \
- libncursesw5-dev:armel \
- libnfs-dev:armel \
- libnuma-dev:armel \
- libpam0g-dev:armel \
- libpipewire-0.3-dev:armel \
- libpixman-1-dev:armel \
- libpng-dev:armel \
- libpulse-dev:armel \
- librbd-dev:armel \
- librdmacm-dev:armel \
- libsasl2-dev:armel \
- libsdl2-dev:armel \
- libsdl2-image-dev:armel \
- libseccomp-dev:armel \
- libselinux1-dev:armel \
- libslirp-dev:armel \
- libsnappy-dev:armel \
- libspice-server-dev:armel \
- libssh-gcrypt-dev:armel \
- libsystemd-dev:armel \
- libtasn1-6-dev:armel \
- libubsan1:armel \
- libudev-dev:armel \
- liburing-dev:armel \
- libusb-1.0-0-dev:armel \
- libusbredirhost-dev:armel \
- libvdeplug-dev:armel \
- libvirglrenderer-dev:armel \
- libvte-2.91-dev:armel \
- libzstd-dev:armel \
- nettle-dev:armel \
- systemtap-sdt-dev:armel \
- zlib1g-dev:armel && \
- eatmydata apt-get autoremove -y && \
- eatmydata apt-get autoclean -y && \
- mkdir -p /usr/local/share/meson/cross && \
- printf "[binaries]\n\
-c = '/usr/bin/arm-linux-gnueabi-gcc'\n\
-ar = '/usr/bin/arm-linux-gnueabi-gcc-ar'\n\
-strip = '/usr/bin/arm-linux-gnueabi-strip'\n\
-pkgconfig = '/usr/bin/arm-linux-gnueabi-pkg-config'\n\
-\n\
-[host_machine]\n\
-system = 'linux'\n\
-cpu_family = 'arm'\n\
-cpu = 'arm'\n\
-endian = 'little'\n" > /usr/local/share/meson/cross/arm-linux-gnueabi && \
- dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt && \
- mkdir -p /usr/libexec/ccache-wrappers && \
- ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabi-cc && \
- ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/arm-linux-gnueabi-gcc
-
-ENV ABI "arm-linux-gnueabi"
-ENV MESON_OPTS "--cross-file=arm-linux-gnueabi"
-ENV QEMU_CONFIGURE_OPTS --cross-prefix=arm-linux-gnueabi-
-ENV DEF_TARGET_LIST arm-softmmu,arm-linux-user,armeb-linux-user
-# As a final step configure the user (if env is defined)
-ARG USER
-ARG UID
-RUN if [ "${USER}" ]; then \
- id ${USER} 2>/dev/null || useradd -u ${UID} -U ${USER}; fi
diff --git a/tests/docker/dockerfiles/debian-armhf-cross.docker b/tests/docker/dockerfiles/debian-armhf-cross.docker
index 8f87656..f26385e 100644
--- a/tests/docker/dockerfiles/debian-armhf-cross.docker
+++ b/tests/docker/dockerfiles/debian-armhf-cross.docker
@@ -30,6 +30,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
git \
hostname \
libglib2.0-dev \
+ libgtk-vnc-2.0-dev \
libpcre2-dev \
libsndio-dev \
libspice-protocol-dev \
diff --git a/tests/docker/dockerfiles/debian-hexagon-cross.docker b/tests/docker/dockerfiles/debian-hexagon-cross.docker
index f2d40f2..23152b4 100644
--- a/tests/docker/dockerfiles/debian-hexagon-cross.docker
+++ b/tests/docker/dockerfiles/debian-hexagon-cross.docker
@@ -33,7 +33,8 @@ RUN apt-get update && \
ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/c++ && \
ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \
ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/g++ && \
- ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc
+ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc && \
+ dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt
RUN /usr/bin/pip3 install tomli
diff --git a/tests/docker/dockerfiles/debian-i686-cross.docker b/tests/docker/dockerfiles/debian-i686-cross.docker
index f4ef054..2328ee1 100644
--- a/tests/docker/dockerfiles/debian-i686-cross.docker
+++ b/tests/docker/dockerfiles/debian-i686-cross.docker
@@ -1,10 +1,10 @@
# THIS FILE WAS AUTO-GENERATED
#
-# $ lcitool dockerfile --layers all --cross-arch i686 debian-11 qemu
+# $ lcitool dockerfile --layers all --cross-arch i686 debian-12 qemu
#
# https://gitlab.com/libvirt/libvirt-ci
-FROM docker.io/library/debian:11-slim
+FROM docker.io/library/debian:12-slim
RUN export DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
@@ -30,6 +30,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
git \
hostname \
libglib2.0-dev \
+ libgtk-vnc-2.0-dev \
libpcre2-dev \
libsndio-dev \
libspice-protocol-dev \
@@ -47,16 +48,15 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
python3-opencv \
python3-pillow \
python3-pip \
- python3-setuptools \
python3-sphinx \
python3-sphinx-rtd-theme \
python3-venv \
- python3-wheel \
python3-yaml \
rpm2cpio \
sed \
socat \
sparse \
+ swtpm \
tar \
tesseract-ocr \
tesseract-ocr-eng \
@@ -68,8 +68,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
dpkg-reconfigure locales && \
rm -f /usr/lib*/python3*/EXTERNALLY-MANAGED
-RUN /usr/bin/pip3 install tomli
-
ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers"
ENV LANG "en_US.UTF-8"
ENV MAKE "/usr/bin/make"
@@ -144,6 +142,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libvdeplug-dev:i386 \
libvirglrenderer-dev:i386 \
libvte-2.91-dev:i386 \
+ libxdp-dev:i386 \
libzstd-dev:i386 \
nettle-dev:i386 \
systemtap-sdt-dev:i386 \
diff --git a/tests/docker/dockerfiles/debian-legacy-test-cross.docker b/tests/docker/dockerfiles/debian-legacy-test-cross.docker
index d75e0b8..5a6616b 100644
--- a/tests/docker/dockerfiles/debian-legacy-test-cross.docker
+++ b/tests/docker/dockerfiles/debian-legacy-test-cross.docker
@@ -36,7 +36,8 @@ RUN DEBIAN_FRONTEND=noninteractive eatmydata \
python3-pip \
python3-setuptools \
python3-venv \
- python3-wheel
+ python3-wheel && \
+ dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt
RUN /usr/bin/pip3 install tomli
diff --git a/tests/docker/dockerfiles/debian-loongarch-cross.docker b/tests/docker/dockerfiles/debian-loongarch-cross.docker
index 6a91975..538ab53 100644
--- a/tests/docker/dockerfiles/debian-loongarch-cross.docker
+++ b/tests/docker/dockerfiles/debian-loongarch-cross.docker
@@ -32,7 +32,8 @@ RUN apt-get update && \
python3-pip \
python3-setuptools \
python3-venv \
- python3-wheel
+ python3-wheel && \
+ dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt
RUN /usr/bin/pip3 install tomli
@@ -42,8 +43,8 @@ RUN curl -#SL https://github.com/loongson/build-tools/releases/download/2023.08.
ENV PATH $PATH:/opt/cross-tools/bin
ENV LD_LIBRARY_PATH /opt/cross-tools/lib:/opt/cross-tools/loongarch64-unknown-linux-gnu/lib:$LD_LIBRARY_PATH
-ENV QEMU_CONFIGURE_OPTS --disable-system --disable-docs --disable-tools
-ENV DEF_TARGET_LIST loongarch64-linux-user,loongarch-softmmu
+ENV QEMU_CONFIGURE_OPTS --disable-docs --disable-tools
+ENV DEF_TARGET_LIST loongarch64-linux-user,loongarch64-softmmu
ENV MAKE /usr/bin/make
# As a final step configure the user (if env is defined)
diff --git a/tests/docker/dockerfiles/debian-microblaze-cross.d/build-toolchain.sh b/tests/docker/dockerfiles/debian-microblaze-cross.d/build-toolchain.sh
index 23ec0aa..c5cd0aa 100755
--- a/tests/docker/dockerfiles/debian-microblaze-cross.d/build-toolchain.sh
+++ b/tests/docker/dockerfiles/debian-microblaze-cross.d/build-toolchain.sh
@@ -10,6 +10,8 @@ TOOLCHAIN_INSTALL=/usr/local
TOOLCHAIN_BIN=${TOOLCHAIN_INSTALL}/bin
CROSS_SYSROOT=${TOOLCHAIN_INSTALL}/$TARGET/sys-root
+GCC_PATCH0_URL=https://raw.githubusercontent.com/Xilinx/meta-xilinx/refs/tags/xlnx-rel-v2024.1/meta-microblaze/recipes-devtools/gcc/gcc-12/0009-Patch-microblaze-Fix-atomic-boolean-return-value.patch
+
export PATH=${TOOLCHAIN_BIN}:$PATH
#
@@ -31,6 +33,12 @@ mv gcc-11.2.0 src-gcc
mv musl-1.2.2 src-musl
mv linux-5.10.70 src-linux
+#
+# Patch gcc
+#
+
+wget -O - ${GCC_PATCH0_URL} | patch -d src-gcc -p1
+
mkdir -p bld-hdr bld-binu bld-gcc bld-musl
mkdir -p ${CROSS_SYSROOT}/usr/include
diff --git a/tests/docker/dockerfiles/debian-mips64el-cross.docker b/tests/docker/dockerfiles/debian-mips64el-cross.docker
index 59c4c68..bfa96cb 100644
--- a/tests/docker/dockerfiles/debian-mips64el-cross.docker
+++ b/tests/docker/dockerfiles/debian-mips64el-cross.docker
@@ -1,10 +1,10 @@
# THIS FILE WAS AUTO-GENERATED
#
-# $ lcitool dockerfile --layers all --cross-arch mips64el debian-11 qemu
+# $ lcitool dockerfile --layers all --cross-arch mips64el debian-12 qemu
#
# https://gitlab.com/libvirt/libvirt-ci
-FROM docker.io/library/debian:11-slim
+FROM docker.io/library/debian:12-slim
RUN export DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
@@ -30,6 +30,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
git \
hostname \
libglib2.0-dev \
+ libgtk-vnc-2.0-dev \
libpcre2-dev \
libsndio-dev \
libspice-protocol-dev \
@@ -47,16 +48,15 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
python3-opencv \
python3-pillow \
python3-pip \
- python3-setuptools \
python3-sphinx \
python3-sphinx-rtd-theme \
python3-venv \
- python3-wheel \
python3-yaml \
rpm2cpio \
sed \
socat \
sparse \
+ swtpm \
tar \
tesseract-ocr \
tesseract-ocr-eng \
@@ -68,8 +68,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
dpkg-reconfigure locales && \
rm -f /usr/lib*/python3*/EXTERNALLY-MANAGED
-RUN /usr/bin/pip3 install tomli
-
ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers"
ENV LANG "en_US.UTF-8"
ENV MAKE "/usr/bin/make"
@@ -96,17 +94,13 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libcmocka-dev:mips64el \
libcurl4-gnutls-dev:mips64el \
libdaxctl-dev:mips64el \
- libdrm-dev:mips64el \
- libepoxy-dev:mips64el \
libfdt-dev:mips64el \
libffi-dev:mips64el \
libfuse3-dev:mips64el \
- libgbm-dev:mips64el \
libgcrypt20-dev:mips64el \
libglib2.0-dev:mips64el \
libglusterfs-dev:mips64el \
libgnutls28-dev:mips64el \
- libgtk-3-dev:mips64el \
libibverbs-dev:mips64el \
libiscsi-dev:mips64el \
libjemalloc-dev:mips64el \
@@ -125,8 +119,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
librbd-dev:mips64el \
librdmacm-dev:mips64el \
libsasl2-dev:mips64el \
- libsdl2-dev:mips64el \
- libsdl2-image-dev:mips64el \
libseccomp-dev:mips64el \
libselinux1-dev:mips64el \
libslirp-dev:mips64el \
@@ -140,8 +132,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libusb-1.0-0-dev:mips64el \
libusbredirhost-dev:mips64el \
libvdeplug-dev:mips64el \
- libvirglrenderer-dev:mips64el \
- libvte-2.91-dev:mips64el \
+ libxdp-dev:mips64el \
libzstd-dev:mips64el \
nettle-dev:mips64el \
systemtap-sdt-dev:mips64el \
diff --git a/tests/docker/dockerfiles/debian-mipsel-cross.docker b/tests/docker/dockerfiles/debian-mipsel-cross.docker
index 880c774..4ac314e 100644
--- a/tests/docker/dockerfiles/debian-mipsel-cross.docker
+++ b/tests/docker/dockerfiles/debian-mipsel-cross.docker
@@ -1,10 +1,10 @@
# THIS FILE WAS AUTO-GENERATED
#
-# $ lcitool dockerfile --layers all --cross-arch mipsel debian-11 qemu
+# $ lcitool dockerfile --layers all --cross-arch mipsel debian-12 qemu
#
# https://gitlab.com/libvirt/libvirt-ci
-FROM docker.io/library/debian:11-slim
+FROM docker.io/library/debian:12-slim
RUN export DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
@@ -30,6 +30,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
git \
hostname \
libglib2.0-dev \
+ libgtk-vnc-2.0-dev \
libpcre2-dev \
libsndio-dev \
libspice-protocol-dev \
@@ -47,16 +48,15 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
python3-opencv \
python3-pillow \
python3-pip \
- python3-setuptools \
python3-sphinx \
python3-sphinx-rtd-theme \
python3-venv \
- python3-wheel \
python3-yaml \
rpm2cpio \
sed \
socat \
sparse \
+ swtpm \
tar \
tesseract-ocr \
tesseract-ocr-eng \
@@ -68,8 +68,6 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
dpkg-reconfigure locales && \
rm -f /usr/lib*/python3*/EXTERNALLY-MANAGED
-RUN /usr/bin/pip3 install tomli
-
ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers"
ENV LANG "en_US.UTF-8"
ENV MAKE "/usr/bin/make"
@@ -142,6 +140,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libvdeplug-dev:mipsel \
libvirglrenderer-dev:mipsel \
libvte-2.91-dev:mipsel \
+ libxdp-dev:mipsel \
libzstd-dev:mipsel \
nettle-dev:mipsel \
systemtap-sdt-dev:mipsel \
diff --git a/tests/docker/dockerfiles/debian-ppc64el-cross.docker b/tests/docker/dockerfiles/debian-ppc64el-cross.docker
index 1d55b95..8c1dcec 100644
--- a/tests/docker/dockerfiles/debian-ppc64el-cross.docker
+++ b/tests/docker/dockerfiles/debian-ppc64el-cross.docker
@@ -30,6 +30,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
git \
hostname \
libglib2.0-dev \
+ libgtk-vnc-2.0-dev \
libpcre2-dev \
libsndio-dev \
libspice-protocol-dev \
diff --git a/tests/docker/dockerfiles/debian-s390x-cross.docker b/tests/docker/dockerfiles/debian-s390x-cross.docker
index 62ccda6..72668e0 100644
--- a/tests/docker/dockerfiles/debian-s390x-cross.docker
+++ b/tests/docker/dockerfiles/debian-s390x-cross.docker
@@ -30,6 +30,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
git \
hostname \
libglib2.0-dev \
+ libgtk-vnc-2.0-dev \
libpcre2-dev \
libsndio-dev \
libspice-protocol-dev \
diff --git a/tests/docker/dockerfiles/debian-toolchain.docker b/tests/docker/dockerfiles/debian-toolchain.docker
index 687a97f..ab4ce29 100644
--- a/tests/docker/dockerfiles/debian-toolchain.docker
+++ b/tests/docker/dockerfiles/debian-toolchain.docker
@@ -10,6 +10,8 @@ FROM docker.io/library/debian:11-slim
# ??? The build-dep isn't working, missing a number of
# minimal build dependiencies, e.g. libmpc.
+RUN sed 's/^deb /deb-src /' </etc/apt/sources.list >/etc/apt/sources.list.d/deb-src.list
+
RUN apt update && \
DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \
DEBIAN_FRONTEND=noninteractive eatmydata \
@@ -33,6 +35,11 @@ RUN cd /root && ./build-toolchain.sh
# and the build trees by restoring the original image,
# then copying the built toolchain from stage 0.
FROM docker.io/library/debian:11-slim
+RUN apt update && \
+ DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \
+ DEBIAN_FRONTEND=noninteractive eatmydata \
+ apt install -y --no-install-recommends \
+ libmpc3
COPY --from=0 /usr/local /usr/local
# As a final step configure the user (if env is defined)
ARG USER
diff --git a/tests/docker/dockerfiles/debian-tricore-cross.docker b/tests/docker/dockerfiles/debian-tricore-cross.docker
index 16276aa..479b4d6 100644
--- a/tests/docker/dockerfiles/debian-tricore-cross.docker
+++ b/tests/docker/dockerfiles/debian-tricore-cross.docker
@@ -34,7 +34,8 @@ RUN apt update && \
python3-pip \
python3-setuptools \
python3-wheel \
- python3-venv
+ python3-venv && \
+ dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt
RUN /usr/bin/pip3 install tomli
diff --git a/tests/docker/dockerfiles/debian-xtensa-cross.docker b/tests/docker/dockerfiles/debian-xtensa-cross.docker
index 4138818..d011eee 100644
--- a/tests/docker/dockerfiles/debian-xtensa-cross.docker
+++ b/tests/docker/dockerfiles/debian-xtensa-cross.docker
@@ -16,7 +16,8 @@ RUN apt-get update && \
curl \
gettext \
git \
- python3-minimal
+ python3-minimal && \
+ dpkg-query --showformat '${Package}_${Version}_${Architecture}\n' --show > /packages.txt
ENV CPU_LIST dc232b dc233c de233_fpu dsp3400
ENV TOOLCHAIN_RELEASE 2020.07
diff --git a/tests/docker/dockerfiles/debian.docker b/tests/docker/dockerfiles/debian.docker
index 0d1d401..42bd006 100644
--- a/tests/docker/dockerfiles/debian.docker
+++ b/tests/docker/dockerfiles/debian.docker
@@ -55,6 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libglusterfs-dev \
libgnutls28-dev \
libgtk-3-dev \
+ libgtk-vnc-2.0-dev \
libibverbs-dev \
libiscsi-dev \
libjemalloc-dev \
diff --git a/tests/docker/dockerfiles/fedora-cris-cross.docker b/tests/docker/dockerfiles/fedora-cris-cross.docker
deleted file mode 100644
index 97c9d37..0000000
--- a/tests/docker/dockerfiles/fedora-cris-cross.docker
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Cross compiler for cris system tests
-#
-
-FROM registry.fedoraproject.org/fedora:33
-ENV PACKAGES gcc-cris-linux-gnu
-ENV MAKE /usr/bin/make
-RUN dnf install -y $PACKAGES
-RUN rpm -q $PACKAGES | sort > /packages.txt
-# As a final step configure the user (if env is defined)
-ARG USER
-ARG UID
-RUN if [ "${USER}" ]; then \
- id ${USER} 2>/dev/null || useradd -u ${UID} -U ${USER}; fi
diff --git a/tests/docker/dockerfiles/fedora-rust-nightly.docker b/tests/docker/dockerfiles/fedora-rust-nightly.docker
new file mode 100644
index 0000000..e642db1
--- /dev/null
+++ b/tests/docker/dockerfiles/fedora-rust-nightly.docker
@@ -0,0 +1,173 @@
+# THIS FILE WAS AUTO-GENERATED
+#
+# $ lcitool dockerfile --layers all fedora-40 qemu
+#
+# https://gitlab.com/libvirt/libvirt-ci
+
+FROM registry.fedoraproject.org/fedora:40
+
+RUN dnf install -y nosync && \
+ printf '#!/bin/sh\n\
+if test -d /usr/lib64\n\
+then\n\
+ export LD_PRELOAD=/usr/lib64/nosync/nosync.so\n\
+else\n\
+ export LD_PRELOAD=/usr/lib/nosync/nosync.so\n\
+fi\n\
+exec "$@"\n' > /usr/bin/nosync && \
+ chmod +x /usr/bin/nosync && \
+ nosync dnf update -y && \
+ nosync dnf install -y \
+ SDL2-devel \
+ SDL2_image-devel \
+ alsa-lib-devel \
+ bash \
+ bc \
+ bison \
+ brlapi-devel \
+ bzip2 \
+ bzip2-devel \
+ ca-certificates \
+ capstone-devel \
+ ccache \
+ clang \
+ ctags \
+ cyrus-sasl-devel \
+ daxctl-devel \
+ dbus-daemon \
+ device-mapper-multipath-devel \
+ diffutils \
+ findutils \
+ flex \
+ fuse3-devel \
+ gcc \
+ gcovr \
+ gettext \
+ git \
+ glib2-devel \
+ glib2-static \
+ glibc-langpack-en \
+ glibc-static \
+ glusterfs-api-devel \
+ gnutls-devel \
+ gtk-vnc2-devel \
+ gtk3-devel \
+ hostname \
+ jemalloc-devel \
+ json-c-devel \
+ libaio-devel \
+ libasan \
+ libattr-devel \
+ libbpf-devel \
+ libcacard-devel \
+ libcap-ng-devel \
+ libcmocka-devel \
+ libcurl-devel \
+ libdrm-devel \
+ libepoxy-devel \
+ libfdt-devel \
+ libffi-devel \
+ libgcrypt-devel \
+ libiscsi-devel \
+ libjpeg-devel \
+ libnfs-devel \
+ libpmem-devel \
+ libpng-devel \
+ librbd-devel \
+ libseccomp-devel \
+ libselinux-devel \
+ libslirp-devel \
+ libssh-devel \
+ libtasn1-devel \
+ libubsan \
+ liburing-devel \
+ libusbx-devel \
+ libxdp-devel \
+ libzstd-devel \
+ llvm \
+ lttng-ust-devel \
+ lzo-devel \
+ make \
+ mesa-libgbm-devel \
+ meson \
+ mtools \
+ ncurses-devel \
+ nettle-devel \
+ ninja-build \
+ nmap-ncat \
+ numactl-devel \
+ openssh-clients \
+ pam-devel \
+ pcre-static \
+ pipewire-devel \
+ pixman-devel \
+ pkgconfig \
+ pulseaudio-libs-devel \
+ python3 \
+ python3-PyYAML \
+ python3-numpy \
+ python3-opencv \
+ python3-pillow \
+ python3-pip \
+ python3-sphinx \
+ python3-sphinx_rtd_theme \
+ python3-zombie-imp \
+ rdma-core-devel \
+ sed \
+ snappy-devel \
+ socat \
+ sparse \
+ spice-protocol \
+ spice-server-devel \
+ swtpm \
+ systemd-devel \
+ systemtap-sdt-devel \
+ tar \
+ tesseract \
+ tesseract-langpack-eng \
+ usbredir-devel \
+ util-linux \
+ virglrenderer-devel \
+ vte291-devel \
+ which \
+ xen-devel \
+ xorriso \
+ zlib-devel \
+ zlib-static \
+ zstd && \
+ nosync dnf autoremove -y && \
+ nosync dnf clean all -y && \
+ rm -f /usr/lib*/python3*/EXTERNALLY-MANAGED && \
+ rpm -qa | sort > /packages.txt && \
+ mkdir -p /usr/libexec/ccache-wrappers && \
+ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \
+ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/clang && \
+ ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc
+
+ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers"
+ENV LANG "en_US.UTF-8"
+ENV MAKE "/usr/bin/make"
+ENV NINJA "/usr/bin/ninja"
+ENV PYTHON "/usr/bin/python3"
+RUN dnf install -y wget
+ENV RUSTUP_HOME=/usr/local/rustup CARGO_HOME=/usr/local/cargo
+ENV RUSTC=/usr/local/rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/rustc
+RUN set -eux && \
+ rustArch='x86_64-unknown-linux-gnu' && \
+ rustupSha256='6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d' && \
+ url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" && \
+ wget "$url" && \
+ echo "${rustupSha256} *rustup-init" | sha256sum -c - && \
+ chmod +x rustup-init && \
+ ./rustup-init -y --no-modify-path --profile default --default-toolchain nightly --default-host ${rustArch} && \
+ chmod -R a+w $RUSTUP_HOME $CARGO_HOME && \
+ /usr/local/cargo/bin/rustup --version && \
+ /usr/local/cargo/bin/rustup run nightly rustc --version && \
+ test "$RUSTC" = "$(/usr/local/cargo/bin/rustup +nightly which rustc)"
+ENV PATH=$CARGO_HOME/bin:$PATH
+RUN /usr/local/cargo/bin/rustup run nightly cargo install bindgen-cli
+# As a final step configure the user (if env is defined)
+ARG USER
+ARG UID
+RUN if [ "${USER}" ]; then \
+ id ${USER} 2>/dev/null || useradd -u ${UID} -U ${USER}; fi
diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker
index 007e157..6b264d9 100644
--- a/tests/docker/dockerfiles/fedora-win64-cross.docker
+++ b/tests/docker/dockerfiles/fedora-win64-cross.docker
@@ -34,6 +34,7 @@ exec "$@"\n' > /usr/bin/nosync && \
git \
glib2-devel \
glibc-langpack-en \
+ gtk-vnc2-devel \
hostname \
llvm \
make \
diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker
index 44f239c..ecdefaf 100644
--- a/tests/docker/dockerfiles/fedora.docker
+++ b/tests/docker/dockerfiles/fedora.docker
@@ -50,6 +50,7 @@ exec "$@"\n' > /usr/bin/nosync && \
glibc-static \
glusterfs-api-devel \
gnutls-devel \
+ gtk-vnc2-devel \
gtk3-devel \
hostname \
jemalloc-devel \
diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker
index 836f531..e359a4e 100644
--- a/tests/docker/dockerfiles/opensuse-leap.docker
+++ b/tests/docker/dockerfiles/opensuse-leap.docker
@@ -4,9 +4,10 @@
#
# https://gitlab.com/libvirt/libvirt-ci
-FROM registry.opensuse.org/opensuse/leap:15.5
+FROM registry.opensuse.org/opensuse/leap:15.6
RUN zypper update -y && \
+ zypper addrepo -fc https://download.opensuse.org/update/leap/15.6/backports/openSUSE:Backports:SLE-15-SP6:Update.repo && \
zypper install -y \
Mesa-devel \
alsa-lib-devel \
@@ -33,6 +34,7 @@ RUN zypper update -y && \
glibc-locale \
glibc-static \
glusterfs-devel \
+ gtk-vnc-devel \
gtk3-devel \
hostname \
jemalloc-devel \
@@ -126,7 +128,7 @@ RUN zypper update -y && \
RUN /usr/bin/pip3.11 install \
PyYAML \
- meson==0.63.2 \
+ meson==1.5.0 \
pillow \
sphinx \
sphinx-rtd-theme
diff --git a/tests/docker/dockerfiles/ubuntu2204.docker b/tests/docker/dockerfiles/ubuntu2204.docker
index beeb44f..3a7de6a 100644
--- a/tests/docker/dockerfiles/ubuntu2204.docker
+++ b/tests/docker/dockerfiles/ubuntu2204.docker
@@ -55,6 +55,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
libglusterfs-dev \
libgnutls28-dev \
libgtk-3-dev \
+ libgtk-vnc-2.0-dev \
libibverbs-dev \
libiscsi-dev \
libjemalloc-dev \
diff --git a/tests/docker/test-debug b/tests/docker/test-debug
index f52f163..678cecc 100755
--- a/tests/docker/test-debug
+++ b/tests/docker/test-debug
@@ -1,6 +1,6 @@
#!/bin/bash -e
#
-# Compile and check with clang & --enable-debug --enable-sanitizers.
+# Compile and check with clang & debug & sanitizers
#
# Copyright (c) 2016-2018 Red Hat Inc.
#
@@ -19,7 +19,7 @@ requires_binary clang
cd "$BUILD_DIR"
OPTS="--cxx=clang++ --cc=clang --host-cc=clang"
-OPTS="--enable-debug --enable-sanitizers $OPTS"
+OPTS="--enable-debug --enable-asan --enable-ubsan $OPTS"
export ASAN_OPTIONS=detect_leaks=0
build_qemu $OPTS
diff --git a/tests/fp/meson.build b/tests/fp/meson.build
index 114b4b4..9059a24 100644
--- a/tests/fp/meson.build
+++ b/tests/fp/meson.build
@@ -7,6 +7,16 @@ if host_os == 'windows'
subdir_done()
endif
+# By default tests run with the usual 30s timeout; particularly
+# slow tests can have that overridden here. The keys here are
+# the testnames without their fp-test- prefix.
+slow_fp_tests = {
+ 'rem': 60,
+ 'div': 60,
+ 'mul': 60,
+ 'mulAdd': 180,
+}
+
sfcflags = [
# softfloat defines
'-DSOFTFLOAT_ROUND_ODD',
@@ -109,6 +119,7 @@ fptest_rounding_args = ['-r', 'all']
foreach k, v : softfloat_conv_tests
test('fp-test-' + k, fptest,
args: fptest_args + fptest_rounding_args + v.split(),
+ timeout: slow_fp_tests.get(k, 30),
suite: ['softfloat', 'softfloat-conv'])
endforeach
@@ -116,6 +127,7 @@ foreach k, v : softfloat_tests
test('fp-test-' + k, fptest,
args: fptest_args + fptest_rounding_args +
['f16_' + k, 'f32_' + k, 'f64_' + k, 'f128_' + k, 'extF80_' + k],
+ timeout: slow_fp_tests.get(k, 30),
suite: ['softfloat', 'softfloat-' + v])
endforeach
@@ -124,7 +136,8 @@ test('fp-test-mulAdd', fptest,
# no fptest_rounding_args
args: fptest_args +
['f16_mulAdd', 'f32_mulAdd', 'f64_mulAdd', 'f128_mulAdd'],
- suite: ['softfloat-slow', 'softfloat-ops-slow', 'slow'], timeout: 180)
+ timeout: slow_fp_tests.get('mulAdd', 30),
+ suite: ['softfloat-slow', 'softfloat-ops-slow', 'slow'])
executable(
'fp-bench',
@@ -140,4 +153,5 @@ fptestlog2 = executable(
c_args: fpcflags,
)
test('fp-test-log2', fptestlog2,
+ timeout: slow_fp_tests.get('log2', 30),
suite: ['softfloat', 'softfloat-ops'])
diff --git a/tests/avocado/acpi-bits/bits-config/bits-cfg.txt b/tests/functional/acpi-bits/bits-config/bits-cfg.txt
index 8010804..8010804 100644
--- a/tests/avocado/acpi-bits/bits-config/bits-cfg.txt
+++ b/tests/functional/acpi-bits/bits-config/bits-cfg.txt
diff --git a/tests/avocado/acpi-bits/bits-tests/smbios.py2 b/tests/functional/acpi-bits/bits-tests/smbios.py2
index 5868a71..5868a71 100644
--- a/tests/avocado/acpi-bits/bits-tests/smbios.py2
+++ b/tests/functional/acpi-bits/bits-tests/smbios.py2
diff --git a/tests/avocado/acpi-bits/bits-tests/smilatency.py2 b/tests/functional/acpi-bits/bits-tests/smilatency.py2
index 405af67..405af67 100644
--- a/tests/avocado/acpi-bits/bits-tests/smilatency.py2
+++ b/tests/functional/acpi-bits/bits-tests/smilatency.py2
diff --git a/tests/avocado/acpi-bits/bits-tests/testacpi.py2 b/tests/functional/acpi-bits/bits-tests/testacpi.py2
index 7bf9075..7bf9075 100644
--- a/tests/avocado/acpi-bits/bits-tests/testacpi.py2
+++ b/tests/functional/acpi-bits/bits-tests/testacpi.py2
diff --git a/tests/avocado/acpi-bits/bits-tests/testcpuid.py2 b/tests/functional/acpi-bits/bits-tests/testcpuid.py2
index 7adefbe..7adefbe 100644
--- a/tests/avocado/acpi-bits/bits-tests/testcpuid.py2
+++ b/tests/functional/acpi-bits/bits-tests/testcpuid.py2
diff --git a/tests/functional/meson.build b/tests/functional/meson.build
new file mode 100644
index 0000000..97c1c59
--- /dev/null
+++ b/tests/functional/meson.build
@@ -0,0 +1,272 @@
+# QEMU functional tests:
+# Tests that are put in the 'quick' category are run by default during
+# 'make check'. Everything that should not be run during 'make check'
+# (e.g. tests that fetch assets from the internet) should be put into
+# the 'thorough' category instead.
+
+# Most tests run too slow with TCI enabled, so skip the functional tests there
+if get_option('tcg_interpreter')
+ subdir_done()
+endif
+
+# Timeouts for individual tests that can be slow e.g. with debugging enabled
+test_timeouts = {
+ 'aarch64_raspi4' : 120,
+ 'aarch64_sbsaref' : 600,
+ 'aarch64_virt' : 360,
+ 'acpi_bits' : 240,
+ 'arm_aspeed' : 600,
+ 'arm_raspi2' : 120,
+ 'arm_tuxrun' : 120,
+ 'mips_malta' : 120,
+ 'netdev_ethtool' : 180,
+ 'ppc_40p' : 240,
+ 'ppc64_hv' : 1000,
+ 'ppc64_powernv' : 240,
+ 'ppc64_pseries' : 240,
+ 's390x_ccw_virtio' : 240,
+}
+
+tests_generic_system = [
+ 'empty_cpu_model',
+ 'info_usernet',
+ 'version',
+]
+
+tests_generic_linuxuser = [
+]
+
+tests_generic_bsduser = [
+]
+
+tests_aarch64_system_thorough = [
+ 'aarch64_raspi3',
+ 'aarch64_raspi4',
+ 'aarch64_sbsaref',
+ 'aarch64_virt',
+ 'multiprocess',
+]
+
+tests_alpha_system_thorough = [
+ 'alpha_clipper',
+]
+
+tests_arm_system_thorough = [
+ 'arm_aspeed',
+ 'arm_canona1100',
+ 'arm_integratorcp',
+ 'arm_raspi2',
+ 'arm_vexpress',
+ 'arm_tuxrun',
+]
+
+tests_arm_linuxuser_thorough = [
+ 'arm_bflt',
+]
+
+tests_avr_system_thorough = [
+ 'avr_mega2560',
+]
+
+tests_i386_system_thorough = [
+ 'i386_tuxrun',
+]
+
+tests_loongarch64_system_thorough = [
+ 'loongarch64_virt',
+]
+
+tests_m68k_system_thorough = [
+ 'm68k_mcf5208evb',
+ 'm68k_nextcube',
+ 'm68k_q800',
+]
+
+tests_microblaze_system_thorough = [
+ 'microblaze_s3adsp1800'
+]
+
+tests_microblazeel_system_thorough = [
+ 'microblazeel_s3adsp1800'
+]
+
+tests_mips_system_thorough = [
+ 'mips_malta',
+ 'mips_tuxrun',
+]
+
+tests_mipsel_system_thorough = [
+ 'mipsel_malta',
+ 'mipsel_tuxrun',
+]
+
+tests_mips64_system_thorough = [
+ 'mips64_tuxrun',
+]
+
+tests_mips64el_system_thorough = [
+ 'mips64el_fuloong2e',
+ 'mips64el_loongson3v',
+ 'mips64el_malta',
+ 'mips64el_tuxrun',
+]
+
+tests_or1k_system_thorough = [
+ 'or1k_sim',
+]
+
+tests_ppc_system_quick = [
+ 'ppc_74xx',
+]
+
+tests_ppc_system_thorough = [
+ 'ppc_405',
+ 'ppc_40p',
+ 'ppc_amiga',
+ 'ppc_bamboo',
+ 'ppc_mac',
+ 'ppc_mpc8544ds',
+ 'ppc_tuxrun',
+ 'ppc_virtex_ml507',
+]
+
+tests_ppc64_system_thorough = [
+ 'ppc64_e500',
+ 'ppc64_hv',
+ 'ppc64_powernv',
+ 'ppc64_pseries',
+]
+
+tests_rx_system_thorough = [
+ 'rx_gdbsim',
+]
+
+tests_riscv32_system_thorough = [
+ 'riscv32_tuxrun',
+]
+
+tests_riscv64_system_thorough = [
+ 'riscv64_tuxrun',
+]
+
+tests_s390x_system_thorough = [
+ 's390x_ccw_virtio',
+ 's390x_topology',
+]
+
+tests_sh4_system_thorough = [
+ 'sh4_r2d',
+ 'sh4_tuxrun',
+]
+
+
+tests_sparc_system_thorough = [
+ 'sparc_sun4m',
+]
+
+tests_sparc64_system_thorough = [
+ 'sparc64_sun4u',
+ 'sparc64_tuxrun',
+]
+
+tests_x86_64_system_quick = [
+ 'cpu_queries',
+ 'mem_addr_space',
+ 'pc_cpu_hotplug_props',
+ 'virtio_version',
+ 'x86_cpu_model_versions',
+]
+
+tests_x86_64_system_thorough = [
+ 'acpi_bits',
+ 'x86_64_tuxrun',
+ 'linux_initrd',
+ 'multiprocess',
+ 'netdev_ethtool',
+ 'virtio_gpu',
+]
+
+tests_xtensa_system_thorough = [
+ 'xtensa_lx60',
+]
+
+precache_all = []
+foreach speed : ['quick', 'thorough']
+ foreach dir : target_dirs
+
+ target_base = dir.split('-')[0]
+
+ if dir.endswith('-softmmu')
+ sysmode = 'system'
+ test_emulator = emulators['qemu-system-' + target_base]
+ elif dir.endswith('-linux-user')
+ sysmode = 'linuxuser'
+ test_emulator = emulators['qemu-' + target_base]
+ elif dir.endswith('-bsd-user')
+ sysmode = 'bsduser'
+ test_emulator = emulators['qemu-' + target_base]
+ else
+ continue
+ endif
+
+ if speed == 'quick'
+ suites = ['func-quick', 'func-' + target_base]
+ target_tests = get_variable('tests_' + target_base + '_' + sysmode + '_quick', []) \
+ + get_variable('tests_generic_' + sysmode)
+ else
+ suites = ['func-' + speed, 'func-' + target_base + '-' + speed, speed]
+ target_tests = get_variable('tests_' + target_base + '_' + sysmode + '_' + speed, [])
+ endif
+
+ test_deps = roms
+ test_env = environment()
+ if have_tools
+ test_env.set('QEMU_TEST_QEMU_IMG', meson.global_build_root() / 'qemu-img')
+ test_deps += [qemu_img]
+ endif
+ test_env.set('QEMU_TEST_QEMU_BINARY', test_emulator.full_path())
+ test_env.set('QEMU_BUILD_ROOT', meson.project_build_root())
+ test_env.set('PYTHONPATH', meson.project_source_root() / 'python:' +
+ meson.current_source_dir())
+
+ foreach test : target_tests
+ testname = '@0@-@1@'.format(target_base, test)
+ testfile = 'test_' + test + '.py'
+ testpath = meson.current_source_dir() / testfile
+ teststamp = testname + '.tstamp'
+ test_precache_env = environment()
+ test_precache_env.set('QEMU_TEST_PRECACHE', meson.current_build_dir() / teststamp)
+ test_precache_env.set('PYTHONPATH', meson.project_source_root() / 'python:' +
+ meson.current_source_dir())
+ precache = custom_target('func-precache-' + testname,
+ output: teststamp,
+ command: [python, testpath],
+ depend_files: files(testpath),
+ build_by_default: false,
+ env: test_precache_env)
+ precache_all += precache
+
+ # Ideally we would add 'precache' to 'depends' here, such that
+ # 'build_by_default: false' lets the pre-caching automatically
+ # run immediately before the test runs. In practice this is
+ # broken in meson, with it running the pre-caching in the normal
+ # compile phase https://github.com/mesonbuild/meson/issues/2518
+ # If the above bug ever gets fixed, when QEMU changes the min
+ # meson version, add the 'depends' and remove the custom
+ # 'run_target' logic below & in Makefile.include
+ test('func-' + testname,
+ python,
+ depends: [test_deps, test_emulator, emulator_modules],
+ env: test_env,
+ args: [testpath],
+ protocol: 'tap',
+ timeout: test_timeouts.get(test, 60),
+ priority: test_timeouts.get(test, 60),
+ suite: suites)
+ endforeach
+ endforeach
+endforeach
+
+run_target('precache-functional',
+ depends: precache_all,
+ command: ['true'])
diff --git a/tests/functional/qemu_test/__init__.py b/tests/functional/qemu_test/__init__.py
new file mode 100644
index 0000000..67f87be
--- /dev/null
+++ b/tests/functional/qemu_test/__init__.py
@@ -0,0 +1,15 @@
+# Test class and utilities for functional tests
+#
+# Copyright 2024 Red Hat, Inc.
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+
+from .asset import Asset
+from .config import BUILD_DIR
+from .cmd import has_cmd, has_cmds, run_cmd, is_readable_executable_file, \
+ interrupt_interactive_console_until_pattern, wait_for_console_pattern, \
+ exec_command, exec_command_and_wait_for_pattern, get_qemu_img
+from .testcase import QemuBaseTest, QemuUserTest, QemuSystemTest
+from .linuxkernel import LinuxKernelTest
diff --git a/tests/functional/qemu_test/asset.py b/tests/functional/qemu_test/asset.py
new file mode 100644
index 0000000..e47bfac
--- /dev/null
+++ b/tests/functional/qemu_test/asset.py
@@ -0,0 +1,177 @@
+# Test utilities for fetching & caching assets
+#
+# Copyright 2024 Red Hat, Inc.
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+import hashlib
+import logging
+import os
+import subprocess
+import sys
+import unittest
+import urllib.request
+from time import sleep
+from pathlib import Path
+from shutil import copyfileobj
+
+
+# Instances of this class must be declared as class level variables
+# starting with a name "ASSET_". This enables the pre-caching logic
+# to easily find all referenced assets and download them prior to
+# execution of the tests.
+class Asset:
+
+ def __init__(self, url, hashsum):
+ self.url = url
+ self.hash = hashsum
+ cache_dir_env = os.getenv('QEMU_TEST_CACHE_DIR')
+ if cache_dir_env:
+ self.cache_dir = Path(cache_dir_env, "download")
+ else:
+ self.cache_dir = Path(Path("~").expanduser(),
+ ".cache", "qemu", "download")
+ self.cache_file = Path(self.cache_dir, hashsum)
+ self.log = logging.getLogger('qemu-test')
+
+ def __repr__(self):
+ return "Asset: url=%s hash=%s cache=%s" % (
+ self.url, self.hash, self.cache_file)
+
+ def _check(self, cache_file):
+ if self.hash is None:
+ return True
+ if len(self.hash) == 64:
+ hl = hashlib.sha256()
+ elif len(self.hash) == 128:
+ hl = hashlib.sha512()
+ else:
+ raise Exception("unknown hash type")
+
+ # Calculate the hash of the file:
+ with open(cache_file, 'rb') as file:
+ while True:
+ chunk = file.read(1 << 20)
+ if not chunk:
+ break
+ hl.update(chunk)
+
+ return self.hash == hl.hexdigest()
+
+ def valid(self):
+ return self.cache_file.exists() and self._check(self.cache_file)
+
+ def _wait_for_other_download(self, tmp_cache_file):
+ # Another thread already seems to download the asset, so wait until
+ # it is done, while also checking the size to see whether it is stuck
+ try:
+ current_size = tmp_cache_file.stat().st_size
+ new_size = current_size
+ except:
+ if os.path.exists(self.cache_file):
+ return True
+ raise
+ waittime = lastchange = 600
+ while waittime > 0:
+ sleep(1)
+ waittime -= 1
+ try:
+ new_size = tmp_cache_file.stat().st_size
+ except:
+ if os.path.exists(self.cache_file):
+ return True
+ raise
+ if new_size != current_size:
+ lastchange = waittime
+ current_size = new_size
+ elif lastchange - waittime > 90:
+ return False
+
+ self.log.debug("Time out while waiting for %s!", tmp_cache_file)
+ raise
+
+ def fetch(self):
+ if not self.cache_dir.exists():
+ self.cache_dir.mkdir(parents=True, exist_ok=True)
+
+ if self.valid():
+ self.log.debug("Using cached asset %s for %s",
+ self.cache_file, self.url)
+ return str(self.cache_file)
+
+ if os.environ.get("QEMU_TEST_NO_DOWNLOAD", False):
+ raise Exception("Asset cache is invalid and downloads disabled")
+
+ self.log.info("Downloading %s to %s...", self.url, self.cache_file)
+ tmp_cache_file = self.cache_file.with_suffix(".download")
+
+ for retries in range(3):
+ try:
+ with tmp_cache_file.open("xb") as dst:
+ with urllib.request.urlopen(self.url) as resp:
+ copyfileobj(resp, dst)
+ break
+ except FileExistsError:
+ self.log.debug("%s already exists, "
+ "waiting for other thread to finish...",
+ tmp_cache_file)
+ if self._wait_for_other_download(tmp_cache_file):
+ return str(self.cache_file)
+ self.log.debug("%s seems to be stale, "
+ "deleting and retrying download...",
+ tmp_cache_file)
+ tmp_cache_file.unlink()
+ continue
+ except Exception as e:
+ self.log.error("Unable to download %s: %s", self.url, e)
+ tmp_cache_file.unlink()
+ raise
+
+ try:
+ # Set these just for informational purposes
+ os.setxattr(str(tmp_cache_file), "user.qemu-asset-url",
+ self.url.encode('utf8'))
+ os.setxattr(str(tmp_cache_file), "user.qemu-asset-hash",
+ self.hash.encode('utf8'))
+ except Exception as e:
+ self.log.debug("Unable to set xattr on %s: %s", tmp_cache_file, e)
+ pass
+
+ if not self._check(tmp_cache_file):
+ tmp_cache_file.unlink()
+ raise Exception("Hash of %s does not match %s" %
+ (self.url, self.hash))
+ tmp_cache_file.replace(self.cache_file)
+
+ self.log.info("Cached %s at %s" % (self.url, self.cache_file))
+ return str(self.cache_file)
+
+ def precache_test(test):
+ log = logging.getLogger('qemu-test')
+ log.setLevel(logging.DEBUG)
+ handler = logging.StreamHandler(sys.stdout)
+ handler.setLevel(logging.DEBUG)
+ formatter = logging.Formatter(
+ '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+ handler.setFormatter(formatter)
+ log.addHandler(handler)
+ for name, asset in vars(test.__class__).items():
+ if name.startswith("ASSET_") and type(asset) == Asset:
+ log.info("Attempting to cache '%s'" % asset)
+ asset.fetch()
+ log.removeHandler(handler)
+
+ def precache_suite(suite):
+ for test in suite:
+ if isinstance(test, unittest.TestSuite):
+ Asset.precache_suite(test)
+ elif isinstance(test, unittest.TestCase):
+ Asset.precache_test(test)
+
+ def precache_suites(path, cacheTstamp):
+ loader = unittest.loader.defaultTestLoader
+ tests = loader.loadTestsFromNames([path], None)
+
+ with open(cacheTstamp, "w") as fh:
+ Asset.precache_suite(tests)
diff --git a/tests/functional/qemu_test/cmd.py b/tests/functional/qemu_test/cmd.py
new file mode 100644
index 0000000..cbabb1c
--- /dev/null
+++ b/tests/functional/qemu_test/cmd.py
@@ -0,0 +1,193 @@
+# Test class and utilities for functional tests
+#
+# Copyright 2018, 2024 Red Hat, Inc.
+#
+# Original Author (Avocado-based tests):
+# Cleber Rosa <crosa@redhat.com>
+#
+# Adaption for standalone version:
+# Thomas Huth <thuth@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+import logging
+import os
+import os.path
+import subprocess
+
+from .config import BUILD_DIR
+
+
+def has_cmd(name, args=None):
+ """
+ This function is for use in a @skipUnless decorator, e.g.:
+
+ @skipUnless(*has_cmd('sudo -n', ('sudo', '-n', 'true')))
+ def test_something_that_needs_sudo(self):
+ ...
+ """
+
+ if args is None:
+ args = ('which', name)
+
+ try:
+ _, stderr, exitcode = run_cmd(args)
+ except Exception as e:
+ exitcode = -1
+ stderr = str(e)
+
+ if exitcode != 0:
+ cmd_line = ' '.join(args)
+ err = f'{name} required, but "{cmd_line}" failed: {stderr.strip()}'
+ return (False, err)
+ else:
+ return (True, '')
+
+def has_cmds(*cmds):
+ """
+ This function is for use in a @skipUnless decorator and
+ allows checking for the availability of multiple commands, e.g.:
+
+ @skipUnless(*has_cmds(('cmd1', ('cmd1', '--some-parameter')),
+ 'cmd2', 'cmd3'))
+ def test_something_that_needs_cmd1_and_cmd2(self):
+ ...
+ """
+
+ for cmd in cmds:
+ if isinstance(cmd, str):
+ cmd = (cmd,)
+
+ ok, errstr = has_cmd(*cmd)
+ if not ok:
+ return (False, errstr)
+
+ return (True, '')
+
+def run_cmd(args):
+ subp = subprocess.Popen(args,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ universal_newlines=True)
+ stdout, stderr = subp.communicate()
+ ret = subp.returncode
+
+ return (stdout, stderr, ret)
+
+def is_readable_executable_file(path):
+ return os.path.isfile(path) and os.access(path, os.R_OK | os.X_OK)
+
+def _console_interaction(test, success_message, failure_message,
+ send_string, keep_sending=False, vm=None):
+ assert not keep_sending or send_string
+ if vm is None:
+ vm = test.vm
+ console = vm.console_file
+ console_logger = logging.getLogger('console')
+ while True:
+ if send_string:
+ vm.console_socket.sendall(send_string.encode())
+ if not keep_sending:
+ send_string = None # send only once
+
+ # Only consume console output if waiting for something
+ if success_message is None and failure_message is None:
+ if send_string is None:
+ break
+ continue
+
+ try:
+ msg = console.readline().decode().strip()
+ except UnicodeDecodeError:
+ msg = None
+ if not msg:
+ continue
+ console_logger.debug(msg)
+ if success_message is None or success_message in msg:
+ break
+ if failure_message and failure_message in msg:
+ console.close()
+ fail = 'Failure message found in console: "%s". Expected: "%s"' % \
+ (failure_message, success_message)
+ test.fail(fail)
+
+def interrupt_interactive_console_until_pattern(test, success_message,
+ failure_message=None,
+ interrupt_string='\r'):
+ """
+ Keep sending a string to interrupt a console prompt, while logging the
+ console output. Typical use case is to break a boot loader prompt, such:
+
+ Press a key within 5 seconds to interrupt boot process.
+ 5
+ 4
+ 3
+ 2
+ 1
+ Booting default image...
+
+ :param test: a test containing a VM that will have its console
+ read and probed for a success or failure message
+ :type test: :class:`qemu_test.QemuSystemTest`
+ :param success_message: if this message appears, test succeeds
+ :param failure_message: if this message appears, test fails
+ :param interrupt_string: a string to send to the console before trying
+ to read a new line
+ """
+ _console_interaction(test, success_message, failure_message,
+ interrupt_string, True)
+
+def wait_for_console_pattern(test, success_message, failure_message=None,
+ vm=None):
+ """
+ Waits for messages to appear on the console, while logging the content
+
+ :param test: a test containing a VM that will have its console
+ read and probed for a success or failure message
+ :type test: :class:`qemu_test.QemuSystemTest`
+ :param success_message: if this message appears, test succeeds
+ :param failure_message: if this message appears, test fails
+ """
+ _console_interaction(test, success_message, failure_message, None, vm=vm)
+
+def exec_command(test, command):
+ """
+ Send a command to a console (appending CRLF characters), while logging
+ the content.
+
+ :param test: a test containing a VM.
+ :type test: :class:`qemu_test.QemuSystemTest`
+ :param command: the command to send
+ :type command: str
+ """
+ _console_interaction(test, None, None, command + '\r')
+
+def exec_command_and_wait_for_pattern(test, command,
+ success_message, failure_message=None):
+ """
+ Send a command to a console (appending CRLF characters), then wait
+ for success_message to appear on the console, while logging the.
+ content. Mark the test as failed if failure_message is found instead.
+
+ :param test: a test containing a VM that will have its console
+ read and probed for a success or failure message
+ :type test: :class:`qemu_test.QemuSystemTest`
+ :param command: the command to send
+ :param success_message: if this message appears, test succeeds
+ :param failure_message: if this message appears, test fails
+ """
+ _console_interaction(test, success_message, failure_message, command + '\r')
+
+def get_qemu_img(test):
+ test.log.debug('Looking for and selecting a qemu-img binary')
+
+ # If qemu-img has been built, use it, otherwise the system wide one
+ # will be used.
+ qemu_img = os.path.join(BUILD_DIR, 'qemu-img')
+ if os.path.exists(qemu_img):
+ return qemu_img
+ (has_system_qemu_img, errmsg) = has_cmd('qemu-img')
+ if has_system_qemu_img:
+ return 'qemu-img'
+ test.skipTest(errmsg)
diff --git a/tests/functional/qemu_test/config.py b/tests/functional/qemu_test/config.py
new file mode 100644
index 0000000..edd75b7
--- /dev/null
+++ b/tests/functional/qemu_test/config.py
@@ -0,0 +1,36 @@
+# Test class and utilities for functional tests
+#
+# Copyright 2018, 2024 Red Hat, Inc.
+#
+# Original Author (Avocado-based tests):
+# Cleber Rosa <crosa@redhat.com>
+#
+# Adaption for standalone version:
+# Thomas Huth <thuth@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+import os
+from pathlib import Path
+
+
+def _source_dir():
+ # Determine top-level directory of the QEMU sources
+ return Path(__file__).parent.parent.parent.parent
+
+def _build_dir():
+ root = os.getenv('QEMU_BUILD_ROOT')
+ if root is not None:
+ return Path(root)
+ # Makefile.mtest only exists in build dir, so if it is available, use CWD
+ if os.path.exists('Makefile.mtest'):
+ return Path(os.getcwd())
+
+ root = os.path.join(_source_dir(), 'build')
+ if os.path.exists(root):
+ return Path(root)
+
+ raise Exception("Cannot identify build dir, set QEMU_BUILD_ROOT")
+
+BUILD_DIR = _build_dir()
diff --git a/tests/functional/qemu_test/linuxkernel.py b/tests/functional/qemu_test/linuxkernel.py
new file mode 100644
index 0000000..2b5b9a5
--- /dev/null
+++ b/tests/functional/qemu_test/linuxkernel.py
@@ -0,0 +1,53 @@
+# Test class for testing the boot process of a Linux kernel
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+import os
+
+from .testcase import QemuSystemTest
+from .cmd import run_cmd, wait_for_console_pattern
+from .utils import archive_extract
+
+class LinuxKernelTest(QemuSystemTest):
+ KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
+
+ def wait_for_console_pattern(self, success_message, vm=None):
+ wait_for_console_pattern(self, success_message,
+ failure_message='Kernel panic - not syncing',
+ vm=vm)
+
+ def launch_kernel(self, kernel, initrd=None, dtb=None, console_index=0,
+ wait_for=None):
+ self.vm.set_console(console_index=console_index)
+ self.vm.add_args('-kernel', kernel)
+ if initrd:
+ self.vm.add_args('-initrd', initrd)
+ if dtb:
+ self.vm.add_args('-dtb', dtb)
+ self.vm.launch()
+ if wait_for:
+ self.wait_for_console_pattern(wait_for)
+
+ def extract_from_deb(self, deb_path, path):
+ """
+ Extracts a file from a deb package into the test workdir
+
+ :param deb_path: path to the deb archive
+ :param path: path within the deb archive of the file to be extracted
+ :returns: path of the extracted file
+ """
+ cwd = os.getcwd()
+ os.chdir(self.workdir)
+ (stdout, stderr, ret) = run_cmd(['ar', 't', deb_path])
+ file_path = stdout.split()[2]
+ run_cmd(['ar', 'x', deb_path, file_path])
+ archive_extract(file_path, self.workdir)
+ os.chdir(cwd)
+ # Return complete path to extracted file. Because callers to
+ # extract_from_deb() specify 'path' with a leading slash, it is
+ # necessary to use os.path.relpath() as otherwise os.path.join()
+ # interprets it as an absolute path and drops the self.workdir part.
+ return os.path.normpath(os.path.join(self.workdir,
+ os.path.relpath(path, '/')))
+
diff --git a/tests/functional/qemu_test/tesseract.py b/tests/functional/qemu_test/tesseract.py
new file mode 100644
index 0000000..db44102
--- /dev/null
+++ b/tests/functional/qemu_test/tesseract.py
@@ -0,0 +1,36 @@
+# ...
+#
+# Copyright (c) 2019 Philippe Mathieu-DaudƩ <f4bug@amsat.org>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+import re
+import logging
+
+from . import has_cmd, run_cmd
+
+def tesseract_available(expected_version):
+ (has_tesseract, _) = has_cmd('tesseract')
+ if not has_tesseract:
+ return False
+ (stdout, stderr, ret) = run_cmd([ 'tesseract', '--version'])
+ if ret:
+ return False
+ version = stdout.split()[1]
+ return int(version.split('.')[0]) >= expected_version
+
+def tesseract_ocr(image_path, tesseract_args=''):
+ console_logger = logging.getLogger('console')
+ console_logger.debug(image_path)
+ (stdout, stderr, ret) = run_cmd(['tesseract', image_path,
+ 'stdout'])
+ if ret:
+ return None
+ lines = []
+ for line in stdout.split('\n'):
+ sline = line.strip()
+ if len(sline):
+ console_logger.debug(sline)
+ lines += [sline]
+ return lines
diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py
new file mode 100644
index 0000000..aa01462
--- /dev/null
+++ b/tests/functional/qemu_test/testcase.py
@@ -0,0 +1,202 @@
+# Test class and utilities for functional tests
+#
+# Copyright 2018, 2024 Red Hat, Inc.
+#
+# Original Author (Avocado-based tests):
+# Cleber Rosa <crosa@redhat.com>
+#
+# Adaption for standalone version:
+# Thomas Huth <thuth@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+import logging
+import os
+import subprocess
+import pycotap
+import sys
+import unittest
+import uuid
+
+from qemu.machine import QEMUMachine
+from qemu.utils import kvm_available, tcg_available
+
+from .asset import Asset
+from .cmd import run_cmd
+from .config import BUILD_DIR
+
+
+class QemuBaseTest(unittest.TestCase):
+
+ qemu_bin = os.getenv('QEMU_TEST_QEMU_BINARY')
+ arch = None
+
+ workdir = None
+ log = None
+ logdir = None
+
+ def setUp(self, bin_prefix):
+ self.assertIsNotNone(self.qemu_bin, 'QEMU_TEST_QEMU_BINARY must be set')
+ self.arch = self.qemu_bin.split('-')[-1]
+
+ self.workdir = os.path.join(BUILD_DIR, 'tests/functional', self.arch,
+ self.id())
+ os.makedirs(self.workdir, exist_ok=True)
+
+ self.logdir = self.workdir
+ self.log = logging.getLogger('qemu-test')
+ self.log.setLevel(logging.DEBUG)
+ self._log_fh = logging.FileHandler(os.path.join(self.logdir,
+ 'base.log'), mode='w')
+ self._log_fh.setLevel(logging.DEBUG)
+ fileFormatter = logging.Formatter(
+ '%(asctime)s - %(levelname)s: %(message)s')
+ self._log_fh.setFormatter(fileFormatter)
+ self.log.addHandler(self._log_fh)
+
+ def tearDown(self):
+ self.log.removeHandler(self._log_fh)
+
+ def main():
+ path = os.path.basename(sys.argv[0])[:-3]
+
+ cache = os.environ.get("QEMU_TEST_PRECACHE", None)
+ if cache is not None:
+ Asset.precache_suites(path, cache)
+ return
+
+ tr = pycotap.TAPTestRunner(message_log = pycotap.LogMode.LogToError,
+ test_output_log = pycotap.LogMode.LogToError)
+ unittest.main(module = None, testRunner = tr, argv=["__dummy__", path])
+
+
+class QemuUserTest(QemuBaseTest):
+
+ def setUp(self):
+ super().setUp('qemu-')
+ self._ldpath = []
+
+ def add_ldpath(self, ldpath):
+ self._ldpath.append(os.path.abspath(ldpath))
+
+ def run_cmd(self, bin_path, args=[]):
+ return subprocess.run([self.qemu_bin]
+ + ["-L %s" % ldpath for ldpath in self._ldpath]
+ + [bin_path]
+ + args,
+ text=True, capture_output=True)
+
+class QemuSystemTest(QemuBaseTest):
+ """Facilitates system emulation tests."""
+
+ cpu = None
+ machine = None
+ _machinehelp = None
+
+ def setUp(self):
+ self._vms = {}
+
+ super().setUp('qemu-system-')
+
+ console_log = logging.getLogger('console')
+ console_log.setLevel(logging.DEBUG)
+ self._console_log_fh = logging.FileHandler(os.path.join(self.workdir,
+ 'console.log'), mode='w')
+ self._console_log_fh.setLevel(logging.DEBUG)
+ fileFormatter = logging.Formatter('%(asctime)s: %(message)s')
+ self._console_log_fh.setFormatter(fileFormatter)
+ console_log.addHandler(self._console_log_fh)
+
+ def set_machine(self, machinename):
+ # TODO: We should use QMP to get the list of available machines
+ if not self._machinehelp:
+ self._machinehelp = run_cmd([self.qemu_bin, '-M', 'help'])[0];
+ if self._machinehelp.find(machinename) < 0:
+ self.skipTest('no support for machine ' + machinename)
+ self.machine = machinename
+
+ def require_accelerator(self, accelerator):
+ """
+ Requires an accelerator to be available for the test to continue
+
+ It takes into account the currently set qemu binary.
+
+ If the check fails, the test is canceled. If the check itself
+ for the given accelerator is not available, the test is also
+ canceled.
+
+ :param accelerator: name of the accelerator, such as "kvm" or "tcg"
+ :type accelerator: str
+ """
+ checker = {'tcg': tcg_available,
+ 'kvm': kvm_available}.get(accelerator)
+ if checker is None:
+ self.skipTest("Don't know how to check for the presence "
+ "of accelerator %s" % accelerator)
+ if not checker(qemu_bin=self.qemu_bin):
+ self.skipTest("%s accelerator does not seem to be "
+ "available" % accelerator)
+
+ def require_netdev(self, netdevname):
+ netdevhelp = run_cmd([self.qemu_bin,
+ '-M', 'none', '-netdev', 'help'])[0];
+ if netdevhelp.find('\n' + netdevname + '\n') < 0:
+ self.skipTest('no support for " + netdevname + " networking')
+
+ def require_device(self, devicename):
+ devhelp = run_cmd([self.qemu_bin,
+ '-M', 'none', '-device', 'help'])[0];
+ if devhelp.find(devicename) < 0:
+ self.skipTest('no support for device ' + devicename)
+
+ def _new_vm(self, name, *args):
+ vm = QEMUMachine(self.qemu_bin, base_temp_dir=self.workdir)
+ self.log.debug('QEMUMachine "%s" created', name)
+ self.log.debug('QEMUMachine "%s" temp_dir: %s', name, vm.temp_dir)
+ self.log.debug('QEMUMachine "%s" log_dir: %s', name, vm.log_dir)
+ if args:
+ vm.add_args(*args)
+ return vm
+
+ @property
+ def vm(self):
+ return self.get_vm(name='default')
+
+ def get_vm(self, *args, name=None):
+ if not name:
+ name = str(uuid.uuid4())
+ if self._vms.get(name) is None:
+ self._vms[name] = self._new_vm(name, *args)
+ if self.cpu is not None:
+ self._vms[name].add_args('-cpu', self.cpu)
+ if self.machine is not None:
+ self._vms[name].set_machine(self.machine)
+ return self._vms[name]
+
+ def set_vm_arg(self, arg, value):
+ """
+ Set an argument to list of extra arguments to be given to the QEMU
+ binary. If the argument already exists then its value is replaced.
+
+ :param arg: the QEMU argument, such as "-cpu" in "-cpu host"
+ :type arg: str
+ :param value: the argument value, such as "host" in "-cpu host"
+ :type value: str
+ """
+ if not arg or not value:
+ return
+ if arg not in self.vm.args:
+ self.vm.args.extend([arg, value])
+ else:
+ idx = self.vm.args.index(arg) + 1
+ if idx < len(self.vm.args):
+ self.vm.args[idx] = value
+ else:
+ self.vm.args.append(value)
+
+ def tearDown(self):
+ for vm in self._vms.values():
+ vm.shutdown()
+ logging.getLogger('console').removeHandler(self._console_log_fh)
+ super().tearDown()
diff --git a/tests/functional/qemu_test/tuxruntest.py b/tests/functional/qemu_test/tuxruntest.py
new file mode 100644
index 0000000..904da6f
--- /dev/null
+++ b/tests/functional/qemu_test/tuxruntest.py
@@ -0,0 +1,158 @@
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex BennƩe <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+import time
+
+from qemu_test import QemuSystemTest
+from qemu_test import exec_command, exec_command_and_wait_for_pattern
+from qemu_test import wait_for_console_pattern
+from qemu_test import has_cmd, run_cmd, get_qemu_img
+
+class TuxRunBaselineTest(QemuSystemTest):
+
+ KERNEL_COMMON_COMMAND_LINE = 'printk.time=0'
+ # Tests are ~10-40s, allow for --debug/--enable-gcov overhead
+ timeout = 100
+
+ def get_tag(self, tagname, default=None):
+ """
+ Get the metadata tag or return the default.
+ """
+ utag = self._get_unique_tag_val(tagname)
+ print(f"{tagname}/{default} -> {utag}")
+ if utag:
+ return utag
+
+ return default
+
+ def setUp(self):
+ super().setUp()
+
+ # We need zstd for all the tuxrun tests
+ # See https://github.com/avocado-framework/avocado/issues/5609
+ (has_zstd, msg) = has_cmd('zstd')
+ if has_zstd is False:
+ self.skipTest(msg)
+ self.zstd = 'zstd'
+
+ # Pre-init TuxRun specific settings: Most machines work with
+ # reasonable defaults but we sometimes need to tweak the
+ # config. To avoid open coding everything we store all these
+ # details in the metadata for each test.
+
+ # The tuxboot tag matches the root directory
+ self.tuxboot = self.arch
+
+ # Most Linux's use ttyS0 for their serial port
+ self.console = "ttyS0"
+
+ # Does the machine shutdown QEMU nicely on "halt"
+ self.wait_for_shutdown = True
+
+ self.root = "vda"
+
+ # Occasionally we need extra devices to hook things up
+ self.extradev = None
+
+ self.qemu_img = get_qemu_img(self)
+
+ def wait_for_console_pattern(self, success_message, vm=None):
+ wait_for_console_pattern(self, success_message,
+ failure_message='Kernel panic - not syncing',
+ vm=vm)
+
+ def fetch_tuxrun_assets(self, kernel_asset, rootfs_asset, dtb_asset=None):
+ """
+ Fetch the TuxBoot assets.
+ """
+ kernel_image = kernel_asset.fetch()
+ disk_image_zst = rootfs_asset.fetch()
+
+ run_cmd([self.zstd, "-f", "-d", disk_image_zst,
+ "-o", self.workdir + "/rootfs.ext4"])
+
+ dtb = dtb_asset.fetch() if dtb_asset is not None else None
+
+ return (kernel_image, self.workdir + "/rootfs.ext4", dtb)
+
+ def prepare_run(self, kernel, disk, drive, dtb=None, console_index=0):
+ """
+ Setup to run and add the common parameters to the system
+ """
+ self.vm.set_console(console_index=console_index)
+
+ # all block devices are raw ext4's
+ blockdev = "driver=raw,file.driver=file," \
+ + f"file.filename={disk},node-name=hd0"
+
+ kcmd_line = self.KERNEL_COMMON_COMMAND_LINE
+ kcmd_line += f" root=/dev/{self.root}"
+ kcmd_line += f" console={self.console}"
+
+ self.vm.add_args('-kernel', kernel,
+ '-append', kcmd_line,
+ '-blockdev', blockdev)
+
+ # Sometimes we need extra devices attached
+ if self.extradev:
+ self.vm.add_args('-device', self.extradev)
+
+ self.vm.add_args('-device',
+ f"{drive},drive=hd0")
+
+ # Some machines need an explicit DTB
+ if dtb:
+ self.vm.add_args('-dtb', dtb)
+
+ def run_tuxtest_tests(self, haltmsg):
+ """
+ Wait for the system to boot up, wait for the login prompt and
+ then do a few things on the console. Trigger a shutdown and
+ wait to exit cleanly.
+ """
+ self.wait_for_console_pattern("Welcome to TuxTest")
+ time.sleep(0.2)
+ exec_command(self, 'root')
+ time.sleep(0.2)
+ exec_command(self, 'cat /proc/interrupts')
+ time.sleep(0.1)
+ exec_command(self, 'cat /proc/self/maps')
+ time.sleep(0.1)
+ exec_command(self, 'uname -a')
+ time.sleep(0.1)
+ exec_command_and_wait_for_pattern(self, 'halt', haltmsg)
+
+ # Wait for VM to shut down gracefully if it can
+ if self.wait_for_shutdown:
+ self.vm.wait()
+ else:
+ self.vm.shutdown()
+
+ def common_tuxrun(self,
+ kernel_asset,
+ rootfs_asset,
+ dtb_asset=None,
+ drive="virtio-blk-device",
+ haltmsg="reboot: System halted",
+ console_index=0):
+ """
+ Common path for LKFT tests. Unless we need to do something
+ special with the command line we can process most things using
+ the tag metadata.
+ """
+ (kernel, disk, dtb) = self.fetch_tuxrun_assets(kernel_asset, rootfs_asset,
+ dtb_asset)
+
+ self.prepare_run(kernel, disk, drive, dtb, console_index)
+ self.vm.launch()
+ self.run_tuxtest_tests(haltmsg)
+ os.remove(disk)
diff --git a/tests/functional/qemu_test/utils.py b/tests/functional/qemu_test/utils.py
new file mode 100644
index 0000000..2a1cb60
--- /dev/null
+++ b/tests/functional/qemu_test/utils.py
@@ -0,0 +1,56 @@
+# Utilities for python-based QEMU tests
+#
+# Copyright 2024 Red Hat, Inc.
+#
+# Authors:
+# Thomas Huth <thuth@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+import gzip
+import lzma
+import os
+import shutil
+import subprocess
+import tarfile
+
+def archive_extract(archive, dest_dir, member=None):
+ with tarfile.open(archive) as tf:
+ if hasattr(tarfile, 'data_filter'):
+ tf.extraction_filter = getattr(tarfile, 'data_filter',
+ (lambda member, path: member))
+ if member:
+ tf.extract(member=member, path=dest_dir)
+ else:
+ tf.extractall(path=dest_dir)
+
+def gzip_uncompress(gz_path, output_path):
+ if os.path.exists(output_path):
+ return
+ with gzip.open(gz_path, 'rb') as gz_in:
+ try:
+ with open(output_path, 'wb') as raw_out:
+ shutil.copyfileobj(gz_in, raw_out)
+ except:
+ os.remove(output_path)
+ raise
+
+def lzma_uncompress(xz_path, output_path):
+ if os.path.exists(output_path):
+ return
+ with lzma.open(xz_path, 'rb') as lzma_in:
+ try:
+ with open(output_path, 'wb') as raw_out:
+ shutil.copyfileobj(lzma_in, raw_out)
+ except:
+ os.remove(output_path)
+ raise
+
+def cpio_extract(cpio_handle, output_path):
+ cwd = os.getcwd()
+ os.chdir(output_path)
+ subprocess.run(['cpio', '-i'],
+ input=cpio_handle.read(),
+ stderr=subprocess.DEVNULL)
+ os.chdir(cwd)
diff --git a/tests/functional/test_aarch64_raspi3.py b/tests/functional/test_aarch64_raspi3.py
new file mode 100755
index 0000000..369f95a
--- /dev/null
+++ b/tests/functional/test_aarch64_raspi3.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on a Raspberry Pi machine
+# and checks the console
+#
+# Copyright (c) 2020 Philippe Mathieu-DaudƩ <f4bug@amsat.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+from zipfile import ZipFile
+
+from qemu_test import LinuxKernelTest, Asset
+
+
+class Aarch64Raspi3Machine(LinuxKernelTest):
+
+ ASSET_RPI3_UEFI = Asset(
+ ('https://github.com/pbatard/RPi3/releases/download/'
+ 'v1.15/RPi3_UEFI_Firmware_v1.15.zip'),
+ '8cff2e979560048b4c84921f41a91893240b9fb71a88f0b5c5d6c8edd994bd5b')
+
+ def test_aarch64_raspi3_atf(self):
+ efi_name = 'RPI_EFI.fd'
+ zip_path = self.ASSET_RPI3_UEFI.fetch()
+
+ with ZipFile(zip_path, 'r') as zf:
+ zf.extract(efi_name, path=self.workdir)
+ efi_fd = os.path.join(self.workdir, efi_name)
+
+ self.set_machine('raspi3b')
+ self.vm.set_console(console_index=1)
+ self.vm.add_args('-cpu', 'cortex-a53',
+ '-nodefaults',
+ '-device', f'loader,file={efi_fd},force-raw=true')
+ self.vm.launch()
+ self.wait_for_console_pattern('version UEFI Firmware v1.15')
+
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_aarch64_raspi4.py b/tests/functional/test_aarch64_raspi4.py
new file mode 100755
index 0000000..e5c9f77
--- /dev/null
+++ b/tests/functional/test_aarch64_raspi4.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on a Raspberry Pi machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test import exec_command_and_wait_for_pattern
+from qemu_test.utils import gzip_uncompress
+
+
+class Aarch64Raspi4Machine(LinuxKernelTest):
+
+ """
+ The kernel can be rebuilt using the kernel source referenced
+ and following the instructions on the on:
+ https://www.raspberrypi.org/documentation/linux/kernel/building.md
+ """
+ ASSET_KERNEL_20190215 = Asset(
+ ('http://archive.raspberrypi.org/debian/'
+ 'pool/main/r/raspberrypi-firmware/'
+ 'raspberrypi-kernel_1.20230106-1_arm64.deb'),
+ '56d5713c8f6eee8a0d3f0e73600ec11391144fef318b08943e9abd94c0a9baf7')
+
+ ASSET_INITRD = Asset(
+ ('https://github.com/groeck/linux-build-test/raw/'
+ '86b2be1384d41c8c388e63078a847f1e1c4cb1de/rootfs/'
+ 'arm64/rootfs.cpio.gz'),
+ '7c0b16d1853772f6f4c3ca63e789b3b9ff4936efac9c8a01fb0c98c05c7a7648')
+
+ def test_arm_raspi4(self):
+ deb_path = self.ASSET_KERNEL_20190215.fetch()
+ kernel_path = self.extract_from_deb(deb_path, '/boot/kernel8.img')
+ dtb_path = self.extract_from_deb(deb_path, '/boot/bcm2711-rpi-4-b.dtb')
+
+ self.set_machine('raspi4b')
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'earlycon=pl011,mmio32,0xfe201000 ' +
+ 'console=ttyAMA0,115200 ' +
+ 'root=/dev/mmcblk1p2 rootwait ' +
+ 'dwc_otg.fiq_fsm_enable=0')
+ self.vm.add_args('-kernel', kernel_path,
+ '-dtb', dtb_path,
+ '-append', kernel_command_line)
+ # When PCI is supported we can add a USB controller:
+ # '-device', 'qemu-xhci,bus=pcie.1,id=xhci',
+ # '-device', 'usb-kbd,bus=xhci.0',
+ self.vm.launch()
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.wait_for_console_pattern(console_pattern)
+ # When USB is enabled we can look for this
+ # console_pattern = 'Product: QEMU USB Keyboard'
+ # self.wait_for_console_pattern(console_pattern)
+ console_pattern = 'Waiting for root device'
+ self.wait_for_console_pattern(console_pattern)
+
+
+ def test_arm_raspi4_initrd(self):
+ deb_path = self.ASSET_KERNEL_20190215.fetch()
+ kernel_path = self.extract_from_deb(deb_path, '/boot/kernel8.img')
+ dtb_path = self.extract_from_deb(deb_path, '/boot/bcm2711-rpi-4-b.dtb')
+ initrd_path_gz = self.ASSET_INITRD.fetch()
+ initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
+ gzip_uncompress(initrd_path_gz, initrd_path)
+
+ self.set_machine('raspi4b')
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'earlycon=pl011,mmio32,0xfe201000 ' +
+ 'console=ttyAMA0,115200 ' +
+ 'panic=-1 noreboot ' +
+ 'dwc_otg.fiq_fsm_enable=0')
+ self.vm.add_args('-kernel', kernel_path,
+ '-dtb', dtb_path,
+ '-initrd', initrd_path,
+ '-append', kernel_command_line,
+ '-no-reboot')
+ # When PCI is supported we can add a USB controller:
+ # '-device', 'qemu-xhci,bus=pcie.1,id=xhci',
+ # '-device', 'usb-kbd,bus=xhci.0',
+ self.vm.launch()
+ self.wait_for_console_pattern('Boot successful.')
+
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
+ 'BCM2835')
+ exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
+ 'cprman@7e101000')
+ exec_command_and_wait_for_pattern(self, 'halt', 'reboot: System halted')
+ # TODO: Raspberry Pi4 doesn't shut down properly with recent kernels
+ # Wait for VM to shut down gracefully
+ #self.vm.wait()
+
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_aarch64_sbsaref.py b/tests/functional/test_aarch64_sbsaref.py
new file mode 100755
index 0000000..b50e1a5
--- /dev/null
+++ b/tests/functional/test_aarch64_sbsaref.py
@@ -0,0 +1,190 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a kernel and checks the console
+#
+# SPDX-FileCopyrightText: 2023-2024 Linaro Ltd.
+# SPDX-FileContributor: Philippe Mathieu-DaudƩ <philmd@linaro.org>
+# SPDX-FileContributor: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern
+from qemu_test import interrupt_interactive_console_until_pattern
+from qemu_test.utils import lzma_uncompress
+from unittest import skipUnless
+
+
+class Aarch64SbsarefMachine(QemuSystemTest):
+ """
+ As firmware runs at a higher privilege level than the hypervisor we
+ can only run these tests under TCG emulation.
+ """
+
+ timeout = 180
+
+ ASSET_FLASH0 = Asset(
+ ('https://artifacts.codelinaro.org/artifactory/linaro-419-sbsa-ref/'
+ '20240619-148232/edk2/SBSA_FLASH0.fd.xz'),
+ '0c954842a590988f526984de22e21ae0ab9cb351a0c99a8a58e928f0c7359cf7')
+
+ ASSET_FLASH1 = Asset(
+ ('https://artifacts.codelinaro.org/artifactory/linaro-419-sbsa-ref/'
+ '20240619-148232/edk2/SBSA_FLASH1.fd.xz'),
+ 'c6ec39374c4d79bb9e9cdeeb6db44732d90bb4a334cec92002b3f4b9cac4b5ee')
+
+ def fetch_firmware(self):
+ """
+ Flash volumes generated using:
+
+ Toolchain from Debian:
+ aarch64-linux-gnu-gcc (Debian 12.2.0-14) 12.2.0
+
+ Used components:
+
+ - Trusted Firmware v2.11.0
+ - Tianocore EDK2 4d4f569924
+ - Tianocore EDK2-platforms 3f08401
+
+ """
+
+ # Secure BootRom (TF-A code)
+ fs0_xz_path = self.ASSET_FLASH0.fetch()
+ fs0_path = os.path.join(self.workdir, "SBSA_FLASH0.fd")
+ lzma_uncompress(fs0_xz_path, fs0_path)
+
+ # Non-secure rom (UEFI and EFI variables)
+ fs1_xz_path = self.ASSET_FLASH1.fetch()
+ fs1_path = os.path.join(self.workdir, "SBSA_FLASH1.fd")
+ lzma_uncompress(fs1_xz_path, fs1_path)
+
+ for path in [fs0_path, fs1_path]:
+ with open(path, "ab+") as fd:
+ fd.truncate(256 << 20) # Expand volumes to 256MiB
+
+ self.set_machine('sbsa-ref')
+ self.vm.set_console()
+ self.vm.add_args(
+ "-drive", f"if=pflash,file={fs0_path},format=raw",
+ "-drive", f"if=pflash,file={fs1_path},format=raw",
+ )
+
+ def test_sbsaref_edk2_firmware(self):
+
+ self.fetch_firmware()
+
+ self.vm.add_args('-cpu', 'cortex-a57')
+ self.vm.launch()
+
+ # TF-A boot sequence:
+ #
+ # https://github.com/ARM-software/arm-trusted-firmware/blob/v2.8.0/\
+ # docs/design/trusted-board-boot.rst#trusted-board-boot-sequence
+ # https://trustedfirmware-a.readthedocs.io/en/v2.8/\
+ # design/firmware-design.html#cold-boot
+
+ # AP Trusted ROM
+ wait_for_console_pattern(self, "Booting Trusted Firmware")
+ wait_for_console_pattern(self, "BL1: v2.11.0(release):")
+ wait_for_console_pattern(self, "BL1: Booting BL2")
+
+ # Trusted Boot Firmware
+ wait_for_console_pattern(self, "BL2: v2.11.0(release)")
+ wait_for_console_pattern(self, "Booting BL31")
+
+ # EL3 Runtime Software
+ wait_for_console_pattern(self, "BL31: v2.11.0(release)")
+
+ # Non-trusted Firmware
+ wait_for_console_pattern(self, "UEFI firmware (version 1.0")
+ interrupt_interactive_console_until_pattern(self, "QEMU SBSA-REF Machine")
+
+
+ ASSET_ALPINE_ISO = Asset(
+ ('https://dl-cdn.alpinelinux.org/'
+ 'alpine/v3.17/releases/aarch64/alpine-standard-3.17.2-aarch64.iso'),
+ '5a36304ecf039292082d92b48152a9ec21009d3a62f459de623e19c4bd9dc027')
+
+ # This tests the whole boot chain from EFI to Userspace
+ # We only boot a whole OS for the current top level CPU and GIC
+ # Other test profiles should use more minimal boots
+ def boot_alpine_linux(self, cpu=None):
+ self.fetch_firmware()
+
+ iso_path = self.ASSET_ALPINE_ISO.fetch()
+
+ self.vm.set_console()
+ self.vm.add_args(
+ "-drive", f"file={iso_path},media=cdrom,format=raw",
+ )
+ if cpu:
+ self.vm.add_args("-cpu", cpu)
+
+ self.vm.launch()
+ wait_for_console_pattern(self, "Welcome to Alpine Linux 3.17")
+
+ def test_sbsaref_alpine_linux_cortex_a57(self):
+ self.boot_alpine_linux("cortex-a57")
+
+ def test_sbsaref_alpine_linux_default_cpu(self):
+ self.boot_alpine_linux()
+
+ def test_sbsaref_alpine_linux_max_pauth_off(self):
+ self.boot_alpine_linux("max,pauth=off")
+
+ def test_sbsaref_alpine_linux_max_pauth_impdef(self):
+ self.boot_alpine_linux("max,pauth-impdef=on")
+
+ @skipUnless(os.getenv('QEMU_TEST_TIMEOUT_EXPECTED'),
+ 'Test might timeout due to PAuth emulation')
+ def test_sbsaref_alpine_linux_max(self):
+ self.boot_alpine_linux("max")
+
+
+ ASSET_FREEBSD_ISO = Asset(
+ ('https://download.freebsd.org/releases/arm64/aarch64/ISO-IMAGES/'
+ '14.1/FreeBSD-14.1-RELEASE-arm64-aarch64-bootonly.iso'),
+ '44cdbae275ef1bb6dab1d5fbb59473d4f741e1c8ea8a80fd9e906b531d6ad461')
+
+ # This tests the whole boot chain from EFI to Userspace
+ # We only boot a whole OS for the current top level CPU and GIC
+ # Other test profiles should use more minimal boots
+ def boot_freebsd14(self, cpu=None):
+ self.fetch_firmware()
+
+ img_path = self.ASSET_FREEBSD_ISO.fetch()
+
+ self.vm.set_console()
+ self.vm.add_args(
+ "-drive", f"file={img_path},format=raw,snapshot=on",
+ )
+ if cpu:
+ self.vm.add_args("-cpu", cpu)
+
+ self.vm.launch()
+ wait_for_console_pattern(self, 'Welcome to FreeBSD!')
+
+ def test_sbsaref_freebsd14_cortex_a57(self):
+ self.boot_freebsd14("cortex-a57")
+
+ def test_sbsaref_freebsd14_default_cpu(self):
+ self.boot_freebsd14()
+
+ def test_sbsaref_freebsd14_max_pauth_off(self):
+ self.boot_freebsd14("max,pauth=off")
+
+ @skipUnless(os.getenv('QEMU_TEST_TIMEOUT_EXPECTED'),
+ 'Test might timeout due to PAuth emulation')
+ def test_sbsaref_freebsd14_max_pauth_impdef(self):
+ self.boot_freebsd14("max,pauth-impdef=on")
+
+ @skipUnless(os.getenv('QEMU_TEST_TIMEOUT_EXPECTED'),
+ 'Test might timeout due to PAuth emulation')
+ def test_sbsaref_freebsd14_max(self):
+ self.boot_freebsd14("max")
+
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/avocado/machine_aarch64_virt.py b/tests/functional/test_aarch64_virt.py
index a90dc6f..c967da4 100644..100755
--- a/tests/avocado/machine_aarch64_virt.py
+++ b/tests/functional/test_aarch64_virt.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Functional test that boots a various Linux systems and checks the
# console output.
#
@@ -12,12 +14,11 @@ import time
import os
import logging
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
-from avocado_qemu import exec_command
-from avocado_qemu import BUILD_DIR
-from avocado.utils import process
-from avocado.utils.path import find_command
+from qemu_test import BUILD_DIR
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import exec_command, wait_for_console_pattern
+from qemu_test import get_qemu_img, run_cmd
+
class Aarch64VirtMachine(QemuSystemTest):
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
@@ -28,23 +29,18 @@ class Aarch64VirtMachine(QemuSystemTest):
failure_message='Kernel panic - not syncing',
vm=vm)
+ ASSET_ALPINE_ISO = Asset(
+ ('https://dl-cdn.alpinelinux.org/'
+ 'alpine/v3.17/releases/aarch64/alpine-standard-3.17.2-aarch64.iso'),
+ '5a36304ecf039292082d92b48152a9ec21009d3a62f459de623e19c4bd9dc027')
+
# This tests the whole boot chain from EFI to Userspace
# We only boot a whole OS for the current top level CPU and GIC
# Other test profiles should use more minimal boots
def test_alpine_virt_tcg_gic_max(self):
- """
- :avocado: tags=arch:aarch64
- :avocado: tags=machine:virt
- :avocado: tags=accel:tcg
- """
- iso_url = ('https://dl-cdn.alpinelinux.org/'
- 'alpine/v3.17/releases/aarch64/'
- 'alpine-standard-3.17.2-aarch64.iso')
-
- # Alpine use sha256 so I recalculated this myself
- iso_sha1 = '76284fcd7b41fe899b0c2375ceb8470803eea839'
- iso_path = self.fetch_asset(iso_url, asset_hash=iso_sha1)
+ iso_path = self.ASSET_ALPINE_ISO.fetch()
+ self.set_machine('virt')
self.vm.set_console()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
'console=ttyAMA0')
@@ -60,7 +56,7 @@ class Aarch64VirtMachine(QemuSystemTest):
self.vm.add_args("-smp", "2", "-m", "1024")
self.vm.add_args('-bios', os.path.join(BUILD_DIR, 'pc-bios',
'edk2-aarch64-code.fd'))
- self.vm.add_args("-drive", f"file={iso_path},format=raw")
+ self.vm.add_args("-drive", f"file={iso_path},media=cdrom,format=raw")
self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0')
self.vm.add_args('-object', 'rng-random,id=rng0,filename=/dev/urandom')
@@ -68,6 +64,11 @@ class Aarch64VirtMachine(QemuSystemTest):
self.wait_for_console_pattern('Welcome to Alpine Linux 3.17')
+ ASSET_KERNEL = Asset(
+ ('https://fileserver.linaro.org/s/'
+ 'z6B2ARM7DQT3HWN/download'),
+ '12a54d4805cda6ab647cb7c7bbdb16fafb3df400e0d6f16445c1a0436100ef8d')
+
def common_aarch64_virt(self, machine):
"""
Common code to launch basic virt machine with kernel+initrd
@@ -75,11 +76,9 @@ class Aarch64VirtMachine(QemuSystemTest):
"""
logger = logging.getLogger('aarch64_virt')
- kernel_url = ('https://fileserver.linaro.org/s/'
- 'z6B2ARM7DQT3HWN/download')
- kernel_hash = 'ed11daab50c151dde0e1e9c9cb8b2d9bd3215347'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
+ kernel_path = self.ASSET_KERNEL.fetch()
+ self.set_machine('virt')
self.vm.set_console()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
'console=ttyAMA0')
@@ -98,14 +97,8 @@ class Aarch64VirtMachine(QemuSystemTest):
# Also add a scratch block device
logger.info('creating scratch qcow2 image')
image_path = os.path.join(self.workdir, 'scratch.qcow2')
- qemu_img = os.path.join(BUILD_DIR, 'qemu-img')
- if not os.path.exists(qemu_img):
- qemu_img = find_command('qemu-img', False)
- if qemu_img is False:
- self.cancel('Could not find "qemu-img", which is required to '
- 'create the temporary qcow2 image')
- cmd = '%s create -f qcow2 %s 8M' % (qemu_img, image_path)
- process.run(cmd)
+ qemu_img = get_qemu_img(self)
+ run_cmd([qemu_img, 'create', '-f', 'qcow2', image_path, '8M'])
# Add the device
self.vm.add_args('-blockdev',
@@ -128,19 +121,11 @@ class Aarch64VirtMachine(QemuSystemTest):
time.sleep(0.1)
def test_aarch64_virt_gicv3(self):
- """
- :avocado: tags=arch:aarch64
- :avocado: tags=machine:virt
- :avocado: tags=accel:tcg
- :avocado: tags=cpu:max
- """
self.common_aarch64_virt("virt,gic_version=3")
def test_aarch64_virt_gicv2(self):
- """
- :avocado: tags=arch:aarch64
- :avocado: tags=machine:virt
- :avocado: tags=accel:tcg
- :avocado: tags=cpu:max
- """
self.common_aarch64_virt("virt,gic-version=2")
+
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/avocado/acpi-bits.py b/tests/functional/test_acpi_bits.py
index efe4f52..ee40647 100644..100755
--- a/tests/avocado/acpi-bits.py
+++ b/tests/functional/test_acpi_bits.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# group: rw quick
+#
# Exercise QEMU generated ACPI/SMBIOS tables using biosbits,
# https://biosbits.org/
#
@@ -24,7 +24,7 @@
# pylint: disable=consider-using-f-string
"""
-This is QEMU ACPI/SMBIOS avocado tests using biosbits.
+This is QEMU ACPI/SMBIOS functional tests using biosbits.
Biosbits is available originally at https://biosbits.org/.
This test uses a fork of the upstream bits and has numerous fixes
including an upgraded acpica. The fork is located here:
@@ -41,15 +41,16 @@ import tarfile
import tempfile
import time
import zipfile
+
+from pathlib import Path
from typing import (
List,
Optional,
Sequence,
)
from qemu.machine import QEMUMachine
-from avocado import skipIf
-from avocado.utils import datadrainer as drainer
-from avocado_qemu import QemuBaseTest
+from unittest import skipIf
+from qemu_test import QemuBaseTest, Asset
deps = ["xorriso", "mformat"] # dependent tools needed in the test setup/box.
supported_platforms = ['x86_64'] # supported test platforms.
@@ -129,34 +130,32 @@ class QEMUBitsMachine(QEMUMachine): # pylint: disable=too-few-public-methods
class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes
"""
ACPI and SMBIOS tests using biosbits.
-
- :avocado: tags=arch:x86_64
- :avocado: tags=acpi
-
"""
# in slower systems the test can take as long as 3 minutes to complete.
timeout = BITS_TIMEOUT
+ # following are some standard configuration constants
+ # gitlab CI does shallow clones of depth 20
+ BITS_INTERNAL_VER = 2020
+ # commit hash must match the artifact tag below
+ BITS_COMMIT_HASH = 'c7920d2b'
+ # this is the latest bits release as of today.
+ BITS_TAG = "qemu-bits-10262023"
+
+ ASSET_BITS = Asset(("https://gitlab.com/qemu-project/"
+ "biosbits-bits/-/jobs/artifacts/%s/"
+ "download?job=qemu-bits-build" % BITS_TAG),
+ '1b8dd612c6831a6b491716a77acc486666aaa867051cdc34f7ce169c2e25f487')
+
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._vm = None
self._workDir = None
self._baseDir = None
- # following are some standard configuration constants
- self._bitsInternalVer = 2020 # gitlab CI does shallow clones of depth 20
- self._bitsCommitHash = 'c7920d2b' # commit hash must match
- # the artifact tag below
- self._bitsTag = "qemu-bits-10262023" # this is the latest bits
- # release as of today.
- self._bitsArtSHA1Hash = 'b22cdfcfc7453875297d06d626f5474ee36a343f'
- self._bitsArtURL = ("https://gitlab.com/qemu-project/"
- "biosbits-bits/-/jobs/artifacts/%s/"
- "download?job=qemu-bits-build" %self._bitsTag)
self._debugcon_addr = '0x403'
self._debugcon_log = 'debugcon-log.txt'
- logging.basicConfig(level=logging.INFO)
- self.logger = logging.getLogger('acpi-bits')
+ self.logger = self.log
def _print_log(self, log):
self.logger.info('\nlogs from biosbits follows:')
@@ -171,7 +170,7 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes
bits_config_dir = os.path.join(self._baseDir, 'acpi-bits',
'bits-config')
target_config_dir = os.path.join(self._workDir,
- 'bits-%d' %self._bitsInternalVer,
+ 'bits-%d' %self.BITS_INTERNAL_VER,
'boot')
self.assertTrue(os.path.exists(bits_config_dir))
self.assertTrue(os.path.exists(target_config_dir))
@@ -188,7 +187,7 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes
bits_test_dir = os.path.join(self._baseDir, 'acpi-bits',
'bits-tests')
target_test_dir = os.path.join(self._workDir,
- 'bits-%d' %self._bitsInternalVer,
+ 'bits-%d' %self.BITS_INTERNAL_VER,
'boot', 'python')
self.assertTrue(os.path.exists(bits_test_dir))
@@ -248,9 +247,9 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes
test scripts
"""
bits_dir = os.path.join(self._workDir,
- 'bits-%d' %self._bitsInternalVer)
+ 'bits-%d' %self.BITS_INTERNAL_VER)
iso_file = os.path.join(self._workDir,
- 'bits-%d.iso' %self._bitsInternalVer)
+ 'bits-%d.iso' %self.BITS_INTERNAL_VER)
mkrescue_script = os.path.join(self._workDir,
'grub-inst-x86_64-efi', 'bin',
'grub-mkrescue')
@@ -264,8 +263,12 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes
try:
if os.getenv('V') or os.getenv('BITS_DEBUG'):
- subprocess.check_call([mkrescue_script, '-o', iso_file,
- bits_dir], stderr=subprocess.STDOUT)
+ proc = subprocess.run([mkrescue_script, '-o', iso_file,
+ bits_dir],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ check=True)
+ self.logger.info("grub-mkrescue output %s" % proc.stdout)
else:
subprocess.check_call([mkrescue_script, '-o',
iso_file, bits_dir],
@@ -282,8 +285,9 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes
def setUp(self): # pylint: disable=arguments-differ
super().setUp('qemu-system-')
+ self.logger = self.log
- self._baseDir = os.getenv('AVOCADO_TEST_BASEDIR')
+ self._baseDir = Path(__file__).parent
# workdir could also be avocado's own workdir in self.workdir.
# At present, I prefer to maintain my own temporary working
@@ -300,15 +304,14 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes
os.mkdir(prebuiltDir, mode=0o775)
bits_zip_file = os.path.join(prebuiltDir, 'bits-%d-%s.zip'
- %(self._bitsInternalVer,
- self._bitsCommitHash))
+ %(self.BITS_INTERNAL_VER,
+ self.BITS_COMMIT_HASH))
grub_tar_file = os.path.join(prebuiltDir,
'bits-%d-%s-grub.tar.gz'
- %(self._bitsInternalVer,
- self._bitsCommitHash))
+ %(self.BITS_INTERNAL_VER,
+ self.BITS_COMMIT_HASH))
- bitsLocalArtLoc = self.fetch_asset(self._bitsArtURL,
- asset_hash=self._bitsArtSHA1Hash)
+ bitsLocalArtLoc = self.ASSET_BITS.fetch()
self.logger.info("downloaded bits artifacts to %s", bitsLocalArtLoc)
# extract the bits artifact in the temp working directory
@@ -369,7 +372,7 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes
"""The main test case implementation."""
iso_file = os.path.join(self._workDir,
- 'bits-%d.iso' %self._bitsInternalVer)
+ 'bits-%d.iso' %self.BITS_INTERNAL_VER)
self.assertTrue(os.access(iso_file, os.R_OK))
@@ -393,12 +396,6 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes
self._vm.set_console()
self._vm.launch()
- self.logger.debug("Console output from bits VM follows ...")
- c_drainer = drainer.LineLogger(self._vm.console_socket.fileno(),
- logger=self.logger.getChild("console"),
- stop_check=(lambda :
- not self._vm.is_running()))
- c_drainer.start()
# biosbits has been configured to run all the specified test suites
# in batch mode and then automatically initiate a vm shutdown.
@@ -406,4 +403,8 @@ class AcpiBitsTest(QemuBaseTest): #pylint: disable=too-many-instance-attributes
# with the avocado test timeout.
self._vm.event_wait('SHUTDOWN', timeout=BITS_TIMEOUT)
self._vm.wait(timeout=None)
+ self.logger.debug("Checking console output ...")
self.parse_log()
+
+if __name__ == '__main__':
+ QemuBaseTest.main()
diff --git a/tests/functional/test_alpha_clipper.py b/tests/functional/test_alpha_clipper.py
new file mode 100755
index 0000000..c1fbf0e
--- /dev/null
+++ b/tests/functional/test_alpha_clipper.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on an Alpha Clipper machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test.utils import gzip_uncompress
+
+
+class AlphaClipperTest(LinuxKernelTest):
+
+ ASSET_KERNEL = Asset(
+ ('http://archive.debian.org/debian/dists/lenny/main/'
+ 'installer-alpha/20090123lenny10/images/cdrom/vmlinuz'),
+ '34f53da3fa32212e4f00b03cb944b2ad81c06bc8faaf9b7193b2e544ceeca576')
+
+ def test_alpha_clipper(self):
+ self.set_machine('clipper')
+ kernel_path = self.ASSET_KERNEL.fetch()
+
+ uncompressed_kernel = os.path.join(self.workdir, 'vmlinux')
+ gzip_uncompress(kernel_path, uncompressed_kernel)
+
+ self.vm.set_console()
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
+ self.vm.add_args('-nodefaults',
+ '-kernel', uncompressed_kernel,
+ '-append', kernel_command_line)
+ self.vm.launch()
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.wait_for_console_pattern(console_pattern)
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_arm_aspeed.py b/tests/functional/test_arm_aspeed.py
new file mode 100644
index 0000000..9761fc0
--- /dev/null
+++ b/tests/functional/test_arm_aspeed.py
@@ -0,0 +1,282 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots the ASPEED SoCs with firmware
+#
+# Copyright (C) 2022 ASPEED Technology Inc
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+import time
+import subprocess
+import tempfile
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test import exec_command_and_wait_for_pattern
+from qemu_test import interrupt_interactive_console_until_pattern
+from qemu_test import exec_command
+from qemu_test import has_cmd
+from qemu_test.utils import archive_extract
+from zipfile import ZipFile
+from unittest import skipUnless
+
+class AST1030Machine(LinuxKernelTest):
+
+ ASSET_ZEPHYR_1_04 = Asset(
+ ('https://github.com/AspeedTech-BMC'
+ '/zephyr/releases/download/v00.01.04/ast1030-evb-demo.zip'),
+ '4ac6210adcbc61294927918707c6762483fd844dde5e07f3ba834ad1f91434d3')
+
+ def test_ast1030_zephyros_1_04(self):
+ self.set_machine('ast1030-evb')
+
+ zip_file = self.ASSET_ZEPHYR_1_04.fetch()
+
+ kernel_name = "ast1030-evb-demo/zephyr.elf"
+ with ZipFile(zip_file, 'r') as zf:
+ zf.extract(kernel_name, path=self.workdir)
+ kernel_file = os.path.join(self.workdir, kernel_name)
+
+ self.vm.set_console()
+ self.vm.add_args('-kernel', kernel_file, '-nographic')
+ self.vm.launch()
+ self.wait_for_console_pattern("Booting Zephyr OS")
+ exec_command_and_wait_for_pattern(self, "help",
+ "Available commands")
+
+ ASSET_ZEPHYR_1_07 = Asset(
+ ('https://github.com/AspeedTech-BMC'
+ '/zephyr/releases/download/v00.01.07/ast1030-evb-demo.zip'),
+ 'ad52e27959746988afaed8429bf4e12ab988c05c4d07c9d90e13ec6f7be4574c')
+
+ def test_ast1030_zephyros_1_07(self):
+ self.set_machine('ast1030-evb')
+
+ zip_file = self.ASSET_ZEPHYR_1_07.fetch()
+
+ kernel_name = "ast1030-evb-demo/zephyr.bin"
+ with ZipFile(zip_file, 'r') as zf:
+ zf.extract(kernel_name, path=self.workdir)
+ kernel_file = os.path.join(self.workdir, kernel_name)
+
+ self.vm.set_console()
+ self.vm.add_args('-kernel', kernel_file, '-nographic')
+ self.vm.launch()
+ self.wait_for_console_pattern("Booting Zephyr OS")
+ for shell_cmd in [
+ 'kernel stacks',
+ 'otp info conf',
+ 'otp info scu',
+ 'hwinfo devid',
+ 'crypto aes256_cbc_vault',
+ 'random get',
+ 'jtag JTAG1 sw_xfer high TMS',
+ 'adc ADC0 resolution 12',
+ 'adc ADC0 read 42',
+ 'adc ADC1 read 69',
+ 'i2c scan I2C_0',
+ 'i3c attach I3C_0',
+ 'hash test',
+ 'kernel uptime',
+ 'kernel reboot warm',
+ 'kernel uptime',
+ 'kernel reboot cold',
+ 'kernel uptime',
+ ]: exec_command_and_wait_for_pattern(self, shell_cmd, "uart:~$")
+
+class AST2x00Machine(LinuxKernelTest):
+
+ def do_test_arm_aspeed(self, machine, image):
+ self.set_machine(machine)
+ self.vm.set_console()
+ self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
+ '-net', 'nic', '-snapshot')
+ self.vm.launch()
+
+ self.wait_for_console_pattern("U-Boot 2016.07")
+ self.wait_for_console_pattern("## Loading kernel from FIT Image at 20080000")
+ self.wait_for_console_pattern("Starting kernel ...")
+ self.wait_for_console_pattern("Booting Linux on physical CPU 0x0")
+ self.wait_for_console_pattern(
+ "aspeed-smc 1e620000.spi: read control register: 203b0641")
+ self.wait_for_console_pattern("ftgmac100 1e660000.ethernet eth0: irq ")
+ self.wait_for_console_pattern("systemd[1]: Set hostname to")
+
+ ASSET_PALMETTO_FLASH = Asset(
+ ('https://github.com/openbmc/openbmc/releases/download/2.9.0/'
+ 'obmc-phosphor-image-palmetto.static.mtd'),
+ '3e13bbbc28e424865dc42f35ad672b10f2e82cdb11846bb28fa625b48beafd0d');
+
+ def test_arm_ast2400_palmetto_openbmc_v2_9_0(self):
+ image_path = self.ASSET_PALMETTO_FLASH.fetch()
+
+ self.do_test_arm_aspeed('palmetto-bmc', image_path)
+
+ ASSET_ROMULUS_FLASH = Asset(
+ ('https://github.com/openbmc/openbmc/releases/download/2.9.0/'
+ 'obmc-phosphor-image-romulus.static.mtd'),
+ '820341076803f1955bc31e647a512c79f9add4f5233d0697678bab4604c7bb25')
+
+ def test_arm_ast2500_romulus_openbmc_v2_9_0(self):
+ image_path = self.ASSET_ROMULUS_FLASH.fetch()
+
+ self.do_test_arm_aspeed('romulus-bmc', image_path)
+
+ def do_test_arm_aspeed_buildroot_start(self, image, cpu_id, pattern='Aspeed EVB'):
+ self.require_netdev('user')
+ self.vm.set_console()
+ self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
+ '-net', 'nic', '-net', 'user')
+ self.vm.launch()
+
+ self.wait_for_console_pattern('U-Boot 2019.04')
+ self.wait_for_console_pattern('## Loading kernel from FIT Image')
+ self.wait_for_console_pattern('Starting kernel ...')
+ self.wait_for_console_pattern('Booting Linux on physical CPU ' + cpu_id)
+ self.wait_for_console_pattern('lease of 10.0.2.15')
+ # the line before login:
+ self.wait_for_console_pattern(pattern)
+ time.sleep(0.1)
+ exec_command(self, 'root')
+ time.sleep(0.1)
+ exec_command(self, "passw0rd")
+
+ def do_test_arm_aspeed_buildroot_poweroff(self):
+ exec_command_and_wait_for_pattern(self, 'poweroff',
+ 'reboot: System halted');
+
+ ASSET_BR2_202311_AST2500_FLASH = Asset(
+ ('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
+ 'images/ast2500-evb/buildroot-2023.11/flash.img'),
+ 'c23db6160cf77d0258397eb2051162c8473a56c441417c52a91ba217186e715f')
+
+ def test_arm_ast2500_evb_buildroot(self):
+ self.set_machine('ast2500-evb')
+
+ image_path = self.ASSET_BR2_202311_AST2500_FLASH.fetch()
+
+ self.vm.add_args('-device',
+ 'tmp105,bus=aspeed.i2c.bus.3,address=0x4d,id=tmp-test');
+ self.do_test_arm_aspeed_buildroot_start(image_path, '0x0',
+ 'Aspeed AST2500 EVB')
+
+ exec_command_and_wait_for_pattern(self,
+ 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-3/device/new_device',
+ 'i2c i2c-3: new_device: Instantiated device lm75 at 0x4d');
+ exec_command_and_wait_for_pattern(self,
+ 'cat /sys/class/hwmon/hwmon1/temp1_input', '0')
+ self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test',
+ property='temperature', value=18000);
+ exec_command_and_wait_for_pattern(self,
+ 'cat /sys/class/hwmon/hwmon1/temp1_input', '18000')
+
+ self.do_test_arm_aspeed_buildroot_poweroff()
+
+ ASSET_BR2_202311_AST2600_FLASH = Asset(
+ ('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
+ 'images/ast2600-evb/buildroot-2023.11/flash.img'),
+ 'b62808daef48b438d0728ee07662290490ecfa65987bb91294cafb1bb7ad1a68')
+
+ def test_arm_ast2600_evb_buildroot(self):
+ self.set_machine('ast2600-evb')
+
+ image_path = self.ASSET_BR2_202311_AST2600_FLASH.fetch()
+
+ self.vm.add_args('-device',
+ 'tmp105,bus=aspeed.i2c.bus.3,address=0x4d,id=tmp-test');
+ self.vm.add_args('-device',
+ 'ds1338,bus=aspeed.i2c.bus.3,address=0x32');
+ self.vm.add_args('-device',
+ 'i2c-echo,bus=aspeed.i2c.bus.3,address=0x42');
+ self.do_test_arm_aspeed_buildroot_start(image_path, '0xf00', 'Aspeed AST2600 EVB')
+
+ exec_command_and_wait_for_pattern(self,
+ 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-3/device/new_device',
+ 'i2c i2c-3: new_device: Instantiated device lm75 at 0x4d');
+ exec_command_and_wait_for_pattern(self,
+ 'cat /sys/class/hwmon/hwmon1/temp1_input', '0')
+ self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test',
+ property='temperature', value=18000);
+ exec_command_and_wait_for_pattern(self,
+ 'cat /sys/class/hwmon/hwmon1/temp1_input', '18000')
+
+ exec_command_and_wait_for_pattern(self,
+ 'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-3/device/new_device',
+ 'i2c i2c-3: new_device: Instantiated device ds1307 at 0x32');
+ year = time.strftime("%Y")
+ exec_command_and_wait_for_pattern(self, 'hwclock -f /dev/rtc1', year);
+
+ exec_command_and_wait_for_pattern(self,
+ 'echo slave-24c02 0x1064 > /sys/bus/i2c/devices/i2c-3/new_device',
+ 'i2c i2c-3: new_device: Instantiated device slave-24c02 at 0x64');
+ exec_command(self, 'i2cset -y 3 0x42 0x64 0x00 0xaa i');
+ time.sleep(0.1)
+ exec_command_and_wait_for_pattern(self,
+ 'hexdump /sys/bus/i2c/devices/3-1064/slave-eeprom',
+ '0000000 ffaa ffff ffff ffff ffff ffff ffff ffff');
+ self.do_test_arm_aspeed_buildroot_poweroff()
+
+ ASSET_BR2_202302_AST2600_TPM_FLASH = Asset(
+ ('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
+ 'images/ast2600-evb/buildroot-2023.02-tpm/flash.img'),
+ 'a46009ae8a5403a0826d607215e731a8c68d27c14c41e55331706b8f9c7bd997')
+
+ @skipUnless(*has_cmd('swtpm'))
+ def test_arm_ast2600_evb_buildroot_tpm(self):
+ self.set_machine('ast2600-evb')
+
+ image_path = self.ASSET_BR2_202302_AST2600_TPM_FLASH.fetch()
+
+ socket_dir = tempfile.TemporaryDirectory(prefix="qemu_")
+ socket = os.path.join(socket_dir.name, 'swtpm-socket')
+
+ subprocess.run(['swtpm', 'socket', '-d', '--tpm2',
+ '--tpmstate', f'dir={self.vm.temp_dir}',
+ '--ctrl', f'type=unixio,path={socket}'])
+
+ self.vm.add_args('-chardev', f'socket,id=chrtpm,path={socket}')
+ self.vm.add_args('-tpmdev', 'emulator,id=tpm0,chardev=chrtpm')
+ self.vm.add_args('-device',
+ 'tpm-tis-i2c,tpmdev=tpm0,bus=aspeed.i2c.bus.12,address=0x2e')
+ self.do_test_arm_aspeed_buildroot_start(image_path, '0xf00', 'Aspeed AST2600 EVB')
+
+ exec_command_and_wait_for_pattern(self,
+ 'echo tpm_tis_i2c 0x2e > /sys/bus/i2c/devices/i2c-12/new_device',
+ 'tpm_tis_i2c 12-002e: 2.0 TPM (device-id 0x1, rev-id 1)');
+ exec_command_and_wait_for_pattern(self,
+ 'cat /sys/class/tpm/tpm0/pcr-sha256/0',
+ 'B804724EA13F52A9072BA87FE8FDCC497DFC9DF9AA15B9088694639C431688E0');
+
+ self.do_test_arm_aspeed_buildroot_poweroff()
+
+class AST2x00MachineMMC(LinuxKernelTest):
+
+ ASSET_RAINIER_EMMC = Asset(
+ ('https://fileserver.linaro.org/s/B6pJTwWEkzSDi36/download/'
+ 'mmc-p10bmc-20240617.qcow2'),
+ 'd523fb478d2b84d5adc5658d08502bc64b1486955683814f89c6137518acd90b')
+
+ def test_arm_aspeed_emmc_boot(self):
+ self.set_machine('rainier-bmc')
+ self.require_netdev('user')
+
+ image_path = self.ASSET_RAINIER_EMMC.fetch()
+
+ self.vm.set_console()
+ self.vm.add_args('-drive',
+ 'file=' + image_path + ',if=sd,id=sd2,index=2',
+ '-net', 'nic', '-net', 'user', '-snapshot')
+ self.vm.launch()
+
+ self.wait_for_console_pattern('U-Boot SPL 2019.04')
+ self.wait_for_console_pattern('Trying to boot from MMC1')
+ self.wait_for_console_pattern('U-Boot 2019.04')
+ self.wait_for_console_pattern('eMMC 2nd Boot')
+ self.wait_for_console_pattern('## Loading kernel from FIT Image')
+ self.wait_for_console_pattern('Starting kernel ...')
+ self.wait_for_console_pattern('Booting Linux on physical CPU 0xf00')
+ self.wait_for_console_pattern('mmcblk0: p1 p2 p3 p4 p5 p6 p7')
+ self.wait_for_console_pattern('IBM eBMC (OpenBMC for IBM Enterprise')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_arm_bflt.py b/tests/functional/test_arm_bflt.py
new file mode 100755
index 0000000..281925d
--- /dev/null
+++ b/tests/functional/test_arm_bflt.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python3
+#
+# Test the bFLT loader format
+#
+# Copyright (C) 2019 Philippe Mathieu-DaudƩ <f4bug@amsat.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+import bz2
+
+from qemu_test import QemuUserTest, Asset
+from qemu_test import has_cmd
+from qemu_test.utils import cpio_extract
+from unittest import skipUnless
+
+
+class LoadBFLT(QemuUserTest):
+
+ ASSET_ROOTFS = Asset(
+ ('https://elinux.org/images/5/51/Stm32_mini_rootfs.cpio.bz2'),
+ 'eefb788e4980c9e8d6c9d60ce7d15d4da6bf4fbc6a80f487673824600d5ba9cc')
+
+ @skipUnless(*has_cmd('cpio'))
+ @skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
+ def test_stm32(self):
+ # See https://elinux.org/STM32#User_Space
+ rootfs_path_bz2 = self.ASSET_ROOTFS.fetch()
+ busybox_path = os.path.join(self.workdir, "bin/busybox")
+
+ with bz2.open(rootfs_path_bz2, 'rb') as cpio_handle:
+ cpio_extract(cpio_handle, self.workdir)
+
+ res = self.run_cmd(busybox_path)
+ ver = 'BusyBox v1.24.0.git (2015-02-03 22:17:13 CET) multi-call binary.'
+ self.assertIn(ver, res.stdout)
+
+ res = self.run_cmd(busybox_path, ['uname', '-a'])
+ unm = 'armv7l GNU/Linux'
+ self.assertIn(unm, res.stdout)
+
+
+if __name__ == '__main__':
+ QemuUserTest.main()
diff --git a/tests/avocado/machine_arm_canona1100.py b/tests/functional/test_arm_canona1100.py
index a42d8b0..65f1228 100644..100755
--- a/tests/avocado/machine_arm_canona1100.py
+++ b/tests/functional/test_arm_canona1100.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Functional test that boots the canon-a1100 machine with firmware
#
# Copyright (c) 2020 Red Hat, Inc.
@@ -8,28 +10,30 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
-from avocado.utils import archive
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern
+from qemu_test.utils import archive_extract
class CanonA1100Machine(QemuSystemTest):
"""Boots the barebox firmware and checks that the console is operational"""
timeout = 90
+ ASSET_BIOS = Asset(('https://qemu-advcal.gitlab.io'
+ '/qac-best-of-multiarch/download/day18.tar.xz'),
+ '28e71874ce985be66b7fd1345ed88cb2523b982f899c8d2900d6353054a1be49')
+
def test_arm_canona1100(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:canon-a1100
- :avocado: tags=device:pflash_cfi02
- """
- tar_url = ('https://qemu-advcal.gitlab.io'
- '/qac-best-of-multiarch/download/day18.tar.xz')
- tar_hash = '068b5fc4242b29381acee94713509f8a876e9db6'
- file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- archive.extract(file_path, self.workdir)
+ self.set_machine('canon-a1100')
+
+ file_path = self.ASSET_BIOS.fetch()
+ archive_extract(file_path, dest_dir=self.workdir,
+ member="day18/barebox.canon-a1100.bin")
self.vm.set_console()
self.vm.add_args('-bios',
self.workdir + '/day18/barebox.canon-a1100.bin')
self.vm.launch()
wait_for_console_pattern(self, 'running /env/bin/init')
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/avocado/machine_arm_integratorcp.py b/tests/functional/test_arm_integratorcp.py
index 87f5cf3..0fe083f 100644..100755
--- a/tests/avocado/machine_arm_integratorcp.py
+++ b/tests/functional/test_arm_integratorcp.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Functional test that boots a Linux kernel and checks the console
#
# Copyright (c) 2020 Red Hat, Inc.
@@ -7,13 +9,15 @@
#
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
import os
import logging
-from avocado import skipUnless
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern
+from unittest import skipUnless
NUMPY_AVAILABLE = True
@@ -33,50 +37,49 @@ class IntegratorMachine(QemuSystemTest):
timeout = 90
- def boot_integratorcp(self):
- kernel_url = ('https://github.com/zayac/qemu-arm/raw/master/'
- 'arm-test/kernel/zImage.integrator')
- kernel_hash = '0d7adba893c503267c946a3cbdc63b4b54f25468'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
+ ASSET_KERNEL = Asset(
+ ('https://github.com/zayac/qemu-arm/raw/master/'
+ 'arm-test/kernel/zImage.integrator'),
+ '26e7c7e8f943de785d95bd3c74d66451604a9b6a7a3d25dceb279e7548fd8e78')
+
+ ASSET_INITRD = Asset(
+ ('https://github.com/zayac/qemu-arm/raw/master/'
+ 'arm-test/kernel/arm_root.img'),
+ 'e187c27fb342ad148c7f33475fbed124933e0b3f4be8c74bc4f3426a4793373a')
- initrd_url = ('https://github.com/zayac/qemu-arm/raw/master/'
- 'arm-test/kernel/arm_root.img')
- initrd_hash = 'b51e4154285bf784e017a37586428332d8c7bd8b'
- initrd_path = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
+ ASSET_TUXLOGO = Asset(
+ ('https://github.com/torvalds/linux/raw/v2.6.12/'
+ 'drivers/video/logo/logo_linux_vga16.ppm'),
+ 'b762f0d91ec018887ad1b334543c2fdf9be9fdfc87672b409211efaa3ea0ef79')
+ def boot_integratorcp(self):
+ kernel_path = self.ASSET_KERNEL.fetch()
+ initrd_path = self.ASSET_INITRD.fetch()
+
+ self.set_machine('integratorcp')
self.vm.set_console()
self.vm.add_args('-kernel', kernel_path,
'-initrd', initrd_path,
'-append', 'printk.time=0 console=ttyAMA0')
self.vm.launch()
- @skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
+ @skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
def test_integratorcp_console(self):
"""
Boots the Linux kernel and checks that the console is operational
- :avocado: tags=arch:arm
- :avocado: tags=machine:integratorcp
- :avocado: tags=device:pl011
"""
self.boot_integratorcp()
wait_for_console_pattern(self, 'Log in as root')
@skipUnless(NUMPY_AVAILABLE, 'Python NumPy not installed')
@skipUnless(CV2_AVAILABLE, 'Python OpenCV not installed')
- @skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
+ @skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
def test_framebuffer_tux_logo(self):
"""
Boot Linux and verify the Tux logo is displayed on the framebuffer.
- :avocado: tags=arch:arm
- :avocado: tags=machine:integratorcp
- :avocado: tags=device:pl110
- :avocado: tags=device:framebuffer
"""
screendump_path = os.path.join(self.workdir, "screendump.pbm")
- tuxlogo_url = ('https://github.com/torvalds/linux/raw/v2.6.12/'
- 'drivers/video/logo/logo_linux_vga16.ppm')
- tuxlogo_hash = '3991c2ddbd1ddaecda7601f8aafbcf5b02dc86af'
- tuxlogo_path = self.fetch_asset(tuxlogo_url, asset_hash=tuxlogo_hash)
+ tuxlogo_path = self.ASSET_TUXLOGO.fetch()
self.boot_integratorcp()
framebuffer_ready = 'Console: switching to colour frame buffer device'
@@ -97,3 +100,6 @@ class IntegratorMachine(QemuSystemTest):
for tux_count, pt in enumerate(zip(*loc[::-1]), start=1):
logger.debug('found Tux at position [x, y] = %s', pt)
self.assertGreaterEqual(tux_count, cpu_count)
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_arm_raspi2.py b/tests/functional/test_arm_raspi2.py
new file mode 100755
index 0000000..3bf079d
--- /dev/null
+++ b/tests/functional/test_arm_raspi2.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on a Raspberry Pi machine
+# and checks the console
+#
+# Copyright (c) 2019 Philippe Mathieu-DaudƩ <f4bug@amsat.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test import exec_command_and_wait_for_pattern
+from qemu_test.utils import gzip_uncompress
+
+
+class ArmRaspi2Machine(LinuxKernelTest):
+
+ ASSET_KERNEL_20190215 = Asset(
+ ('http://archive.raspberrypi.org/debian/'
+ 'pool/main/r/raspberrypi-firmware/'
+ 'raspberrypi-kernel_1.20190215-1_armhf.deb'),
+ '9f1759f7228113da24f5ee2aa6312946ec09a83e076aba9406c46ff776dfb291')
+
+ ASSET_INITRD = Asset(
+ ('https://github.com/groeck/linux-build-test/raw/'
+ '2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
+ 'arm/rootfs-armv7a.cpio.gz'),
+ '2c8dbdb16ea7af2dfbcbea96044dde639fb07d09fd3c4fb31f2027ef71e55ddd')
+
+ def do_test_arm_raspi2(self, uart_id):
+ """
+ The kernel can be rebuilt using the kernel source referenced
+ and following the instructions on the on:
+ https://www.raspberrypi.org/documentation/linux/kernel/building.md
+ """
+ serial_kernel_cmdline = {
+ 0: 'earlycon=pl011,0x3f201000 console=ttyAMA0',
+ }
+ deb_path = self.ASSET_KERNEL_20190215.fetch()
+ kernel_path = self.extract_from_deb(deb_path, '/boot/kernel7.img')
+ dtb_path = self.extract_from_deb(deb_path, '/boot/bcm2709-rpi-2-b.dtb')
+
+ self.set_machine('raspi2b')
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ serial_kernel_cmdline[uart_id] +
+ ' root=/dev/mmcblk0p2 rootwait ' +
+ 'dwc_otg.fiq_fsm_enable=0')
+ self.vm.add_args('-kernel', kernel_path,
+ '-dtb', dtb_path,
+ '-append', kernel_command_line,
+ '-device', 'usb-kbd')
+ self.vm.launch()
+
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.wait_for_console_pattern(console_pattern)
+ self.wait_for_console_pattern('Product: QEMU USB Keyboard')
+
+ def test_arm_raspi2_uart0(self):
+ self.do_test_arm_raspi2(0)
+
+ def test_arm_raspi2_initrd(self):
+ deb_path = self.ASSET_KERNEL_20190215.fetch()
+ kernel_path = self.extract_from_deb(deb_path, '/boot/kernel7.img')
+ dtb_path = self.extract_from_deb(deb_path, '/boot/bcm2709-rpi-2-b.dtb')
+ initrd_path_gz = self.ASSET_INITRD.fetch()
+ initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
+ gzip_uncompress(initrd_path_gz, initrd_path)
+
+ self.set_machine('raspi2b')
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'earlycon=pl011,0x3f201000 console=ttyAMA0 '
+ 'panic=-1 noreboot ' +
+ 'dwc_otg.fiq_fsm_enable=0')
+ self.vm.add_args('-kernel', kernel_path,
+ '-dtb', dtb_path,
+ '-initrd', initrd_path,
+ '-append', kernel_command_line,
+ '-no-reboot')
+ self.vm.launch()
+ self.wait_for_console_pattern('Boot successful.')
+
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
+ 'BCM2835')
+ exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
+ '/soc/cprman@7e101000')
+ exec_command_and_wait_for_pattern(self, 'halt', 'reboot: System halted')
+ # Wait for VM to shut down gracefully
+ self.vm.wait()
+
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_arm_tuxrun.py b/tests/functional/test_arm_tuxrun.py
new file mode 100755
index 0000000..944f075
--- /dev/null
+++ b/tests/functional/test_arm_tuxrun.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex BennƩe <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunArmTest(TuxRunBaselineTest):
+
+ ASSET_ARMV5_KERNEL = Asset(
+ 'https://storage.tuxboot.com/20230331/armv5/zImage',
+ 'c95af2f27647c12265d75e9df44c22ff5228c59855f54aaa70f41ec2842e3a4d')
+ ASSET_ARMV5_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/20230331/armv5/rootfs.ext4.zst',
+ '17177afa74e7294da0642861f08c88ca3c836764299a54bf6d1ce276cb9712a5')
+ ASSET_ARMV5_DTB = Asset(
+ 'https://storage.tuxboot.com/20230331/armv5/versatile-pb.dtb',
+ '0bc0c0b0858cefd3c32b385c0d66d97142ded29472a496f4f490e42fc7615b25')
+
+ def test_armv5(self):
+ self.set_machine('versatilepb')
+ self.cpu='arm926'
+ self.console='ttyAMA0'
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_ARMV5_KERNEL,
+ rootfs_asset=self.ASSET_ARMV5_ROOTFS,
+ dtb_asset=self.ASSET_ARMV5_DTB,
+ drive="virtio-blk-pci")
+
+ ASSET_ARMV7_KERNEL = Asset(
+ 'https://storage.tuxboot.com/20230331/armv7/zImage',
+ '4c7a22e9f15875bec06bd2a29d822496571eb297d4f22694099ffcdb19077572')
+ ASSET_ARMV7_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/20230331/armv7/rootfs.ext4.zst',
+ 'ab1fbbeaddda1ffdd45c9405a28cd5370c20f23a7cbc809cc90dc9f243a8eb5a')
+
+ def test_armv7(self):
+ self.set_machine('virt')
+ self.cpu='cortex-a15'
+ self.console='ttyAMA0'
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_ARMV7_KERNEL,
+ rootfs_asset=self.ASSET_ARMV7_ROOTFS)
+
+ ASSET_ARMV7BE_KERNEL = Asset(
+ 'https://storage.tuxboot.com/20230331/armv7be/zImage',
+ '7facc62082b57af12015b08f7fdbaf2f123ba07a478367853ae12b219afc9f2f')
+ ASSET_ARMV7BE_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/20230331/armv7be/rootfs.ext4.zst',
+ '42ed46dd2d59986206c5b1f6cf35eab58fe3fd20c96b41aaa16b32f3f90a9835')
+
+ def test_armv7be(self):
+ self.set_machine('virt')
+ self.cpu='cortex-a15'
+ self.console='ttyAMA0'
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_ARMV7BE_KERNEL,
+ rootfs_asset=self.ASSET_ARMV7BE_ROOTFS)
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_arm_vexpress.py b/tests/functional/test_arm_vexpress.py
new file mode 100755
index 0000000..6bd6290
--- /dev/null
+++ b/tests/functional/test_arm_vexpress.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on an versatile express machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test.utils import archive_extract
+
+class VExpressTest(LinuxKernelTest):
+
+ ASSET_DAY16 = Asset(
+ 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day16.tar.xz',
+ '63311adb2d4c4e7a73214a86d29988add87266a909719c56acfadd026b4110a7')
+
+ def test_arm_vexpressa9(self):
+ self.set_machine('vexpress-a9')
+ file_path = self.ASSET_DAY16.fetch()
+ archive_extract(file_path, self.workdir)
+ self.launch_kernel(self.workdir + '/day16/winter.zImage',
+ dtb=self.workdir + '/day16/vexpress-v2p-ca9.dtb',
+ wait_for='QEMU advent calendar')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/avocado/machine_avr6.py b/tests/functional/test_avr_mega2560.py
index 5485db7..8e47b42 100644..100755
--- a/tests/avocado/machine_avr6.py
+++ b/tests/functional/test_avr_mega2560.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python3
#
# QEMU AVR integration tests
#
@@ -19,26 +20,24 @@
import time
-from avocado_qemu import QemuSystemTest
+from qemu_test import QemuSystemTest, Asset
class AVR6Machine(QemuSystemTest):
timeout = 5
+ ASSET_ROM = Asset(('https://github.com/seharris/qemu-avr-tests'
+ '/raw/36c3e67b8755dcf/free-rtos/Demo'
+ '/AVR_ATMega2560_GCC/demo.elf'),
+ 'ee4833bd65fc69e84a79ed1c608affddbd499a60e63acf87d9113618401904e4')
+
def test_freertos(self):
"""
- :avocado: tags=arch:avr
- :avocado: tags=machine:arduino-mega-2560-v3
- """
- """
https://github.com/seharris/qemu-avr-tests/raw/master/free-rtos/Demo/AVR_ATMega2560_GCC/demo.elf
constantly prints out 'ABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWX'
"""
- rom_url = ('https://github.com/seharris/qemu-avr-tests'
- '/raw/36c3e67b8755dcf/free-rtos/Demo'
- '/AVR_ATMega2560_GCC/demo.elf')
- rom_hash = '7eb521f511ca8f2622e0a3c5e8dd686efbb911d4'
- rom_path = self.fetch_asset(rom_url, asset_hash=rom_hash)
+ rom_path = self.ASSET_ROM.fetch()
+ self.set_machine('arduino-mega-2560-v3')
self.vm.add_args('-bios', rom_path)
self.vm.add_args('-nographic')
self.vm.launch()
@@ -48,3 +47,6 @@ class AVR6Machine(QemuSystemTest):
self.assertIn('ABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWX',
self.vm.get_log())
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/avocado/cpu_queries.py b/tests/functional/test_cpu_queries.py
index d3faa14..b1122a0 100644..100755
--- a/tests/avocado/cpu_queries.py
+++ b/tests/functional/test_cpu_queries.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Sanity check of query-cpu-* results
#
# Copyright (c) 2019 Red Hat, Inc.
@@ -8,7 +10,7 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from avocado_qemu import QemuSystemTest
+from qemu_test import QemuSystemTest
class QueryCPUModelExpansion(QemuSystemTest):
"""
@@ -16,10 +18,7 @@ class QueryCPUModelExpansion(QemuSystemTest):
"""
def test(self):
- """
- :avocado: tags=arch:x86_64
- :avocado: tags=machine:none
- """
+ self.set_machine('none')
self.vm.add_args('-S')
self.vm.launch()
@@ -33,3 +32,6 @@ class QueryCPUModelExpansion(QemuSystemTest):
e = self.vm.cmd('query-cpu-model-expansion', model=model,
type='full')
self.assertEqual(e['model']['name'], c['name'])
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/avocado/empty_cpu_model.py b/tests/functional/test_empty_cpu_model.py
index d906ef3..0081b06 100644..100755
--- a/tests/avocado/empty_cpu_model.py
+++ b/tests/functional/test_empty_cpu_model.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Check for crash when using empty -cpu option
#
# Copyright (c) 2019 Red Hat, Inc.
@@ -7,7 +9,7 @@
#
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from avocado_qemu import QemuSystemTest
+from qemu_test import QemuSystemTest
class EmptyCPUModel(QemuSystemTest):
def test(self):
@@ -17,3 +19,6 @@ class EmptyCPUModel(QemuSystemTest):
self.vm.wait()
self.assertEqual(self.vm.exitcode(), 1, "QEMU exit code should be 1")
self.assertRegex(self.vm.get_log(), r'-cpu option cannot be empty')
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_i386_tuxrun.py b/tests/functional/test_i386_tuxrun.py
new file mode 100755
index 0000000..c593ffb
--- /dev/null
+++ b/tests/functional/test_i386_tuxrun.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex BennƩe <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunI386Test(TuxRunBaselineTest):
+
+ ASSET_I386_KERNEL = Asset(
+ 'https://storage.tuxboot.com/20230331/i386/bzImage',
+ 'a3e5b32a354729e65910f5a1ffcda7c14a6c12a55e8213fb86e277f1b76ed956')
+ ASSET_I386_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/20230331/i386/rootfs.ext4.zst',
+ 'f15e66b2bf673a210ec2a4b2e744a80530b36289e04f5388aab812b97f69754a')
+
+ def test_i386(self):
+ self.set_machine('q35')
+ self.cpu="coreduo"
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_I386_KERNEL,
+ rootfs_asset=self.ASSET_I386_ROOTFS,
+ drive="virtio-blk-pci")
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/avocado/info_usernet.py b/tests/functional/test_info_usernet.py
index e1aa7a6..cd37524 100644..100755
--- a/tests/avocado/info_usernet.py
+++ b/tests/functional/test_info_usernet.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Test for the hmp command "info usernet"
#
# Copyright (c) 2021 Red Hat, Inc.
@@ -8,18 +10,16 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from avocado_qemu import QemuSystemTest
+from qemu_test import QemuSystemTest
from qemu.utils import get_info_usernet_hostfwd_port
class InfoUsernet(QemuSystemTest):
- """
- :avocado: tags=machine:none
- """
def test_hostfwd(self):
self.require_netdev('user')
+ self.set_machine('none')
self.vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22')
self.vm.launch()
res = self.vm.cmd('human-monitor-command',
@@ -31,3 +31,6 @@ class InfoUsernet(QemuSystemTest):
self.assertGreater(port, 0,
('Found a redirected port that is not greater than'
' zero'))
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/avocado/linux_initrd.py b/tests/functional/test_linux_initrd.py
index aad5b19..c71a59d 100644..100755
--- a/tests/avocado/linux_initrd.py
+++ b/tests/functional/test_linux_initrd.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Linux initrd integration test.
#
# Copyright (c) 2018 Red Hat, Inc.
@@ -12,20 +14,27 @@ import os
import logging
import tempfile
-from avocado_qemu import QemuSystemTest
-from avocado import skipUnless
+from qemu_test import QemuSystemTest, Asset
+from unittest import skipUnless
class LinuxInitrd(QemuSystemTest):
"""
Checks QEMU evaluates correctly the initrd file passed as -initrd option.
-
- :avocado: tags=arch:x86_64
- :avocado: tags=machine:pc
"""
timeout = 300
+ ASSET_F18_KERNEL = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/'
+ 'releases/18/Fedora/x86_64/os/images/pxeboot/vmlinuz'),
+ '1a27cb42559ce29237ac186699d063556ad69c8349d732bb1bd8d614e5a8cc2e')
+
+ ASSET_F28_KERNEL = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/'
+ 'releases/28/Everything/x86_64/os/images/pxeboot/vmlinuz'),
+ 'd05909c9d4a742a6fcc84dcc0361009e4611769619cc187a07107579a035f24e')
+
def test_with_2gib_file_should_exit_error_msg_with_linux_v3_6(self):
"""
Pretends to boot QEMU with an initrd file with size of 2GiB
@@ -33,10 +42,8 @@ class LinuxInitrd(QemuSystemTest):
Fedora-18 shipped with linux-3.6 which have not supported xloadflags
cannot support more than 2GiB initrd.
"""
- kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora/li'
- 'nux/releases/18/Fedora/x86_64/os/images/pxeboot/vmlinuz')
- kernel_hash = '41464f68efe42b9991250bed86c7081d2ccdbb21'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
+ self.set_machine('pc')
+ kernel_path = self.ASSET_F18_KERNEL.fetch()
max_size = 2 * (1024 ** 3) - 1
with tempfile.NamedTemporaryFile() as initrd:
@@ -54,19 +61,13 @@ class LinuxInitrd(QemuSystemTest):
self.assertRegex(self.vm.get_log(), expected_msg)
@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
-
def test_with_2gib_file_should_work_with_linux_v4_16(self):
"""
- :avocado: tags=flaky
-
QEMU has supported up to 4 GiB initrd for recent kernel
Expect guest can reach 'Unpacking initramfs...'
"""
- kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
- '/linux/releases/28/Everything/x86_64/os/images/pxeboot/'
- 'vmlinuz')
- kernel_hash = '238e083e114c48200f80d889f7e32eeb2793e02a'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
+ self.set_machine('pc')
+ kernel_path = self.ASSET_F28_KERNEL.fetch()
max_size = 2 * (1024 ** 3) + 1
with tempfile.NamedTemporaryFile() as initrd:
@@ -90,3 +91,6 @@ class LinuxInitrd(QemuSystemTest):
break
if 'Kernel panic - not syncing' in msg:
self.fail("Kernel panic reached")
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/avocado/machine_loongarch.py b/tests/functional/test_loongarch64_virt.py
index 8de308f..2b8baa2 100644..100755
--- a/tests/avocado/machine_loongarch.py
+++ b/tests/functional/test_loongarch64_virt.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# SPDX-License-Identifier: GPL-2.0-or-later
#
# LoongArch virt test.
@@ -5,15 +7,28 @@
# Copyright (c) 2023 Loongson Technology Corporation Limited
#
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import exec_command_and_wait_for_pattern
-from avocado_qemu import wait_for_console_pattern
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import exec_command_and_wait_for_pattern
+from qemu_test import wait_for_console_pattern
class LoongArchMachine(QemuSystemTest):
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
timeout = 120
+ ASSET_KERNEL = Asset(
+ ('https://github.com/yangxiaojuan-loongson/qemu-binary/'
+ 'releases/download/2024-05-30/vmlinuz.efi'),
+ '08b88a45f48a5fd92260bae895be4e5175be2397481a6f7821b9f39b2965b79e')
+ ASSET_INITRD = Asset(
+ ('https://github.com/yangxiaojuan-loongson/qemu-binary/'
+ 'releases/download/2024-05-30/ramdisk'),
+ '03d6fb6f8ee64ecac961120a0bdacf741f17b3bee2141f17fa01908c8baf176a')
+ ASSET_BIOS = Asset(
+ ('https://github.com/yangxiaojuan-loongson/qemu-binary/'
+ 'releases/download/2024-05-30/QEMU_EFI.fd'),
+ '937c1e7815e2340150c194a9f8f0474259038a3d7b8845ed62cc08163c46bea1')
+
def wait_for_console_pattern(self, success_message, vm=None):
wait_for_console_pattern(self, success_message,
failure_message='Kernel panic - not syncing',
@@ -21,25 +36,11 @@ class LoongArchMachine(QemuSystemTest):
def test_loongarch64_devices(self):
- """
- :avocado: tags=arch:loongarch64
- :avocado: tags=machine:virt
- """
-
- kernel_url = ('https://github.com/yangxiaojuan-loongson/qemu-binary/'
- 'releases/download/2024-05-30/vmlinuz.efi')
- kernel_hash = '951b485b16e3788b6db03a3e1793c067009e31a2'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
+ self.set_machine('virt')
- initrd_url = ('https://github.com/yangxiaojuan-loongson/qemu-binary/'
- 'releases/download/2024-05-30/ramdisk')
- initrd_hash = 'c67658d9b2a447ce7db2f73ba3d373c9b2b90ab2'
- initrd_path = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
-
- bios_url = ('https://github.com/yangxiaojuan-loongson/qemu-binary/'
- 'releases/download/2024-05-30/QEMU_EFI.fd')
- bios_hash = ('f4d0966b5117d4cd82327c050dd668741046be69')
- bios_path = self.fetch_asset(bios_url, asset_hash=bios_hash)
+ kernel_path = self.ASSET_KERNEL.fetch()
+ initrd_path = self.ASSET_INITRD.fetch()
+ bios_path = self.ASSET_BIOS.fetch()
self.vm.set_console()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
@@ -56,3 +57,6 @@ class LoongArchMachine(QemuSystemTest):
self.wait_for_console_pattern('Run /sbin/init as init process')
exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
'processor : 3')
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_m68k_mcf5208evb.py b/tests/functional/test_m68k_mcf5208evb.py
new file mode 100755
index 0000000..00c5959
--- /dev/null
+++ b/tests/functional/test_m68k_mcf5208evb.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on an MCF5208EVB machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test.utils import archive_extract
+
+class Mcf5208EvbTest(LinuxKernelTest):
+
+ ASSET_DAY07 = Asset(
+ 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day07.tar.xz',
+ '753c2f3837126b7c6ba92d0b1e0b156e8a2c5131d2d576bb0b9a763fae73c08a')
+
+ def test_m68k_mcf5208evb(self):
+ self.set_machine('mcf5208evb')
+ file_path = self.ASSET_DAY07.fetch()
+ archive_extract(file_path, self.workdir)
+ self.vm.set_console()
+ self.vm.add_args('-kernel', self.workdir + '/day07/sanity-clause.elf')
+ self.vm.launch()
+ self.wait_for_console_pattern('QEMU advent calendar')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/avocado/machine_m68k_nextcube.py b/tests/functional/test_m68k_nextcube.py
index 1f3c883..89385a1 100644..100755
--- a/tests/avocado/machine_m68k_nextcube.py
+++ b/tests/functional/test_m68k_nextcube.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Functional test that boots a VM and run OCR on the framebuffer
#
# Copyright (c) 2019 Philippe Mathieu-DaudƩ <f4bug@amsat.org>
@@ -8,10 +10,10 @@
import os
import time
-from avocado_qemu import QemuSystemTest
-from avocado import skipUnless
+from qemu_test import QemuSystemTest, Asset
+from unittest import skipUnless
-from tesseract_utils import tesseract_available, tesseract_ocr
+from qemu_test.tesseract import tesseract_available, tesseract_ocr
PIL_AVAILABLE = True
try:
@@ -21,19 +23,15 @@ except ImportError:
class NextCubeMachine(QemuSystemTest):
- """
- :avocado: tags=arch:m68k
- :avocado: tags=machine:next-cube
- :avocado: tags=device:framebuffer
- """
timeout = 15
+ ASSET_ROM = Asset(('https://sourceforge.net/p/previous/code/1350/tree/'
+ 'trunk/src/Rev_2.5_v66.BIN?format=raw'),
+ '1b753890b67095b73e104c939ddf62eca9e7d0aedde5108e3893b0ed9d8000a4')
+
def check_bootrom_framebuffer(self, screenshot_path):
- rom_url = ('https://sourceforge.net/p/previous/code/1350/tree/'
- 'trunk/src/Rev_2.5_v66.BIN?format=raw')
- rom_hash = 'b3534796abae238a0111299fc406a9349f7fee24'
- rom_path = self.fetch_asset(rom_url, asset_hash=rom_hash)
+ rom_path = self.ASSET_ROM.fetch()
self.vm.add_args('-bios', rom_path)
self.vm.launch()
@@ -48,6 +46,7 @@ class NextCubeMachine(QemuSystemTest):
@skipUnless(PIL_AVAILABLE, 'Python PIL not installed')
def test_bootrom_framebuffer_size(self):
+ self.set_machine('next-cube')
screenshot_path = os.path.join(self.workdir, "dump.ppm")
self.check_bootrom_framebuffer(screenshot_path)
@@ -60,11 +59,15 @@ class NextCubeMachine(QemuSystemTest):
# that it is still alpha-level software.
@skipUnless(tesseract_available(4), 'tesseract OCR tool not available')
def test_bootrom_framebuffer_ocr_with_tesseract(self):
+ self.set_machine('next-cube')
screenshot_path = os.path.join(self.workdir, "dump.ppm")
self.check_bootrom_framebuffer(screenshot_path)
- lines = tesseract_ocr(screenshot_path, tesseract_version=4)
+ lines = tesseract_ocr(screenshot_path)
text = '\n'.join(lines)
self.assertIn('Testing the FPU', text)
self.assertIn('System test failed. Error code', text)
self.assertIn('Boot command', text)
self.assertIn('Next>', text)
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_m68k_q800.py b/tests/functional/test_m68k_q800.py
new file mode 100755
index 0000000..3b17244
--- /dev/null
+++ b/tests/functional/test_m68k_q800.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python3
+#
+# Functional test for testing the q800 m68k machine
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+from qemu_test import LinuxKernelTest, Asset
+
+class Q800MachineTest(LinuxKernelTest):
+
+ ASSET_KERNEL = Asset(
+ ('https://snapshot.debian.org/'
+ 'archive/debian-ports/20191021T083923Z/pool-m68k/main/l/linux/'
+ 'kernel-image-5.3.0-1-m68k-di_5.3.7-1_m68k.udeb'),
+ '949e50d74d4b9bc15d26c06d402717b7a4c0e32ff8100014f5930d8024de7b73')
+
+ def test_m68k_q800(self):
+ self.set_machine('q800')
+
+ deb_path = self.ASSET_KERNEL.fetch()
+ kernel_path = self.extract_from_deb(deb_path,
+ '/boot/vmlinux-5.3.0-1-m68k')
+
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'console=ttyS0 vga=off')
+ self.vm.add_args('-kernel', kernel_path,
+ '-append', kernel_command_line)
+ self.vm.launch()
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.wait_for_console_pattern(console_pattern)
+ console_pattern = 'No filesystem could mount root'
+ self.wait_for_console_pattern(console_pattern)
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/avocado/mem-addr-space-check.py b/tests/functional/test_mem_addr_space.py
index 85541ea..bb0cf06 100644..100755
--- a/tests/avocado/mem-addr-space-check.py
+++ b/tests/functional/test_mem_addr_space.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Check for crash when using memory beyond the available guest processor
# address space.
#
@@ -8,8 +10,7 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
-from avocado_qemu import QemuSystemTest
-import signal
+from qemu_test import QemuSystemTest
import time
class MemAddrCheck(QemuSystemTest):
@@ -23,9 +24,6 @@ class MemAddrCheck(QemuSystemTest):
# for all 32-bit cases, pci64_hole_size is 0.
def test_phybits_low_pse36(self):
"""
- :avocado: tags=machine:q35
- :avocado: tags=arch:x86_64
-
With pse36 feature ON, a processor has 36 bits of addressing. So it can
access up to a maximum of 64GiB of memory. Memory hotplug region begins
at 4 GiB boundary when "above_4g_mem_size" is 0 (this would be true when
@@ -53,9 +51,6 @@ class MemAddrCheck(QemuSystemTest):
def test_phybits_low_pae(self):
"""
- :avocado: tags=machine:q35
- :avocado: tags=arch:x86_64
-
With pae feature ON, a processor has 36 bits of addressing. So it can
access up to a maximum of 64GiB of memory. Rest is the same as the case
with pse36 above.
@@ -73,9 +68,6 @@ class MemAddrCheck(QemuSystemTest):
def test_phybits_ok_pentium_pse36(self):
"""
- :avocado: tags=machine:q35
- :avocado: tags=arch:x86_64
-
Setting maxmem to 59.5G and making sure that QEMU can start with the
same options as the failing case above with pse36 cpu feature.
"""
@@ -92,9 +84,6 @@ class MemAddrCheck(QemuSystemTest):
def test_phybits_ok_pentium_pae(self):
"""
- :avocado: tags=machine:q35
- :avocado: tags=arch:x86_64
-
Test is same as above but now with pae cpu feature turned on.
Setting maxmem to 59.5G and making sure that QEMU can start fine
with the same options as the case above.
@@ -112,9 +101,6 @@ class MemAddrCheck(QemuSystemTest):
def test_phybits_ok_pentium2(self):
"""
- :avocado: tags=machine:q35
- :avocado: tags=arch:x86_64
-
Pentium2 has 36 bits of addressing, so its same as pentium
with pse36 ON.
"""
@@ -131,9 +117,6 @@ class MemAddrCheck(QemuSystemTest):
def test_phybits_low_nonpse36(self):
"""
- :avocado: tags=machine:q35
- :avocado: tags=arch:x86_64
-
Pentium processor has 32 bits of addressing without pse36 or pae
so it can access physical address up to 4 GiB. Setting maxmem to
4 GiB should make QEMU fail to start with "phys-bits too low"
@@ -154,9 +137,6 @@ class MemAddrCheck(QemuSystemTest):
# now lets test some 64-bit CPU cases.
def test_phybits_low_tcg_q35_70_amd(self):
"""
- :avocado: tags=machine:q35
- :avocado: tags=arch:x86_64
-
For q35 7.1 machines and above, there is a HT window that starts at
1024 GiB and ends at 1 TiB - 1. If the max GPA falls in this range,
"above_4G" memory is adjusted to start at 1 TiB boundary for AMD cpus
@@ -183,9 +163,6 @@ class MemAddrCheck(QemuSystemTest):
def test_phybits_low_tcg_q35_71_amd(self):
"""
- :avocado: tags=machine:q35
- :avocado: tags=arch:x86_64
-
AMD_HT_START is defined to be at 1012 GiB. So for q35 machines
version > 7.0 and AMD cpus, instead of 1024 GiB limit for 40 bit
processor address space, it has to be 1012 GiB , that is 12 GiB
@@ -206,9 +183,6 @@ class MemAddrCheck(QemuSystemTest):
def test_phybits_ok_tcg_q35_70_amd(self):
"""
- :avocado: tags=machine:q35
- :avocado: tags=arch:x86_64
-
Same as q35-7.0 AMD case except that here we check that QEMU can
successfully start when maxmem is < 988G.
"""
@@ -225,9 +199,6 @@ class MemAddrCheck(QemuSystemTest):
def test_phybits_ok_tcg_q35_71_amd(self):
"""
- :avocado: tags=machine:q35
- :avocado: tags=arch:x86_64
-
Same as q35-7.1 AMD case except that here we check that QEMU can
successfully start when maxmem is < 976G.
"""
@@ -244,9 +215,6 @@ class MemAddrCheck(QemuSystemTest):
def test_phybits_ok_tcg_q35_71_intel(self):
"""
- :avocado: tags=machine:q35
- :avocado: tags=arch:x86_64
-
Same parameters as test_phybits_low_tcg_q35_71_amd() but use
Intel cpu instead. QEMU should start fine in this case as
"above_4G" memory starts at 4G.
@@ -265,9 +233,6 @@ class MemAddrCheck(QemuSystemTest):
def test_phybits_low_tcg_q35_71_amd_41bits(self):
"""
- :avocado: tags=machine:q35
- :avocado: tags=arch:x86_64
-
AMD processor with 41 bits. Max cpu hw address = 2 TiB.
By setting maxram above 1012 GiB - 32 GiB - 4 GiB = 976 GiB, we can
force "above_4G" memory to start at 1 TiB for q35-7.1 machines
@@ -292,9 +257,6 @@ class MemAddrCheck(QemuSystemTest):
def test_phybits_ok_tcg_q35_71_amd_41bits(self):
"""
- :avocado: tags=machine:q35
- :avocado: tags=arch:x86_64
-
AMD processor with 41 bits. Max cpu hw address = 2 TiB.
Same as above but by setting maxram between 976 GiB and 992 Gib,
QEMU should start fine.
@@ -313,9 +275,6 @@ class MemAddrCheck(QemuSystemTest):
def test_phybits_low_tcg_q35_intel_cxl(self):
"""
- :avocado: tags=machine:q35
- :avocado: tags=arch:x86_64
-
cxl memory window starts after memory device range. Here, we use 1 GiB
of cxl window memory. 4G_mem end aligns at 4G. pci64_hole is 32 GiB and
starts after the cxl memory window.
@@ -336,9 +295,6 @@ class MemAddrCheck(QemuSystemTest):
def test_phybits_ok_tcg_q35_intel_cxl(self):
"""
- :avocado: tags=machine:q35
- :avocado: tags=arch:x86_64
-
Same as above but here we do not reserve any cxl memory window. Hence,
with the exact same parameters as above, QEMU should start fine even
with cxl enabled.
@@ -353,3 +309,6 @@ class MemAddrCheck(QemuSystemTest):
time.sleep(self.DELAY_Q35_BOOT_SEQUENCE)
self.vm.shutdown()
self.assertNotRegex(self.vm.get_log(), r'phys-bits too low')
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_microblaze_s3adsp1800.py b/tests/functional/test_microblaze_s3adsp1800.py
new file mode 100755
index 0000000..4f692ff
--- /dev/null
+++ b/tests/functional/test_microblaze_s3adsp1800.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a microblaze Linux kernel and checks the console
+#
+# Copyright (c) 2018, 2021 Red Hat, Inc.
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+import time
+from qemu_test import exec_command, exec_command_and_wait_for_pattern
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern
+from qemu_test.utils import archive_extract
+
+class MicroblazeMachine(QemuSystemTest):
+
+ timeout = 90
+
+ ASSET_IMAGE = Asset(
+ ('https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/'
+ 'day17.tar.xz'),
+ '3ba7439dfbea7af4876662c97f8e1f0cdad9231fc166e4861d17042489270057')
+
+ def test_microblaze_s3adsp1800(self):
+ self.set_machine('petalogix-s3adsp1800')
+ file_path = self.ASSET_IMAGE.fetch()
+ archive_extract(file_path, self.workdir)
+ self.vm.set_console()
+ self.vm.add_args('-kernel', self.workdir + '/day17/ballerina.bin')
+ self.vm.launch()
+ wait_for_console_pattern(self, 'This architecture does not have '
+ 'kernel memory protection')
+ # Note:
+ # The kernel sometimes gets stuck after the "This architecture ..."
+ # message, that's why we don't test for a later string here. This
+ # needs some investigation by a microblaze wizard one day...
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_microblazeel_s3adsp1800.py b/tests/functional/test_microblazeel_s3adsp1800.py
new file mode 100755
index 0000000..faa3927
--- /dev/null
+++ b/tests/functional/test_microblazeel_s3adsp1800.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a microblaze Linux kernel and checks the console
+#
+# Copyright (c) 2018, 2021 Red Hat, Inc.
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+import time
+from qemu_test import exec_command, exec_command_and_wait_for_pattern
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern
+from qemu_test.utils import archive_extract
+
+class MicroblazeelMachine(QemuSystemTest):
+
+ timeout = 90
+
+ ASSET_IMAGE = Asset(
+ ('http://www.qemu-advent-calendar.org/2023/download/day13.tar.gz'),
+ 'b9b3d43c5dd79db88ada495cc6e0d1f591153fe41355e925d791fbf44de50c22')
+
+ def test_microblazeel_s3adsp1800(self):
+ self.require_netdev('user')
+ self.set_machine('petalogix-s3adsp1800')
+ file_path = self.ASSET_IMAGE.fetch()
+ archive_extract(file_path, self.workdir)
+ self.vm.set_console()
+ self.vm.add_args('-kernel', self.workdir + '/day13/xmaton.bin')
+ self.vm.add_args('-nic', 'user,tftp=' + self.workdir + '/day13/')
+ self.vm.launch()
+ wait_for_console_pattern(self, 'QEMU Advent Calendar 2023')
+ time.sleep(0.1)
+ exec_command(self, 'root')
+ time.sleep(0.1)
+ exec_command_and_wait_for_pattern(self,
+ 'tftp -g -r xmaton.png 10.0.2.2 ; md5sum xmaton.png',
+ '821cd3cab8efd16ad6ee5acc3642a8ea')
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_mips64_tuxrun.py b/tests/functional/test_mips64_tuxrun.py
new file mode 100755
index 0000000..54af1ae
--- /dev/null
+++ b/tests/functional/test_mips64_tuxrun.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex BennƩe <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunMips64Test(TuxRunBaselineTest):
+
+ ASSET_MIPS64_KERNEL = Asset(
+ 'https://storage.tuxboot.com/20230331/mips64/vmlinux',
+ '09010e51e4b8bcbbd2494786ffb48eca78f228e96e5c5438344b0eac4029dc61')
+ ASSET_MIPS64_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/20230331/mips64/rootfs.ext4.zst',
+ '69d91eeb04df3d8d172922c6993bb37d4deeb6496def75d8580f6f9de3e431da')
+
+ def test_mips64(self):
+ self.set_machine('malta')
+ self.root="sda"
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_MIPS64_KERNEL,
+ rootfs_asset=self.ASSET_MIPS64_ROOTFS,
+ drive="driver=ide-hd,bus=ide.0,unit=0")
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_mips64el_fuloong2e.py b/tests/functional/test_mips64el_fuloong2e.py
new file mode 100755
index 0000000..a32d5f9
--- /dev/null
+++ b/tests/functional/test_mips64el_fuloong2e.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python3
+#
+# Functional tests for the Lemote Fuloong-2E machine.
+#
+# Copyright (c) 2019 Philippe Mathieu-DaudƩ <f4bug@amsat.org>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+# See the COPYING file in the top-level directory.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+import subprocess
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test import wait_for_console_pattern
+from unittest import skipUnless
+
+class MipsFuloong2e(LinuxKernelTest):
+
+ timeout = 60
+
+ ASSET_KERNEL = Asset(
+ ('http://archive.debian.org/debian/pool/main/l/linux/'
+ 'linux-image-3.16.0-6-loongson-2e_3.16.56-1+deb8u1_mipsel.deb'),
+ '2a70f15b397f4ced632b0c15cb22660394190644146d804d60a4796eefbe1f50')
+
+ def test_linux_kernel_3_16(self):
+ deb_path = self.ASSET_KERNEL.fetch()
+ kernel_path = self.extract_from_deb(deb_path,
+ '/boot/vmlinux-3.16.0-6-loongson-2e')
+
+ self.set_machine('fuloong2e')
+ self.vm.set_console()
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
+ self.vm.add_args('-kernel', kernel_path,
+ '-append', kernel_command_line)
+ self.vm.launch()
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.wait_for_console_pattern(console_pattern)
+
+ @skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
+ @skipUnless(os.getenv('RESCUE_YL_PATH'), 'RESCUE_YL_PATH not available')
+ def test_linux_kernel_2_6_27_isa_serial(self):
+ # Recovery system for the Yeeloong laptop
+ # (enough to test the fuloong2e southbridge, accessing its ISA bus)
+ # http://dev.lemote.com/files/resource/download/rescue/rescue-yl
+ sha = 'ab588d3316777c62cc81baa20ac92e98b01955c244dff3794b711bc34e26e51d'
+ kernel_path = os.getenv('RESCUE_YL_PATH')
+ output = subprocess.check_output(['sha256sum', kernel_path])
+ checksum = output.split()[0]
+ assert checksum.decode("utf-8") == sha
+
+ self.set_machine('fuloong2e')
+ self.vm.set_console()
+ self.vm.add_args('-kernel', kernel_path)
+ self.vm.launch()
+ wait_for_console_pattern(self, 'Linux version 2.6.27.7lemote')
+ cpu_revision = 'CPU revision is: 00006302 (ICT Loongson-2)'
+ wait_for_console_pattern(self, cpu_revision)
+
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_mips64el_loongson3v.py b/tests/functional/test_mips64el_loongson3v.py
new file mode 100755
index 0000000..55d6292
--- /dev/null
+++ b/tests/functional/test_mips64el_loongson3v.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python3
+#
+# Functional tests for the Generic Loongson-3 Platform.
+#
+# Copyright (c) 2021 Jiaxun Yang <jiaxun.yang@flygoat.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.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+import time
+
+from unittest import skipUnless
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern
+
+class MipsLoongson3v(QemuSystemTest):
+ timeout = 60
+
+ ASSET_PMON = Asset(
+ ('https://github.com/loongson-community/pmon/'
+ 'releases/download/20210112/pmon-3avirt.bin'),
+ 'fcdf6bb2cb7885a4a62f31fcb0d5e368bac7b6cea28f40c6dfa678af22fea20a')
+
+ @skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
+ def test_pmon_serial_console(self):
+ self.set_machine('loongson3-virt')
+
+ pmon_path = self.ASSET_PMON.fetch()
+
+ self.vm.set_console()
+ self.vm.add_args('-bios', pmon_path)
+ self.vm.launch()
+ wait_for_console_pattern(self, 'CPU GODSON3 BogoMIPS:')
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_mips64el_malta.py b/tests/functional/test_mips64el_malta.py
new file mode 100755
index 0000000..6c6355b
--- /dev/null
+++ b/tests/functional/test_mips64el_malta.py
@@ -0,0 +1,186 @@
+#!/usr/bin/env python3
+#
+# Functional tests for the little-endian 64-bit MIPS Malta board
+#
+# Copyright (c) Philippe Mathieu-DaudƩ <f4bug@amsat.org>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+# See the COPYING file in the top-level directory.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+import logging
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test import exec_command_and_wait_for_pattern
+from qemu_test.utils import gzip_uncompress
+from unittest import skipUnless
+
+NUMPY_AVAILABLE = True
+try:
+ import numpy as np
+except ImportError:
+ NUMPY_AVAILABLE = False
+
+CV2_AVAILABLE = True
+try:
+ import cv2
+except ImportError:
+ CV2_AVAILABLE = False
+
+
+class MaltaMachineConsole(LinuxKernelTest):
+
+ ASSET_KERNEL_2_63_2 = Asset(
+ ('http://snapshot.debian.org/archive/debian/'
+ '20130217T032700Z/pool/main/l/linux-2.6/'
+ 'linux-image-2.6.32-5-5kc-malta_2.6.32-48_mipsel.deb'),
+ '35eb476f03be589824b0310358f1c447d85e645b88cbcd2ac02b97ef560f9f8d')
+
+ def test_mips64el_malta(self):
+ """
+ This test requires the ar tool to extract "data.tar.gz" from
+ the Debian package.
+
+ The kernel can be rebuilt using this Debian kernel source [1] and
+ following the instructions on [2].
+
+ [1] http://snapshot.debian.org/package/linux-2.6/2.6.32-48/
+ #linux-source-2.6.32_2.6.32-48
+ [2] https://kernel-team.pages.debian.net/kernel-handbook/
+ ch-common-tasks.html#s-common-official
+ """
+ deb_path = self.ASSET_KERNEL_2_63_2.fetch()
+ kernel_path = self.extract_from_deb(deb_path,
+ '/boot/vmlinux-2.6.32-5-5kc-malta')
+
+ self.set_machine('malta')
+ self.vm.set_console()
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
+ self.vm.add_args('-kernel', kernel_path,
+ '-append', kernel_command_line)
+ self.vm.launch()
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.wait_for_console_pattern(console_pattern)
+
+ ASSET_KERNEL_3_19_3 = Asset(
+ ('https://github.com/philmd/qemu-testing-blob/'
+ 'raw/9ad2df38/mips/malta/mips64el/'
+ 'vmlinux-3.19.3.mtoman.20150408'),
+ '8d3beb003bc66051ead98e7172139017fcf9ce2172576541c57e86418dfa5ab8')
+
+ ASSET_CPIO_R1 = Asset(
+ ('https://github.com/groeck/linux-build-test/'
+ 'raw/8584a59e/rootfs/mipsel64/'
+ 'rootfs.mipsel64r1.cpio.gz'),
+ '75ba10cd35fb44e32948eeb26974f061b703c81c4ba2fab1ebcacf1d1bec3b61')
+
+ @skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
+ def test_mips64el_malta_5KEc_cpio(self):
+ kernel_path = self.ASSET_KERNEL_3_19_3.fetch()
+ initrd_path_gz = self.ASSET_CPIO_R1.fetch()
+ initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
+ gzip_uncompress(initrd_path_gz, initrd_path)
+
+ self.set_machine('malta')
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE
+ + 'console=ttyS0 console=tty '
+ + 'rdinit=/sbin/init noreboot')
+ self.vm.add_args('-cpu', '5KEc',
+ '-kernel', kernel_path,
+ '-initrd', initrd_path,
+ '-append', kernel_command_line,
+ '-no-reboot')
+ self.vm.launch()
+ self.wait_for_console_pattern('Boot successful.')
+
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
+ 'MIPS 5KE')
+ exec_command_and_wait_for_pattern(self, 'uname -a',
+ '3.19.3.mtoman.20150408')
+ exec_command_and_wait_for_pattern(self, 'reboot',
+ 'reboot: Restarting system')
+ # Wait for VM to shut down gracefully
+ self.vm.wait()
+
+
+@skipUnless(NUMPY_AVAILABLE, 'Python NumPy not installed')
+@skipUnless(CV2_AVAILABLE, 'Python OpenCV not installed')
+class MaltaMachineFramebuffer(LinuxKernelTest):
+
+ timeout = 30
+
+ ASSET_KERNEL_4_7_0 = Asset(
+ ('https://github.com/philmd/qemu-testing-blob/raw/a5966ca4b5/'
+ 'mips/malta/mips64el/vmlinux-4.7.0-rc1.I6400.gz'),
+ '1f64efc59968a3c328672e6b10213fe574bb2308d9d2ed44e75e40be59e9fbc2')
+
+ ASSET_TUXLOGO = Asset(
+ ('https://github.com/torvalds/linux/raw/v2.6.12/'
+ 'drivers/video/logo/logo_linux_vga16.ppm'),
+ 'b762f0d91ec018887ad1b334543c2fdf9be9fdfc87672b409211efaa3ea0ef79')
+
+ def do_test_i6400_framebuffer_logo(self, cpu_cores_count):
+ """
+ Boot Linux kernel and check Tux logo is displayed on the framebuffer.
+ """
+ screendump_path = os.path.join(self.workdir, 'screendump.pbm')
+
+ kernel_path_gz = self.ASSET_KERNEL_4_7_0.fetch()
+ kernel_path = self.workdir + "vmlinux"
+ gzip_uncompress(kernel_path_gz, kernel_path)
+
+ tuxlogo_path = self.ASSET_TUXLOGO.fetch()
+
+ self.set_machine('malta')
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'clocksource=GIC console=tty0 console=ttyS0')
+ self.vm.add_args('-kernel', kernel_path,
+ '-cpu', 'I6400',
+ '-smp', '%u' % cpu_cores_count,
+ '-vga', 'std',
+ '-append', kernel_command_line)
+ self.vm.launch()
+ framebuffer_ready = 'Console: switching to colour frame buffer device'
+ self.wait_for_console_pattern(framebuffer_ready)
+ self.vm.cmd('human-monitor-command', command_line='stop')
+ self.vm.cmd('human-monitor-command',
+ command_line='screendump %s' % screendump_path)
+ logger = logging.getLogger('framebuffer')
+
+ match_threshold = 0.95
+ screendump_bgr = cv2.imread(screendump_path, cv2.IMREAD_COLOR)
+ tuxlogo_bgr = cv2.imread(tuxlogo_path, cv2.IMREAD_COLOR)
+ result = cv2.matchTemplate(screendump_bgr, tuxlogo_bgr,
+ cv2.TM_CCOEFF_NORMED)
+ loc = np.where(result >= match_threshold)
+ tuxlogo_count = 0
+ h, w = tuxlogo_bgr.shape[:2]
+ debug_png = os.getenv('AVOCADO_CV2_SCREENDUMP_PNG_PATH')
+ for tuxlogo_count, pt in enumerate(zip(*loc[::-1]), start=1):
+ logger.debug('found Tux at position (x, y) = %s', pt)
+ cv2.rectangle(screendump_bgr, pt,
+ (pt[0] + w, pt[1] + h), (0, 0, 255), 2)
+ if debug_png:
+ cv2.imwrite(debug_png, screendump_bgr)
+ self.assertGreaterEqual(tuxlogo_count, cpu_cores_count)
+
+ def test_mips_malta_i6400_framebuffer_logo_1core(self):
+ self.do_test_i6400_framebuffer_logo(1)
+
+ @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
+ def test_mips_malta_i6400_framebuffer_logo_7cores(self):
+ self.do_test_i6400_framebuffer_logo(7)
+
+ @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
+ def test_mips_malta_i6400_framebuffer_logo_8cores(self):
+ self.do_test_i6400_framebuffer_logo(8)
+
+
+from test_mipsel_malta import MaltaMachineYAMON
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_mips64el_tuxrun.py b/tests/functional/test_mips64el_tuxrun.py
new file mode 100755
index 0000000..819549a
--- /dev/null
+++ b/tests/functional/test_mips64el_tuxrun.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex BennƩe <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunMips64ELTest(TuxRunBaselineTest):
+
+ ASSET_MIPS64EL_KERNEL = Asset(
+ 'https://storage.tuxboot.com/20230331/mips64el/vmlinux',
+ 'd4e08965e2155c4cccce7c5f34d18fe34c636cda2f2c9844387d614950155266')
+ ASSET_MIPS64EL_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/20230331/mips64el/rootfs.ext4.zst',
+ 'fba585368f5915b1498ed081863474b2d7ec4e97cdd46d21bdcb2f9698f83de4')
+
+ def test_mips64el(self):
+ self.set_machine('malta')
+ self.root="sda"
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_MIPS64EL_KERNEL,
+ rootfs_asset=self.ASSET_MIPS64EL_ROOTFS,
+ drive="driver=ide-hd,bus=ide.0,unit=0")
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_mips_malta.py b/tests/functional/test_mips_malta.py
new file mode 100755
index 0000000..a012081
--- /dev/null
+++ b/tests/functional/test_mips_malta.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python3
+#
+# Functional tests for the little-endian 32-bit MIPS Malta board
+#
+# Copyright (c) Philippe Mathieu-DaudƩ <f4bug@amsat.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test import exec_command_and_wait_for_pattern
+from qemu_test.utils import gzip_uncompress
+
+
+class MaltaMachineConsole(LinuxKernelTest):
+
+ ASSET_KERNEL_2_63_2 = Asset(
+ ('http://snapshot.debian.org/archive/debian/'
+ '20130217T032700Z/pool/main/l/linux-2.6/'
+ 'linux-image-2.6.32-5-4kc-malta_2.6.32-48_mips.deb'),
+ '16ca524148afb0626f483163e5edf352bc1ab0e4fc7b9f9d473252762f2c7a43')
+
+ def test_mips_malta(self):
+ deb_path = self.ASSET_KERNEL_2_63_2.fetch()
+ kernel_path = self.extract_from_deb(deb_path,
+ '/boot/vmlinux-2.6.32-5-4kc-malta')
+
+ self.set_machine('malta')
+ self.vm.set_console()
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
+ self.vm.add_args('-kernel', kernel_path,
+ '-append', kernel_command_line)
+ self.vm.launch()
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.wait_for_console_pattern(console_pattern)
+
+ ASSET_KERNEL_4_5_0 = Asset(
+ ('http://snapshot.debian.org/archive/debian/'
+ '20160601T041800Z/pool/main/l/linux/'
+ 'linux-image-4.5.0-2-4kc-malta_4.5.5-1_mips.deb'),
+ '526b17d5889840888b76fc2c36a0ebde182c9b1410a3a1e68203c3b160eb2027')
+
+ ASSET_INITRD = Asset(
+ ('https://github.com/groeck/linux-build-test/raw/'
+ '8584a59ed9e5eb5ee7ca91f6d74bbb06619205b8/rootfs/'
+ 'mips/rootfs.cpio.gz'),
+ 'dcfe3a7fe3200da3a00d176b95caaa086495eb158f2bff64afc67d7e1eb2cddc')
+
+ def test_mips_malta_cpio(self):
+ deb_path = self.ASSET_KERNEL_4_5_0.fetch()
+ kernel_path = self.extract_from_deb(deb_path,
+ '/boot/vmlinux-4.5.0-2-4kc-malta')
+ initrd_path_gz = self.ASSET_INITRD.fetch()
+ initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
+ gzip_uncompress(initrd_path_gz, initrd_path)
+
+ self.set_machine('malta')
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE
+ + 'console=ttyS0 console=tty '
+ + 'rdinit=/sbin/init noreboot')
+ self.vm.add_args('-kernel', kernel_path,
+ '-initrd', initrd_path,
+ '-append', kernel_command_line,
+ '-no-reboot')
+ self.vm.launch()
+ self.wait_for_console_pattern('Boot successful.')
+
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
+ 'BogoMIPS')
+ exec_command_and_wait_for_pattern(self, 'uname -a',
+ 'Debian')
+ exec_command_and_wait_for_pattern(self, 'reboot',
+ 'reboot: Restarting system')
+ # Wait for VM to shut down gracefully
+ self.vm.wait()
+
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_mips_tuxrun.py b/tests/functional/test_mips_tuxrun.py
new file mode 100755
index 0000000..6fec44c
--- /dev/null
+++ b/tests/functional/test_mips_tuxrun.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex BennƩe <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunMipsTest(TuxRunBaselineTest):
+
+ ASSET_MIPS_KERNEL = Asset(
+ 'https://storage.tuxboot.com/20230331/mips32/vmlinux',
+ 'bfd2172f8b17fb32970ca0c8c58f59c5a4ca38aa5855d920be3a69b5d16e52f0')
+ ASSET_MIPS_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/20230331/mips32/rootfs.ext4.zst',
+ 'fc3da0b4c2f38d74c6d705123bb0f633c76ed953128f9d0859378c328a6d11a0')
+
+ def test_mips32(self):
+ self.set_machine('malta')
+ self.cpu="mips32r6-generic"
+ self.root="sda"
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_MIPS_KERNEL,
+ rootfs_asset=self.ASSET_MIPS_ROOTFS,
+ drive="driver=ide-hd,bus=ide.0,unit=0")
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_mipsel_malta.py b/tests/functional/test_mipsel_malta.py
new file mode 100755
index 0000000..b8dfddd
--- /dev/null
+++ b/tests/functional/test_mipsel_malta.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python3
+#
+# Functional tests for the little-endian 32-bit MIPS Malta board
+#
+# Copyright (c) Philippe Mathieu-DaudƩ <f4bug@amsat.org>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+# See the COPYING file in the top-level directory.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+
+from qemu_test import QemuSystemTest, LinuxKernelTest, Asset
+from qemu_test import interrupt_interactive_console_until_pattern
+from qemu_test import wait_for_console_pattern
+from qemu_test.utils import lzma_uncompress
+from zipfile import ZipFile
+
+
+class MaltaMachineConsole(LinuxKernelTest):
+
+ ASSET_KERNEL_4K = Asset(
+ ('http://mipsdistros.mips.com/LinuxDistro/nanomips/'
+ 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/'
+ 'generic_nano32r6el_page4k.xz'),
+ '019e034094ac6cf3aa77df5e130fb023ce4dbc804b04bfcc560c6403e1ae6bdb')
+ ASSET_KERNEL_16K = Asset(
+ ('http://mipsdistros.mips.com/LinuxDistro/nanomips/'
+ 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/'
+ 'generic_nano32r6el_page16k_up.xz'),
+ '3a54a10b3108c16a448dca9ea3db378733a27423befc2a45a5bdf990bd85e12c')
+ ASSET_KERNEL_64K = Asset(
+ ('http://mipsdistros.mips.com/LinuxDistro/nanomips/'
+ 'kernels/v4.15.18-432-gb2eb9a8b07a1-20180627102142/'
+ 'generic_nano32r6el_page64k_dbg.xz'),
+ 'ce21ff4b07a981ecb8a39db2876616f5a2473eb2ab459c6f67465b9914b0c6b6')
+
+ def do_test_mips_malta32el_nanomips(self, kernel_path_xz):
+ kernel_path = os.path.join(self.workdir, 'kernel')
+ lzma_uncompress(kernel_path_xz, kernel_path)
+
+ self.set_machine('malta')
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE
+ + 'mem=256m@@0x0 '
+ + 'console=ttyS0')
+ self.vm.add_args('-cpu', 'I7200',
+ '-no-reboot',
+ '-kernel', kernel_path,
+ '-append', kernel_command_line)
+ self.vm.launch()
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.wait_for_console_pattern(console_pattern)
+
+ def test_mips_malta32el_nanomips_4k(self):
+ kernel_path_xz = self.ASSET_KERNEL_4K.fetch()
+ self.do_test_mips_malta32el_nanomips(kernel_path_xz)
+
+ def test_mips_malta32el_nanomips_16k_up(self):
+ kernel_path_xz = self.ASSET_KERNEL_16K.fetch()
+ self.do_test_mips_malta32el_nanomips(kernel_path_xz)
+
+ def test_mips_malta32el_nanomips_64k_dbg(self):
+ kernel_path_xz = self.ASSET_KERNEL_16K.fetch()
+ self.do_test_mips_malta32el_nanomips(kernel_path_xz)
+
+
+class MaltaMachineYAMON(QemuSystemTest):
+
+ ASSET_YAMON_ROM = Asset(
+ ('https://s3-eu-west-1.amazonaws.com/downloads-mips/mips-downloads/'
+ 'YAMON/yamon-bin-02.22.zip'),
+ 'eef86f0eed0ef554f041dcd47b87eebea0e6f9f1184ed31f7e9e8b4a803860ab')
+
+ def test_mipsel_malta_yamon(self):
+ yamon_bin = 'yamon-02.22.bin'
+ zip_path = self.ASSET_YAMON_ROM.fetch()
+ with ZipFile(zip_path, 'r') as zf:
+ zf.extract(yamon_bin, path=self.workdir)
+ yamon_path = os.path.join(self.workdir, yamon_bin)
+
+ self.set_machine('malta')
+ self.vm.set_console()
+ self.vm.add_args('-bios', yamon_path)
+ self.vm.launch()
+
+ prompt = 'YAMON>'
+ pattern = 'YAMON ROM Monitor'
+ interrupt_interactive_console_until_pattern(self, pattern, prompt)
+ wait_for_console_pattern(self, prompt)
+ self.vm.shutdown()
+
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_mipsel_tuxrun.py b/tests/functional/test_mipsel_tuxrun.py
new file mode 100755
index 0000000..2965bbd
--- /dev/null
+++ b/tests/functional/test_mipsel_tuxrun.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex BennƩe <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunMipsELTest(TuxRunBaselineTest):
+
+ ASSET_MIPSEL_KERNEL = Asset(
+ 'https://storage.tuxboot.com/20230331/mips32el/vmlinux',
+ '8573867c68a8443db8de6d08bb33fb291c189ca2ca671471d3973a3e712096a3')
+ ASSET_MIPSEL_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/20230331/mips32el/rootfs.ext4.zst',
+ 'e799768e289fd69209c21f4dacffa11baea7543d5db101e8ce27e3bc2c41d90e')
+
+ def test_mips32el(self):
+ self.set_machine('malta')
+ self.cpu="mips32r6-generic"
+ self.root="sda"
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_MIPSEL_KERNEL,
+ rootfs_asset=self.ASSET_MIPSEL_ROOTFS,
+ drive="driver=ide-hd,bus=ide.0,unit=0")
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_multiprocess.py b/tests/functional/test_multiprocess.py
new file mode 100755
index 0000000..751cf10
--- /dev/null
+++ b/tests/functional/test_multiprocess.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+#
+# Test for multiprocess qemu
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+
+import os
+import socket
+
+from qemu_test import QemuSystemTest, Asset, wait_for_console_pattern
+from qemu_test import exec_command, exec_command_and_wait_for_pattern
+
+class Multiprocess(QemuSystemTest):
+
+ KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
+
+ ASSET_KERNEL_X86 = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux'
+ '/releases/31/Everything/x86_64/os/images/pxeboot/vmlinuz'),
+ 'd4738d03dbbe083ca610d0821d0a8f1488bebbdccef54ce33e3adb35fda00129')
+
+ ASSET_INITRD_X86 = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux'
+ '/releases/31/Everything/x86_64/os/images/pxeboot/initrd.img'),
+ '3b6cb5c91a14c42e2f61520f1689264d865e772a1f0069e660a800d31dd61fb9')
+
+ ASSET_KERNEL_AARCH64 = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux'
+ '/releases/31/Everything/aarch64/os/images/pxeboot/vmlinuz'),
+ '3ae07fcafbfc8e4abeb693035a74fe10698faae15e9ccd48882a9167800c1527')
+
+ ASSET_INITRD_AARCH64 = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux'
+ '/releases/31/Everything/aarch64/os/images/pxeboot/initrd.img'),
+ '9fd230cab10b1dafea41cf00150e6669d37051fad133bd618d2130284e16d526')
+
+ def do_test(self, kernel_asset, initrd_asset,
+ kernel_command_line, machine_type):
+ """Main test method"""
+ self.require_accelerator('kvm')
+ self.require_device('x-pci-proxy-dev')
+
+ # Create socketpair to connect proxy and remote processes
+ proxy_sock, remote_sock = socket.socketpair(socket.AF_UNIX,
+ socket.SOCK_STREAM)
+ os.set_inheritable(proxy_sock.fileno(), True)
+ os.set_inheritable(remote_sock.fileno(), True)
+
+ kernel_path = kernel_asset.fetch()
+ initrd_path = initrd_asset.fetch()
+
+ # Create remote process
+ remote_vm = self.get_vm()
+ remote_vm.add_args('-machine', 'x-remote')
+ remote_vm.add_args('-nodefaults')
+ remote_vm.add_args('-device', 'lsi53c895a,id=lsi1')
+ remote_vm.add_args('-object', 'x-remote-object,id=robj1,'
+ 'devid=lsi1,fd='+str(remote_sock.fileno()))
+ remote_vm.launch()
+
+ # Create proxy process
+ self.vm.set_console()
+ self.vm.add_args('-machine', machine_type)
+ self.vm.add_args('-accel', 'kvm')
+ self.vm.add_args('-cpu', 'host')
+ self.vm.add_args('-object',
+ 'memory-backend-memfd,id=sysmem-file,size=2G')
+ self.vm.add_args('--numa', 'node,memdev=sysmem-file')
+ self.vm.add_args('-m', '2048')
+ self.vm.add_args('-kernel', kernel_path,
+ '-initrd', initrd_path,
+ '-append', kernel_command_line)
+ self.vm.add_args('-device',
+ 'x-pci-proxy-dev,'
+ 'id=lsi1,fd='+str(proxy_sock.fileno()))
+ self.vm.launch()
+ wait_for_console_pattern(self, 'as init process',
+ 'Kernel panic - not syncing')
+ exec_command(self, 'mount -t sysfs sysfs /sys')
+ exec_command_and_wait_for_pattern(self,
+ 'cat /sys/bus/pci/devices/*/uevent',
+ 'PCI_ID=1000:0012')
+
+ def test_multiprocess(self):
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE
+ if self.arch == 'x86_64':
+ kernel_command_line += 'console=ttyS0 rdinit=/bin/bash'
+ self.do_test(self.ASSET_KERNEL_X86, self.ASSET_INITRD_X86,
+ kernel_command_line, 'pc')
+ elif self.arch == 'aarch64':
+ kernel_command_line += 'rdinit=/bin/bash console=ttyAMA0'
+ self.do_test(self.ASSET_KERNEL_AARCH64, self.ASSET_INITRD_AARCH64,
+ kernel_command_line, 'virt,gic-version=3')
+ else:
+ assert False
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/avocado/netdev-ethtool.py b/tests/functional/test_netdev_ethtool.py
index 5f33288..ee1a397 100644..100755
--- a/tests/avocado/netdev-ethtool.py
+++ b/tests/functional/test_netdev_ethtool.py
@@ -1,43 +1,39 @@
+#!/usr/bin/env python3
+#
# ethtool tests for emulated network devices
#
# This test leverages ethtool's --test sequence to validate network
# device behaviour.
#
-# SPDX-License-Identifier: GPL-2.0-or-late
+# SPDX-License-Identifier: GPL-2.0-or-later
-from avocado import skip
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
+from unittest import skip
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern
class NetDevEthtool(QemuSystemTest):
- """
- :avocado: tags=arch:x86_64
- :avocado: tags=machine:q35
- """
# Runs in about 17s under KVM, 19s under TCG, 25s under GCOV
timeout = 45
# Fetch assets from the netdev-ethtool subdir of my shared test
# images directory on fileserver.linaro.org.
- def get_asset(self, name, sha1):
- base_url = ('https://fileserver.linaro.org/s/'
- 'kE4nCFLdQcoBF9t/download?'
- 'path=%2Fnetdev-ethtool&files=' )
- url = base_url + name
- # use explicit name rather than failing to neatly parse the
- # URL into a unique one
- return self.fetch_asset(name=name, locations=(url), asset_hash=sha1)
+ ASSET_BASEURL = ('https://fileserver.linaro.org/s/kE4nCFLdQcoBF9t/'
+ 'download?path=%2Fnetdev-ethtool&files=')
+ ASSET_BZIMAGE = Asset(
+ ASSET_BASEURL + "bzImage",
+ "ed62ee06ea620b1035747f3f66a5e9fc5d3096b29f75562ada888b04cd1c4baf")
+ ASSET_ROOTFS = Asset(
+ ASSET_BASEURL + "rootfs.squashfs",
+ "8f0207e3c4d40832ae73c1a927e42ca30ccb1e71f047acb6ddb161ba422934e6")
def common_test_code(self, netdev, extra_args=None):
+ self.set_machine('q35')
# This custom kernel has drivers for all the supported network
# devices we can emulate in QEMU
- kernel = self.get_asset("bzImage",
- "33469d7802732d5815226166581442395cb289e2")
-
- rootfs = self.get_asset("rootfs.squashfs",
- "9793cea7021414ae844bda51f558bd6565b50cdc")
+ kernel = self.ASSET_BZIMAGE.fetch()
+ rootfs = self.ASSET_ROOTFS.fetch()
append = 'printk.time=0 console=ttyS0 '
append += 'root=/dev/sr0 rootfstype=squashfs '
@@ -68,15 +64,9 @@ class NetDevEthtool(QemuSystemTest):
self.vm.kill()
def test_igb(self):
- """
- :avocado: tags=device:igb
- """
self.common_test_code("igb")
def test_igb_nomsi(self):
- """
- :avocado: tags=device:igb
- """
self.common_test_code("igb", "pci=nomsi")
# It seems the other popular cards we model in QEMU currently fail
@@ -88,14 +78,11 @@ class NetDevEthtool(QemuSystemTest):
@skip("Incomplete reg 0x00178 support")
def test_e1000(self):
- """
- :avocado: tags=device:e1000
- """
self.common_test_code("e1000")
@skip("Incomplete reg 0x00178 support")
def test_i82550(self):
- """
- :avocado: tags=device:i82550
- """
self.common_test_code("i82550")
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_or1k_sim.py b/tests/functional/test_or1k_sim.py
new file mode 100755
index 0000000..10e0437
--- /dev/null
+++ b/tests/functional/test_or1k_sim.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on an OpenRISC-1000 SIM machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test.utils import archive_extract
+
+class OpenRISC1kSimTest(LinuxKernelTest):
+
+ ASSET_DAY20 = Asset(
+ 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day20.tar.xz',
+ 'ff9d7dd7c6bdba325bd85ee85c02db61ff653e129558aeffe6aff55bffb6763a')
+
+ def test_or1k_sim(self):
+ self.set_machine('or1k-sim')
+ file_path = self.ASSET_DAY20.fetch()
+ archive_extract(file_path, self.workdir)
+ self.vm.set_console()
+ self.vm.add_args('-kernel', self.workdir + '/day20/vmlinux')
+ self.vm.launch()
+ self.wait_for_console_pattern('QEMU advent calendar')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/avocado/pc_cpu_hotplug_props.py b/tests/functional/test_pc_cpu_hotplug_props.py
index 4bd3e02..9d5a37c 100644..100755
--- a/tests/avocado/pc_cpu_hotplug_props.py
+++ b/tests/functional/test_pc_cpu_hotplug_props.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python3
#
# Ensure CPU die-id can be omitted on -device
#
@@ -20,16 +21,16 @@
# License along with this library; if not, see <http://www.gnu.org/licenses/>.
#
-from avocado_qemu import QemuSystemTest
+from qemu_test import QemuSystemTest
class OmittedCPUProps(QemuSystemTest):
- """
- :avocado: tags=arch:x86_64
- :avocado: tags=cpu:qemu64
- """
+
def test_no_die_id(self):
self.vm.add_args('-nodefaults', '-S')
self.vm.add_args('-smp', '1,sockets=2,cores=2,threads=2,maxcpus=8')
self.vm.add_args('-device', 'qemu64-x86_64-cpu,socket-id=1,core-id=0,thread-id=0')
self.vm.launch()
self.assertEqual(len(self.vm.cmd('query-cpus-fast')), 2)
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_ppc64_e500.py b/tests/functional/test_ppc64_e500.py
new file mode 100755
index 0000000..f1af923
--- /dev/null
+++ b/tests/functional/test_ppc64_e500.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python3
+#
+# Boot a Linux kernel on a e500 ppc64 machine and check the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test.utils import archive_extract
+
+class E500Test(LinuxKernelTest):
+
+ ASSET_DAY19 = Asset(
+ 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day19.tar.xz',
+ '20b1bb5a8488c664defbb5d283addc91a05335a936c63b3f5ff7eee74b725755')
+
+ def test_ppc64_e500(self):
+ self.set_machine('ppce500')
+ self.cpu = 'e5500'
+ file_path = self.ASSET_DAY19.fetch()
+ archive_extract(file_path, self.workdir)
+ self.launch_kernel(self.workdir + '/day19/uImage',
+ wait_for='QEMU advent calendar')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/avocado/ppc_hv_tests.py b/tests/functional/test_ppc64_hv.py
index bf8822b..1a6e4b6 100644..100755
--- a/tests/avocado/ppc_hv_tests.py
+++ b/tests/functional/test_ppc64_hv.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Tests that specifically try to exercise hypervisor features of the
# target machines. powernv supports the Power hypervisor ISA, and
# pseries supports the nested-HV hypervisor spec.
@@ -7,10 +9,9 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from avocado import skipIf, skipUnless
-from avocado.utils import archive
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern, exec_command
+from unittest import skipIf, skipUnless
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern, exec_command
import os
import time
import subprocess
@@ -45,9 +46,7 @@ def missing_deps():
# QEMU already installed and use that.
# XXX: The order of these tests seems to matter, see git blame.
@skipIf(missing_deps(), 'dependencies (%s) not installed' % ','.join(deps))
-@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test sometimes gets stuck due to console handling problem')
-@skipUnless(os.getenv('AVOCADO_ALLOW_LARGE_STORAGE'), 'storage limited')
-@skipUnless(os.getenv('SPEED') == 'slow', 'runtime limited')
+@skipUnless(os.getenv('QEMU_TEST_ALLOW_LARGE_STORAGE'), 'storage limited')
class HypervisorTest(QemuSystemTest):
timeout = 1000
@@ -55,6 +54,11 @@ class HypervisorTest(QemuSystemTest):
panic_message = 'Kernel panic - not syncing'
good_message = 'VFS: Cannot open root device'
+ ASSET_ISO = Asset(
+ ('https://dl-cdn.alpinelinux.org/alpine/v3.18/'
+ 'releases/ppc64le/alpine-standard-3.18.4-ppc64le.iso'),
+ 'c26b8d3e17c2f3f0fed02b4b1296589c2390e6d5548610099af75300edd7b3ff')
+
def extract_from_iso(self, iso, path):
"""
Extracts a file from an iso file into the test workdir
@@ -73,6 +77,7 @@ class HypervisorTest(QemuSystemTest):
subprocess.run(cmd.split(),
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+ os.chmod(filename, 0o600)
os.chdir(cwd)
# Return complete path to extracted file. Because callers to
@@ -84,16 +89,9 @@ class HypervisorTest(QemuSystemTest):
def setUp(self):
super().setUp()
- iso_url = ('https://dl-cdn.alpinelinux.org/alpine/v3.18/releases/ppc64le/alpine-standard-3.18.4-ppc64le.iso')
-
- # Alpine use sha256 so I recalculated this myself
- iso_sha256 = 'c26b8d3e17c2f3f0fed02b4b1296589c2390e6d5548610099af75300edd7b3ff'
- iso_path = self.fetch_asset(iso_url, asset_hash=iso_sha256,
- algorithm = "sha256")
-
- self.iso_path = iso_path
- self.vmlinuz = self.extract_from_iso(iso_path, '/boot/vmlinuz-lts')
- self.initramfs = self.extract_from_iso(iso_path, '/boot/initramfs-lts')
+ self.iso_path = self.ASSET_ISO.fetch()
+ self.vmlinuz = self.extract_from_iso(self.iso_path, '/boot/vmlinuz-lts')
+ self.initramfs = self.extract_from_iso(self.iso_path, '/boot/initramfs-lts')
def do_start_alpine(self):
self.vm.set_console()
@@ -159,12 +157,8 @@ class HypervisorTest(QemuSystemTest):
wait_for_console_pattern(self, 'alpine:~#')
def test_hv_pseries(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:pseries
- :avocado: tags=accel:tcg
- """
self.require_accelerator("tcg")
+ self.set_machine('pseries')
self.vm.add_args("-accel", "tcg,thread=multi")
self.vm.add_args('-device', 'nvme,serial=1234,drive=drive0')
self.vm.add_args("-machine", "x-vof=on,cap-nested-hv=on")
@@ -174,12 +168,8 @@ class HypervisorTest(QemuSystemTest):
self.do_stop_alpine()
def test_hv_pseries_kvm(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:pseries
- :avocado: tags=accel:kvm
- """
self.require_accelerator("kvm")
+ self.set_machine('pseries')
self.vm.add_args("-accel", "kvm")
self.vm.add_args('-device', 'nvme,serial=1234,drive=drive0')
self.vm.add_args("-machine", "x-vof=on,cap-nested-hv=on,cap-ccf-assist=off")
@@ -189,12 +179,8 @@ class HypervisorTest(QemuSystemTest):
self.do_stop_alpine()
def test_hv_powernv(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:powernv
- :avocado: tags=accel:tcg
- """
self.require_accelerator("tcg")
+ self.set_machine('powernv')
self.vm.add_args("-accel", "tcg,thread=multi")
self.vm.add_args('-device', 'nvme,bus=pcie.2,addr=0x0,serial=1234,drive=drive0',
'-device', 'e1000e,netdev=net0,mac=C0:FF:EE:00:00:02,bus=pcie.0,addr=0x0',
@@ -204,3 +190,6 @@ class HypervisorTest(QemuSystemTest):
self.do_test_kvm()
self.do_test_kvm(True)
self.do_stop_alpine()
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/avocado/ppc_powernv.py b/tests/functional/test_ppc64_powernv.py
index 4342941..685e217 100644..100755
--- a/tests/avocado/ppc_powernv.py
+++ b/tests/functional/test_ppc64_powernv.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Test that Linux kernel boots on ppc powernv machines and check the console
#
# Copyright (c) 2018, 2020 Red Hat, Inc.
@@ -5,24 +7,24 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from avocado.utils import archive
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test import wait_for_console_pattern
-class powernvMachine(QemuSystemTest):
+class powernvMachine(LinuxKernelTest):
timeout = 90
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 console=hvc0 '
panic_message = 'Kernel panic - not syncing'
good_message = 'VFS: Cannot open root device'
+ ASSET_KERNEL = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora-secondary/'
+ 'releases/29/Everything/ppc64le/os/ppc/ppc64/vmlinuz'),
+ '383c2f5c23bc0d9d32680c3924d3fd7ee25cc5ef97091ac1aa5e1d853422fc5f')
+
def do_test_linux_boot(self, command_line = KERNEL_COMMON_COMMAND_LINE):
self.require_accelerator("tcg")
- kernel_url = ('https://archives.fedoraproject.org/pub/archive'
- '/fedora-secondary/releases/29/Everything/ppc64le/os'
- '/ppc/ppc64/vmlinuz')
- kernel_hash = '3fe04abfc852b66653b8c3c897a59a689270bc77'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
+ kernel_path = self.ASSET_KERNEL.fetch()
self.vm.set_console()
self.vm.add_args('-kernel', kernel_path,
@@ -30,23 +32,13 @@ class powernvMachine(QemuSystemTest):
self.vm.launch()
def test_linux_boot(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:powernv
- :avocado: tags=accel:tcg
- """
-
+ self.set_machine('powernv')
self.do_test_linux_boot()
console_pattern = 'VFS: Cannot open root device'
wait_for_console_pattern(self, console_pattern, self.panic_message)
def test_linux_smp_boot(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:powernv
- :avocado: tags=accel:tcg
- """
-
+ self.set_machine('powernv')
self.vm.add_args('-smp', '4')
self.do_test_linux_boot()
console_pattern = 'smp: Brought up 1 node, 4 CPUs'
@@ -54,12 +46,7 @@ class powernvMachine(QemuSystemTest):
wait_for_console_pattern(self, self.good_message, self.panic_message)
def test_linux_smp_hpt_boot(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:powernv
- :avocado: tags=accel:tcg
- """
-
+ self.set_machine('powernv')
self.vm.add_args('-smp', '4')
self.do_test_linux_boot(self.KERNEL_COMMON_COMMAND_LINE +
'disable_radix')
@@ -70,12 +57,7 @@ class powernvMachine(QemuSystemTest):
wait_for_console_pattern(self, self.good_message, self.panic_message)
def test_linux_smt_boot(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:powernv
- :avocado: tags=accel:tcg
- """
-
+ self.set_machine('powernv')
self.vm.add_args('-smp', '4,threads=4')
self.do_test_linux_boot()
console_pattern = 'CPU maps initialized for 4 threads per core'
@@ -85,12 +67,7 @@ class powernvMachine(QemuSystemTest):
wait_for_console_pattern(self, self.good_message, self.panic_message)
def test_linux_big_boot(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:powernv
- :avocado: tags=accel:tcg
- """
-
+ self.set_machine('powernv')
self.vm.add_args('-smp', '16,threads=4,cores=2,sockets=2')
# powernv does not support NUMA
@@ -100,3 +77,42 @@ class powernvMachine(QemuSystemTest):
console_pattern = 'smp: Brought up 2 nodes, 16 CPUs'
wait_for_console_pattern(self, console_pattern, self.panic_message)
wait_for_console_pattern(self, self.good_message, self.panic_message)
+
+
+ ASSET_EPAPR_KERNEL = Asset(
+ ('https://github.com/open-power/op-build/releases/download/v2.7/'
+ 'zImage.epapr'),
+ '0ab237df661727e5392cee97460e8674057a883c5f74381a128fa772588d45cd')
+
+ def do_test_ppc64_powernv(self, proc):
+ self.require_accelerator("tcg")
+ kernel_path = self.ASSET_EPAPR_KERNEL.fetch()
+ self.vm.set_console()
+ self.vm.add_args('-kernel', kernel_path,
+ '-append', 'console=tty0 console=hvc0',
+ '-device', 'pcie-pci-bridge,id=bridge1,bus=pcie.1,addr=0x0',
+ '-device', 'nvme,bus=pcie.2,addr=0x0,serial=1234',
+ '-device', 'e1000e,bus=bridge1,addr=0x3',
+ '-device', 'nec-usb-xhci,bus=bridge1,addr=0x2')
+ self.vm.launch()
+
+ self.wait_for_console_pattern("CPU: " + proc + " generation processor")
+ self.wait_for_console_pattern("zImage starting: loaded")
+ self.wait_for_console_pattern("Run /init as init process")
+ # Device detection output driven by udev probing is sometimes cut off
+ # from console output, suspect S14silence-console init script.
+
+ def test_powernv8(self):
+ self.set_machine('powernv8')
+ self.do_test_ppc64_powernv('P8')
+
+ def test_powernv9(self):
+ self.set_machine('powernv9')
+ self.do_test_ppc64_powernv('P9')
+
+ def test_powernv10(self):
+ self.set_machine('powernv10')
+ self.do_test_ppc64_powernv('P10')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/avocado/ppc_pseries.py b/tests/functional/test_ppc64_pseries.py
index 74aaa4a..fdc404e 100644..100755
--- a/tests/avocado/ppc_pseries.py
+++ b/tests/functional/test_ppc64_pseries.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Test that Linux kernel boots on ppc machines and check the console
#
# Copyright (c) 2018, 2020 Red Hat, Inc.
@@ -5,9 +7,8 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from avocado.utils import archive
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern
class pseriesMachine(QemuSystemTest):
@@ -16,12 +17,13 @@ class pseriesMachine(QemuSystemTest):
panic_message = 'Kernel panic - not syncing'
good_message = 'VFS: Cannot open root device'
+ ASSET_KERNEL = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora-secondary/'
+ 'releases/29/Everything/ppc64le/os/ppc/ppc64/vmlinuz'),
+ '383c2f5c23bc0d9d32680c3924d3fd7ee25cc5ef97091ac1aa5e1d853422fc5f')
+
def do_test_ppc64_linux_boot(self, kernel_command_line = KERNEL_COMMON_COMMAND_LINE):
- kernel_url = ('https://archives.fedoraproject.org/pub/archive'
- '/fedora-secondary/releases/29/Everything/ppc64le/os'
- '/ppc/ppc64/vmlinuz')
- kernel_hash = '3fe04abfc852b66653b8c3c897a59a689270bc77'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
+ kernel_path = self.ASSET_KERNEL.fetch()
self.vm.set_console()
self.vm.add_args('-kernel', kernel_path,
@@ -29,32 +31,20 @@ class pseriesMachine(QemuSystemTest):
self.vm.launch()
def test_ppc64_vof_linux_boot(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:pseries
- """
-
+ self.set_machine('pseries')
self.vm.add_args('-machine', 'x-vof=on')
self.do_test_ppc64_linux_boot()
console_pattern = 'VFS: Cannot open root device'
wait_for_console_pattern(self, console_pattern, self.panic_message)
def test_ppc64_linux_boot(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:pseries
- """
-
+ self.set_machine('pseries')
self.do_test_ppc64_linux_boot()
console_pattern = 'VFS: Cannot open root device'
wait_for_console_pattern(self, console_pattern, self.panic_message)
def test_ppc64_linux_smp_boot(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:pseries
- """
-
+ self.set_machine('pseries')
self.vm.add_args('-smp', '4')
self.do_test_ppc64_linux_boot()
console_pattern = 'smp: Brought up 1 node, 4 CPUs'
@@ -62,11 +52,7 @@ class pseriesMachine(QemuSystemTest):
wait_for_console_pattern(self, self.good_message, self.panic_message)
def test_ppc64_linux_hpt_smp_boot(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:pseries
- """
-
+ self.set_machine('pseries')
self.vm.add_args('-smp', '4')
self.do_test_ppc64_linux_boot(self.KERNEL_COMMON_COMMAND_LINE +
'disable_radix')
@@ -77,11 +63,6 @@ class pseriesMachine(QemuSystemTest):
wait_for_console_pattern(self, self.good_message, self.panic_message)
def test_ppc64_linux_smt_boot(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:pseries
- """
-
self.vm.add_args('-smp', '4,threads=4')
self.do_test_ppc64_linux_boot()
console_pattern = 'CPU maps initialized for 4 threads per core'
@@ -91,11 +72,7 @@ class pseriesMachine(QemuSystemTest):
wait_for_console_pattern(self, self.good_message, self.panic_message)
def test_ppc64_linux_big_boot(self):
- """
- :avocado: tags=arch:ppc64
- :avocado: tags=machine:pseries
- """
-
+ self.set_machine('pseries')
self.vm.add_args('-smp', '16,threads=4,cores=2,sockets=2')
self.vm.add_args('-m', '512M',
'-object', 'memory-backend-ram,size=256M,id=m0',
@@ -108,3 +85,6 @@ class pseriesMachine(QemuSystemTest):
console_pattern = 'smp: Brought up 2 nodes, 16 CPUs'
wait_for_console_pattern(self, console_pattern, self.panic_message)
wait_for_console_pattern(self, self.good_message, self.panic_message)
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_ppc64_tuxrun.py b/tests/functional/test_ppc64_tuxrun.py
new file mode 100755
index 0000000..552b53c
--- /dev/null
+++ b/tests/functional/test_ppc64_tuxrun.py
@@ -0,0 +1,110 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex BennƩe <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import tempfile
+
+from qemu_test import run_cmd, Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunPPC64Test(TuxRunBaselineTest):
+
+ def ppc64_common_tuxrun(self, kernel_asset, rootfs_asset, prefix):
+ self.set_machine('pseries')
+ self.cpu='POWER10'
+ self.console='hvc0'
+ self.root='sda'
+ self.extradev='spapr-vscsi'
+ # add device args to command line.
+ self.require_netdev('user')
+ self.vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22',
+ '-device', 'virtio-net,netdev=vnet')
+ self.vm.add_args('-netdev', '{"type":"user","id":"hostnet0"}',
+ '-device', '{"driver":"virtio-net-pci","netdev":'
+ '"hostnet0","id":"net0","mac":"52:54:00:4c:e3:86",'
+ '"bus":"pci.0","addr":"0x9"}')
+ self.vm.add_args('-device', '{"driver":"qemu-xhci","p2":15,"p3":15,'
+ '"id":"usb","bus":"pci.0","addr":"0x2"}')
+ self.vm.add_args('-device', '{"driver":"virtio-scsi-pci","id":"scsi0"'
+ ',"bus":"pci.0","addr":"0x3"}')
+ self.vm.add_args('-device', '{"driver":"virtio-serial-pci","id":'
+ '"virtio-serial0","bus":"pci.0","addr":"0x4"}')
+ self.vm.add_args('-device', '{"driver":"scsi-cd","bus":"scsi0.0"'
+ ',"channel":0,"scsi-id":0,"lun":0,"device_id":'
+ '"drive-scsi0-0-0-0","id":"scsi0-0-0-0"}')
+ self.vm.add_args('-device', '{"driver":"virtio-balloon-pci",'
+ '"id":"balloon0","bus":"pci.0","addr":"0x6"}')
+ self.vm.add_args('-audiodev', '{"id":"audio1","driver":"none"}')
+ self.vm.add_args('-device', '{"driver":"usb-tablet","id":"input0"'
+ ',"bus":"usb.0","port":"1"}')
+ self.vm.add_args('-device', '{"driver":"usb-kbd","id":"input1"'
+ ',"bus":"usb.0","port":"2"}')
+ self.vm.add_args('-device', '{"driver":"VGA","id":"video0",'
+ '"vgamem_mb":16,"bus":"pci.0","addr":"0x7"}')
+ self.vm.add_args('-object', '{"qom-type":"rng-random","id":"objrng0"'
+ ',"filename":"/dev/urandom"}',
+ '-device', '{"driver":"virtio-rng-pci","rng":"objrng0"'
+ ',"id":"rng0","bus":"pci.0","addr":"0x8"}')
+ self.vm.add_args('-object', '{"qom-type":"cryptodev-backend-builtin",'
+ '"id":"objcrypto0","queues":1}',
+ '-device', '{"driver":"virtio-crypto-pci",'
+ '"cryptodev":"objcrypto0","id":"crypto0","bus"'
+ ':"pci.0","addr":"0xa"}')
+ self.vm.add_args('-device', '{"driver":"spapr-pci-host-bridge"'
+ ',"index":1,"id":"pci.1"}')
+ self.vm.add_args('-device', '{"driver":"spapr-vscsi","id":"scsi1"'
+ ',"reg":12288}')
+ self.vm.add_args('-m', '2G,slots=32,maxmem=4G',
+ '-object', 'memory-backend-ram,id=ram1,size=1G',
+ '-device', 'pc-dimm,id=dimm1,memdev=ram1')
+
+ # Create a temporary qcow2 and launch the test-case
+ with tempfile.NamedTemporaryFile(prefix=prefix,
+ suffix='.qcow2') as qcow2:
+ run_cmd([self.qemu_img, 'create', '-f', 'qcow2', qcow2.name, ' 1G'])
+
+ self.vm.add_args('-drive', 'file=' + qcow2.name +
+ ',format=qcow2,if=none,id='
+ 'drive-virtio-disk1',
+ '-device', 'virtio-blk-pci,bus=pci.0,'
+ 'addr=0xb,drive=drive-virtio-disk1,id=virtio-disk1'
+ ',bootindex=2')
+ self.common_tuxrun(kernel_asset, rootfs_asset=rootfs_asset,
+ drive="scsi-hd")
+
+ ASSET_PPC64_KERNEL = Asset(
+ 'https://storage.tuxboot.com/20230331/ppc64/vmlinux',
+ '1d953e81a4379e537fc8e41e05a0a59d9b453eef97aa03d47866c6c45b00bdff')
+ ASSET_PPC64_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/20230331/ppc64/rootfs.ext4.zst',
+ 'f22a9b9e924174a4c199f4c7e5d91a2339fcfe51c6eafd0907dc3e09b64ab728')
+
+ def test_ppc64(self):
+ self.ppc64_common_tuxrun(kernel_asset=self.ASSET_PPC64_KERNEL,
+ rootfs_asset=self.ASSET_PPC64_ROOTFS,
+ prefix='tuxrun_ppc64_')
+
+ ASSET_PPC64LE_KERNEL = Asset(
+ 'https://storage.tuxboot.com/20230331/ppc64le/vmlinux',
+ '979eb61b445a010fb13e2b927126991f8ceef9c590fa2be0996c00e293e80cf2')
+ ASSET_PPC64LE_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/20230331/ppc64le/rootfs.ext4.zst',
+ 'b442678c93fb8abe1f7d3bfa20556488de6b475c22c8fed363f42cf81a0a3906')
+
+ def test_ppc64le(self):
+ self.ppc64_common_tuxrun(kernel_asset=self.ASSET_PPC64LE_KERNEL,
+ rootfs_asset=self.ASSET_PPC64LE_ROOTFS,
+ prefix='tuxrun_ppc64le_')
+
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/avocado/ppc_405.py b/tests/functional/test_ppc_405.py
index 4e7e01a..9851c03 100644..100755
--- a/tests/avocado/ppc_405.py
+++ b/tests/functional/test_ppc_405.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Test that the U-Boot firmware boots on ppc 405 machines and check the console
#
# Copyright (c) 2021 Red Hat, Inc.
@@ -5,20 +7,21 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from avocado.utils import archive
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
-from avocado_qemu import exec_command_and_wait_for_pattern
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern
+from qemu_test import exec_command_and_wait_for_pattern
class Ppc405Machine(QemuSystemTest):
timeout = 90
+ ASSET_UBOOT = Asset(
+ ('https://gitlab.com/huth/u-boot/-/raw/taihu-2021-10-09/'
+ 'u-boot-taihu.bin'),
+ 'a076bb6cdeaafa406330e51e074b66d8878d9036d67d4caa0137be03ee4c112c')
+
def do_test_ppc405(self):
- uboot_url = ('https://gitlab.com/huth/u-boot/-/raw/'
- 'taihu-2021-10-09/u-boot-taihu.bin')
- uboot_hash = ('3208940e908a5edc7c03eab072c60f0dcfadc2ab');
- file_path = self.fetch_asset(uboot_url, asset_hash=uboot_hash)
+ file_path = self.ASSET_UBOOT.fetch()
self.vm.set_console(console_index=1)
self.vm.add_args('-bios', file_path)
self.vm.launch()
@@ -26,11 +29,9 @@ class Ppc405Machine(QemuSystemTest):
exec_command_and_wait_for_pattern(self, 'reset', 'AMCC PowerPC 405EP')
def test_ppc_ref405ep(self):
- """
- :avocado: tags=arch:ppc
- :avocado: tags=machine:ref405ep
- :avocado: tags=cpu:405ep
- :avocado: tags=accel:tcg
- """
self.require_accelerator("tcg")
+ self.set_machine('ref405ep')
self.do_test_ppc405()
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/avocado/ppc_prep_40p.py b/tests/functional/test_ppc_40p.py
index d4f1eb7..c64e876 100644..100755
--- a/tests/avocado/ppc_prep_40p.py
+++ b/tests/functional/test_ppc_40p.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Functional test that boots a PReP/40p machine and checks its serial console.
#
# Copyright (c) Philippe Mathieu-DaudƩ <f4bug@amsat.org>
@@ -7,39 +9,40 @@
import os
-from avocado import skipUnless
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
+from unittest import skipUnless
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern
class IbmPrep40pMachine(QemuSystemTest):
timeout = 60
+ ASSET_BIOS = Asset(
+ ('http://ftpmirror.your.org/pub/misc/'
+ 'ftp.software.ibm.com/rs6000/firmware/'
+ '7020-40p/P12H0456.IMG'),
+ 'd957f79c73f760d1455d2286fcd901ed6d06167320eb73511b478a939be25b3f')
+ ASSET_NETBSD40 = Asset(
+ ('https://archive.netbsd.org/pub/NetBSD-archive/'
+ 'NetBSD-4.0/prep/installation/floppy/generic_com0.fs'),
+ 'f86236e9d01b3f0dd0f5d3b8d5bbd40c68e78b4db560a108358f5ad58e636619')
+ ASSET_NETBSD71 = Asset(
+ ('https://archive.netbsd.org/pub/NetBSD-archive/'
+ 'NetBSD-7.1.2/iso/NetBSD-7.1.2-prep.iso'),
+ 'cc7cb290b06aaa839362deb7bd9f417ac5015557db24088508330f76c3f825ec')
+
# 12H0455 PPS Firmware Licensed Materials
# Property of IBM (C) Copyright IBM Corp. 1994.
# All rights reserved.
# U.S. Government Users Restricted Rights - Use, duplication or disclosure
# restricted by GSA ADP Schedule Contract with IBM Corp.
- @skipUnless(os.getenv('AVOCADO_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
+ @skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
def test_factory_firmware_and_netbsd(self):
- """
- :avocado: tags=arch:ppc
- :avocado: tags=machine:40p
- :avocado: tags=os:netbsd
- :avocado: tags=slowness:high
- :avocado: tags=accel:tcg
- """
+ self.set_machine('40p')
self.require_accelerator("tcg")
- bios_url = ('http://ftpmirror.your.org/pub/misc/'
- 'ftp.software.ibm.com/rs6000/firmware/'
- '7020-40p/P12H0456.IMG')
- bios_hash = '1775face4e6dc27f3a6ed955ef6eb331bf817f03'
- bios_path = self.fetch_asset(bios_url, asset_hash=bios_hash)
- drive_url = ('https://archive.netbsd.org/pub/NetBSD-archive/'
- 'NetBSD-4.0/prep/installation/floppy/generic_com0.fs')
- drive_hash = 'dbcfc09912e71bd5f0d82c7c1ee43082fb596ceb'
- drive_path = self.fetch_asset(drive_url, asset_hash=drive_hash)
+ bios_path = self.ASSET_BIOS.fetch()
+ drive_path = self.ASSET_NETBSD40.fetch()
self.vm.set_console()
self.vm.add_args('-bios', bios_path,
@@ -50,11 +53,7 @@ class IbmPrep40pMachine(QemuSystemTest):
wait_for_console_pattern(self, 'Model: IBM PPS Model 6015')
def test_openbios_192m(self):
- """
- :avocado: tags=arch:ppc
- :avocado: tags=machine:40p
- :avocado: tags=accel:tcg
- """
+ self.set_machine('40p')
self.require_accelerator("tcg")
self.vm.set_console()
self.vm.add_args('-m', '192') # test fw_cfg
@@ -65,21 +64,15 @@ class IbmPrep40pMachine(QemuSystemTest):
wait_for_console_pattern(self, '>> CPU type PowerPC,604')
def test_openbios_and_netbsd(self):
- """
- :avocado: tags=arch:ppc
- :avocado: tags=machine:40p
- :avocado: tags=os:netbsd
- :avocado: tags=accel:tcg
- """
+ self.set_machine('40p')
self.require_accelerator("tcg")
- drive_url = ('https://archive.netbsd.org/pub/NetBSD-archive/'
- 'NetBSD-7.1.2/iso/NetBSD-7.1.2-prep.iso')
- drive_hash = 'ac6fa2707d888b36d6fa64de6e7fe48e'
- drive_path = self.fetch_asset(drive_url, asset_hash=drive_hash,
- algorithm='md5')
+ drive_path = self.ASSET_NETBSD71.fetch()
self.vm.set_console()
self.vm.add_args('-cdrom', drive_path,
'-boot', 'd')
self.vm.launch()
wait_for_console_pattern(self, 'NetBSD/prep BOOT, Revision 1.9')
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/avocado/ppc_74xx.py b/tests/functional/test_ppc_74xx.py
index f54757c..5386016 100644..100755
--- a/tests/avocado/ppc_74xx.py
+++ b/tests/functional/test_ppc_74xx.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Smoke tests for 74xx cpus (aka G4).
#
# Copyright (c) 2021, IBM Corp.
@@ -5,132 +7,120 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
+from qemu_test import QemuSystemTest
+from qemu_test import wait_for_console_pattern
class ppc74xxCpu(QemuSystemTest):
- """
- :avocado: tags=arch:ppc
- :avocado: tags=accel:tcg
- """
+
timeout = 5
def test_ppc_7400(self):
- """
- :avocado: tags=cpu:7400
- """
self.require_accelerator("tcg")
+ self.set_machine('g3beige')
self.vm.set_console()
+ self.vm.add_args('-cpu', '7400')
self.vm.launch()
wait_for_console_pattern(self, '>> OpenBIOS')
wait_for_console_pattern(self, '>> CPU type PowerPC,G4')
def test_ppc_7410(self):
- """
- :avocado: tags=cpu:7410
- """
self.require_accelerator("tcg")
+ self.set_machine('g3beige')
self.vm.set_console()
+ self.vm.add_args('-cpu', '7410')
self.vm.launch()
wait_for_console_pattern(self, '>> OpenBIOS')
wait_for_console_pattern(self, '>> CPU type PowerPC,74xx')
def test_ppc_7441(self):
- """
- :avocado: tags=cpu:7441
- """
self.require_accelerator("tcg")
+ self.set_machine('g3beige')
self.vm.set_console()
+ self.vm.add_args('-cpu', '7441')
self.vm.launch()
wait_for_console_pattern(self, '>> OpenBIOS')
wait_for_console_pattern(self, '>> CPU type PowerPC,G4')
def test_ppc_7445(self):
- """
- :avocado: tags=cpu:7445
- """
self.require_accelerator("tcg")
+ self.set_machine('g3beige')
self.vm.set_console()
+ self.vm.add_args('-cpu', '7445')
self.vm.launch()
wait_for_console_pattern(self, '>> OpenBIOS')
wait_for_console_pattern(self, '>> CPU type PowerPC,G4')
def test_ppc_7447(self):
- """
- :avocado: tags=cpu:7447
- """
self.require_accelerator("tcg")
+ self.set_machine('g3beige')
self.vm.set_console()
+ self.vm.add_args('-cpu', '7447')
self.vm.launch()
wait_for_console_pattern(self, '>> OpenBIOS')
wait_for_console_pattern(self, '>> CPU type PowerPC,G4')
def test_ppc_7447a(self):
- """
- :avocado: tags=cpu:7447a
- """
self.require_accelerator("tcg")
+ self.set_machine('g3beige')
self.vm.set_console()
+ self.vm.add_args('-cpu', '7447a')
self.vm.launch()
wait_for_console_pattern(self, '>> OpenBIOS')
wait_for_console_pattern(self, '>> CPU type PowerPC,G4')
def test_ppc_7448(self):
- """
- :avocado: tags=cpu:7448
- """
self.require_accelerator("tcg")
+ self.set_machine('g3beige')
self.vm.set_console()
+ self.vm.add_args('-cpu', '7448')
self.vm.launch()
wait_for_console_pattern(self, '>> OpenBIOS')
wait_for_console_pattern(self, '>> CPU type PowerPC,MPC86xx')
def test_ppc_7450(self):
- """
- :avocado: tags=cpu:7450
- """
self.require_accelerator("tcg")
+ self.set_machine('g3beige')
self.vm.set_console()
+ self.vm.add_args('-cpu', '7450')
self.vm.launch()
wait_for_console_pattern(self, '>> OpenBIOS')
wait_for_console_pattern(self, '>> CPU type PowerPC,G4')
def test_ppc_7451(self):
- """
- :avocado: tags=cpu:7451
- """
self.require_accelerator("tcg")
+ self.set_machine('g3beige')
self.vm.set_console()
+ self.vm.add_args('-cpu', '7451')
self.vm.launch()
wait_for_console_pattern(self, '>> OpenBIOS')
wait_for_console_pattern(self, '>> CPU type PowerPC,G4')
def test_ppc_7455(self):
- """
- :avocado: tags=cpu:7455
- """
self.require_accelerator("tcg")
+ self.set_machine('g3beige')
self.vm.set_console()
+ self.vm.add_args('-cpu', '7455')
self.vm.launch()
wait_for_console_pattern(self, '>> OpenBIOS')
wait_for_console_pattern(self, '>> CPU type PowerPC,G4')
def test_ppc_7457(self):
- """
- :avocado: tags=cpu:7457
- """
self.require_accelerator("tcg")
+ self.set_machine('g3beige')
self.vm.set_console()
+ self.vm.add_args('-cpu', '7457')
self.vm.launch()
wait_for_console_pattern(self, '>> OpenBIOS')
wait_for_console_pattern(self, '>> CPU type PowerPC,G4')
def test_ppc_7457a(self):
- """
- :avocado: tags=cpu:7457a
- """
self.require_accelerator("tcg")
+ self.set_machine('g3beige')
self.vm.set_console()
+ self.vm.add_args('-cpu', '7457a')
self.vm.launch()
wait_for_console_pattern(self, '>> OpenBIOS')
wait_for_console_pattern(self, '>> CPU type PowerPC,G4')
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_ppc_amiga.py b/tests/functional/test_ppc_amiga.py
new file mode 100755
index 0000000..b793b5c
--- /dev/null
+++ b/tests/functional/test_ppc_amiga.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python3
+#
+# Test AmigaNG boards
+#
+# Copyright (c) 2023 BALATON Zoltan
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+import subprocess
+
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern, run_cmd
+from zipfile import ZipFile
+
+class AmigaOneMachine(QemuSystemTest):
+
+ timeout = 90
+
+ ASSET_IMAGE = Asset(
+ ('https://www.hyperion-entertainment.com/index.php/'
+ 'downloads?view=download&format=raw&file=25'),
+ '8ff39330ba47d4f64de4ee8fd6809e9c010a9ef17fe51e95c3c1d53437cb481f')
+
+ def test_ppc_amigaone(self):
+ self.require_accelerator("tcg")
+ self.set_machine('amigaone')
+ tar_name = 'A1Firmware_Floppy_05-Mar-2005.zip'
+ zip_file = self.ASSET_IMAGE.fetch()
+ with ZipFile(zip_file, 'r') as zf:
+ zf.extractall(path=self.workdir)
+ bios_fh = open(self.workdir + "/u-boot-amigaone.bin", "wb")
+ subprocess.run(['tail', '-c', '524288',
+ self.workdir + "/floppy_edition/updater.image"],
+ stdout=bios_fh)
+
+ self.vm.set_console()
+ self.vm.add_args('-bios', self.workdir + '/u-boot-amigaone.bin')
+ self.vm.launch()
+ wait_for_console_pattern(self, 'FLASH:')
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/avocado/ppc_bamboo.py b/tests/functional/test_ppc_bamboo.py
index a81be3d..e72cbde 100644..100755
--- a/tests/avocado/ppc_bamboo.py
+++ b/tests/functional/test_ppc_bamboo.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Test that Linux kernel boots on the ppc bamboo board and check the console
#
# Copyright (c) 2021 Red Hat
@@ -5,30 +7,26 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from avocado.utils import archive
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
-from avocado_qemu import exec_command_and_wait_for_pattern
+from qemu_test.utils import archive_extract
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern
+from qemu_test import exec_command_and_wait_for_pattern
class BambooMachine(QemuSystemTest):
timeout = 90
+ ASSET_IMAGE = Asset(
+ ('http://landley.net/aboriginal/downloads/binaries/'
+ 'system-image-powerpc-440fp.tar.gz'),
+ 'c12b58f841c775a0e6df4832a55afe6b74814d1565d08ddeafc1fb949a075c5e')
+
def test_ppc_bamboo(self):
- """
- :avocado: tags=arch:ppc
- :avocado: tags=machine:bamboo
- :avocado: tags=cpu:440epb
- :avocado: tags=device:rtl8139
- :avocado: tags=accel:tcg
- """
+ self.set_machine('bamboo')
self.require_accelerator("tcg")
self.require_netdev('user')
- tar_url = ('http://landley.net/aboriginal/downloads/binaries/'
- 'system-image-powerpc-440fp.tar.gz')
- tar_hash = '53e5f16414b195b82d2c70272f81c2eedb39bad9'
- file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- archive.extract(file_path, self.workdir)
+ file_path = self.ASSET_IMAGE.fetch()
+ archive_extract(file_path, self.workdir)
self.vm.set_console()
self.vm.add_args('-kernel', self.workdir +
'/system-image-powerpc-440fp/linux',
@@ -40,3 +38,6 @@ class BambooMachine(QemuSystemTest):
exec_command_and_wait_for_pattern(self, 'ping 10.0.2.2',
'10.0.2.2 is alive!')
exec_command_and_wait_for_pattern(self, 'halt', 'System Halted')
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_ppc_mac.py b/tests/functional/test_ppc_mac.py
new file mode 100755
index 0000000..3f45e37
--- /dev/null
+++ b/tests/functional/test_ppc_mac.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python3
+#
+# Boot Linux kernel on a mac99 and g3beige ppc machine and check the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test.utils import archive_extract
+
+class MacTest(LinuxKernelTest):
+
+ ASSET_DAY15 = Asset(
+ 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day15.tar.xz',
+ '03e0757c131d2959decf293a3572d3b96c5a53587165bf05ce41b2818a2bccd5')
+
+ def do_day15_test(self):
+ # mac99 also works with kvm_pr but we don't have a reliable way at
+ # the moment (e.g. by looking at /proc/modules) to detect whether
+ # we're running kvm_hv or kvm_pr. For now let's disable this test
+ # if we don't have TCG support.
+ self.require_accelerator("tcg")
+
+ file_path = self.ASSET_DAY15.fetch()
+ archive_extract(file_path, self.workdir)
+ self.vm.add_args('-M', 'graphics=off')
+ self.launch_kernel(self.workdir + '/day15/invaders.elf',
+ wait_for='QEMU advent calendar')
+
+ def test_ppc_g3beige(self):
+ self.set_machine('g3beige')
+ self.do_day15_test()
+
+ def test_ppc_mac99(self):
+ self.set_machine('mac99')
+ self.do_day15_test()
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/avocado/ppc_mpc8544ds.py b/tests/functional/test_ppc_mpc8544ds.py
index b599fb1..2b3f089 100644..100755
--- a/tests/avocado/ppc_mpc8544ds.py
+++ b/tests/functional/test_ppc_mpc8544ds.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Test that Linux kernel boots on ppc machines and check the console
#
# Copyright (c) 2018, 2020 Red Hat, Inc.
@@ -5,9 +7,9 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from avocado.utils import archive
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
+from qemu_test.utils import archive_extract
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern
class Mpc8544dsMachine(QemuSystemTest):
@@ -15,20 +17,21 @@ class Mpc8544dsMachine(QemuSystemTest):
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
panic_message = 'Kernel panic - not syncing'
+ ASSET_IMAGE = Asset(
+ ('https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/'
+ 'day04.tar.xz'),
+ '88bc83f3c9f3d633bcfc108a6342d677abca247066a2fb8d4636744a0d319f94')
+
def test_ppc_mpc8544ds(self):
- """
- :avocado: tags=arch:ppc
- :avocado: tags=machine:mpc8544ds
- :avocado: tags=accel:tcg
- """
self.require_accelerator("tcg")
- tar_url = ('https://qemu-advcal.gitlab.io'
- '/qac-best-of-multiarch/download/day04.tar.xz')
- tar_hash = 'f46724d281a9f30fa892d458be7beb7d34dc25f9'
- file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- archive.extract(file_path, self.workdir)
+ self.set_machine('mpc8544ds')
+ file_path = self.ASSET_IMAGE.fetch()
+ archive_extract(file_path, self.workdir, member='creek/creek.bin')
self.vm.set_console()
self.vm.add_args('-kernel', self.workdir + '/creek/creek.bin')
self.vm.launch()
wait_for_console_pattern(self, 'QEMU advent calendar 2020',
self.panic_message)
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_ppc_tuxrun.py b/tests/functional/test_ppc_tuxrun.py
new file mode 100755
index 0000000..50b7694
--- /dev/null
+++ b/tests/functional/test_ppc_tuxrun.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex BennƩe <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunPPC32Test(TuxRunBaselineTest):
+
+ ASSET_PPC32_KERNEL = Asset(
+ 'https://storage.tuxboot.com/20230331/ppc32/uImage',
+ '1a68f74b860fda022fb12e03c5efece8c2b8b590d96cca37a8481a3ae0b3f81f')
+ ASSET_PPC32_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/20230331/ppc32/rootfs.ext4.zst',
+ '8885b9d999cc24d679542a02e9b6aaf48f718f2050ece6b8347074b6ee41dd09')
+
+ def test_ppc32(self):
+ self.set_machine('ppce500')
+ self.cpu='e500mc'
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_PPC32_KERNEL,
+ rootfs_asset=self.ASSET_PPC32_ROOTFS,
+ drive="virtio-blk-pci")
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/avocado/ppc_virtex_ml507.py b/tests/functional/test_ppc_virtex_ml507.py
index a73f8ae..ffa9a06 100644..100755
--- a/tests/avocado/ppc_virtex_ml507.py
+++ b/tests/functional/test_ppc_virtex_ml507.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Test that Linux kernel boots on ppc machines and check the console
#
# Copyright (c) 2018, 2020 Red Hat, Inc.
@@ -5,9 +7,9 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from avocado.utils import archive
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
+from qemu_test.utils import archive_extract
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern
class VirtexMl507Machine(QemuSystemTest):
@@ -15,18 +17,16 @@ class VirtexMl507Machine(QemuSystemTest):
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
panic_message = 'Kernel panic - not syncing'
+ ASSET_IMAGE = Asset(
+ ('https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/'
+ 'day08.tar.xz'),
+ 'cefe5b8aeb5e9d2d1d4fd22dcf48d917d68d5a765132bf2ddd6332dc393b824c')
+
def test_ppc_virtex_ml507(self):
- """
- :avocado: tags=arch:ppc
- :avocado: tags=machine:virtex-ml507
- :avocado: tags=accel:tcg
- """
self.require_accelerator("tcg")
- tar_url = ('https://qemu-advcal.gitlab.io'
- '/qac-best-of-multiarch/download/day08.tar.xz')
- tar_hash = '74c68f5af7a7b8f21c03097b298f3bb77ff52c1f'
- file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- archive.extract(file_path, self.workdir)
+ self.set_machine('virtex-ml507')
+ file_path = self.ASSET_IMAGE.fetch()
+ archive_extract(file_path, self.workdir)
self.vm.set_console()
self.vm.add_args('-kernel', self.workdir + '/hippo/hippo.linux',
'-dtb', self.workdir + '/hippo/virtex440-ml507.dtb',
@@ -34,3 +34,6 @@ class VirtexMl507Machine(QemuSystemTest):
self.vm.launch()
wait_for_console_pattern(self, 'QEMU advent calendar 2020',
self.panic_message)
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_riscv32_tuxrun.py b/tests/functional/test_riscv32_tuxrun.py
new file mode 100755
index 0000000..49b57cd
--- /dev/null
+++ b/tests/functional/test_riscv32_tuxrun.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex BennƩe <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunRiscV32Test(TuxRunBaselineTest):
+
+ ASSET_RISCV32_KERNEL = Asset(
+ 'https://storage.tuxboot.com/20230331/riscv32/Image',
+ '89599407d7334de629a40e7ad6503c73670359eb5f5ae9d686353a3d6deccbd5')
+ ASSET_RISCV32_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/20230331/riscv32/rootfs.ext4.zst',
+ '7168d296d0283238ea73cd5a775b3dd608e55e04c7b92b76ecce31bb13108cba')
+
+ def test_riscv32(self):
+ self.set_machine('virt')
+ self.common_tuxrun(kernel_asset=self.ASSET_RISCV32_KERNEL,
+ rootfs_asset=self.ASSET_RISCV32_ROOTFS)
+
+ def test_riscv32_maxcpu(self):
+ self.set_machine('virt')
+ self.cpu='max'
+ self.common_tuxrun(kernel_asset=self.ASSET_RISCV32_KERNEL,
+ rootfs_asset=self.ASSET_RISCV32_ROOTFS)
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_riscv64_tuxrun.py b/tests/functional/test_riscv64_tuxrun.py
new file mode 100755
index 0000000..1350162
--- /dev/null
+++ b/tests/functional/test_riscv64_tuxrun.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex BennƩe <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunRiscV64Test(TuxRunBaselineTest):
+
+ ASSET_RISCV64_KERNEL = Asset(
+ 'https://storage.tuxboot.com/20230331/riscv64/Image',
+ 'cd634badc65e52fb63465ec99e309c0de0369f0841b7d9486f9729e119bac25e')
+ ASSET_RISCV64_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/20230331/riscv64/rootfs.ext4.zst',
+ 'b18e3a3bdf27be03da0b285e84cb71bf09eca071c3a087b42884b6982ed679eb')
+
+ def test_riscv64(self):
+ self.set_machine('virt')
+ self.common_tuxrun(kernel_asset=self.ASSET_RISCV64_KERNEL,
+ rootfs_asset=self.ASSET_RISCV64_ROOTFS)
+
+ def test_riscv64_maxcpu(self):
+ self.set_machine('virt')
+ self.cpu='max'
+ self.common_tuxrun(kernel_asset=self.ASSET_RISCV64_KERNEL,
+ rootfs_asset=self.ASSET_RISCV64_ROOTFS)
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/avocado/machine_rx_gdbsim.py b/tests/functional/test_rx_gdbsim.py
index 412a7a5..5687f75 100644..100755
--- a/tests/avocado/machine_rx_gdbsim.py
+++ b/tests/functional/test_rx_gdbsim.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Functional test that boots a Linux kernel and checks the console
#
# Copyright (c) 2018 Red Hat, Inc.
@@ -10,11 +12,11 @@
import os
-from avocado import skipUnless
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import exec_command_and_wait_for_pattern
-from avocado_qemu import wait_for_console_pattern
-from avocado.utils import archive
+from unittest import skipUnless
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import exec_command_and_wait_for_pattern
+from qemu_test import wait_for_console_pattern
+from qemu_test.utils import gzip_uncompress
class RxGdbSimMachine(QemuSystemTest):
@@ -22,21 +24,25 @@ class RxGdbSimMachine(QemuSystemTest):
timeout = 30
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
+ ASSET_UBOOT = Asset(
+ 'https://acc.dl.osdn.jp/users/23/23888/u-boot.bin.gz',
+ '7146567d669e91dbac166384b29aeba1715beb844c8551e904b86831bfd9d046')
+ ASSET_DTB = Asset(
+ 'https://acc.dl.osdn.jp/users/23/23887/rx-virt.dtb',
+ 'aa278d9c1907a4501741d7ee57e7f65c02dd1b3e0323b33c6d4247f1b32cf29a')
+ ASSET_KERNEL = Asset(
+ 'http://acc.dl.osdn.jp/users/23/23845/zImage',
+ 'baa43205e74a7220ed8482188c5e9ce497226712abb7f4e7e4f825ce19ff9656')
def test_uboot(self):
"""
U-Boot and checks that the console is operational.
-
- :avocado: tags=arch:rx
- :avocado: tags=machine:gdbsim-r5f562n8
- :avocado: tags=endian:little
- :avocado: tags=flaky
"""
- uboot_url = ('https://acc.dl.osdn.jp/users/23/23888/u-boot.bin.gz')
- uboot_hash = '9b78dbd43b40b2526848c0b1ce9de02c24f4dcdb'
- uboot_path = self.fetch_asset(uboot_url, asset_hash=uboot_hash)
- uboot_path = archive.uncompress(uboot_path, self.workdir)
+ self.set_machine('gdbsim-r5f562n8')
+
+ uboot_path_gz = self.ASSET_UBOOT.fetch()
+ uboot_path = os.path.join(self.workdir, 'u-boot.bin')
+ gzip_uncompress(uboot_path_gz, uboot_path)
self.vm.set_console()
self.vm.add_args('-bios', uboot_path,
@@ -49,22 +55,14 @@ class RxGdbSimMachine(QemuSystemTest):
#exec_command_and_wait_for_pattern(self, 'version', gcc_version)
@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
-
def test_linux_sash(self):
"""
Boots a Linux kernel and checks that the console is operational.
-
- :avocado: tags=arch:rx
- :avocado: tags=machine:gdbsim-r5f562n7
- :avocado: tags=endian:little
- :avocado: tags=flaky
"""
- dtb_url = ('https://acc.dl.osdn.jp/users/23/23887/rx-virt.dtb')
- dtb_hash = '7b4e4e2c71905da44e86ce47adee2210b026ac18'
- dtb_path = self.fetch_asset(dtb_url, asset_hash=dtb_hash)
- kernel_url = ('http://acc.dl.osdn.jp/users/23/23845/zImage')
- kernel_hash = '39a81067f8d72faad90866ddfefa19165d68fc99'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
+ self.set_machine('gdbsim-r5f562n7')
+
+ dtb_path = self.ASSET_DTB.fetch()
+ kernel_path = self.ASSET_KERNEL.fetch()
self.vm.set_console()
kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'earlycon'
@@ -75,3 +73,6 @@ class RxGdbSimMachine(QemuSystemTest):
wait_for_console_pattern(self, 'Sash command shell (version 1.1.1)',
failure_message='Kernel panic - not syncing')
exec_command_and_wait_for_pattern(self, 'printenv', 'TERM=linux')
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/avocado/machine_s390_ccw_virtio.py b/tests/functional/test_s390x_ccw_virtio.py
index 26e938c..f7acd90 100644..100755
--- a/tests/avocado/machine_s390_ccw_virtio.py
+++ b/tests/functional/test_s390x_ccw_virtio.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Functional test that boots an s390x Linux guest with ccw and PCI devices
# attached and checks whether the devices are recognized by Linux
#
@@ -12,17 +14,38 @@
import os
import tempfile
-from avocado import skipUnless
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import exec_command_and_wait_for_pattern
-from avocado_qemu import wait_for_console_pattern
-from avocado.utils import archive
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import exec_command_and_wait_for_pattern
+from qemu_test import wait_for_console_pattern
+from qemu_test.utils import lzma_uncompress
class S390CCWVirtioMachine(QemuSystemTest):
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
timeout = 120
+ ASSET_BUSTER_KERNEL = Asset(
+ ('https://snapshot.debian.org/archive/debian/'
+ '20201126T092837Z/dists/buster/main/installer-s390x/'
+ '20190702+deb10u6/images/generic/kernel.debian'),
+ 'd411d17c39ae7ad38d27534376cbe88b68b403c325739364122c2e6f1537e818')
+ ASSET_BUSTER_INITRD = Asset(
+ ('https://snapshot.debian.org/archive/debian/'
+ '20201126T092837Z/dists/buster/main/installer-s390x/'
+ '20190702+deb10u6/images/generic/initrd.debian'),
+ '836bbd0fe6a5ca81274c28c2b063ea315ce1868660866e9b60180c575fef9fd5')
+
+ ASSET_F31_KERNEL = Asset(
+ ('https://archives.fedoraproject.org/pub/archive'
+ '/fedora-secondary/releases/31/Server/s390x/os'
+ '/images/kernel.img'),
+ '480859574f3f44caa6cd35c62d70e1ac0609134e22ce2a954bbed9b110c06e0b')
+ ASSET_F31_INITRD = Asset(
+ ('https://archives.fedoraproject.org/pub/archive'
+ '/fedora-secondary/releases/31/Server/s390x/os'
+ '/images/initrd.img'),
+ '04c46095b2c49020b1c2327158898b7db747e4892ae319726192fb949716aa9c')
+
def wait_for_console_pattern(self, success_message, vm=None):
wait_for_console_pattern(self, success_message,
failure_message='Kernel panic - not syncing',
@@ -41,23 +64,10 @@ class S390CCWVirtioMachine(QemuSystemTest):
self.dmesg_clear_count += 1
def test_s390x_devices(self):
+ self.set_machine('s390-ccw-virtio')
- """
- :avocado: tags=arch:s390x
- :avocado: tags=machine:s390-ccw-virtio
- """
-
- kernel_url = ('https://snapshot.debian.org/archive/debian/'
- '20201126T092837Z/dists/buster/main/installer-s390x/'
- '20190702+deb10u6/images/generic/kernel.debian')
- kernel_hash = '5821fbee57d6220a067a8b967d24595621aa1eb6'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
-
- initrd_url = ('https://snapshot.debian.org/archive/debian/'
- '20201126T092837Z/dists/buster/main/installer-s390x/'
- '20190702+deb10u6/images/generic/initrd.debian')
- initrd_hash = '81ba09c97bef46e8f4660ac25b4ac0a5be3a94d6'
- initrd_path = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
+ kernel_path = self.ASSET_BUSTER_KERNEL.fetch()
+ initrd_path = self.ASSET_BUSTER_INITRD.fetch()
self.vm.set_console()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
@@ -160,29 +170,13 @@ class S390CCWVirtioMachine(QemuSystemTest):
def test_s390x_fedora(self):
+ self.set_machine('s390-ccw-virtio')
- """
- :avocado: tags=arch:s390x
- :avocado: tags=machine:s390-ccw-virtio
- :avocado: tags=device:virtio-gpu
- :avocado: tags=device:virtio-crypto
- :avocado: tags=device:virtio-net
- :avocado: tags=flaky
- """
-
- kernel_url = ('https://archives.fedoraproject.org/pub/archive'
- '/fedora-secondary/releases/31/Server/s390x/os'
- '/images/kernel.img')
- kernel_hash = 'b93d1efcafcf29c1673a4ce371a1f8b43941cfeb'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
+ kernel_path = self.ASSET_F31_KERNEL.fetch()
- initrd_url = ('https://archives.fedoraproject.org/pub/archive'
- '/fedora-secondary/releases/31/Server/s390x/os'
- '/images/initrd.img')
- initrd_hash = '3de45d411df5624b8d8ef21cd0b44419ab59b12f'
- initrd_path_xz = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
+ initrd_path_xz = self.ASSET_F31_INITRD.fetch()
initrd_path = os.path.join(self.workdir, 'initrd-raw.img')
- archive.lzma_uncompress(initrd_path_xz, initrd_path)
+ lzma_uncompress(initrd_path_xz, initrd_path)
self.vm.set_console()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + ' audit=0 '
@@ -200,6 +194,8 @@ class S390CCWVirtioMachine(QemuSystemTest):
'-device', 'virtio-rng-ccw,devno=fe.1.9876',
'-device', 'virtio-gpu-ccw,devno=fe.2.5432')
self.vm.launch()
+ self.wait_for_console_pattern('Kernel command line: %s'
+ % kernel_command_line)
self.wait_for_console_pattern('Entering emergency mode')
# Some tests to see whether the CLI options have been considered:
@@ -275,3 +271,6 @@ class S390CCWVirtioMachine(QemuSystemTest):
exec_command_and_wait_for_pattern(self,
'while ! (dmesg -c | grep Start.virtcrypto_remove) ; do'
' sleep 1 ; done', 'Start virtcrypto_remove.')
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/avocado/s390_topology.py b/tests/functional/test_s390x_topology.py
index 9154ac8..20727f6 100644..100755
--- a/tests/avocado/s390_topology.py
+++ b/tests/functional/test_s390x_topology.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Functional test that boots a Linux kernel and checks the console
#
# Copyright IBM Corp. 2023
@@ -9,16 +11,13 @@
# later. See the COPYING file in the top-level directory.
import os
-import shutil
import time
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import exec_command
-from avocado_qemu import exec_command_and_wait_for_pattern
-from avocado_qemu import interrupt_interactive_console_until_pattern
-from avocado_qemu import wait_for_console_pattern
-from avocado.utils import process
-from avocado.utils import archive
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import exec_command
+from qemu_test import exec_command_and_wait_for_pattern
+from qemu_test import wait_for_console_pattern
+from qemu_test.utils import lzma_uncompress
class S390CPUTopology(QemuSystemTest):
@@ -47,6 +46,17 @@ class S390CPUTopology(QemuSystemTest):
'root=/dev/ram '
'selinux=0 '
'rdinit=/bin/sh')
+ ASSET_F35_KERNEL = Asset(
+ ('https://archives.fedoraproject.org/pub/archive'
+ '/fedora-secondary/releases/35/Server/s390x/os'
+ '/images/kernel.img'),
+ '1f2dddfd11bb1393dd2eb2e784036fbf6fc11057a6d7d27f9eb12d3edc67ef73')
+
+ ASSET_F35_INITRD = Asset(
+ ('https://archives.fedoraproject.org/pub/archive'
+ '/fedora-secondary/releases/35/Server/s390x/os'
+ '/images/initrd.img'),
+ '1100145fbca00240c8c372ae4b89b48c99844bc189b3dfbc3f481dc60055ca46')
def wait_until_booted(self):
wait_for_console_pattern(self, 'no job control',
@@ -78,21 +88,10 @@ class S390CPUTopology(QemuSystemTest):
We need a minimal root filesystem with a shell.
"""
self.require_accelerator("kvm")
- kernel_url = ('https://archives.fedoraproject.org/pub/archive'
- '/fedora-secondary/releases/35/Server/s390x/os'
- '/images/kernel.img')
- kernel_hash = '0d1aaaf303f07cf0160c8c48e56fe638'
- kernel_path = self.fetch_asset(kernel_url, algorithm='md5',
- asset_hash=kernel_hash)
-
- initrd_url = ('https://archives.fedoraproject.org/pub/archive'
- '/fedora-secondary/releases/35/Server/s390x/os'
- '/images/initrd.img')
- initrd_hash = 'a122057d95725ac030e2ec51df46e172'
- initrd_path_xz = self.fetch_asset(initrd_url, algorithm='md5',
- asset_hash=initrd_hash)
+ kernel_path = self.ASSET_F35_KERNEL.fetch()
+ initrd_path_xz = self.ASSET_F35_INITRD.fetch()
initrd_path = os.path.join(self.workdir, 'initrd-raw.img')
- archive.lzma_uncompress(initrd_path_xz, initrd_path)
+ lzma_uncompress(initrd_path_xz, initrd_path)
self.vm.set_console()
kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE
@@ -115,10 +114,8 @@ class S390CPUTopology(QemuSystemTest):
def test_single(self):
"""
This test checks the simplest topology with a single CPU.
-
- :avocado: tags=arch:s390x
- :avocado: tags=machine:s390-ccw-virtio
"""
+ self.set_machine('s390-ccw-virtio')
self.kernel_init()
self.vm.launch()
self.wait_until_booted()
@@ -127,10 +124,8 @@ class S390CPUTopology(QemuSystemTest):
def test_default(self):
"""
This test checks the implicit topology.
-
- :avocado: tags=arch:s390x
- :avocado: tags=machine:s390-ccw-virtio
"""
+ self.set_machine('s390-ccw-virtio')
self.kernel_init()
self.vm.add_args('-smp',
'13,drawers=2,books=2,sockets=3,cores=2,maxcpus=24')
@@ -154,10 +149,8 @@ class S390CPUTopology(QemuSystemTest):
"""
This test checks the topology modification by moving a CPU
to another socket: CPU 0 is moved from socket 0 to socket 2.
-
- :avocado: tags=arch:s390x
- :avocado: tags=machine:s390-ccw-virtio
"""
+ self.set_machine('s390-ccw-virtio')
self.kernel_init()
self.vm.add_args('-smp',
'1,drawers=2,books=2,sockets=3,cores=2,maxcpus=24')
@@ -174,10 +167,8 @@ class S390CPUTopology(QemuSystemTest):
"""
This test verifies that a CPU defined with the '-device'
command line option finds its right place inside the topology.
-
- :avocado: tags=arch:s390x
- :avocado: tags=machine:s390-ccw-virtio
"""
+ self.set_machine('s390-ccw-virtio')
self.kernel_init()
self.vm.add_args('-smp',
'1,drawers=2,books=2,sockets=3,cores=2,maxcpus=24')
@@ -221,10 +212,8 @@ class S390CPUTopology(QemuSystemTest):
"""
This test verifies that QEMU modifies the entitlement change after
several guest polarization change requests.
-
- :avocado: tags=arch:s390x
- :avocado: tags=machine:s390-ccw-virtio
"""
+ self.set_machine('s390-ccw-virtio')
self.kernel_init()
self.vm.launch()
self.wait_until_booted()
@@ -267,10 +256,8 @@ class S390CPUTopology(QemuSystemTest):
"""
This test verifies that QEMU modifies the entitlement
after a guest request and that the guest sees the change.
-
- :avocado: tags=arch:s390x
- :avocado: tags=machine:s390-ccw-virtio
"""
+ self.set_machine('s390-ccw-virtio')
self.kernel_init()
self.vm.launch()
self.wait_until_booted()
@@ -313,10 +300,8 @@ class S390CPUTopology(QemuSystemTest):
CPU is made dedicated.
QEMU retains the entitlement value when horizontal polarization is in effect.
For the guest, the field shows the effective value of the entitlement.
-
- :avocado: tags=arch:s390x
- :avocado: tags=machine:s390-ccw-virtio
"""
+ self.set_machine('s390-ccw-virtio')
self.kernel_init()
self.vm.launch()
self.wait_until_booted()
@@ -345,10 +330,8 @@ class S390CPUTopology(QemuSystemTest):
This test verifies that QEMU does not accept to overload a socket.
The socket-id 0 on book-id 0 already contains CPUs 0 and 1 and can
not accept any new CPU while socket-id 0 on book-id 1 is free.
-
- :avocado: tags=arch:s390x
- :avocado: tags=machine:s390-ccw-virtio
"""
+ self.set_machine('s390-ccw-virtio')
self.kernel_init()
self.vm.add_args('-smp',
'3,drawers=2,books=2,sockets=3,cores=2,maxcpus=24')
@@ -369,10 +352,8 @@ class S390CPUTopology(QemuSystemTest):
"""
This test verifies that QEMU refuses to lower the entitlement
of a dedicated CPU
-
- :avocado: tags=arch:s390x
- :avocado: tags=machine:s390-ccw-virtio
"""
+ self.set_machine('s390-ccw-virtio')
self.kernel_init()
self.vm.launch()
self.wait_until_booted()
@@ -417,10 +398,8 @@ class S390CPUTopology(QemuSystemTest):
"""
This test verifies that QEMU refuses to move a CPU to an
nonexistent location
-
- :avocado: tags=arch:s390x
- :avocado: tags=machine:s390-ccw-virtio
"""
+ self.set_machine('s390-ccw-virtio')
self.kernel_init()
self.vm.launch()
self.wait_until_booted()
@@ -437,3 +416,6 @@ class S390CPUTopology(QemuSystemTest):
self.assertEqual(res['error']['class'], 'GenericError')
self.check_topology(0, 0, 0, 0, 'medium', False)
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_s390x_tuxrun.py b/tests/functional/test_s390x_tuxrun.py
new file mode 100755
index 0000000..dcab17c
--- /dev/null
+++ b/tests/functional/test_s390x_tuxrun.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex BennƩe <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunS390xTest(TuxRunBaselineTest):
+
+ ASSET_S390X_KERNEL = Asset(
+ 'https://storage.tuxboot.com/20230331/s390/bzImage',
+ '0414e98dd1c3dafff8496c9cd9c28a5f8d04553bb5ba37e906a812b48d442ef0')
+ ASSET_S390X_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/20230331/s390/rootfs.ext4.zst',
+ '88c37c32276677f873a25ab9ec6247895b8e3e6f8259134de2a616080b8ab3fc')
+
+ def test_s390(self):
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_S390X_KERNEL,
+ rootfs_asset=self.ASSET_S390X_ROOTFS,
+ drive="virtio-blk-ccw",
+ haltmsg="Requesting system halt")
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_sh4_r2d.py b/tests/functional/test_sh4_r2d.py
new file mode 100755
index 0000000..c3cfff7
--- /dev/null
+++ b/tests/functional/test_sh4_r2d.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python3
+#
+# Boot a Linux kernel on a r2d sh4 machine and check the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test.utils import archive_extract
+from unittest import skipUnless
+
+class R2dTest(LinuxKernelTest):
+
+ ASSET_DAY09 = Asset(
+ 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day09.tar.xz',
+ 'a61b44d2630a739d1380cc4ff4b80981d47ccfd5992f1484ccf48322c35f09ac')
+
+ # This test has a 6-10% failure rate on various hosts that look
+ # like issues with a buggy kernel.
+ @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable')
+ def test_r2d(self):
+ self.set_machine('r2d')
+ file_path = self.ASSET_DAY09.fetch()
+ archive_extract(file_path, self.workdir)
+ self.vm.add_args('-append', 'console=ttySC1')
+ self.launch_kernel(self.workdir + '/day09/zImage', console_index=1,
+ wait_for='QEMU advent calendar')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_sh4_tuxrun.py b/tests/functional/test_sh4_tuxrun.py
new file mode 100755
index 0000000..352cb36
--- /dev/null
+++ b/tests/functional/test_sh4_tuxrun.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex BennƩe <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+import time
+
+from unittest import skipUnless
+from qemu_test import Asset, exec_command_and_wait_for_pattern, exec_command
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunSh4Test(TuxRunBaselineTest):
+
+ ASSET_SH4_KERNEL = Asset(
+ 'https://storage.tuxboot.com/20230331/sh4/zImage',
+ '29d9b2aba604a0f53a5dc3b5d0f2b8e35d497de1129f8ee5139eb6fdf0db692f')
+ ASSET_SH4_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/20230331/sh4/rootfs.ext4.zst',
+ '3592a7a3d5a641e8b9821449e77bc43c9904a56c30d45da0694349cfd86743fd')
+
+ # Note: some segfaults caused by unaligned userspace access
+ @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable')
+ def test_sh4(self):
+ self.set_machine('r2d')
+ self.cpu='sh7785'
+ self.root='sda'
+ self.console='ttySC1'
+
+ # The test is currently too unstable to do much in userspace
+ # so we skip common_tuxrun and do a minimal boot and shutdown.
+ (kernel, disk, dtb) = self.fetch_tuxrun_assets(self.ASSET_SH4_KERNEL,
+ self.ASSET_SH4_ROOTFS)
+
+ # the console comes on the second serial port
+ self.prepare_run(kernel, disk,
+ "driver=ide-hd,bus=ide.0,unit=0",
+ console_index=1)
+ self.vm.launch()
+
+ self.wait_for_console_pattern("Welcome to TuxTest")
+ time.sleep(0.1)
+ exec_command(self, 'root')
+ time.sleep(0.1)
+ exec_command_and_wait_for_pattern(self, 'halt',
+ "reboot: System halted")
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_sparc64_sun4u.py b/tests/functional/test_sparc64_sun4u.py
new file mode 100755
index 0000000..32e245f
--- /dev/null
+++ b/tests/functional/test_sparc64_sun4u.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel and checks the console
+#
+# Copyright (c) 2020 Red Hat, Inc.
+#
+# Author:
+# Thomas Huth <thuth@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+import os
+
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern
+from qemu_test.utils import archive_extract
+
+class Sun4uMachine(QemuSystemTest):
+ """Boots the Linux kernel and checks that the console is operational"""
+
+ timeout = 90
+
+ ASSET_IMAGE = Asset(
+ ('https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/'
+ 'day23.tar.xz'),
+ 'a3ed92450704af244178351afd0e769776e7decb298e95a63abfd9a6e3f6c854')
+
+ def test_sparc64_sun4u(self):
+ self.set_machine('sun4u')
+ file_path = self.ASSET_IMAGE.fetch()
+ kernel_name = 'day23/vmlinux'
+ archive_extract(file_path, self.workdir, kernel_name)
+ self.vm.set_console()
+ self.vm.add_args('-kernel', os.path.join(self.workdir, kernel_name),
+ '-append', 'printk.time=0')
+ self.vm.launch()
+ wait_for_console_pattern(self, 'Starting logging: OK')
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_sparc64_tuxrun.py b/tests/functional/test_sparc64_tuxrun.py
new file mode 100755
index 0000000..1c2c005
--- /dev/null
+++ b/tests/functional/test_sparc64_tuxrun.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex BennƩe <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunSparc64Test(TuxRunBaselineTest):
+
+ ASSET_SPARC64_KERNEL = Asset(
+ 'https://storage.tuxboot.com/20230331/sparc64/vmlinux',
+ 'e34313e4325ff21deaa3d38a502aa09a373ef62b9bd4d7f8f29388b688225c55')
+ ASSET_SPARC64_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/20230331/sparc64/rootfs.ext4.zst',
+ 'ad2f1dc436ab51583543d25d2c210cab478645d47078d30d129a66ab0e281d76')
+
+ def test_sparc64(self):
+ self.root='sda'
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_SPARC64_KERNEL,
+ rootfs_asset=self.ASSET_SPARC64_ROOTFS,
+ drive="driver=ide-hd,bus=ide.0,unit=0")
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/functional/test_sparc_sun4m.py b/tests/functional/test_sparc_sun4m.py
new file mode 100755
index 0000000..573f852
--- /dev/null
+++ b/tests/functional/test_sparc_sun4m.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on a sparc sun4m machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test.utils import archive_extract
+
+class Sun4mTest(LinuxKernelTest):
+
+ ASSET_DAY11 = Asset(
+ 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day11.tar.xz',
+ 'c776533ba756bf4dd3f1fc4c024fb50ef0d853e05c5f5ddf0900a32d1eaa49e0')
+
+ def test_sparc_ss20(self):
+ self.set_machine('SS-20')
+ file_path = self.ASSET_DAY11.fetch()
+ archive_extract(file_path, self.workdir)
+ self.launch_kernel(self.workdir + '/day11/zImage.elf',
+ wait_for='QEMU advent calendar')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/avocado/version.py b/tests/functional/test_version.py
index c613956..3ab3b67 100644..100755
--- a/tests/avocado/version.py
+++ b/tests/functional/test_version.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Version check example test
#
# Copyright (c) 2018 Red Hat, Inc.
@@ -9,17 +11,18 @@
# later. See the COPYING file in the top-level directory.
-from avocado_qemu import QemuSystemTest
+from qemu_test import QemuSystemTest
class Version(QemuSystemTest):
- """
- :avocado: tags=quick
- :avocado: tags=machine:none
- """
+
def test_qmp_human_info_version(self):
+ self.set_machine('none')
self.vm.add_args('-nodefaults')
self.vm.launch()
res = self.vm.cmd('human-monitor-command',
command_line='info version')
self.assertRegex(res, r'^(\d+\.\d+\.\d)')
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/avocado/virtio-gpu.py b/tests/functional/test_virtio_gpu.py
index 6091f61..441cbdc 100644..100755
--- a/tests/avocado/virtio-gpu.py
+++ b/tests/functional/test_virtio_gpu.py
@@ -1,14 +1,16 @@
+#!/usr/bin/env python3
+#
# virtio-gpu tests
#
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from avocado_qemu import BUILD_DIR
-from avocado_qemu import QemuSystemTest
-from avocado_qemu import wait_for_console_pattern
-from avocado_qemu import exec_command_and_wait_for_pattern
-from avocado_qemu import is_readable_executable_file
+from qemu_test import BUILD_DIR
+from qemu_test import QemuSystemTest, Asset
+from qemu_test import wait_for_console_pattern
+from qemu_test import exec_command_and_wait_for_pattern
+from qemu_test import is_readable_executable_file
from qemu.utils import kvm_available
@@ -28,25 +30,18 @@ def pick_default_vug_bin():
class VirtioGPUx86(QemuSystemTest):
- """
- :avocado: tags=virtio-gpu
- :avocado: tags=arch:x86_64
- :avocado: tags=cpu:host
- """
KERNEL_COMMAND_LINE = "printk.time=0 console=ttyS0 rdinit=/bin/bash"
- KERNEL_URL = (
- "https://archives.fedoraproject.org/pub/archive/fedora"
- "/linux/releases/33/Everything/x86_64/os/images"
- "/pxeboot/vmlinuz"
- )
- KERNEL_HASH = '1433cfe3f2ffaa44de4ecfb57ec25dc2399cdecf'
- INITRD_URL = (
- "https://archives.fedoraproject.org/pub/archive/fedora"
- "/linux/releases/33/Everything/x86_64/os/images"
- "/pxeboot/initrd.img"
- )
- INITRD_HASH = 'c828d68a027b53e5220536585efe03412332c2d9'
+ ASSET_KERNEL = Asset(
+ ("https://archives.fedoraproject.org/pub/archive/fedora"
+ "/linux/releases/33/Everything/x86_64/os/images"
+ "/pxeboot/vmlinuz"),
+ '2dc5fb5cfe9ac278fa45640f3602d9b7a08cc189ed63fd9b162b07073e4df397')
+ ASSET_INITRD = Asset(
+ ("https://archives.fedoraproject.org/pub/archive/fedora"
+ "/linux/releases/33/Everything/x86_64/os/images"
+ "/pxeboot/initrd.img"),
+ 'c49b97f893a5349e4883452178763e402bdc5caa8845b226a2d1329b5f356045')
def wait_for_console_pattern(self, success_message, vm=None):
wait_for_console_pattern(
@@ -57,16 +52,14 @@ class VirtioGPUx86(QemuSystemTest):
)
def test_virtio_vga_virgl(self):
- """
- :avocado: tags=device:virtio-vga-gl
- """
# FIXME: should check presence of virtio, virgl etc
self.require_accelerator('kvm')
- kernel_path = self.fetch_asset(self.KERNEL_URL, self.KERNEL_HASH)
- initrd_path = self.fetch_asset(self.INITRD_URL, self.INITRD_HASH)
+ kernel_path = self.ASSET_KERNEL.fetch()
+ initrd_path = self.ASSET_INITRD.fetch()
self.vm.set_console()
+ self.vm.add_args("-cpu", "host")
self.vm.add_args("-m", "2G")
self.vm.add_args("-machine", "pc,accel=kvm")
self.vm.add_args("-device", "virtio-vga-gl")
@@ -83,7 +76,7 @@ class VirtioGPUx86(QemuSystemTest):
self.vm.launch()
except:
# TODO: probably fails because we are missing the VirGL features
- self.cancel("VirGL not enabled?")
+ self.skipTest("VirGL not enabled?")
self.wait_for_console_pattern("as init process")
exec_command_and_wait_for_pattern(
@@ -92,18 +85,15 @@ class VirtioGPUx86(QemuSystemTest):
self.wait_for_console_pattern("features: +virgl +edid")
def test_vhost_user_vga_virgl(self):
- """
- :avocado: tags=device:vhost-user-vga
- """
# FIXME: should check presence of vhost-user-gpu, virgl, memfd etc
self.require_accelerator('kvm')
vug = pick_default_vug_bin()
if not vug:
- self.cancel("Could not find vhost-user-gpu")
+ self.skipTest("Could not find vhost-user-gpu")
- kernel_path = self.fetch_asset(self.KERNEL_URL, self.KERNEL_HASH)
- initrd_path = self.fetch_asset(self.INITRD_URL, self.INITRD_HASH)
+ kernel_path = self.ASSET_KERNEL.fetch()
+ initrd_path = self.ASSET_INITRD.fetch()
# Create socketpair to connect proxy and remote processes
qemu_sock, vug_sock = socket.socketpair(
@@ -129,6 +119,7 @@ class VirtioGPUx86(QemuSystemTest):
)
self.vm.set_console()
+ self.vm.add_args("-cpu", "host")
self.vm.add_args("-m", "2G")
self.vm.add_args("-object", "memory-backend-memfd,id=mem,size=2G")
self.vm.add_args("-machine", "pc,memory-backend=mem,accel=kvm")
@@ -147,7 +138,7 @@ class VirtioGPUx86(QemuSystemTest):
self.vm.launch()
except:
# TODO: probably fails because we are missing the VirGL features
- self.cancel("VirGL not enabled?")
+ self.skipTest("VirGL not enabled?")
self.wait_for_console_pattern("as init process")
exec_command_and_wait_for_pattern(self, "/usr/sbin/modprobe virtio_gpu",
"features: +virgl +edid")
@@ -155,3 +146,6 @@ class VirtioGPUx86(QemuSystemTest):
qemu_sock.close()
vugp.terminate()
vugp.wait()
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/avocado/virtio_version.py b/tests/functional/test_virtio_version.py
index afe5e82..eb23060 100644..100755
--- a/tests/avocado/virtio_version.py
+++ b/tests/functional/test_virtio_version.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python3
"""
Check compatibility of virtio device types
"""
@@ -12,7 +13,7 @@ import sys
import os
from qemu.machine import QEMUMachine
-from avocado_qemu import QemuSystemTest
+from qemu_test import QemuSystemTest
# Virtio Device IDs:
VIRTIO_NET = 1
@@ -60,8 +61,6 @@ class VirtioVersionCheck(QemuSystemTest):
Check if virtio-version-specific device types result in the
same device tree created by `disable-modern` and
`disable-legacy`.
-
- :avocado: tags=arch:x86_64
"""
# just in case there are failures, show larger diff:
@@ -173,3 +172,6 @@ class VirtioVersionCheck(QemuSystemTest):
self.check_modern_only('virtio-mouse-pci', VIRTIO_INPUT)
self.check_modern_only('virtio-tablet-pci', VIRTIO_INPUT)
self.check_modern_only('virtio-keyboard-pci', VIRTIO_INPUT)
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_x86_64_tuxrun.py b/tests/functional/test_x86_64_tuxrun.py
new file mode 100755
index 0000000..4f96139
--- /dev/null
+++ b/tests/functional/test_x86_64_tuxrun.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots known good tuxboot images the same way
+# that tuxrun (www.tuxrun.org) does. This tool is used by things like
+# the LKFT project to run regression tests on kernels.
+#
+# Copyright (c) 2023 Linaro Ltd.
+#
+# Author:
+# Alex BennƩe <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import Asset
+from qemu_test.tuxruntest import TuxRunBaselineTest
+
+class TuxRunX86Test(TuxRunBaselineTest):
+
+ ASSET_X86_64_KERNEL = Asset(
+ 'https://storage.tuxboot.com/20230331/x86_64/bzImage',
+ '2bc7480a669ee9b6b82500a236aba0c54233debe98cb968268fa230f52f03461')
+ ASSET_X86_64_ROOTFS = Asset(
+ 'https://storage.tuxboot.com/20230331/x86_64/rootfs.ext4.zst',
+ 'b72ac729769b8f51c6dffb221113c9a063c774dbe1d66af30eb593c4e9999b4b')
+
+ def test_x86_64(self):
+ self.set_machine('q35')
+ self.cpu="Nehalem"
+ self.root='sda'
+ self.wait_for_shutdown=False
+ self.common_tuxrun(kernel_asset=self.ASSET_X86_64_KERNEL,
+ rootfs_asset=self.ASSET_X86_64_ROOTFS,
+ drive="driver=ide-hd,bus=ide.0,unit=0")
+
+if __name__ == '__main__':
+ TuxRunBaselineTest.main()
diff --git a/tests/avocado/x86_cpu_model_versions.py b/tests/functional/test_x86_cpu_model_versions.py
index 11101e0..bd18acd 100644..100755
--- a/tests/avocado/x86_cpu_model_versions.py
+++ b/tests/functional/test_x86_cpu_model_versions.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python3
#
# Basic validation of x86 versioned CPU models and CPU model aliases
#
@@ -20,15 +21,13 @@
# License along with this library; if not, see <http://www.gnu.org/licenses/>.
#
-
-import avocado_qemu
import re
-class X86CPUModelAliases(avocado_qemu.QemuSystemTest):
+from qemu_test import QemuSystemTest
+
+class X86CPUModelAliases(QemuSystemTest):
"""
Validation of PC CPU model versions and CPU model aliases
-
- :avocado: tags=arch:x86_64
"""
def validate_aliases(self, cpus):
for c in cpus.values():
@@ -76,9 +75,8 @@ class X86CPUModelAliases(avocado_qemu.QemuSystemTest):
def test_4_0_alias_compatibility(self):
"""
Check if pc-*-4.0 unversioned CPU model won't be reported as aliases
-
- :avocado: tags=machine:pc-i440fx-4.0
"""
+ self.set_machine('pc-i440fx-4.0')
# pc-*-4.0 won't expose non-versioned CPU models as aliases
# We do this to help management software to keep compatibility
# with older QEMU versions that didn't have the versioned CPU model
@@ -110,9 +108,8 @@ class X86CPUModelAliases(avocado_qemu.QemuSystemTest):
def test_4_1_alias(self):
"""
Check if unversioned CPU model is an alias pointing to right version
-
- :avocado: tags=machine:pc-i440fx-4.1
"""
+ self.set_machine('pc-i440fx-4.1')
self.vm.add_args('-S')
self.vm.launch()
@@ -217,9 +214,8 @@ class X86CPUModelAliases(avocado_qemu.QemuSystemTest):
def test_none_alias(self):
"""
Check if unversioned CPU model is an alias pointing to some version
-
- :avocado: tags=machine:none
"""
+ self.set_machine('none')
self.vm.add_args('-S')
self.vm.launch()
@@ -243,21 +239,16 @@ class X86CPUModelAliases(avocado_qemu.QemuSystemTest):
self.validate_aliases(cpus)
-class CascadelakeArchCapabilities(avocado_qemu.QemuSystemTest):
+class CascadelakeArchCapabilities(QemuSystemTest):
"""
Validation of Cascadelake arch-capabilities
-
- :avocado: tags=arch:x86_64
"""
def get_cpu_prop(self, prop):
cpu_path = self.vm.cmd('query-cpus-fast')[0].get('qom-path')
return self.vm.cmd('qom-get', path=cpu_path, property=prop)
def test_4_1(self):
- """
- :avocado: tags=machine:pc-i440fx-4.1
- :avocado: tags=cpu:Cascadelake-Server
- """
+ self.set_machine('pc-i440fx-4.1')
# machine-type only:
self.vm.add_args('-S')
self.set_vm_arg('-cpu',
@@ -268,10 +259,7 @@ class CascadelakeArchCapabilities(avocado_qemu.QemuSystemTest):
'pc-i440fx-4.1 + Cascadelake-Server should not have arch-capabilities')
def test_4_0(self):
- """
- :avocado: tags=machine:pc-i440fx-4.0
- :avocado: tags=cpu:Cascadelake-Server
- """
+ self.set_machine('pc-i440fx-4.0')
self.vm.add_args('-S')
self.set_vm_arg('-cpu',
'Cascadelake-Server,x-force-features=on,check=off,'
@@ -281,10 +269,7 @@ class CascadelakeArchCapabilities(avocado_qemu.QemuSystemTest):
'pc-i440fx-4.0 + Cascadelake-Server should not have arch-capabilities')
def test_set_4_0(self):
- """
- :avocado: tags=machine:pc-i440fx-4.0
- :avocado: tags=cpu:Cascadelake-Server
- """
+ self.set_machine('pc-i440fx-4.0')
# command line must override machine-type if CPU model is not versioned:
self.vm.add_args('-S')
self.set_vm_arg('-cpu',
@@ -295,10 +280,7 @@ class CascadelakeArchCapabilities(avocado_qemu.QemuSystemTest):
'pc-i440fx-4.0 + Cascadelake-Server,+arch-capabilities should have arch-capabilities')
def test_unset_4_1(self):
- """
- :avocado: tags=machine:pc-i440fx-4.1
- :avocado: tags=cpu:Cascadelake-Server
- """
+ self.set_machine('pc-i440fx-4.1')
self.vm.add_args('-S')
self.set_vm_arg('-cpu',
'Cascadelake-Server,x-force-features=on,check=off,'
@@ -308,10 +290,7 @@ class CascadelakeArchCapabilities(avocado_qemu.QemuSystemTest):
'pc-i440fx-4.1 + Cascadelake-Server,-arch-capabilities should not have arch-capabilities')
def test_v1_4_0(self):
- """
- :avocado: tags=machine:pc-i440fx-4.0
- :avocado: tags=cpu:Cascadelake-Server
- """
+ self.set_machine('pc-i440fx-4.0')
# versioned CPU model overrides machine-type:
self.vm.add_args('-S')
self.set_vm_arg('-cpu',
@@ -322,10 +301,7 @@ class CascadelakeArchCapabilities(avocado_qemu.QemuSystemTest):
'pc-i440fx-4.0 + Cascadelake-Server-v1 should not have arch-capabilities')
def test_v2_4_0(self):
- """
- :avocado: tags=machine:pc-i440fx-4.0
- :avocado: tags=cpu:Cascadelake-Server
- """
+ self.set_machine('pc-i440fx-4.0')
self.vm.add_args('-S')
self.set_vm_arg('-cpu',
'Cascadelake-Server-v2,x-force-features=on,check=off,'
@@ -335,10 +311,7 @@ class CascadelakeArchCapabilities(avocado_qemu.QemuSystemTest):
'pc-i440fx-4.0 + Cascadelake-Server-v2 should have arch-capabilities')
def test_v1_set_4_0(self):
- """
- :avocado: tags=machine:pc-i440fx-4.0
- :avocado: tags=cpu:Cascadelake-Server
- """
+ self.set_machine('pc-i440fx-4.0')
# command line must override machine-type and versioned CPU model:
self.vm.add_args('-S')
self.set_vm_arg('-cpu',
@@ -349,10 +322,7 @@ class CascadelakeArchCapabilities(avocado_qemu.QemuSystemTest):
'pc-i440fx-4.0 + Cascadelake-Server-v1,+arch-capabilities should have arch-capabilities')
def test_v2_unset_4_1(self):
- """
- :avocado: tags=machine:pc-i440fx-4.1
- :avocado: tags=cpu:Cascadelake-Server
- """
+ self.set_machine('pc-i440fx-4.1')
self.vm.add_args('-S')
self.set_vm_arg('-cpu',
'Cascadelake-Server-v2,x-force-features=on,check=off,'
@@ -360,3 +330,6 @@ class CascadelakeArchCapabilities(avocado_qemu.QemuSystemTest):
self.vm.launch()
self.assertFalse(self.get_cpu_prop('arch-capabilities'),
'pc-i440fx-4.1 + Cascadelake-Server-v2,-arch-capabilities should not have arch-capabilities')
+
+if __name__ == '__main__':
+ QemuSystemTest.main()
diff --git a/tests/functional/test_xtensa_lx60.py b/tests/functional/test_xtensa_lx60.py
new file mode 100755
index 0000000..d4ad92d
--- /dev/null
+++ b/tests/functional/test_xtensa_lx60.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel on an xtensa lx650 machine
+# and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+from qemu_test.utils import archive_extract
+
+class XTensaLX60Test(LinuxKernelTest):
+
+ ASSET_DAY02 = Asset(
+ 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day02.tar.xz',
+ '68ff07f9b3fd3df36d015eb46299ba44748e94bfbb2d5295fddc1a8d4a9fd324')
+
+ def test_xtensa_lx60(self):
+ self.set_machine('lx60')
+ self.cpu = 'dc233c'
+ file_path = self.ASSET_DAY02.fetch()
+ archive_extract(file_path, self.workdir)
+ self.launch_kernel(self.workdir + '/day02/santas-sleigh-ride.elf',
+ wait_for='QEMU advent calendar')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/guest-debug/run-test.py b/tests/guest-debug/run-test.py
index 368ff8a..5a091db 100755
--- a/tests/guest-debug/run-test.py
+++ b/tests/guest-debug/run-test.py
@@ -27,6 +27,10 @@ def get_args():
parser.add_argument("--binary", help="Binary to debug",
required=True)
parser.add_argument("--test", help="GDB test script")
+ parser.add_argument('test_args', nargs='*',
+ help="Additional args for GDB test script. "
+ "The args should be preceded by -- to avoid confusion "
+ "with flags for runner script")
parser.add_argument("--gdb", help="The gdb binary to use",
default=None)
parser.add_argument("--gdb-args", help="Additional gdb arguments")
@@ -91,6 +95,8 @@ if __name__ == '__main__':
gdb_cmd += " -ex 'target remote %s'" % (socket_name)
# finally the test script itself
if args.test:
+ if args.test_args:
+ gdb_cmd += f" -ex \"py sys.argv={args.test_args}\""
gdb_cmd += " -x %s" % (args.test)
diff --git a/tests/guest-debug/test_gdbstub.py b/tests/guest-debug/test_gdbstub.py
index 46fbf98..a715c0e 100644
--- a/tests/guest-debug/test_gdbstub.py
+++ b/tests/guest-debug/test_gdbstub.py
@@ -2,6 +2,7 @@
"""
from __future__ import print_function
+import argparse
import gdb
import os
import sys
@@ -9,6 +10,10 @@ import traceback
fail_count = 0
+class arg_parser(argparse.ArgumentParser):
+ def exit(self, status=None, message=""):
+ print("Wrong GDB script test argument! " + message)
+ gdb.execute("exit 1")
def report(cond, msg):
"""Report success/fail of a test"""
diff --git a/tests/lcitool/libvirt-ci b/tests/lcitool/libvirt-ci
-Subproject 0e9490cebc726ef772b6c9e27dac32e7ae99f9b
+Subproject 6b19006b2cbe01adea6a857c71860a8e7ba7ddd
diff --git a/tests/lcitool/mappings.yml b/tests/lcitool/mappings.yml
index 03b974a..9c5ac87 100644
--- a/tests/lcitool/mappings.yml
+++ b/tests/lcitool/mappings.yml
@@ -2,6 +2,20 @@ mappings:
flake8:
OpenSUSELeap15:
+ # Due to https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1081535 we
+ # have to disable all packages that depend on libgl1-mesa-dri:mips64el
+ gtk3:
+ mips64el-deb:
+
+ libdrm:
+ mips64el-deb:
+
+ libepoxy:
+ mips64el-deb:
+
+ mesa-libgbm:
+ mips64el-deb:
+
meson:
OpenSUSELeap15:
@@ -60,10 +74,22 @@ mappings:
python3-wheel:
OpenSUSELeap15: python311-pip
+ sdl2:
+ mips64el-deb:
+
+ sdl2-image:
+ mips64el-deb:
+
+ virglrenderer:
+ mips64el-deb:
+
+ vte:
+ mips64el-deb:
+
pypi_mappings:
# Request more recent version
meson:
- default: meson==0.63.2
+ default: meson==1.5.0
# Drop packages that need devel headers
python3-numpy:
diff --git a/tests/lcitool/projects/qemu.yml b/tests/lcitool/projects/qemu.yml
index 0c85784..252e871 100644
--- a/tests/lcitool/projects/qemu.yml
+++ b/tests/lcitool/projects/qemu.yml
@@ -32,6 +32,7 @@ packages:
- glusterfs
- gnutls
- gtk3
+ - gtk-vnc
- hostname
- json-c
- libaio
diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh
index ac803e3..0f16f4d 100755
--- a/tests/lcitool/refresh
+++ b/tests/lcitool/refresh
@@ -116,6 +116,26 @@ debian12_extras = [
"ENV QEMU_CONFIGURE_OPTS --enable-netmap\n"
]
+# Based on the hub.docker.com/library/rust Dockerfiles
+fedora_rustup_nightly_extras = [
+ "RUN dnf install -y wget\n",
+ "ENV RUSTUP_HOME=/usr/local/rustup CARGO_HOME=/usr/local/cargo\n",
+ "ENV RUSTC=/usr/local/rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/rustc\n",
+ "RUN set -eux && \\\n",
+ " rustArch='x86_64-unknown-linux-gnu' && \\\n",
+ " rustupSha256='6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d' && \\\n",
+ ' url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" && \\\n',
+ ' wget "$url" && \\\n',
+ ' echo "${rustupSha256} *rustup-init" | sha256sum -c - && \\\n',
+ " chmod +x rustup-init && \\\n",
+ " ./rustup-init -y --no-modify-path --profile default --default-toolchain nightly --default-host ${rustArch} && \\\n",
+ " chmod -R a+w $RUSTUP_HOME $CARGO_HOME && \\\n",
+ " /usr/local/cargo/bin/rustup --version && \\\n",
+ " /usr/local/cargo/bin/rustup run nightly rustc --version && \\\n",
+ ' test "$RUSTC" = "$(/usr/local/cargo/bin/rustup +nightly which rustc)"\n',
+ 'ENV PATH=$CARGO_HOME/bin:$PATH\n',
+ 'RUN /usr/local/cargo/bin/rustup run nightly cargo install bindgen-cli\n',
+]
def cross_build(prefix, targets):
conf = "ENV QEMU_CONFIGURE_OPTS --cross-prefix=%s\n" % (prefix)
@@ -140,6 +160,12 @@ try:
generate_dockerfile("ubuntu2204", "ubuntu-2204")
#
+ # Non-fatal Rust-enabled build
+ #
+ generate_dockerfile("fedora-rust-nightly", "fedora-40",
+ trailer="".join(fedora_rustup_nightly_extras))
+
+ #
# Cross compiling builds
#
generate_dockerfile("debian-amd64-cross", "debian-12",
@@ -154,30 +180,24 @@ try:
trailer=cross_build("aarch64-linux-gnu-",
"aarch64-softmmu,aarch64-linux-user"))
- # migration to bookworm stalled: https://lists.debian.org/debian-arm/2023/09/msg00006.html
- generate_dockerfile("debian-armel-cross", "debian-11",
- cross="armv6l",
- trailer=cross_build("arm-linux-gnueabi-",
- "arm-softmmu,arm-linux-user,armeb-linux-user"))
-
generate_dockerfile("debian-armhf-cross", "debian-12",
cross="armv7l",
trailer=cross_build("arm-linux-gnueabihf-",
"arm-softmmu,arm-linux-user"))
- generate_dockerfile("debian-i686-cross", "debian-11",
+ generate_dockerfile("debian-i686-cross", "debian-12",
cross="i686",
trailer=cross_build("i686-linux-gnu-",
"x86_64-softmmu,"
"x86_64-linux-user,"
"i386-softmmu,i386-linux-user"))
- generate_dockerfile("debian-mips64el-cross", "debian-11",
+ generate_dockerfile("debian-mips64el-cross", "debian-12",
cross="mips64el",
trailer=cross_build("mips64el-linux-gnuabi64-",
"mips64el-softmmu,mips64el-linux-user"))
- generate_dockerfile("debian-mipsel-cross", "debian-11",
+ generate_dockerfile("debian-mipsel-cross", "debian-12",
cross="mipsel",
trailer=cross_build("mipsel-linux-gnu-",
"mipsel-softmmu,mipsel-linux-user"))
@@ -207,14 +227,14 @@ try:
#
# Cirrus packages lists for GitLab
#
- generate_cirrus("freebsd-13")
- generate_cirrus("macos-13")
+ generate_cirrus("freebsd-14")
generate_cirrus("macos-14")
+ generate_cirrus("macos-15")
#
# VM packages lists
#
- generate_pkglist("freebsd", "freebsd-13")
+ generate_pkglist("freebsd", "freebsd-14")
#
# Ansible package lists
diff --git a/tests/meson.build b/tests/meson.build
index acb6807..907a4c1 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -78,10 +78,11 @@ subdir('decode')
if 'CONFIG_TCG' in config_all_accel
subdir('fp')
- subdir('plugin')
+ subdir('tcg/plugins')
endif
subdir('unit')
subdir('qapi-schema')
subdir('qtest')
subdir('migration')
+subdir('functional')
diff --git a/tests/plugin/mem.c b/tests/plugin/mem.c
deleted file mode 100644
index b650ddd..0000000
--- a/tests/plugin/mem.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2018, Emilio G. Cota <cota@braap.org>
- *
- * License: GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-#include <inttypes.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <glib.h>
-
-#include <qemu-plugin.h>
-
-QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
-
-typedef struct {
- uint64_t mem_count;
- uint64_t io_count;
-} CPUCount;
-
-static struct qemu_plugin_scoreboard *counts;
-static qemu_plugin_u64 mem_count;
-static qemu_plugin_u64 io_count;
-static bool do_inline, do_callback;
-static bool do_haddr;
-static enum qemu_plugin_mem_rw rw = QEMU_PLUGIN_MEM_RW;
-
-static void plugin_exit(qemu_plugin_id_t id, void *p)
-{
- g_autoptr(GString) out = g_string_new("");
-
- if (do_inline || do_callback) {
- g_string_printf(out, "mem accesses: %" PRIu64 "\n",
- qemu_plugin_u64_sum(mem_count));
- }
- if (do_haddr) {
- g_string_append_printf(out, "io accesses: %" PRIu64 "\n",
- qemu_plugin_u64_sum(io_count));
- }
- qemu_plugin_outs(out->str);
- qemu_plugin_scoreboard_free(counts);
-}
-
-static void vcpu_mem(unsigned int cpu_index, qemu_plugin_meminfo_t meminfo,
- uint64_t vaddr, void *udata)
-{
- if (do_haddr) {
- struct qemu_plugin_hwaddr *hwaddr;
- hwaddr = qemu_plugin_get_hwaddr(meminfo, vaddr);
- if (qemu_plugin_hwaddr_is_io(hwaddr)) {
- qemu_plugin_u64_add(io_count, cpu_index, 1);
- } else {
- qemu_plugin_u64_add(mem_count, cpu_index, 1);
- }
- } else {
- qemu_plugin_u64_add(mem_count, cpu_index, 1);
- }
-}
-
-static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
-{
- size_t n = qemu_plugin_tb_n_insns(tb);
- size_t i;
-
- for (i = 0; i < n; i++) {
- struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
-
- if (do_inline) {
- qemu_plugin_register_vcpu_mem_inline_per_vcpu(
- insn, rw,
- QEMU_PLUGIN_INLINE_ADD_U64,
- mem_count, 1);
- }
- if (do_callback) {
- qemu_plugin_register_vcpu_mem_cb(insn, vcpu_mem,
- QEMU_PLUGIN_CB_NO_REGS,
- rw, NULL);
- }
- }
-}
-
-QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
- const qemu_info_t *info,
- int argc, char **argv)
-{
-
- for (int i = 0; i < argc; i++) {
- char *opt = argv[i];
- g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
-
- if (g_strcmp0(tokens[0], "haddr") == 0) {
- if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_haddr)) {
- fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
- return -1;
- }
- } else if (g_strcmp0(tokens[0], "track") == 0) {
- if (g_strcmp0(tokens[1], "r") == 0) {
- rw = QEMU_PLUGIN_MEM_R;
- } else if (g_strcmp0(tokens[1], "w") == 0) {
- rw = QEMU_PLUGIN_MEM_W;
- } else if (g_strcmp0(tokens[1], "rw") == 0) {
- rw = QEMU_PLUGIN_MEM_RW;
- } else {
- fprintf(stderr, "invalid value for argument track: %s\n", opt);
- return -1;
- }
- } else if (g_strcmp0(tokens[0], "inline") == 0) {
- if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_inline)) {
- fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
- return -1;
- }
- } else if (g_strcmp0(tokens[0], "callback") == 0) {
- if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_callback)) {
- fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
- return -1;
- }
- } else {
- fprintf(stderr, "option parsing failed: %s\n", opt);
- return -1;
- }
- }
-
- if (do_inline && do_callback) {
- fprintf(stderr,
- "can't enable inline and callback counting at the same time\n");
- return -1;
- }
-
- counts = qemu_plugin_scoreboard_new(sizeof(CPUCount));
- mem_count = qemu_plugin_scoreboard_u64_in_struct(
- counts, CPUCount, mem_count);
- io_count = qemu_plugin_scoreboard_u64_in_struct(counts, CPUCount, io_count);
- qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
- qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
- return 0;
-}
diff --git a/tests/qapi-schema/alternate-array.out b/tests/qapi-schema/alternate-array.out
index a657d85..2f30973 100644
--- a/tests/qapi-schema/alternate-array.out
+++ b/tests/qapi-schema/alternate-array.out
@@ -1,7 +1,6 @@
module ./builtin
object q_empty
enum QType
- prefix QTYPE
member none
member qnull
member qnum
diff --git a/tests/qapi-schema/comments.out b/tests/qapi-schema/comments.out
index ce4f6a4..937070c 100644
--- a/tests/qapi-schema/comments.out
+++ b/tests/qapi-schema/comments.out
@@ -1,7 +1,6 @@
module ./builtin
object q_empty
enum QType
- prefix QTYPE
member none
member qnull
member qnum
diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out
index 6d24f11..ec277be 100644
--- a/tests/qapi-schema/doc-good.out
+++ b/tests/qapi-schema/doc-good.out
@@ -1,7 +1,6 @@
module ./builtin
object q_empty
enum QType
- prefix QTYPE
member none
member qnull
member qnum
diff --git a/tests/qapi-schema/empty.out b/tests/qapi-schema/empty.out
index 3feb3f6..d1981f8 100644
--- a/tests/qapi-schema/empty.out
+++ b/tests/qapi-schema/empty.out
@@ -1,7 +1,6 @@
module ./builtin
object q_empty
enum QType
- prefix QTYPE
member none
member qnull
member qnum
diff --git a/tests/qapi-schema/include-repetition.out b/tests/qapi-schema/include-repetition.out
index 16dbd9b..c564d27 100644
--- a/tests/qapi-schema/include-repetition.out
+++ b/tests/qapi-schema/include-repetition.out
@@ -1,7 +1,6 @@
module ./builtin
object q_empty
enum QType
- prefix QTYPE
member none
member qnull
member qnum
diff --git a/tests/qapi-schema/include-simple.out b/tests/qapi-schema/include-simple.out
index 48e923b..ec8200a 100644
--- a/tests/qapi-schema/include-simple.out
+++ b/tests/qapi-schema/include-simple.out
@@ -1,7 +1,6 @@
module ./builtin
object q_empty
enum QType
- prefix QTYPE
member none
member qnull
member qnum
diff --git a/tests/qapi-schema/indented-expr.out b/tests/qapi-schema/indented-expr.out
index 6a30ded..a7c22c3 100644
--- a/tests/qapi-schema/indented-expr.out
+++ b/tests/qapi-schema/indented-expr.out
@@ -1,7 +1,6 @@
module ./builtin
object q_empty
enum QType
- prefix QTYPE
member none
member qnull
member qnum
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index e2f0981..4617eb4 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -1,7 +1,6 @@
module ./builtin
object q_empty
enum QType
- prefix QTYPE
member none
member qnull
member qnum
diff --git a/tests/qemu-iotests/024 b/tests/qemu-iotests/024
index 285f17e..b29c76e 100755
--- a/tests/qemu-iotests/024
+++ b/tests/qemu-iotests/024
@@ -283,7 +283,7 @@ TEST_IMG=$BASE_OLD _make_test_img -b "$BASE_NEW" -F $IMGFMT \
CLUSTER_SIZE=$(( CLUSTER_SIZE * 2 )) TEST_IMG=$OVERLAY \
_make_test_img -b "$BASE_OLD" -F $IMGFMT $(( CLUSTER_SIZE * 6 ))
-TEST_IMG=$OVERLAY _img_info
+TEST_IMG=$OVERLAY _img_info | grep -v '^backing file format:'
echo
echo "Fill backing files with data"
diff --git a/tests/qemu-iotests/024.out b/tests/qemu-iotests/024.out
index e1e8eea..3d1e319 100644
--- a/tests/qemu-iotests/024.out
+++ b/tests/qemu-iotests/024.out
@@ -214,7 +214,6 @@ file format: IMGFMT
virtual size: 384 KiB (393216 bytes)
cluster_size: 131072
backing file: TEST_DIR/subdir/t.IMGFMT.base_old
-backing file format: IMGFMT
Fill backing files with data
diff --git a/tests/qemu-iotests/211.out b/tests/qemu-iotests/211.out
index f02c754..ff9f9a6 100644
--- a/tests/qemu-iotests/211.out
+++ b/tests/qemu-iotests/211.out
@@ -17,7 +17,7 @@ file format: IMGFMT
virtual size: 128 MiB (134217728 bytes)
cluster_size: 1048576
-[{"data": false, "depth": 0, "length": 134217728, "present": true, "start": 0, "zero": true}]
+[{"compressed": false, "data": false, "depth": 0, "length": 134217728, "present": true, "start": 0, "zero": true}]
=== Successful image creation (explicit defaults) ===
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}}
@@ -35,7 +35,7 @@ file format: IMGFMT
virtual size: 64 MiB (67108864 bytes)
cluster_size: 1048576
-[{"data": false, "depth": 0, "length": 67108864, "present": true, "start": 0, "zero": true}]
+[{"compressed": false, "data": false, "depth": 0, "length": 67108864, "present": true, "start": 0, "zero": true}]
=== Successful image creation (with non-default options) ===
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vdi", "size": 0}}}
@@ -53,7 +53,7 @@ file format: IMGFMT
virtual size: 32 MiB (33554432 bytes)
cluster_size: 1048576
-[{"data": true, "depth": 0, "length": 3072, "offset": 1024, "present": true, "start": 0, "zero": false}, {"data": true, "depth": 0, "length": 33551360, "offset": 4096, "present": true, "start": 3072, "zero": true}]
+[{"compressed": false, "data": true, "depth": 0, "length": 3072, "offset": 1024, "present": true, "start": 0, "zero": false}, {"compressed": false, "data": true, "depth": 0, "length": 33551360, "offset": 4096, "present": true, "start": 3072, "zero": true}]
=== Invalid BlockdevRef ===
{"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "vdi", "file": "this doesn't exist", "size": 33554432}}}
diff --git a/tests/qemu-iotests/233.out b/tests/qemu-iotests/233.out
index 1910f7d..d498d55 100644
--- a/tests/qemu-iotests/233.out
+++ b/tests/qemu-iotests/233.out
@@ -69,8 +69,8 @@ read 1048576/1048576 bytes at offset 1048576
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== check TLS with authorization ==
-qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': Failed to read option reply: Cannot read from TLS channel: Software caused connection abort
-qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': Failed to read option reply: Cannot read from TLS channel: Software caused connection abort
+qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': Failed to read option reply: Cannot read from TLS channel: The TLS connection was non-properly terminated.
+qemu-img: Could not open 'driver=nbd,host=127.0.0.1,port=PORT,tls-creds=tls0': Failed to read option reply: Cannot read from TLS channel: The TLS connection was non-properly terminated.
== check TLS fail over UNIX with no hostname ==
qemu-img: Could not open 'driver=nbd,path=SOCK_DIR/qemu-nbd.sock,tls-creds=tls0': No hostname for certificate validation
@@ -103,14 +103,14 @@ qemu-img: Could not open 'driver=nbd,path=SOCK_DIR/qemu-nbd.sock,tls-creds=tls0'
qemu-nbd: TLS handshake failed: The TLS connection was non-properly terminated.
== final server log ==
-qemu-nbd: option negotiation failed: Failed to read opts magic: Cannot read from TLS channel: Software caused connection abort
-qemu-nbd: option negotiation failed: Failed to read opts magic: Cannot read from TLS channel: Software caused connection abort
+qemu-nbd: option negotiation failed: Failed to read opts magic: Cannot read from TLS channel: The TLS connection was non-properly terminated.
+qemu-nbd: option negotiation failed: Failed to read opts magic: Cannot read from TLS channel: The TLS connection was non-properly terminated.
qemu-nbd: option negotiation failed: Verify failed: No certificate was found.
qemu-nbd: option negotiation failed: Verify failed: No certificate was found.
qemu-nbd: option negotiation failed: TLS x509 authz check for DISTINGUISHED-NAME is denied
qemu-nbd: option negotiation failed: TLS x509 authz check for DISTINGUISHED-NAME is denied
-qemu-nbd: option negotiation failed: Failed to read opts magic: Cannot read from TLS channel: Software caused connection abort
-qemu-nbd: option negotiation failed: Failed to read opts magic: Cannot read from TLS channel: Software caused connection abort
+qemu-nbd: option negotiation failed: Failed to read opts magic: Cannot read from TLS channel: The TLS connection was non-properly terminated.
+qemu-nbd: option negotiation failed: Failed to read opts magic: Cannot read from TLS channel: The TLS connection was non-properly terminated.
qemu-nbd: option negotiation failed: TLS handshake failed: An illegal parameter has been received.
qemu-nbd: option negotiation failed: TLS handshake failed: An illegal parameter has been received.
*** done
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
index 56d88ca..545f9ec 100755
--- a/tests/qemu-iotests/check
+++ b/tests/qemu-iotests/check
@@ -84,7 +84,7 @@ def make_argparser() -> argparse.ArgumentParser:
p.set_defaults(imgfmt='raw', imgproto='file')
format_list = ['raw', 'bochs', 'cloop', 'parallels', 'qcow', 'qcow2',
- 'qed', 'vdi', 'vpc', 'vhdx', 'vmdk', 'luks', 'dmg']
+ 'qed', 'vdi', 'vpc', 'vhdx', 'vmdk', 'luks', 'dmg', 'vvfat']
g_fmt = p.add_argument_group(
' image format options',
'The following options set the IMGFMT environment variable. '
diff --git a/tests/qemu-iotests/fat16.py b/tests/qemu-iotests/fat16.py
new file mode 100644
index 0000000..7d2d052
--- /dev/null
+++ b/tests/qemu-iotests/fat16.py
@@ -0,0 +1,690 @@
+# A simple FAT16 driver that is used to test the `vvfat` driver in QEMU.
+#
+# Copyright (C) 2024 Amjad Alsharafi <amjadsharafi10@gmail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 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/>.
+
+from typing import Callable, List, Optional, Protocol, Set
+import string
+
+SECTOR_SIZE = 512
+DIRENTRY_SIZE = 32
+ALLOWED_FILE_CHARS = set(
+ "!#$%&'()-@^_`{}~" + string.digits + string.ascii_uppercase
+)
+
+
+class MBR:
+ def __init__(self, data: bytes):
+ assert len(data) == 512
+ self.partition_table = []
+ for i in range(4):
+ partition = data[446 + i * 16 : 446 + (i + 1) * 16]
+ self.partition_table.append(
+ {
+ "status": partition[0],
+ "start_head": partition[1],
+ "start_sector": partition[2] & 0x3F,
+ "start_cylinder": ((partition[2] & 0xC0) << 2)
+ | partition[3],
+ "type": partition[4],
+ "end_head": partition[5],
+ "end_sector": partition[6] & 0x3F,
+ "end_cylinder": ((partition[6] & 0xC0) << 2)
+ | partition[7],
+ "start_lba": int.from_bytes(partition[8:12], "little"),
+ "size": int.from_bytes(partition[12:16], "little"),
+ }
+ )
+
+ def __str__(self):
+ return "\n".join(
+ [
+ f"{i}: {partition}"
+ for i, partition in enumerate(self.partition_table)
+ ]
+ )
+
+
+class FatBootSector:
+ # pylint: disable=too-many-instance-attributes
+ def __init__(self, data: bytes):
+ assert len(data) == 512
+ self.bytes_per_sector = int.from_bytes(data[11:13], "little")
+ self.sectors_per_cluster = data[13]
+ self.reserved_sectors = int.from_bytes(data[14:16], "little")
+ self.fat_count = data[16]
+ self.root_entries = int.from_bytes(data[17:19], "little")
+ total_sectors_16 = int.from_bytes(data[19:21], "little")
+ self.media_descriptor = data[21]
+ self.sectors_per_fat = int.from_bytes(data[22:24], "little")
+ self.sectors_per_track = int.from_bytes(data[24:26], "little")
+ self.heads = int.from_bytes(data[26:28], "little")
+ self.hidden_sectors = int.from_bytes(data[28:32], "little")
+ total_sectors_32 = int.from_bytes(data[32:36], "little")
+ assert (
+ total_sectors_16 == 0 or total_sectors_32 == 0
+ ), "Both total sectors (16 and 32) fields are non-zero"
+ self.total_sectors = total_sectors_16 or total_sectors_32
+ self.drive_number = data[36]
+ self.volume_id = int.from_bytes(data[39:43], "little")
+ self.volume_label = data[43:54].decode("ascii").strip()
+ self.fs_type = data[54:62].decode("ascii").strip()
+
+ def root_dir_start(self):
+ """
+ Calculate the start sector of the root directory.
+ """
+ return self.reserved_sectors + self.fat_count * self.sectors_per_fat
+
+ def root_dir_size(self):
+ """
+ Calculate the size of the root directory in sectors.
+ """
+ return (
+ self.root_entries * DIRENTRY_SIZE + self.bytes_per_sector - 1
+ ) // self.bytes_per_sector
+
+ def data_sector_start(self):
+ """
+ Calculate the start sector of the data region.
+ """
+ return self.root_dir_start() + self.root_dir_size()
+
+ def first_sector_of_cluster(self, cluster: int) -> int:
+ """
+ Calculate the first sector of the given cluster.
+ """
+ return (
+ self.data_sector_start() + (cluster - 2) * self.sectors_per_cluster
+ )
+
+ def cluster_bytes(self):
+ """
+ Calculate the number of bytes in a cluster.
+ """
+ return self.bytes_per_sector * self.sectors_per_cluster
+
+ def __str__(self):
+ return (
+ f"Bytes per sector: {self.bytes_per_sector}\n"
+ f"Sectors per cluster: {self.sectors_per_cluster}\n"
+ f"Reserved sectors: {self.reserved_sectors}\n"
+ f"FAT count: {self.fat_count}\n"
+ f"Root entries: {self.root_entries}\n"
+ f"Total sectors: {self.total_sectors}\n"
+ f"Media descriptor: {self.media_descriptor}\n"
+ f"Sectors per FAT: {self.sectors_per_fat}\n"
+ f"Sectors per track: {self.sectors_per_track}\n"
+ f"Heads: {self.heads}\n"
+ f"Hidden sectors: {self.hidden_sectors}\n"
+ f"Drive number: {self.drive_number}\n"
+ f"Volume ID: {self.volume_id}\n"
+ f"Volume label: {self.volume_label}\n"
+ f"FS type: {self.fs_type}\n"
+ )
+
+
+class FatDirectoryEntry:
+ # pylint: disable=too-many-instance-attributes
+ def __init__(self, data: bytes, sector: int, offset: int):
+ self.name = data[0:8].decode("ascii").strip()
+ self.ext = data[8:11].decode("ascii").strip()
+ self.attributes = data[11]
+ self.reserved = data[12]
+ self.create_time_tenth = data[13]
+ self.create_time = int.from_bytes(data[14:16], "little")
+ self.create_date = int.from_bytes(data[16:18], "little")
+ self.last_access_date = int.from_bytes(data[18:20], "little")
+ high_cluster = int.from_bytes(data[20:22], "little")
+ self.last_mod_time = int.from_bytes(data[22:24], "little")
+ self.last_mod_date = int.from_bytes(data[24:26], "little")
+ low_cluster = int.from_bytes(data[26:28], "little")
+ self.cluster = (high_cluster << 16) | low_cluster
+ self.size_bytes = int.from_bytes(data[28:32], "little")
+
+ # extra (to help write back to disk)
+ self.sector = sector
+ self.offset = offset
+
+ def as_bytes(self) -> bytes:
+ return (
+ self.name.ljust(8, " ").encode("ascii")
+ + self.ext.ljust(3, " ").encode("ascii")
+ + self.attributes.to_bytes(1, "little")
+ + self.reserved.to_bytes(1, "little")
+ + self.create_time_tenth.to_bytes(1, "little")
+ + self.create_time.to_bytes(2, "little")
+ + self.create_date.to_bytes(2, "little")
+ + self.last_access_date.to_bytes(2, "little")
+ + (self.cluster >> 16).to_bytes(2, "little")
+ + self.last_mod_time.to_bytes(2, "little")
+ + self.last_mod_date.to_bytes(2, "little")
+ + (self.cluster & 0xFFFF).to_bytes(2, "little")
+ + self.size_bytes.to_bytes(4, "little")
+ )
+
+ def whole_name(self):
+ if self.ext:
+ return f"{self.name}.{self.ext}"
+ else:
+ return self.name
+
+ def __str__(self):
+ return (
+ f"Name: {self.name}\n"
+ f"Ext: {self.ext}\n"
+ f"Attributes: {self.attributes}\n"
+ f"Reserved: {self.reserved}\n"
+ f"Create time tenth: {self.create_time_tenth}\n"
+ f"Create time: {self.create_time}\n"
+ f"Create date: {self.create_date}\n"
+ f"Last access date: {self.last_access_date}\n"
+ f"Last mod time: {self.last_mod_time}\n"
+ f"Last mod date: {self.last_mod_date}\n"
+ f"Cluster: {self.cluster}\n"
+ f"Size: {self.size_bytes}\n"
+ )
+
+ def __repr__(self):
+ # convert to dict
+ return str(vars(self))
+
+
+class SectorReader(Protocol):
+ def __call__(self, start_sector: int, num_sectors: int = 1) -> bytes: ...
+
+# pylint: disable=broad-exception-raised
+class Fat16:
+ def __init__(
+ self,
+ start_sector: int,
+ size: int,
+ sector_reader: SectorReader,
+ sector_writer: Callable[[int, bytes], None]
+ ):
+ self.start_sector = start_sector
+ self.size_in_sectors = size
+ self.sector_reader = sector_reader
+ self.sector_writer = sector_writer
+
+ self.boot_sector = FatBootSector(self.sector_reader(start_sector, 1))
+
+ fat_size_in_sectors = (
+ self.boot_sector.sectors_per_fat * self.boot_sector.fat_count
+ )
+ self.fats = self.read_sectors(
+ self.boot_sector.reserved_sectors, fat_size_in_sectors
+ )
+ self.fats_dirty_sectors: Set[int] = set()
+
+ def read_sectors(self, start_sector: int, num_sectors: int) -> bytes:
+ return self.sector_reader(start_sector + self.start_sector,
+ num_sectors)
+
+ def write_sectors(self, start_sector: int, data: bytes) -> None:
+ return self.sector_writer(start_sector + self.start_sector, data)
+
+ def directory_from_bytes(
+ self, data: bytes, start_sector: int
+ ) -> List[FatDirectoryEntry]:
+ """
+ Convert `bytes` into a list of `FatDirectoryEntry` objects.
+ Will ignore long file names.
+ Will stop when it encounters a 0x00 byte.
+ """
+
+ entries = []
+ for i in range(0, len(data), DIRENTRY_SIZE):
+ entry = data[i : i + DIRENTRY_SIZE]
+
+ current_sector = start_sector + (i // SECTOR_SIZE)
+ current_offset = i % SECTOR_SIZE
+
+ if entry[0] == 0:
+ break
+
+ if entry[0] == 0xE5:
+ # Deleted file
+ continue
+
+ if entry[11] & 0xF == 0xF:
+ # Long file name
+ continue
+
+ entries.append(
+ FatDirectoryEntry(entry, current_sector, current_offset)
+ )
+ return entries
+
+ def read_root_directory(self) -> List[FatDirectoryEntry]:
+ root_dir = self.read_sectors(
+ self.boot_sector.root_dir_start(), self.boot_sector.root_dir_size()
+ )
+ return self.directory_from_bytes(
+ root_dir, self.boot_sector.root_dir_start()
+ )
+
+ def read_fat_entry(self, cluster: int) -> int:
+ """
+ Read the FAT entry for the given cluster.
+ """
+ fat_offset = cluster * 2 # FAT16
+ return int.from_bytes(self.fats[fat_offset : fat_offset + 2], "little")
+
+ def write_fat_entry(self, cluster: int, value: int) -> None:
+ """
+ Write the FAT entry for the given cluster.
+ """
+ fat_offset = cluster * 2
+ self.fats = (
+ self.fats[:fat_offset]
+ + value.to_bytes(2, "little")
+ + self.fats[fat_offset + 2 :]
+ )
+ self.fats_dirty_sectors.add(fat_offset // SECTOR_SIZE)
+
+ def flush_fats(self) -> None:
+ """
+ Write the FATs back to the disk.
+ """
+ for sector in self.fats_dirty_sectors:
+ data = self.fats[sector * SECTOR_SIZE : (sector + 1) * SECTOR_SIZE]
+ sector = self.boot_sector.reserved_sectors + sector
+ self.write_sectors(sector, data)
+ self.fats_dirty_sectors = set()
+
+ def next_cluster(self, cluster: int) -> Optional[int]:
+ """
+ Get the next cluster in the chain.
+ If its `None`, then its the last cluster.
+ The function will crash if the next cluster
+ is `FREE` (unexpected) or invalid entry.
+ """
+ fat_entry = self.read_fat_entry(cluster)
+ if fat_entry == 0:
+ raise Exception("Unexpected: FREE cluster")
+ if fat_entry == 1:
+ raise Exception("Unexpected: RESERVED cluster")
+ if fat_entry >= 0xFFF8:
+ return None
+ if fat_entry >= 0xFFF7:
+ raise Exception("Invalid FAT entry")
+
+ return fat_entry
+
+ def next_free_cluster(self) -> int:
+ """
+ Find the next free cluster.
+ """
+ # simple linear search
+ for i in range(2, 0xFFFF):
+ if self.read_fat_entry(i) == 0:
+ return i
+ raise Exception("No free clusters")
+
+ def next_free_cluster_non_continuous(self) -> int:
+ """
+ Find the next free cluster, but makes sure
+ that the cluster before and after it are not allocated.
+ """
+ # simple linear search
+ before = False
+ for i in range(2, 0xFFFF):
+ if self.read_fat_entry(i) == 0:
+ if before and self.read_fat_entry(i + 1) == 0:
+ return i
+ else:
+ before = True
+ else:
+ before = False
+
+ raise Exception("No free clusters")
+
+ def read_cluster(self, cluster: int) -> bytes:
+ """
+ Read the cluster at the given cluster.
+ """
+ return self.read_sectors(
+ self.boot_sector.first_sector_of_cluster(cluster),
+ self.boot_sector.sectors_per_cluster,
+ )
+
+ def write_cluster(self, cluster: int, data: bytes) -> None:
+ """
+ Write the cluster at the given cluster.
+ """
+ assert len(data) == self.boot_sector.cluster_bytes()
+ self.write_sectors(
+ self.boot_sector.first_sector_of_cluster(cluster),
+ data,
+ )
+
+ def read_directory(
+ self, cluster: Optional[int]
+ ) -> List[FatDirectoryEntry]:
+ """
+ Read the directory at the given cluster.
+ """
+ entries = []
+ while cluster is not None:
+ data = self.read_cluster(cluster)
+ entries.extend(
+ self.directory_from_bytes(
+ data, self.boot_sector.first_sector_of_cluster(cluster)
+ )
+ )
+ cluster = self.next_cluster(cluster)
+ return entries
+
+ def add_direntry(
+ self, cluster: Optional[int], name: str, ext: str, attributes: int
+ ) -> FatDirectoryEntry:
+ """
+ Add a new directory entry to the given cluster.
+ If the cluster is `None`, then it will be added to the root directory.
+ """
+
+ def find_free_entry(data: bytes) -> Optional[int]:
+ for i in range(0, len(data), DIRENTRY_SIZE):
+ entry = data[i : i + DIRENTRY_SIZE]
+ if entry[0] == 0 or entry[0] == 0xE5:
+ return i
+ return None
+
+ assert len(name) <= 8, "Name must be 8 characters or less"
+ assert len(ext) <= 3, "Ext must be 3 characters or less"
+ assert attributes % 0x15 != 0x15, "Invalid attributes"
+
+ # initial dummy data
+ new_entry = FatDirectoryEntry(b"\0" * 32, 0, 0)
+ new_entry.name = name.ljust(8, " ")
+ new_entry.ext = ext.ljust(3, " ")
+ new_entry.attributes = attributes
+ new_entry.reserved = 0
+ new_entry.create_time_tenth = 0
+ new_entry.create_time = 0
+ new_entry.create_date = 0
+ new_entry.last_access_date = 0
+ new_entry.last_mod_time = 0
+ new_entry.last_mod_date = 0
+ new_entry.cluster = self.next_free_cluster()
+ new_entry.size_bytes = 0
+
+ # mark as EOF
+ self.write_fat_entry(new_entry.cluster, 0xFFFF)
+
+ if cluster is None:
+ for i in range(self.boot_sector.root_dir_size()):
+ sector_data = self.read_sectors(
+ self.boot_sector.root_dir_start() + i, 1
+ )
+ offset = find_free_entry(sector_data)
+ if offset is not None:
+ new_entry.sector = self.boot_sector.root_dir_start() + i
+ new_entry.offset = offset
+ self.update_direntry(new_entry)
+ return new_entry
+ else:
+ while cluster is not None:
+ data = self.read_cluster(cluster)
+ offset = find_free_entry(data)
+ if offset is not None:
+ new_entry.sector = (
+ self.boot_sector.first_sector_of_cluster(cluster)
+ + (offset // SECTOR_SIZE))
+ new_entry.offset = offset % SECTOR_SIZE
+ self.update_direntry(new_entry)
+ return new_entry
+ cluster = self.next_cluster(cluster)
+
+ raise Exception("No free directory entries")
+
+ def update_direntry(self, entry: FatDirectoryEntry) -> None:
+ """
+ Write the directory entry back to the disk.
+ """
+ sector = self.read_sectors(entry.sector, 1)
+ sector = (
+ sector[: entry.offset]
+ + entry.as_bytes()
+ + sector[entry.offset + DIRENTRY_SIZE :]
+ )
+ self.write_sectors(entry.sector, sector)
+
+ def find_direntry(self, path: str) -> Optional[FatDirectoryEntry]:
+ """
+ Find the directory entry for the given path.
+ """
+ assert path[0] == "/", "Path must start with /"
+
+ path = path[1:] # remove the leading /
+ parts = path.split("/")
+ directory = self.read_root_directory()
+
+ current_entry = None
+
+ for i, part in enumerate(parts):
+ is_last = i == len(parts) - 1
+
+ for entry in directory:
+ if entry.whole_name() == part:
+ current_entry = entry
+ break
+ if current_entry is None:
+ return None
+
+ if is_last:
+ return current_entry
+
+ if current_entry.attributes & 0x10 == 0:
+ raise Exception(
+ f"{current_entry.whole_name()} is not a directory"
+ )
+
+ directory = self.read_directory(current_entry.cluster)
+
+ assert False, "Exited loop with is_last == False"
+
+ def read_file(self, entry: Optional[FatDirectoryEntry]) -> Optional[bytes]:
+ """
+ Read the content of the file at the given path.
+ """
+ if entry is None:
+ return None
+ if entry.attributes & 0x10 != 0:
+ raise Exception(f"{entry.whole_name()} is a directory")
+
+ data = b""
+ cluster: Optional[int] = entry.cluster
+ while cluster is not None and len(data) <= entry.size_bytes:
+ data += self.read_cluster(cluster)
+ cluster = self.next_cluster(cluster)
+ return data[: entry.size_bytes]
+
+ def truncate_file(
+ self,
+ entry: FatDirectoryEntry,
+ new_size: int,
+ allocate_non_continuous: bool = False,
+ ) -> None:
+ """
+ Truncate the file at the given path to the new size.
+ """
+ if entry is None:
+ raise Exception("entry is None")
+ if entry.attributes & 0x10 != 0:
+ raise Exception(f"{entry.whole_name()} is a directory")
+
+ def clusters_from_size(size: int) -> int:
+ return (
+ size + self.boot_sector.cluster_bytes() - 1
+ ) // self.boot_sector.cluster_bytes()
+
+ # First, allocate new FATs if we need to
+ required_clusters = clusters_from_size(new_size)
+ current_clusters = clusters_from_size(entry.size_bytes)
+
+ affected_clusters = set()
+
+ # Keep at least one cluster, easier to manage this way
+ if required_clusters == 0:
+ required_clusters = 1
+ if current_clusters == 0:
+ current_clusters = 1
+
+ cluster: Optional[int]
+
+ if required_clusters > current_clusters:
+ # Allocate new clusters
+ cluster = entry.cluster
+ to_add = required_clusters
+ for _ in range(current_clusters - 1):
+ to_add -= 1
+ assert cluster is not None, "Cluster is None"
+ affected_clusters.add(cluster)
+ cluster = self.next_cluster(cluster)
+ assert required_clusters > 0, "No new clusters to allocate"
+ assert cluster is not None, "Cluster is None"
+ assert (
+ self.next_cluster(cluster) is None
+ ), "Cluster is not the last cluster"
+
+ # Allocate new clusters
+ for _ in range(to_add - 1):
+ if allocate_non_continuous:
+ new_cluster = self.next_free_cluster_non_continuous()
+ else:
+ new_cluster = self.next_free_cluster()
+ self.write_fat_entry(cluster, new_cluster)
+ self.write_fat_entry(new_cluster, 0xFFFF)
+ cluster = new_cluster
+
+ elif required_clusters < current_clusters:
+ # Truncate the file
+ cluster = entry.cluster
+ for _ in range(required_clusters - 1):
+ assert cluster is not None, "Cluster is None"
+ cluster = self.next_cluster(cluster)
+ assert cluster is not None, "Cluster is None"
+
+ next_cluster = self.next_cluster(cluster)
+ # mark last as EOF
+ self.write_fat_entry(cluster, 0xFFFF)
+ # free the rest
+ while next_cluster is not None:
+ cluster = next_cluster
+ next_cluster = self.next_cluster(next_cluster)
+ self.write_fat_entry(cluster, 0)
+
+ self.flush_fats()
+
+ # verify number of clusters
+ cluster = entry.cluster
+ count = 0
+ while cluster is not None:
+ count += 1
+ affected_clusters.add(cluster)
+ cluster = self.next_cluster(cluster)
+ assert (
+ count == required_clusters
+ ), f"Expected {required_clusters} clusters, got {count}"
+
+ # update the size
+ entry.size_bytes = new_size
+ self.update_direntry(entry)
+
+ # trigger every affected cluster
+ for cluster in affected_clusters:
+ first_sector = self.boot_sector.first_sector_of_cluster(cluster)
+ first_sector_data = self.read_sectors(first_sector, 1)
+ self.write_sectors(first_sector, first_sector_data)
+
+ def write_file(self, entry: FatDirectoryEntry, data: bytes) -> None:
+ """
+ Write the content of the file at the given path.
+ """
+ if entry is None:
+ raise Exception("entry is None")
+ if entry.attributes & 0x10 != 0:
+ raise Exception(f"{entry.whole_name()} is a directory")
+
+ data_len = len(data)
+
+ self.truncate_file(entry, data_len)
+
+ cluster: Optional[int] = entry.cluster
+ while cluster is not None:
+ data_to_write = data[: self.boot_sector.cluster_bytes()]
+ if len(data_to_write) < self.boot_sector.cluster_bytes():
+ old_data = self.read_cluster(cluster)
+ data_to_write += old_data[len(data_to_write) :]
+
+ self.write_cluster(cluster, data_to_write)
+ data = data[self.boot_sector.cluster_bytes() :]
+ if len(data) == 0:
+ break
+ cluster = self.next_cluster(cluster)
+
+ assert (
+ len(data) == 0
+ ), "Data was not written completely, clusters missing"
+
+ def create_file(self, path: str) -> Optional[FatDirectoryEntry]:
+ """
+ Create a new file at the given path.
+ """
+ assert path[0] == "/", "Path must start with /"
+
+ path = path[1:] # remove the leading /
+
+ parts = path.split("/")
+
+ directory_cluster = None
+ directory = self.read_root_directory()
+
+ parts, filename = parts[:-1], parts[-1]
+
+ for _, part in enumerate(parts):
+ current_entry = None
+ for entry in directory:
+ if entry.whole_name() == part:
+ current_entry = entry
+ break
+ if current_entry is None:
+ return None
+
+ if current_entry.attributes & 0x10 == 0:
+ raise Exception(
+ f"{current_entry.whole_name()} is not a directory"
+ )
+
+ directory = self.read_directory(current_entry.cluster)
+ directory_cluster = current_entry.cluster
+
+ # add new entry to the directory
+
+ filename, ext = filename.split(".")
+
+ if len(ext) > 3:
+ raise Exception("Ext must be 3 characters or less")
+ if len(filename) > 8:
+ raise Exception("Name must be 8 characters or less")
+
+ for c in filename + ext:
+
+ if c not in ALLOWED_FILE_CHARS:
+ raise Exception("Invalid character in filename")
+
+ return self.add_direntry(directory_cluster, filename, ext, 0)
diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py
index 96d69e5..8cd620c 100644
--- a/tests/qemu-iotests/testenv.py
+++ b/tests/qemu-iotests/testenv.py
@@ -240,9 +240,11 @@ class TestEnv(ContextManager['TestEnv']):
('aarch64', 'virt'),
('avr', 'mega2560'),
('m68k', 'virt'),
+ ('or1k', 'virt'),
('riscv32', 'virt'),
('riscv64', 'virt'),
('rx', 'gdbsim-r5f562n8'),
+ ('sh4', 'r2d'),
('tricore', 'tricore_testboard')
)
for suffix, machine in machine_map:
@@ -255,7 +257,7 @@ class TestEnv(ContextManager['TestEnv']):
self.qemu_img_options = os.getenv('QEMU_IMG_OPTIONS')
self.qemu_nbd_options = os.getenv('QEMU_NBD_OPTIONS')
- is_generic = self.imgfmt not in ['bochs', 'cloop', 'dmg']
+ is_generic = self.imgfmt not in ['bochs', 'cloop', 'dmg', 'vvfat']
self.imgfmt_generic = 'true' if is_generic else 'false'
self.qemu_io_options = f'--cache {self.cachemode} --aio {self.aiomode}'
diff --git a/tests/qemu-iotests/tests/backup-discard-source b/tests/qemu-iotests/tests/backup-discard-source
index 2391b12..17fef9c 100755
--- a/tests/qemu-iotests/tests/backup-discard-source
+++ b/tests/qemu-iotests/tests/backup-discard-source
@@ -28,20 +28,14 @@ from iotests import qemu_img_create, qemu_img_map, qemu_io
temp_img = os.path.join(iotests.test_dir, 'temp')
source_img = os.path.join(iotests.test_dir, 'source')
target_img = os.path.join(iotests.test_dir, 'target')
-size = '1M'
-
-
-def get_actual_size(vm, node_name):
- nodes = vm.cmd('query-named-block-nodes', flat=True)
- node = next(n for n in nodes if n['node-name'] == node_name)
- return node['image']['actual-size']
+size = 1024 * 1024
class TestBackup(iotests.QMPTestCase):
def setUp(self):
- qemu_img_create('-f', iotests.imgfmt, source_img, size)
- qemu_img_create('-f', iotests.imgfmt, temp_img, size)
- qemu_img_create('-f', iotests.imgfmt, target_img, size)
+ qemu_img_create('-f', iotests.imgfmt, source_img, str(size))
+ qemu_img_create('-f', iotests.imgfmt, temp_img, str(size))
+ qemu_img_create('-f', iotests.imgfmt, target_img, str(size))
qemu_io('-c', 'write 0 1M', source_img)
self.vm = iotests.VM()
@@ -84,7 +78,12 @@ class TestBackup(iotests.QMPTestCase):
}
})
- self.assertLess(get_actual_size(self.vm, 'temp'), 512 * 1024)
+ self.bitmap = {
+ 'node': 'temp',
+ 'name': 'bitmap0'
+ }
+
+ self.vm.cmd('block-dirty-bitmap-add', self.bitmap)
def tearDown(self):
# That should fail, because region is discarded
@@ -98,7 +97,7 @@ class TestBackup(iotests.QMPTestCase):
mapping = qemu_img_map(temp_img)
self.assertEqual(len(mapping), 1)
self.assertEqual(mapping[0]['start'], 0)
- self.assertEqual(mapping[0]['length'], 1024 * 1024)
+ self.assertEqual(mapping[0]['length'], size)
self.assertEqual(mapping[0]['data'], False)
os.remove(temp_img)
@@ -113,6 +112,13 @@ class TestBackup(iotests.QMPTestCase):
self.vm.event_wait(name='BLOCK_JOB_COMPLETED')
+ def get_bitmap_count(self):
+ nodes = self.vm.cmd('query-named-block-nodes', flat=True)
+ temp = next(n for n in nodes if n['node-name'] == 'temp')
+ bitmap = temp['dirty-bitmaps'][0]
+ assert bitmap['name'] == self.bitmap['name']
+ return bitmap['count']
+
def test_discard_written(self):
"""
1. Guest writes
@@ -125,7 +131,7 @@ class TestBackup(iotests.QMPTestCase):
self.assert_qmp(result, 'return', '')
# Check that data is written to temporary image
- self.assertGreater(get_actual_size(self.vm, 'temp'), 1024 * 1024)
+ self.assertEqual(self.get_bitmap_count(), size)
self.do_backup()
@@ -138,13 +144,18 @@ class TestBackup(iotests.QMPTestCase):
"""
self.do_backup()
+ # backup job did discard operation and pollute the bitmap,
+ # we have to clean the bitmap, to check next write
+ self.assertEqual(self.get_bitmap_count(), size)
+ self.vm.cmd('block-dirty-bitmap-clear', self.bitmap)
+
# Try trigger copy-before-write operation
result = self.vm.hmp_qemu_io('cbw', 'write 0 1M')
self.assert_qmp(result, 'return', '')
# Check that data is not written to temporary image, as region
# is discarded from copy-before-write process
- self.assertLess(get_actual_size(self.vm, 'temp'), 512 * 1024)
+ self.assertEqual(self.get_bitmap_count(), 0)
if __name__ == '__main__':
diff --git a/tests/qemu-iotests/tests/vvfat b/tests/qemu-iotests/tests/vvfat
new file mode 100755
index 0000000..acdc6ce
--- /dev/null
+++ b/tests/qemu-iotests/tests/vvfat
@@ -0,0 +1,485 @@
+#!/usr/bin/env python3
+# group: rw vvfat
+#
+# Test vvfat driver implementation
+# Here, we use a simple FAT16 implementation and check the behavior of
+# the vvfat driver.
+#
+# Copyright (C) 2024 Amjad Alsharafi <amjadsharafi10@gmail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 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/>.
+
+import os
+import shutil
+import iotests
+from iotests import imgfmt, QMPTestCase
+from fat16 import MBR, Fat16, DIRENTRY_SIZE
+
+filesystem = os.path.join(iotests.test_dir, "filesystem")
+
+nbd_sock = iotests.file_path("nbd.sock", base_dir=iotests.sock_dir)
+nbd_uri = "nbd+unix:///disk?socket=" + nbd_sock
+
+SECTOR_SIZE = 512
+
+
+class TestVVFatDriver(QMPTestCase):
+ # pylint: disable=broad-exception-raised
+ def setUp(self) -> None:
+ if os.path.exists(filesystem):
+ if os.path.isdir(filesystem):
+ shutil.rmtree(filesystem)
+ else:
+ raise Exception(f"{filesystem} exists and is not a directory")
+
+ os.mkdir(filesystem)
+
+ # Add some text files to the filesystem
+ for i in range(10):
+ with open(os.path.join(filesystem, f"file{i}.txt"),
+ "w", encoding="ascii") as f:
+ f.write(f"Hello, world! {i}\n")
+
+ # Add 2 large files, above the cluster size (8KB)
+ with open(os.path.join(filesystem, "large1.txt"), "wb") as f:
+ # write 'A' * 1KB, 'B' * 1KB, 'C' * 1KB, ...
+ for i in range(8 * 2): # two clusters
+ f.write(bytes([0x41 + i] * 1024))
+
+ with open(os.path.join(filesystem, "large2.txt"), "wb") as f:
+ # write 'A' * 1KB, 'B' * 1KB, 'C' * 1KB, ...
+ for i in range(8 * 3): # 3 clusters
+ f.write(bytes([0x41 + i] * 1024))
+
+ self.vm = iotests.VM()
+
+ self.vm.add_blockdev(
+ self.vm.qmp_to_opts(
+ {
+ "driver": imgfmt,
+ "node-name": "disk",
+ "rw": "true",
+ "fat-type": "16",
+ "dir": filesystem,
+ }
+ )
+ )
+
+ self.vm.launch()
+
+ self.vm.qmp_log("block-dirty-bitmap-add", **{
+ "node": "disk",
+ "name": "bitmap0",
+ })
+
+ # attach nbd server
+ self.vm.qmp_log(
+ "nbd-server-start",
+ **{"addr": {"type": "unix", "data": {"path": nbd_sock}}},
+ filters=[],
+ )
+
+ self.vm.qmp_log(
+ "nbd-server-add",
+ **{"device": "disk", "writable": True, "bitmap": "bitmap0"},
+ )
+
+ self.qio = iotests.QemuIoInteractive("-f", "raw", nbd_uri)
+
+ def tearDown(self) -> None:
+ self.qio.close()
+ self.vm.shutdown()
+ # print(self.vm.get_log())
+ shutil.rmtree(filesystem)
+
+ def read_sectors(self, sector: int, num: int = 1) -> bytes:
+ """
+ Read `num` sectors starting from `sector` from the `disk`.
+ This uses `QemuIoInteractive` to read the sectors into `stdout` and
+ then parse the output.
+ """
+ self.assertGreater(num, 0)
+
+ # The output contains the content of the sector in hex dump format
+ # We need to extract the content from it
+ output = self.qio.cmd(
+ f"read -v {sector * SECTOR_SIZE} {num * SECTOR_SIZE}")
+
+ # Each row is 16 bytes long, and we are writing `num` sectors
+ rows = num * SECTOR_SIZE // 16
+ output_rows = output.split("\n")[:rows]
+
+ hex_content = "".join(
+ [(row.split(": ")[1]).split(" ")[0] for row in output_rows]
+ )
+ bytes_content = bytes.fromhex(hex_content)
+
+ self.assertEqual(len(bytes_content), num * SECTOR_SIZE)
+
+ return bytes_content
+
+ def write_sectors(self, sector: int, data: bytes) -> None:
+ """
+ Write `data` to the `disk` starting from `sector`.
+ This uses `QemuIoInteractive` to write the data into the disk.
+ """
+
+ self.assertGreater(len(data), 0)
+ self.assertEqual(len(data) % SECTOR_SIZE, 0)
+
+ temp_file = os.path.join(iotests.test_dir, "temp.bin")
+ with open(temp_file, "wb") as f:
+ f.write(data)
+
+ self.qio.cmd(
+ f"write -s {temp_file} {sector * SECTOR_SIZE} {len(data)}"
+ )
+
+ os.remove(temp_file)
+
+ def init_fat16(self):
+ mbr = MBR(self.read_sectors(0))
+ return Fat16(
+ mbr.partition_table[0]["start_lba"],
+ mbr.partition_table[0]["size"],
+ self.read_sectors,
+ self.write_sectors,
+ )
+
+ # Tests
+
+ def test_fat_filesystem(self):
+ """
+ Test that vvfat produce a valid FAT16 and MBR sectors
+ """
+ mbr = MBR(self.read_sectors(0))
+
+ self.assertEqual(mbr.partition_table[0]["status"], 0x80)
+ self.assertEqual(mbr.partition_table[0]["type"], 6)
+
+ fat16 = Fat16(
+ mbr.partition_table[0]["start_lba"],
+ mbr.partition_table[0]["size"],
+ self.read_sectors,
+ self.write_sectors,
+ )
+ self.assertEqual(fat16.boot_sector.bytes_per_sector, 512)
+ self.assertEqual(fat16.boot_sector.volume_label, "QEMU VVFAT")
+
+ def test_read_root_directory(self):
+ """
+ Test the content of the root directory
+ """
+ fat16 = self.init_fat16()
+
+ root_dir = fat16.read_root_directory()
+
+ self.assertEqual(len(root_dir), 13) # 12 + 1 special file
+
+ files = {
+ "QEMU VVF.AT": 0, # special empty file
+ "FILE0.TXT": 16,
+ "FILE1.TXT": 16,
+ "FILE2.TXT": 16,
+ "FILE3.TXT": 16,
+ "FILE4.TXT": 16,
+ "FILE5.TXT": 16,
+ "FILE6.TXT": 16,
+ "FILE7.TXT": 16,
+ "FILE8.TXT": 16,
+ "FILE9.TXT": 16,
+ "LARGE1.TXT": 0x2000 * 2,
+ "LARGE2.TXT": 0x2000 * 3,
+ }
+
+ for entry in root_dir:
+ self.assertIn(entry.whole_name(), files)
+ self.assertEqual(entry.size_bytes, files[entry.whole_name()])
+
+ def test_direntry_as_bytes(self):
+ """
+ Test if we can convert Direntry back to bytes, so that we can write it
+ back to the disk safely.
+ """
+ fat16 = self.init_fat16()
+
+ root_dir = fat16.read_root_directory()
+ first_entry_bytes = fat16.read_sectors(
+ fat16.boot_sector.root_dir_start(), 1)
+
+ # The first entry won't be deleted, so we can compare it with the first
+ # entry in the root directory
+ self.assertEqual(root_dir[0].as_bytes(),
+ first_entry_bytes[:DIRENTRY_SIZE])
+
+ def test_read_files(self):
+ """
+ Test reading the content of the files
+ """
+ fat16 = self.init_fat16()
+
+ for i in range(10):
+ file = fat16.find_direntry(f"/FILE{i}.TXT")
+ self.assertIsNotNone(file)
+ self.assertEqual(
+ fat16.read_file(file), f"Hello, world! {i}\n".encode("ascii")
+ )
+
+ # test large files
+ large1 = fat16.find_direntry("/LARGE1.TXT")
+ with open(os.path.join(filesystem, "large1.txt"), "rb") as f:
+ self.assertEqual(fat16.read_file(large1), f.read())
+
+ large2 = fat16.find_direntry("/LARGE2.TXT")
+ self.assertIsNotNone(large2)
+ with open(os.path.join(filesystem, "large2.txt"), "rb") as f:
+ self.assertEqual(fat16.read_file(large2), f.read())
+
+ def test_write_file_same_content_direct(self):
+ """
+ Similar to `test_write_file_in_same_content`, but we write the file
+ directly clusters and thus we don't go through the modification of
+ direntry.
+ """
+ fat16 = self.init_fat16()
+
+ file = fat16.find_direntry("/FILE0.TXT")
+ self.assertIsNotNone(file)
+
+ data = fat16.read_cluster(file.cluster)
+ fat16.write_cluster(file.cluster, data)
+
+ with open(os.path.join(filesystem, "file0.txt"), "rb") as f:
+ self.assertEqual(fat16.read_file(file), f.read())
+
+ def test_write_file_in_same_content(self):
+ """
+ Test writing the same content to the file back to it
+ """
+ fat16 = self.init_fat16()
+
+ file = fat16.find_direntry("/FILE0.TXT")
+ self.assertIsNotNone(file)
+
+ self.assertEqual(fat16.read_file(file), b"Hello, world! 0\n")
+
+ fat16.write_file(file, b"Hello, world! 0\n")
+ self.assertEqual(fat16.read_file(file), b"Hello, world! 0\n")
+
+ with open(os.path.join(filesystem, "file0.txt"), "rb") as f:
+ self.assertEqual(f.read(), b"Hello, world! 0\n")
+
+ def test_modify_content_same_clusters(self):
+ """
+ Test modifying the content of the file without changing the number of
+ clusters
+ """
+ fat16 = self.init_fat16()
+
+ file = fat16.find_direntry("/FILE0.TXT")
+ self.assertIsNotNone(file)
+
+ new_content = b"Hello, world! Modified\n"
+ self.assertEqual(fat16.read_file(file), b"Hello, world! 0\n")
+
+ fat16.write_file(file, new_content)
+ self.assertEqual(fat16.read_file(file), new_content)
+
+ with open(os.path.join(filesystem, "file0.txt"), "rb") as f:
+ self.assertEqual(f.read(), new_content)
+
+ def test_truncate_file_same_clusters_less(self):
+ """
+ Test truncating the file without changing number of clusters
+ Test decreasing the file size
+ """
+ fat16 = self.init_fat16()
+
+ file = fat16.find_direntry("/FILE0.TXT")
+ self.assertIsNotNone(file)
+
+ self.assertEqual(fat16.read_file(file), b"Hello, world! 0\n")
+
+ fat16.truncate_file(file, 5)
+ new_content = fat16.read_file(file)
+ self.assertEqual(new_content, b"Hello")
+
+ with open(os.path.join(filesystem, "file0.txt"), "rb") as f:
+ self.assertEqual(f.read(), new_content)
+
+ def test_truncate_file_same_clusters_more(self):
+ """
+ Test truncating the file without changing number of clusters
+ Test increase the file size
+ """
+ fat16 = self.init_fat16()
+
+ file = fat16.find_direntry("/FILE0.TXT")
+ self.assertIsNotNone(file)
+
+ self.assertEqual(fat16.read_file(file), b"Hello, world! 0\n")
+
+ fat16.truncate_file(file, 20)
+ new_content = fat16.read_file(file)
+ self.assertIsNotNone(new_content)
+
+ # random pattern will be appended to the file, and its not always the
+ # same
+ self.assertEqual(new_content[:16], b"Hello, world! 0\n")
+ self.assertEqual(len(new_content), 20)
+
+ with open(os.path.join(filesystem, "file0.txt"), "rb") as f:
+ self.assertEqual(f.read(), new_content)
+
+ def test_write_large_file(self):
+ """
+ Test writing a large file
+ """
+ fat16 = self.init_fat16()
+
+ file = fat16.find_direntry("/LARGE1.TXT")
+ self.assertIsNotNone(file)
+
+ # The content of LARGE1 is A * 1KB, B * 1KB, C * 1KB, ..., P * 1KB
+ # Lets change it to be Z * 1KB, Y * 1KB, X * 1KB, ..., K * 1KB
+ # without changing the number of clusters or filesize
+ new_content = b"".join([bytes([0x5A - i] * 1024) for i in range(16)])
+ fat16.write_file(file, new_content)
+ self.assertEqual(fat16.read_file(file), new_content)
+
+ with open(os.path.join(filesystem, "large1.txt"), "rb") as f:
+ self.assertEqual(f.read(), new_content)
+
+ def test_truncate_file_change_clusters_less(self):
+ """
+ Test truncating a file by reducing the number of clusters
+ """
+ fat16 = self.init_fat16()
+
+ file = fat16.find_direntry("/LARGE1.TXT")
+ self.assertIsNotNone(file)
+
+ fat16.truncate_file(file, 1)
+ self.assertEqual(fat16.read_file(file), b"A")
+
+ with open(os.path.join(filesystem, "large1.txt"), "rb") as f:
+ self.assertEqual(f.read(), b"A")
+
+ def test_write_file_change_clusters_less(self):
+ """
+ Test truncating a file by reducing the number of clusters
+ """
+ fat16 = self.init_fat16()
+
+ file = fat16.find_direntry("/LARGE2.TXT")
+ self.assertIsNotNone(file)
+
+ new_content = b"X" * 8 * 1024 + b"Y" * 8 * 1024
+ fat16.write_file(file, new_content)
+ self.assertEqual(fat16.read_file(file), new_content)
+
+ with open(os.path.join(filesystem, "large2.txt"), "rb") as f:
+ self.assertEqual(f.read(), new_content)
+
+ def test_write_file_change_clusters_more(self):
+ """
+ Test truncating a file by increasing the number of clusters
+ """
+ fat16 = self.init_fat16()
+
+ file = fat16.find_direntry("/LARGE2.TXT")
+ self.assertIsNotNone(file)
+
+ # from 3 clusters to 4 clusters
+ new_content = (
+ b"W" * 8 * 1024 +
+ b"X" * 8 * 1024 +
+ b"Y" * 8 * 1024 +
+ b"Z" * 8 * 1024
+ )
+ fat16.write_file(file, new_content)
+ self.assertEqual(fat16.read_file(file), new_content)
+
+ with open(os.path.join(filesystem, "large2.txt"), "rb") as f:
+ self.assertEqual(f.read(), new_content)
+
+ def test_write_file_change_clusters_more_non_contiguous_2_mappings(self):
+ """
+ Test truncating a file by increasing the number of clusters Here we
+ allocate the new clusters in a way that makes them non-contiguous so
+ that we will get 2 cluster mappings for the file
+ """
+ fat16 = self.init_fat16()
+
+ file = fat16.find_direntry("/LARGE1.TXT")
+ self.assertIsNotNone(file)
+
+ # from 2 clusters to 3 clusters with non-contiguous allocation
+ fat16.truncate_file(file, 3 * 0x2000, allocate_non_continuous=True)
+ new_content = b"X" * 8 * 1024 + b"Y" * 8 * 1024 + b"Z" * 8 * 1024
+ fat16.write_file(file, new_content)
+ self.assertEqual(fat16.read_file(file), new_content)
+
+ with open(os.path.join(filesystem, "large1.txt"), "rb") as f:
+ self.assertEqual(f.read(), new_content)
+
+ def test_write_file_change_clusters_more_non_contiguous_3_mappings(self):
+ """
+ Test truncating a file by increasing the number of clusters Here we
+ allocate the new clusters in a way that makes them non-contiguous so
+ that we will get 3 cluster mappings for the file
+ """
+ fat16 = self.init_fat16()
+
+ file = fat16.find_direntry("/LARGE1.TXT")
+ self.assertIsNotNone(file)
+
+ # from 2 clusters to 4 clusters with non-contiguous allocation
+ fat16.truncate_file(file, 4 * 0x2000, allocate_non_continuous=True)
+ new_content = (
+ b"W" * 8 * 1024 +
+ b"X" * 8 * 1024 +
+ b"Y" * 8 * 1024 +
+ b"Z" * 8 * 1024
+ )
+ fat16.write_file(file, new_content)
+ self.assertEqual(fat16.read_file(file), new_content)
+
+ with open(os.path.join(filesystem, "large1.txt"), "rb") as f:
+ self.assertEqual(f.read(), new_content)
+
+ def test_create_file(self):
+ """
+ Test creating a new file
+ """
+ fat16 = self.init_fat16()
+
+ new_file = fat16.create_file("/NEWFILE.TXT")
+
+ self.assertIsNotNone(new_file)
+ self.assertEqual(new_file.size_bytes, 0)
+
+ new_content = b"Hello, world! New file\n"
+ fat16.write_file(new_file, new_content)
+ self.assertEqual(fat16.read_file(new_file), new_content)
+
+ with open(os.path.join(filesystem, "newfile.txt"), "rb") as f:
+ self.assertEqual(f.read(), new_content)
+
+ # TODO: support deleting files
+
+
+if __name__ == "__main__":
+ # This is a specific test for vvfat driver
+ iotests.main(supported_fmts=["vvfat"], supported_protocols=["file"])
diff --git a/tests/qemu-iotests/tests/vvfat.out b/tests/qemu-iotests/tests/vvfat.out
new file mode 100755
index 0000000..b6f2576
--- /dev/null
+++ b/tests/qemu-iotests/tests/vvfat.out
@@ -0,0 +1,5 @@
+................
+----------------------------------------------------------------------
+Ran 16 tests
+
+OK
diff --git a/tests/qtest/acpi-utils.c b/tests/qtest/acpi-utils.c
index 673fc97..9dc24fb 100644
--- a/tests/qtest/acpi-utils.c
+++ b/tests/qtest/acpi-utils.c
@@ -156,5 +156,4 @@ uint64_t acpi_find_rsdp_address_uefi(QTestState *qts, uint64_t start,
g_usleep(TEST_DELAY);
}
g_assert_not_reached();
- return 0;
}
diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c
index c713a37..4673371 100644
--- a/tests/qtest/aspeed_smc-test.c
+++ b/tests/qtest/aspeed_smc-test.c
@@ -353,7 +353,8 @@ static void test_read_page_mem(void)
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
- /* Enable 4BYTE mode for controller. This is should be strapped by
+ /*
+ * Enable 4BYTE mode for controller. This is should be strapped by
* HW for CE0 anyhow.
*/
spi_ce_ctrl(1 << CRTL_EXTENDED0);
@@ -394,7 +395,8 @@ static void test_write_page_mem(void)
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
- /* Enable 4BYTE mode for controller. This is should be strapped by
+ /*
+ * Enable 4BYTE mode for controller. This is should be strapped by
* HW for CE0 anyhow.
*/
spi_ce_ctrl(1 << CRTL_EXTENDED0);
diff --git a/tests/qtest/ast2700-gpio-test.c b/tests/qtest/ast2700-gpio-test.c
new file mode 100644
index 0000000..9275845
--- /dev/null
+++ b/tests/qtest/ast2700-gpio-test.c
@@ -0,0 +1,95 @@
+/*
+ * QTest testcase for the ASPEED AST2700 GPIO Controller.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (C) 2024 ASPEED Technology Inc.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/bitops.h"
+#include "qemu/timer.h"
+#include "qapi/qmp/qdict.h"
+#include "libqtest-single.h"
+
+#define AST2700_GPIO_BASE 0x14C0B000
+#define GPIOA0_CONTROL 0x180
+
+static void test_output_pins(const char *machine, const uint32_t base)
+{
+ QTestState *s = qtest_init(machine);
+ uint32_t offset = 0;
+ uint32_t value = 0;
+ uint32_t pin = 0;
+
+ for (char c = 'A'; c <= 'D'; c++) {
+ for (int i = 0; i < 8; i++) {
+ offset = base + (pin * 4);
+
+ /* output direction and output hi */
+ qtest_writel(s, offset, 0x00000003);
+ value = qtest_readl(s, offset);
+ g_assert_cmphex(value, ==, 0x00000003);
+
+ /* output direction and output low */
+ qtest_writel(s, offset, 0x00000002);
+ value = qtest_readl(s, offset);
+ g_assert_cmphex(value, ==, 0x00000002);
+ pin++;
+ }
+ }
+
+ qtest_quit(s);
+}
+
+static void test_input_pins(const char *machine, const uint32_t base)
+{
+ QTestState *s = qtest_init(machine);
+ char name[16];
+ uint32_t offset = 0;
+ uint32_t value = 0;
+ uint32_t pin = 0;
+
+ for (char c = 'A'; c <= 'D'; c++) {
+ for (int i = 0; i < 8; i++) {
+ sprintf(name, "gpio%c%d", c, i);
+ offset = base + (pin * 4);
+ /* input direction */
+ qtest_writel(s, offset, 0);
+
+ /* set input */
+ qtest_qom_set_bool(s, "/machine/soc/gpio", name, true);
+ value = qtest_readl(s, offset);
+ g_assert_cmphex(value, ==, 0x00002000);
+
+ /* clear input */
+ qtest_qom_set_bool(s, "/machine/soc/gpio", name, false);
+ value = qtest_readl(s, offset);
+ g_assert_cmphex(value, ==, 0);
+ pin++;
+ }
+ }
+
+ qtest_quit(s);
+}
+
+static void test_2700_input_pins(void)
+{
+ test_input_pins("-machine ast2700-evb",
+ AST2700_GPIO_BASE + GPIOA0_CONTROL);
+}
+
+static void test_2700_output_pins(void)
+{
+ test_output_pins("-machine ast2700-evb",
+ AST2700_GPIO_BASE + GPIOA0_CONTROL);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ qtest_add_func("/ast2700/gpio/input_pins", test_2700_input_pins);
+ qtest_add_func("/ast2700/gpio/output_pins", test_2700_output_pins);
+
+ return g_test_run();
+}
diff --git a/tests/qtest/bcm2835-i2c-test.c b/tests/qtest/bcm2835-i2c-test.c
index 513ecce..1599194 100644
--- a/tests/qtest/bcm2835-i2c-test.c
+++ b/tests/qtest/bcm2835-i2c-test.c
@@ -81,7 +81,7 @@ static void test_i2c_read_write(gconstpointer data)
g_assert_cmpint(i2cdata, ==, 0xde);
i2cdata = readl(base_addr + BCM2835_I2C_FIFO);
- g_assert_cmpint(i2cdata, ==, 0xad);
+ g_assert_cmpint(i2cdata, ==, 0xa0);
/* Clear flags */
writel(base_addr + BCM2835_I2C_S, BCM2835_I2C_S_DONE | BCM2835_I2C_S_ERR |
diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
index f4c4704..e79f3a0 100644
--- a/tests/qtest/bios-tables-test.c
+++ b/tests/qtest/bios-tables-test.c
@@ -267,15 +267,6 @@ static void dump_aml_files(test_data *data, bool rebuild)
data->arch, data->machine,
sdt->aml, ext);
- /*
- * To keep test cases not failing before the DATA files are moved to
- * ${arch}/${machine} folder, add this check as well.
- */
- if (!g_file_test(aml_file, G_FILE_TEST_EXISTS)) {
- aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir,
- data->machine, sdt->aml, ext);
- }
-
if (!g_file_test(aml_file, G_FILE_TEST_EXISTS) &&
sdt->aml_len == exp_sdt->aml_len &&
!memcmp(sdt->aml, exp_sdt->aml, sdt->aml_len)) {
@@ -412,11 +403,6 @@ static GArray *load_expected_aml(test_data *data)
try_again:
aml_file = g_strdup_printf("%s/%s/%s/%.4s%s", data_dir, data->arch,
data->machine, sdt->aml, ext);
- if (!g_file_test(aml_file, G_FILE_TEST_EXISTS)) {
- aml_file = g_strdup_printf("%s/%s/%.4s%s", data_dir, data->machine,
- sdt->aml, ext);
- }
-
if (verbosity_level >= 2) {
fprintf(stderr, "Looking for expected file '%s'\n", aml_file);
}
@@ -1720,6 +1706,32 @@ static void test_acpi_microvm_ioapic2_tcg(void)
free_test_data(&data);
}
+static void test_acpi_riscv64_virt_tcg_numamem(void)
+{
+ test_data data = {
+ .machine = "virt",
+ .arch = "riscv64",
+ .tcg_only = true,
+ .uefi_fl1 = "pc-bios/edk2-riscv-code.fd",
+ .uefi_fl2 = "pc-bios/edk2-riscv-vars.fd",
+ .cd = "tests/data/uefi-boot-images/bios-tables-test.riscv64.iso.qcow2",
+ .ram_start = 0x80000000ULL,
+ .scan_len = 128ULL * 1024 * 1024,
+ };
+
+ data.variant = ".numamem";
+ /*
+ * RHCT will have ISA string encoded. To reduce the effort
+ * of updating expected AML file for any new default ISA extension,
+ * use the profile rva22s64.
+ */
+ test_acpi_one(" -cpu rva22s64"
+ " -object memory-backend-ram,id=ram0,size=128M"
+ " -numa node,memdev=ram0",
+ &data);
+ free_test_data(&data);
+}
+
static void test_acpi_aarch64_virt_tcg_numamem(void)
{
test_data data = {
@@ -1977,6 +1989,28 @@ static void test_acpi_microvm_acpi_erst(void)
}
#endif /* CONFIG_POSIX */
+static void test_acpi_riscv64_virt_tcg(void)
+{
+ test_data data = {
+ .machine = "virt",
+ .arch = "riscv64",
+ .tcg_only = true,
+ .uefi_fl1 = "pc-bios/edk2-riscv-code.fd",
+ .uefi_fl2 = "pc-bios/edk2-riscv-vars.fd",
+ .cd = "tests/data/uefi-boot-images/bios-tables-test.riscv64.iso.qcow2",
+ .ram_start = 0x80000000ULL,
+ .scan_len = 128ULL * 1024 * 1024,
+ };
+
+ /*
+ * RHCT will have ISA string encoded. To reduce the effort
+ * of updating expected AML file for any new default ISA extension,
+ * use the profile rva22s64.
+ */
+ test_acpi_one("-cpu rva22s64 ", &data);
+ free_test_data(&data);
+}
+
static void test_acpi_aarch64_virt_tcg(void)
{
test_data data = {
@@ -2455,6 +2489,12 @@ int main(int argc, char *argv[])
qtest_add_func("acpi/virt/viot", test_acpi_aarch64_virt_viot);
}
}
+ } else if (strcmp(arch, "riscv64") == 0) {
+ if (has_tcg && qtest_has_device("virtio-blk-pci")) {
+ qtest_add_func("acpi/virt", test_acpi_riscv64_virt_tcg);
+ qtest_add_func("acpi/virt/numamem",
+ test_acpi_riscv64_virt_tcg_numamem);
+ }
}
ret = g_test_run();
boot_sector_cleanup(disk);
diff --git a/tests/qtest/boot-order-test.c b/tests/qtest/boot-order-test.c
index 8f2b6ef..c67b8cf 100644
--- a/tests/qtest/boot-order-test.c
+++ b/tests/qtest/boot-order-test.c
@@ -31,7 +31,7 @@ static void test_a_boot_order(const char *machine,
uint64_t actual;
QTestState *qts;
- if (machine && !qtest_has_machine(machine)) {
+ if (!qtest_has_machine(machine)) {
g_test_skip("Machine is not available");
return;
}
@@ -107,7 +107,7 @@ static const boot_order_test test_cases_pc[] = {
static void test_pc_boot_order(void)
{
- test_boot_orders(NULL, read_boot_order_pc, test_cases_pc);
+ test_boot_orders("pc", read_boot_order_pc, test_cases_pc);
}
static uint64_t read_boot_order_pmac(QTestState *qts)
diff --git a/tests/qtest/cdrom-test.c b/tests/qtest/cdrom-test.c
index 5d89e62..c86725a 100644
--- a/tests/qtest/cdrom-test.c
+++ b/tests/qtest/cdrom-test.c
@@ -135,13 +135,35 @@ static void add_x86_tests(void)
return;
}
- qtest_add_data_func("cdrom/boot/default", "-cdrom ", test_cdboot);
- if (qtest_has_device("virtio-scsi-ccw")) {
- qtest_add_data_func("cdrom/boot/virtio-scsi",
- "-device virtio-scsi -device scsi-cd,drive=cdr "
- "-blockdev file,node-name=cdr,filename=",
- test_cdboot);
+ if (qtest_has_machine("pc")) {
+ qtest_add_data_func("cdrom/boot/default", "-cdrom ", test_cdboot);
+ if (qtest_has_device("virtio-scsi-ccw")) {
+ qtest_add_data_func("cdrom/boot/virtio-scsi",
+ "-device virtio-scsi -device scsi-cd,drive=cdr "
+ "-blockdev file,node-name=cdr,filename=",
+ test_cdboot);
+ }
+
+ if (qtest_has_device("am53c974")) {
+ qtest_add_data_func("cdrom/boot/am53c974",
+ "-device am53c974 -device scsi-cd,drive=cd1 "
+ "-drive if=none,id=cd1,format=raw,file=",
+ test_cdboot);
+ }
+ if (qtest_has_device("dc390")) {
+ qtest_add_data_func("cdrom/boot/dc390",
+ "-device dc390 -device scsi-cd,drive=cd1 "
+ "-blockdev file,node-name=cd1,filename=",
+ test_cdboot);
+ }
+ if (qtest_has_device("lsi53c895a")) {
+ qtest_add_data_func("cdrom/boot/lsi53c895a",
+ "-device lsi53c895a -device scsi-cd,drive=cd1 "
+ "-blockdev file,node-name=cd1,filename=",
+ test_cdboot);
+ }
}
+
/*
* Unstable CI test under load
* See https://lists.gnu.org/archive/html/qemu-devel/2019-02/msg05509.html
@@ -150,35 +172,20 @@ static void add_x86_tests(void)
qtest_add_data_func("cdrom/boot/isapc", "-M isapc "
"-drive if=ide,media=cdrom,file=", test_cdboot);
}
- if (qtest_has_device("am53c974")) {
- qtest_add_data_func("cdrom/boot/am53c974",
- "-device am53c974 -device scsi-cd,drive=cd1 "
- "-drive if=none,id=cd1,format=raw,file=",
- test_cdboot);
- }
- if (qtest_has_device("dc390")) {
- qtest_add_data_func("cdrom/boot/dc390",
- "-device dc390 -device scsi-cd,drive=cd1 "
- "-blockdev file,node-name=cd1,filename=",
- test_cdboot);
- }
- if (qtest_has_device("lsi53c895a")) {
- qtest_add_data_func("cdrom/boot/lsi53c895a",
- "-device lsi53c895a -device scsi-cd,drive=cd1 "
- "-blockdev file,node-name=cd1,filename=",
- test_cdboot);
- }
- if (qtest_has_device("megasas")) {
- qtest_add_data_func("cdrom/boot/megasas", "-M q35 "
- "-device megasas -device scsi-cd,drive=cd1 "
- "-blockdev file,node-name=cd1,filename=",
- test_cdboot);
- }
- if (qtest_has_device("megasas-gen2")) {
- qtest_add_data_func("cdrom/boot/megasas-gen2", "-M q35 "
- "-device megasas-gen2 -device scsi-cd,drive=cd1 "
- "-blockdev file,node-name=cd1,filename=",
- test_cdboot);
+
+ if (qtest_has_machine("q35")) {
+ if (qtest_has_device("megasas")) {
+ qtest_add_data_func("cdrom/boot/megasas", "-M q35 "
+ "-device megasas -device scsi-cd,drive=cd1 "
+ "-blockdev file,node-name=cd1,filename=",
+ test_cdboot);
+ }
+ if (qtest_has_device("megasas-gen2")) {
+ qtest_add_data_func("cdrom/boot/megasas-gen2", "-M q35 "
+ "-device megasas-gen2 -device scsi-cd,drive=cd1 "
+ "-blockdev file,node-name=cd1,filename=",
+ test_cdboot);
+ }
}
}
@@ -206,6 +213,30 @@ static void add_s390x_tests(void)
"-drive driver=null-co,read-zeroes=on,if=none,id=d1 "
"-device virtio-blk,drive=d2,bootindex=1 "
"-drive if=none,id=d2,media=cdrom,file=", test_cdboot);
+ qtest_add_data_func("cdrom/boot/as-fallback-device",
+ "-device virtio-serial -device virtio-scsi "
+ "-device virtio-blk,drive=d1,bootindex=1 "
+ "-drive driver=null-co,read-zeroes=on,if=none,id=d1 "
+ "-device virtio-blk,drive=d2,bootindex=2 "
+ "-drive if=none,id=d2,media=cdrom,file=", test_cdboot);
+ qtest_add_data_func("cdrom/boot/as-last-option",
+ "-device virtio-serial -device virtio-scsi "
+ "-device virtio-blk,drive=d1,bootindex=1 "
+ "-drive driver=null-co,read-zeroes=on,if=none,id=d1 "
+ "-device virtio-blk,drive=d2,bootindex=2 "
+ "-drive driver=null-co,read-zeroes=on,if=none,id=d2 "
+ "-device virtio-blk,drive=d3,bootindex=3 "
+ "-drive driver=null-co,read-zeroes=on,if=none,id=d3 "
+ "-device scsi-hd,drive=d4,bootindex=4 "
+ "-drive driver=null-co,read-zeroes=on,if=none,id=d4 "
+ "-device scsi-hd,drive=d5,bootindex=5 "
+ "-drive driver=null-co,read-zeroes=on,if=none,id=d5 "
+ "-device virtio-blk,drive=d6,bootindex=6 "
+ "-drive driver=null-co,read-zeroes=on,if=none,id=d6 "
+ "-device scsi-hd,drive=d7,bootindex=7 "
+ "-drive driver=null-co,read-zeroes=on,if=none,id=d7 "
+ "-device scsi-cd,drive=d8,bootindex=8 "
+ "-drive if=none,id=d8,media=cdrom,file=", test_cdboot);
if (qtest_has_device("x-terminal3270")) {
qtest_add_data_func("cdrom/boot/without-bootindex",
"-device virtio-scsi -device virtio-serial "
diff --git a/tests/qtest/dbus-display-test.c b/tests/qtest/dbus-display-test.c
index 0390bdc..f7fc873 100644
--- a/tests/qtest/dbus-display-test.c
+++ b/tests/qtest/dbus-display-test.c
@@ -2,9 +2,14 @@
#include "qemu/sockets.h"
#include "qemu/dbus.h"
#include "qemu/sockets.h"
+#include "glib.h"
+#include "glibconfig.h"
#include <gio/gio.h>
#include <gio/gunixfdlist.h>
#include "libqtest.h"
+#ifndef WIN32
+#include <sys/mman.h>
+#endif
#include "ui/dbus-display1.h"
static GDBusConnection*
@@ -82,6 +87,7 @@ typedef struct TestDBusConsoleRegister {
GThread *thread;
GDBusConnection *listener_conn;
GDBusObjectManagerServer *server;
+ bool with_map;
} TestDBusConsoleRegister;
static gboolean listener_handle_scanout(
@@ -94,13 +100,49 @@ static gboolean listener_handle_scanout(
GVariant *arg_data,
TestDBusConsoleRegister *test)
{
+ if (!test->with_map) {
+ g_main_loop_quit(test->loop);
+ }
+
+ return DBUS_METHOD_INVOCATION_HANDLED;
+}
+
+#ifndef WIN32
+static gboolean listener_handle_scanout_map(
+ QemuDBusDisplay1ListenerUnixMap *object,
+ GDBusMethodInvocation *invocation,
+ GUnixFDList *fd_list,
+ GVariant *arg_handle,
+ guint arg_offset,
+ guint arg_width,
+ guint arg_height,
+ guint arg_stride,
+ guint arg_pixman_format,
+ TestDBusConsoleRegister *test)
+{
+ int fd = -1;
+ gint32 handle = g_variant_get_handle(arg_handle);
+ g_autoptr(GError) error = NULL;
+ void *addr = NULL;
+ size_t len = arg_height * arg_stride;
+
+ g_assert_cmpuint(g_unix_fd_list_get_length(fd_list), ==, 1);
+ fd = g_unix_fd_list_get(fd_list, handle, &error);
+ g_assert_no_error(error);
+
+ addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, arg_offset);
+ g_assert_no_errno(addr == MAP_FAILED ? -1 : 0);
+ g_assert_no_errno(munmap(addr, len));
+
g_main_loop_quit(test->loop);
+ close(fd);
return DBUS_METHOD_INVOCATION_HANDLED;
}
+#endif
static void
-test_dbus_console_setup_listener(TestDBusConsoleRegister *test)
+test_dbus_console_setup_listener(TestDBusConsoleRegister *test, bool with_map)
{
g_autoptr(GDBusObjectSkeleton) listener = NULL;
g_autoptr(QemuDBusDisplay1ListenerSkeleton) iface = NULL;
@@ -114,6 +156,25 @@ test_dbus_console_setup_listener(TestDBusConsoleRegister *test)
NULL);
g_dbus_object_skeleton_add_interface(listener,
G_DBUS_INTERFACE_SKELETON(iface));
+ if (with_map) {
+#ifdef WIN32
+ g_test_skip("map test lacking on win32");
+ return;
+#else
+ g_autoptr(QemuDBusDisplay1ListenerUnixMapSkeleton) iface_map =
+ QEMU_DBUS_DISPLAY1_LISTENER_UNIX_MAP_SKELETON(
+ qemu_dbus_display1_listener_unix_map_skeleton_new());
+
+ g_object_connect(iface_map,
+ "signal::handle-scanout-map", listener_handle_scanout_map, test,
+ NULL);
+ g_dbus_object_skeleton_add_interface(listener,
+ G_DBUS_INTERFACE_SKELETON(iface_map));
+ g_object_set(iface, "interfaces",
+ (const gchar *[]) { "org.qemu.Display1.Listener.Unix.Map", NULL },
+ NULL);
+#endif
+ }
g_dbus_object_manager_server_export(test->server, listener);
g_dbus_object_manager_server_set_connection(test->server,
test->listener_conn);
@@ -145,7 +206,7 @@ test_dbus_console_registered(GObject *source_object,
g_assert_no_error(err);
test->listener_conn = g_thread_join(test->thread);
- test_dbus_console_setup_listener(test);
+ test_dbus_console_setup_listener(test, test->with_map);
}
static gpointer
@@ -155,7 +216,7 @@ test_dbus_p2p_server_setup_thread(gpointer data)
}
static void
-test_dbus_display_console(void)
+test_dbus_display_console(const void* data)
{
g_autoptr(GError) err = NULL;
g_autoptr(GDBusConnection) conn = NULL;
@@ -163,7 +224,7 @@ test_dbus_display_console(void)
g_autoptr(GMainLoop) loop = NULL;
QTestState *qts = NULL;
int pair[2];
- TestDBusConsoleRegister test = { 0, };
+ TestDBusConsoleRegister test = { 0, .with_map = GPOINTER_TO_INT(data) };
#ifdef WIN32
WSAPROTOCOL_INFOW info;
g_autoptr(GVariant) listener = NULL;
@@ -299,7 +360,8 @@ main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
qtest_add_func("/dbus-display/vm", test_dbus_display_vm);
- qtest_add_func("/dbus-display/console", test_dbus_display_console);
+ qtest_add_data_func("/dbus-display/console", GINT_TO_POINTER(false), test_dbus_display_console);
+ qtest_add_data_func("/dbus-display/console/map", GINT_TO_POINTER(true), test_dbus_display_console);
qtest_add_func("/dbus-display/keyboard", test_dbus_display_keyboard);
return g_test_run();
diff --git a/tests/qtest/dm163-test.c b/tests/qtest/dm163-test.c
index 3161c92..4c8e654 100644
--- a/tests/qtest/dm163-test.c
+++ b/tests/qtest/dm163-test.c
@@ -182,6 +182,8 @@ static void test_dm163_gpio_connection(void)
g_assert_false(qtest_get_irq(qts, LAT_B));
g_assert_false(qtest_get_irq(qts, SELBK));
g_assert_false(qtest_get_irq(qts, RST_B));
+
+ qtest_quit(qts);
}
int main(int argc, char **argv)
diff --git a/tests/qtest/endianness-test.c b/tests/qtest/endianness-test.c
index 222d116..f4872b0 100644
--- a/tests/qtest/endianness-test.c
+++ b/tests/qtest/endianness-test.c
@@ -41,7 +41,6 @@ static const TestCase test_cases[] = {
{ "ppc64", "pseries-2.7", 0x10080000000ULL,
.bswap = true, .superio = "i82378" },
{ "sh4", "r2d", 0xfe240000, .superio = "i82378" },
- { "sh4eb", "r2d", 0xfe240000, .bswap = true, .superio = "i82378" },
{ "sparc64", "sun4u", 0x1fe02000000LL, .bswap = true },
{ "x86_64", "pc", -1 },
{}
diff --git a/tests/qtest/fdc-test.c b/tests/qtest/fdc-test.c
index 5e8fbda..8645b080 100644
--- a/tests/qtest/fdc-test.c
+++ b/tests/qtest/fdc-test.c
@@ -552,7 +552,7 @@ static bool qtest_check_clang_sanitizer(void)
#ifdef QEMU_SANITIZE_ADDRESS
return true;
#else
- g_test_skip("QEMU not configured using --enable-sanitizers");
+ g_test_skip("QEMU not configured using --enable-asan");
return false;
#endif
}
diff --git a/tests/qtest/fuzz/generic_fuzz.c b/tests/qtest/fuzz/generic_fuzz.c
index ec842e0..d107a49 100644
--- a/tests/qtest/fuzz/generic_fuzz.c
+++ b/tests/qtest/fuzz/generic_fuzz.c
@@ -11,6 +11,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/range.h"
#include <wordexp.h>
@@ -211,7 +212,7 @@ void fuzz_dma_read_cb(size_t addr, size_t len, MemoryRegion *mr)
i < dma_regions->len && (avoid_double_fetches || qtest_log_enabled);
++i) {
region = g_array_index(dma_regions, address_range, i);
- if (addr < region.addr + region.size && addr + len > region.addr) {
+ if (ranges_overlap(addr, len, region.addr, region.size)) {
double_fetch = true;
if (addr < region.addr
&& avoid_double_fetches) {
diff --git a/tests/qtest/hd-geo-test.c b/tests/qtest/hd-geo-test.c
index d08bffa..85eb8d7 100644
--- a/tests/qtest/hd-geo-test.c
+++ b/tests/qtest/hd-geo-test.c
@@ -1074,17 +1074,26 @@ int main(int argc, char **argv)
}
}
- qtest_add_func("hd-geo/ide/none", test_ide_none);
- qtest_add_func("hd-geo/ide/drive/mbr/blank", test_ide_drive_mbr_blank);
- qtest_add_func("hd-geo/ide/drive/mbr/lba", test_ide_drive_mbr_lba);
- qtest_add_func("hd-geo/ide/drive/mbr/chs", test_ide_drive_mbr_chs);
- qtest_add_func("hd-geo/ide/drive/cd_0", test_ide_drive_cd_0);
- qtest_add_func("hd-geo/ide/device/mbr/blank", test_ide_device_mbr_blank);
- qtest_add_func("hd-geo/ide/device/mbr/lba", test_ide_device_mbr_lba);
- qtest_add_func("hd-geo/ide/device/mbr/chs", test_ide_device_mbr_chs);
- qtest_add_func("hd-geo/ide/device/user/chs", test_ide_device_user_chs);
- qtest_add_func("hd-geo/ide/device/user/chst", test_ide_device_user_chst);
- if (have_qemu_img()) {
+ if (qtest_has_machine("pc")) {
+ qtest_add_func("hd-geo/ide/none", test_ide_none);
+ qtest_add_func("hd-geo/ide/drive/mbr/blank", test_ide_drive_mbr_blank);
+ qtest_add_func("hd-geo/ide/drive/mbr/lba", test_ide_drive_mbr_lba);
+ qtest_add_func("hd-geo/ide/drive/mbr/chs", test_ide_drive_mbr_chs);
+ qtest_add_func("hd-geo/ide/drive/cd_0", test_ide_drive_cd_0);
+ qtest_add_func("hd-geo/ide/device/mbr/blank", test_ide_device_mbr_blank);
+ qtest_add_func("hd-geo/ide/device/mbr/lba", test_ide_device_mbr_lba);
+ qtest_add_func("hd-geo/ide/device/mbr/chs", test_ide_device_mbr_chs);
+ qtest_add_func("hd-geo/ide/device/user/chs", test_ide_device_user_chs);
+ qtest_add_func("hd-geo/ide/device/user/chst", test_ide_device_user_chst);
+ }
+
+ if (!have_qemu_img()) {
+ g_test_message("QTEST_QEMU_IMG not set or qemu-img missing; "
+ "skipping hd-geo/override/* tests");
+ goto test_add_done;
+ }
+
+ if (qtest_has_machine("pc")) {
qtest_add_func("hd-geo/override/ide", test_override_ide);
if (qtest_has_device("lsi53c895a")) {
qtest_add_func("hd-geo/override/scsi", test_override_scsi);
@@ -1104,30 +1113,26 @@ int main(int argc, char **argv)
qtest_add_func("hd-geo/override/virtio_blk",
test_override_virtio_blk);
}
+ }
- if (qtest_has_machine("q35")) {
- qtest_add_func("hd-geo/override/sata", test_override_sata);
- qtest_add_func("hd-geo/override/zero_chs_q35",
- test_override_zero_chs_q35);
- if (qtest_has_device("lsi53c895a")) {
- qtest_add_func("hd-geo/override/scsi_q35",
- test_override_scsi_q35);
- }
- if (qtest_has_device("virtio-scsi-pci")) {
- qtest_add_func("hd-geo/override/scsi_hot_unplug_q35",
- test_override_scsi_hot_unplug_q35);
- }
- if (qtest_has_device("virtio-blk-pci")) {
- qtest_add_func("hd-geo/override/virtio_hot_unplug_q35",
- test_override_virtio_hot_unplug_q35);
- qtest_add_func("hd-geo/override/virtio_blk_q35",
- test_override_virtio_blk_q35);
- }
-
+ if (qtest_has_machine("q35")) {
+ qtest_add_func("hd-geo/override/sata", test_override_sata);
+ qtest_add_func("hd-geo/override/zero_chs_q35",
+ test_override_zero_chs_q35);
+ if (qtest_has_device("lsi53c895a")) {
+ qtest_add_func("hd-geo/override/scsi_q35",
+ test_override_scsi_q35);
+ }
+ if (qtest_has_device("virtio-scsi-pci")) {
+ qtest_add_func("hd-geo/override/scsi_hot_unplug_q35",
+ test_override_scsi_hot_unplug_q35);
+ }
+ if (qtest_has_device("virtio-blk-pci")) {
+ qtest_add_func("hd-geo/override/virtio_hot_unplug_q35",
+ test_override_virtio_hot_unplug_q35);
+ qtest_add_func("hd-geo/override/virtio_blk_q35",
+ test_override_virtio_blk_q35);
}
- } else {
- g_test_message("QTEST_QEMU_IMG not set or qemu-img missing; "
- "skipping hd-geo/override/* tests");
}
test_add_done:
diff --git a/tests/qtest/ipmi-bt-test.c b/tests/qtest/ipmi-bt-test.c
index 383239b..637732f 100644
--- a/tests/qtest/ipmi-bt-test.c
+++ b/tests/qtest/ipmi-bt-test.c
@@ -251,7 +251,7 @@ static void emu_msg_handler(void)
msg[msg_len++] = 0xa0;
write_emu_msg(msg, msg_len);
} else {
- g_assert(0);
+ g_assert_not_reached();
}
}
@@ -411,7 +411,7 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
global_qtest = qtest_initf(
- " -chardev socket,id=ipmi0,host=127.0.0.1,port=%d,reconnect=10"
+ " -chardev socket,id=ipmi0,host=127.0.0.1,port=%d,reconnect-ms=10000"
" -device ipmi-bmc-extern,chardev=ipmi0,id=bmc0"
" -device isa-ipmi-bt,bmc=bmc0", emu_port);
qtest_irq_intercept_in(global_qtest, "ioapic");
diff --git a/tests/qtest/ipmi-kcs-test.c b/tests/qtest/ipmi-kcs-test.c
index afc24dd..3186c6a 100644
--- a/tests/qtest/ipmi-kcs-test.c
+++ b/tests/qtest/ipmi-kcs-test.c
@@ -145,7 +145,7 @@ static void kcs_cmd(uint8_t *cmd, unsigned int cmd_len,
break;
default:
- g_assert(0);
+ g_assert_not_reached();
}
*rsp_len = j;
}
@@ -184,7 +184,7 @@ static void kcs_abort(uint8_t *cmd, unsigned int cmd_len,
break;
default:
- g_assert(0);
+ g_assert_not_reached();
}
/* Start the abort here */
diff --git a/tests/qtest/libqos/arm-n800-machine.c b/tests/qtest/libqos/arm-n800-machine.c
deleted file mode 100644
index 4e5afe0..0000000
--- a/tests/qtest/libqos/arm-n800-machine.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * libqos driver framework
- *
- * Copyright (c) 2019 Red Hat, Inc.
- *
- * Author: Paolo Bonzini <pbonzini@redhat.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 "libqos-malloc.h"
-#include "qgraph.h"
-#include "i2c.h"
-
-#define ARM_PAGE_SIZE 4096
-#define N800_RAM_START 0x80000000
-#define N800_RAM_END 0x88000000
-
-typedef struct QN800Machine QN800Machine;
-
-struct QN800Machine {
- QOSGraphObject obj;
- QGuestAllocator alloc;
- OMAPI2C i2c_1;
-};
-
-static void *n800_get_driver(void *object, const char *interface)
-{
- QN800Machine *machine = object;
- if (!g_strcmp0(interface, "memory")) {
- return &machine->alloc;
- }
-
- fprintf(stderr, "%s not present in arm/n800\n", interface);
- g_assert_not_reached();
-}
-
-static QOSGraphObject *n800_get_device(void *obj, const char *device)
-{
- QN800Machine *machine = obj;
- if (!g_strcmp0(device, "omap_i2c")) {
- return &machine->i2c_1.obj;
- }
-
- fprintf(stderr, "%s not present in arm/n800\n", device);
- g_assert_not_reached();
-}
-
-static void n800_destructor(QOSGraphObject *obj)
-{
- QN800Machine *machine = (QN800Machine *) obj;
- alloc_destroy(&machine->alloc);
-}
-
-static void *qos_create_machine_arm_n800(QTestState *qts)
-{
- QN800Machine *machine = g_new0(QN800Machine, 1);
-
- alloc_init(&machine->alloc, 0,
- N800_RAM_START,
- N800_RAM_END,
- ARM_PAGE_SIZE);
- machine->obj.get_device = n800_get_device;
- machine->obj.get_driver = n800_get_driver;
- machine->obj.destructor = n800_destructor;
-
- omap_i2c_init(&machine->i2c_1, qts, 0x48070000);
- return &machine->obj;
-}
-
-static void n800_register_nodes(void)
-{
- QOSGraphEdgeOptions edge = {
- .extra_device_opts = "bus=i2c-bus.0"
- };
- qos_node_create_machine("arm/n800", qos_create_machine_arm_n800);
- qos_node_contains("arm/n800", "omap_i2c", &edge, NULL);
-}
-
-libqos_init(n800_register_nodes);
diff --git a/tests/qtest/libqos/meson.build b/tests/qtest/libqos/meson.build
index 1b2b2db..270439c 100644
--- a/tests/qtest/libqos/meson.build
+++ b/tests/qtest/libqos/meson.build
@@ -52,7 +52,6 @@ libqos_srcs = files(
# qgraph machines:
'aarch64-xlnx-zcu102-machine.c',
'arm-imx25-pdk-machine.c',
- 'arm-n800-machine.c',
'arm-raspi2-machine.c',
'arm-sabrelite-machine.c',
'arm-smdkc210-machine.c',
diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
index 1326e34..9d07de1 100644
--- a/tests/qtest/libqtest.c
+++ b/tests/qtest/libqtest.c
@@ -514,7 +514,12 @@ static QTestState *qtest_init_internal(const char *qemu_bin,
kill(s->qemu_pid, SIGSTOP);
}
#endif
- return s;
+
+ /* ask endianness of the target */
+
+ s->big_endian = qtest_query_target_endianness(s);
+
+ return s;
}
QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
@@ -522,21 +527,11 @@ QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
return qtest_init_internal(qtest_qemu_binary(NULL), extra_args);
}
-QTestState *qtest_init_with_env_no_handshake(const char *var,
- const char *extra_args)
-{
- return qtest_init_internal(qtest_qemu_binary(var), extra_args);
-}
-
QTestState *qtest_init_with_env(const char *var, const char *extra_args)
{
QTestState *s = qtest_init_internal(qtest_qemu_binary(var), extra_args);
QDict *greeting;
- /* ask endianness of the target */
-
- s->big_endian = qtest_query_target_endianness(s);
-
/* Read the QMP greeting and then do the handshake */
greeting = qtest_qmp_receive(s);
qobject_unref(greeting);
diff --git a/tests/qtest/libqtest.h b/tests/qtest/libqtest.h
index c261b7e..beb96b1 100644
--- a/tests/qtest/libqtest.h
+++ b/tests/qtest/libqtest.h
@@ -68,8 +68,6 @@ QTestState *qtest_init(const char *extra_args);
*/
QTestState *qtest_init_with_env(const char *var, const char *extra_args);
-QTestState *qtest_init_with_env_no_handshake(const char *var,
- const char *extra_args);
/**
* qtest_init_without_qmp_handshake:
* @extra_args: other arguments to pass to QEMU. CAUTION: these
diff --git a/tests/qtest/machine-none-test.c b/tests/qtest/machine-none-test.c
index 05da7bc..9cf95be 100644
--- a/tests/qtest/machine-none-test.c
+++ b/tests/qtest/machine-none-test.c
@@ -30,7 +30,6 @@ static struct arch2cpu cpus_map[] = {
{ "x86_64", "qemu64,apic-id=0" },
{ "i386", "qemu32,apic-id=0" },
{ "alpha", "ev67" },
- { "cris", "crisv32" },
{ "m68k", "m5206" },
{ "microblaze", "any" },
{ "microblazeel", "any" },
@@ -43,7 +42,6 @@ static struct arch2cpu cpus_map[] = {
{ "ppc64", "power8e_v2.1" },
{ "s390x", "qemu" },
{ "sh4", "sh7750r" },
- { "sh4eb", "sh7751r" },
{ "sparc", "LEON2" },
{ "sparc64", "Fujitsu Sparc64" },
{ "tricore", "tc1796" },
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 6508bfb..f7a1903 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -1,11 +1,14 @@
slow_qtests = {
+ 'ahci-test': 150,
'aspeed_smc-test': 360,
- 'bios-tables-test' : 610,
+ 'bios-tables-test' : 910,
'cdrom-test' : 610,
'device-introspect-test' : 720,
+ 'ide-test' : 120,
'migration-test' : 480,
'npcm7xx_pwm-test': 300,
'npcm7xx_watchdog_timer-test': 120,
+ 'qmp-cmd-test' : 120,
'qom-test' : 900,
'stm32l4x5_usart-test' : 600,
'test-hmp' : 240,
@@ -49,7 +52,15 @@ qtests_filter = \
qtests_i386 = \
(slirp.found() ? ['pxe-test'] : []) + \
qtests_filter + \
- (have_tools ? ['ahci-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_ACPI_VMGENID') ? ['vmgenid-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_AHCI_ICH9') and have_tools ? ['ahci-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_AHCI_ICH9') ? ['tco-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_FDC_ISA') ? ['fdc-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_I440FX') ? ['fw_cfg-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_I440FX') ? ['i440fx-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_I440FX') ? ['ide-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_I440FX') ? ['numa-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_I440FX') ? ['test-x86-cpuid-compat'] : []) + \
(config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \
(config_all_devices.has_key('CONFIG_SGA') ? ['boot-serial-test'] : []) + \
(config_all_devices.has_key('CONFIG_ISA_IPMI_KCS') ? ['ipmi-kcs-test'] : []) + \
@@ -63,6 +74,7 @@ qtests_i386 = \
(config_all_devices.has_key('CONFIG_I82801B11') ? ['i82801b11-test'] : []) + \
(config_all_devices.has_key('CONFIG_IOH3420') ? ['ioh3420-test'] : []) + \
(config_all_devices.has_key('CONFIG_LPC_ICH9') ? ['lpc-ich9-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_MC146818RTC') ? ['rtc-test'] : []) + \
(config_all_devices.has_key('CONFIG_USB_UHCI') ? ['usb-hcd-uhci-test'] : []) + \
(config_all_devices.has_key('CONFIG_USB_UHCI') and \
config_all_devices.has_key('CONFIG_USB_EHCI') ? ['usb-hcd-ehci-test'] : []) + \
@@ -76,6 +88,7 @@ qtests_i386 = \
(config_all_devices.has_key('CONFIG_MEGASAS_SCSI_PCI') ? ['fuzz-megasas-test'] : []) + \
(config_all_devices.has_key('CONFIG_LSI_SCSI_PCI') ? ['fuzz-lsi53c895a-test'] : []) + \
(config_all_devices.has_key('CONFIG_VIRTIO_SCSI') ? ['fuzz-virtio-scsi-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_Q35') ? ['q35-test'] : []) + \
(config_all_devices.has_key('CONFIG_SB16') ? ['fuzz-sb16-test'] : []) + \
(config_all_devices.has_key('CONFIG_SDHCI_PCI') ? ['fuzz-sdcard-test'] : []) + \
(config_all_devices.has_key('CONFIG_ESP_PCI') ? ['am53c974-test'] : []) + \
@@ -91,25 +104,16 @@ qtests_i386 = \
config_all_devices.has_key('CONFIG_PARALLEL') ? ['bios-tables-test'] : []) + \
qtests_pci + \
qtests_cxl + \
- ['fdc-test',
- 'ide-test',
+ [
'hd-geo-test',
'boot-order-test',
- 'rtc-test',
- 'i440fx-test',
- 'fw_cfg-test',
'device-plug-test',
'drive_del-test',
- 'tco-test',
'cpu-plug-test',
- 'q35-test',
- 'vmgenid-test',
'migration-test',
- 'test-x86-cpuid-compat',
- 'numa-test'
]
-if dbus_display
+if dbus_display and config_all_devices.has_key('CONFIG_VGA')
qtests_i386 += ['dbus-display-test']
endif
@@ -140,7 +144,8 @@ qtests_hppa = ['boot-serial-test'] + \
(config_all_devices.has_key('CONFIG_VGA') ? ['display-vga-test'] : [])
qtests_loongarch64 = qtests_filter + \
- ['boot-serial-test', 'numa-test']
+ (config_all_devices.has_key('CONFIG_LOONGARCH_VIRT') ? ['numa-test'] : []) + \
+ ['boot-serial-test']
qtests_m68k = ['boot-serial-test'] + \
qtests_filter
@@ -171,15 +176,16 @@ qtests_ppc64 = \
qtests_ppc + \
(config_all_devices.has_key('CONFIG_PSERIES') ? ['device-plug-test'] : []) + \
(config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-xscom-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-spi-seeprom-test'] : []) + \
(config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-host-i2c-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_PSERIES') ? ['numa-test'] : []) + \
(config_all_devices.has_key('CONFIG_PSERIES') ? ['rtas-test'] : []) + \
(slirp.found() ? ['pxe-test'] : []) + \
(config_all_devices.has_key('CONFIG_USB_UHCI') ? ['usb-hcd-uhci-test'] : []) + \
(config_all_devices.has_key('CONFIG_USB_XHCI_NEC') ? ['usb-hcd-xhci-test'] : []) + \
- qtests_pci + ['migration-test', 'numa-test', 'cpu-plug-test', 'drive_del-test']
+ qtests_pci + ['migration-test', 'cpu-plug-test', 'drive_del-test']
qtests_sh4 = (config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : [])
-qtests_sh4eb = (config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : [])
qtests_sparc = ['prom-env-test', 'm48t59-test', 'boot-serial-test'] + \
qtests_filter
@@ -204,6 +210,8 @@ qtests_aspeed = \
['aspeed_hace-test',
'aspeed_smc-test',
'aspeed_gpio-test']
+qtests_aspeed64 = \
+ ['ast2700-gpio-test']
qtests_stm32l4x5 = \
['stm32l4x5_exti-test',
@@ -242,6 +250,7 @@ qtests_aarch64 = \
(config_all_devices.has_key('CONFIG_RASPI') ? ['bcm2835-dma-test', 'bcm2835-i2c-test'] : []) + \
(config_all_accel.has_key('CONFIG_TCG') and \
config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_ASPEED_SOC') ? qtests_aspeed64 : []) + \
['arm-cpu-features',
'numa-test',
'boot-serial-test',
@@ -322,8 +331,7 @@ if gnutls.found()
migration_files += [files('../unit/crypto-tls-psk-helpers.c'), gnutls]
if tasn1.found()
- migration_files += [files('../unit/crypto-tls-x509-helpers.c',
- '../unit/pkix_asn1_tab.c'), tasn1]
+ migration_files += [files('../unit/crypto-tls-x509-helpers.c'), tasn1]
endif
endif
diff --git a/tests/qtest/migration-helpers.c b/tests/qtest/migration-helpers.c
index 84f49db..0025933 100644
--- a/tests/qtest/migration-helpers.c
+++ b/tests/qtest/migration-helpers.c
@@ -76,17 +76,15 @@ static QDict *SocketAddress_to_qdict(SocketAddress *addr)
break;
default:
g_assert_not_reached();
- break;
}
return dict;
}
-static SocketAddress *migrate_get_socket_address(QTestState *who)
+static SocketAddressList *migrate_get_socket_address(QTestState *who)
{
QDict *rsp;
SocketAddressList *addrs;
- SocketAddress *addr;
Visitor *iv = NULL;
QObject *object;
@@ -95,36 +93,35 @@ static SocketAddress *migrate_get_socket_address(QTestState *who)
iv = qobject_input_visitor_new(object);
visit_type_SocketAddressList(iv, NULL, &addrs, &error_abort);
- addr = addrs->value;
visit_free(iv);
qobject_unref(rsp);
- return addr;
+ return addrs;
}
static char *
migrate_get_connect_uri(QTestState *who)
{
- SocketAddress *addrs;
+ SocketAddressList *addrs;
char *connect_uri;
addrs = migrate_get_socket_address(who);
- connect_uri = SocketAddress_to_str(addrs);
+ connect_uri = SocketAddress_to_str(addrs->value);
- qapi_free_SocketAddress(addrs);
+ qapi_free_SocketAddressList(addrs);
return connect_uri;
}
static QDict *
migrate_get_connect_qdict(QTestState *who)
{
- SocketAddress *addrs;
+ SocketAddressList *addrs;
QDict *connect_qdict;
addrs = migrate_get_socket_address(who);
- connect_qdict = SocketAddress_to_qdict(addrs);
+ connect_qdict = SocketAddress_to_qdict(addrs->value);
- qapi_free_SocketAddress(addrs);
+ qapi_free_SocketAddressList(addrs);
return connect_qdict;
}
@@ -144,7 +141,7 @@ static void migrate_set_ports(QTestState *to, QList *channel_list)
qdict_haskey(addr, "port") &&
(strcmp(qdict_get_str(addrdict, "port"), "0") == 0)) {
addr_port = qdict_get_str(addr, "port");
- qdict_put_str(addrdict, "port", g_strdup(addr_port));
+ qdict_put_str(addrdict, "port", addr_port);
}
}
diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index 70b606b..95e45b5 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -64,7 +64,6 @@ static QTestMigrationState dst_state;
#define DIRTYLIMIT_TOLERANCE_RANGE 25 /* MB/s */
#define ANALYZE_SCRIPT "scripts/analyze-migration.py"
-#define VMSTATE_CHECKER_SCRIPT "scripts/vmstate-static-checker.py"
#define QEMU_VM_FILE_MAGIC 0x5145564d
#define FILE_TEST_FILENAME "migfile"
@@ -144,12 +143,23 @@ static char *bootpath;
#include "tests/migration/ppc64/a-b-kernel.h"
#include "tests/migration/s390x/a-b-bios.h"
+static void bootfile_delete(void)
+{
+ if (!bootpath) {
+ return;
+ }
+ unlink(bootpath);
+ g_free(bootpath);
+ bootpath = NULL;
+}
+
static void bootfile_create(char *dir, bool suspend_me)
{
const char *arch = qtest_get_arch();
unsigned char *content;
size_t len;
+ bootfile_delete();
bootpath = g_strdup_printf("%s/bootsect", dir);
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
/* the assembled x86 boot sector should be exactly one sector large */
@@ -177,13 +187,6 @@ static void bootfile_create(char *dir, bool suspend_me)
fclose(bootfile);
}
-static void bootfile_delete(void)
-{
- unlink(bootpath);
- g_free(bootpath);
- bootpath = NULL;
-}
-
/*
* Wait for some output in the serial output file,
* we get an 'A' followed by an endless string of 'B's
@@ -1058,12 +1061,15 @@ test_migrate_tls_x509_start_common(QTestState *from,
QCRYPTO_TLS_TEST_CLIENT_HOSTILE_NAME :
QCRYPTO_TLS_TEST_CLIENT_NAME,
data->clientcert);
+ test_tls_deinit_cert(&servercertreq);
}
TLS_CERT_REQ_SIMPLE_SERVER(clientcertreq, cacertreq,
data->servercert,
args->certhostname,
args->certipaddr);
+ test_tls_deinit_cert(&clientcertreq);
+ test_tls_deinit_cert(&cacertreq);
qtest_qmp_assert_success(from,
"{ 'execute': 'object-add',"
@@ -1688,85 +1694,6 @@ static void test_analyze_script(void)
test_migrate_end(from, to, false);
cleanup("migfile");
}
-
-static void test_vmstate_checker_script(void)
-{
- g_autofree gchar *cmd_src = NULL;
- g_autofree gchar *cmd_dst = NULL;
- g_autofree gchar *vmstate_src = NULL;
- g_autofree gchar *vmstate_dst = NULL;
- const char *machine_alias, *machine_opts = "";
- g_autofree char *machine = NULL;
- const char *arch = qtest_get_arch();
- int pid, wstatus;
- const char *python = g_getenv("PYTHON");
-
- if (!getenv(QEMU_ENV_SRC) && !getenv(QEMU_ENV_DST)) {
- g_test_skip("Test needs two different QEMU versions");
- return;
- }
-
- if (!python) {
- g_test_skip("PYTHON variable not set");
- return;
- }
-
- if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
- if (g_str_equal(arch, "i386")) {
- machine_alias = "pc";
- } else {
- machine_alias = "q35";
- }
- } else if (g_str_equal(arch, "s390x")) {
- machine_alias = "s390-ccw-virtio";
- } else if (strcmp(arch, "ppc64") == 0) {
- machine_alias = "pseries";
- } else if (strcmp(arch, "aarch64") == 0) {
- machine_alias = "virt";
- } else {
- g_assert_not_reached();
- }
-
- if (!qtest_has_machine(machine_alias)) {
- g_autofree char *msg = g_strdup_printf("machine %s not supported", machine_alias);
- g_test_skip(msg);
- return;
- }
-
- machine = resolve_machine_version(machine_alias, QEMU_ENV_SRC,
- QEMU_ENV_DST);
-
- vmstate_src = g_strdup_printf("%s/vmstate-src", tmpfs);
- vmstate_dst = g_strdup_printf("%s/vmstate-dst", tmpfs);
-
- cmd_dst = g_strdup_printf("-machine %s,%s -dump-vmstate %s",
- machine, machine_opts, vmstate_dst);
- cmd_src = g_strdup_printf("-machine %s,%s -dump-vmstate %s",
- machine, machine_opts, vmstate_src);
-
- qtest_init_with_env_no_handshake(QEMU_ENV_SRC, cmd_src);
- qtest_init_with_env_no_handshake(QEMU_ENV_DST, cmd_dst);
-
- pid = fork();
- if (!pid) {
- close(1);
- open("/dev/null", O_WRONLY);
- execl(python, python, VMSTATE_CHECKER_SCRIPT,
- "-s", vmstate_src,
- "-d", vmstate_dst,
- NULL);
- g_assert_not_reached();
- }
-
- g_assert(waitpid(pid, &wstatus, 0) == pid);
- if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0) {
- g_test_message("Failed to run vmstate-static-checker.py");
- g_test_fail();
- }
-
- cleanup("vmstate-src");
- cleanup("vmstate-dst");
-}
#endif
static void test_precopy_common(MigrateCommon *args)
@@ -2391,6 +2318,7 @@ static void multifd_mapped_ram_fdset_end(QTestState *from, QTestState *to,
g_assert(qdict_haskey(resp, "return"));
fdsets = qdict_get_qlist(resp, "return");
g_assert(fdsets && qlist_empty(fdsets));
+ qobject_unref(resp);
}
static void *multifd_mapped_ram_fdset_dio(QTestState *from, QTestState *to)
@@ -2992,6 +2920,18 @@ test_migrate_precopy_tcp_multifd_zstd_start(QTestState *from,
}
#endif /* CONFIG_ZSTD */
+#ifdef CONFIG_QATZIP
+static void *
+test_migrate_precopy_tcp_multifd_qatzip_start(QTestState *from,
+ QTestState *to)
+{
+ migrate_set_parameter_int(from, "multifd-qatzip-level", 2);
+ migrate_set_parameter_int(to, "multifd-qatzip-level", 2);
+
+ return test_migrate_precopy_tcp_multifd_start_common(from, to, "qatzip");
+}
+#endif
+
#ifdef CONFIG_QPL
static void *
test_migrate_precopy_tcp_multifd_qpl_start(QTestState *from,
@@ -3089,6 +3029,17 @@ static void test_multifd_tcp_zstd(void)
}
#endif
+#ifdef CONFIG_QATZIP
+static void test_multifd_tcp_qatzip(void)
+{
+ MigrateCommon args = {
+ .listen_uri = "defer",
+ .start_hook = test_migrate_precopy_tcp_multifd_qatzip_start,
+ };
+ test_precopy_common(&args);
+}
+#endif
+
#ifdef CONFIG_QPL
static void test_multifd_tcp_qpl(void)
{
@@ -3314,6 +3265,17 @@ static void test_multifd_tcp_cancel(void)
/* Make sure QEMU process "to" exited */
qtest_set_expected_status(to, EXIT_FAILURE);
qtest_wait_qemu(to);
+ qtest_quit(to);
+
+ /*
+ * Ensure the source QEMU finishes its cancellation process before we
+ * proceed with the setup of the next migration. The test_migrate_start()
+ * function and others might want to interact with the source in a way that
+ * is not possible while the migration is not canceled properly. For
+ * example, setting migration capabilities when the migration is still
+ * running leads to an error.
+ */
+ wait_for_migration_status(from, "cancelled", NULL);
args = (MigrateStart){
.only_target = true,
@@ -3330,8 +3292,6 @@ static void test_multifd_tcp_cancel(void)
/* Start incoming migration from the 1st socket */
migrate_incoming_qmp(to2, "tcp:127.0.0.1:0", "{}");
- wait_for_migration_status(from, "cancelled", NULL);
-
migrate_ensure_non_converge(from);
migrate_qmp(from, to2, NULL, NULL, "{}");
@@ -3393,15 +3353,18 @@ static QDict *query_vcpu_dirty_limit(QTestState *who)
static bool calc_dirtyrate_ready(QTestState *who)
{
QDict *rsp_return;
- gchar *status;
+ const char *status;
+ bool ready;
rsp_return = query_dirty_rate(who);
g_assert(rsp_return);
- status = g_strdup(qdict_get_str(rsp_return, "status"));
+ status = qdict_get_str(rsp_return, "status");
g_assert(status);
+ ready = g_strcmp0(status, "measuring");
+ qobject_unref(rsp_return);
- return g_strcmp0(status, "measuring");
+ return ready;
}
static void wait_for_calc_dirtyrate_complete(QTestState *who,
@@ -3424,7 +3387,7 @@ static void wait_for_calc_dirtyrate_complete(QTestState *who,
static int64_t get_dirty_rate(QTestState *who)
{
QDict *rsp_return;
- gchar *status;
+ const char *status;
QList *rates;
const QListEntry *entry;
QDict *rate;
@@ -3433,7 +3396,7 @@ static int64_t get_dirty_rate(QTestState *who)
rsp_return = query_dirty_rate(who);
g_assert(rsp_return);
- status = g_strdup(qdict_get_str(rsp_return, "status"));
+ status = qdict_get_str(rsp_return, "status");
g_assert(status);
g_assert_cmpstr(status, ==, "measured");
@@ -3819,8 +3782,6 @@ int main(int argc, char **argv)
migration_test_add("/migration/bad_dest", test_baddest);
#ifndef _WIN32
migration_test_add("/migration/analyze-script", test_analyze_script);
- migration_test_add("/migration/vmstate-checker-script",
- test_vmstate_checker_script);
#endif
if (is_x86) {
@@ -3850,8 +3811,10 @@ int main(int argc, char **argv)
migration_test_add("/migration/precopy/unix/plain",
test_precopy_unix_plain);
- migration_test_add("/migration/precopy/unix/xbzrle",
- test_precopy_unix_xbzrle);
+ if (g_test_slow()) {
+ migration_test_add("/migration/precopy/unix/xbzrle",
+ test_precopy_unix_xbzrle);
+ }
migration_test_add("/migration/precopy/file",
test_precopy_file);
migration_test_add("/migration/precopy/file/offset",
@@ -3992,6 +3955,10 @@ int main(int argc, char **argv)
migration_test_add("/migration/multifd/tcp/plain/zstd",
test_multifd_tcp_zstd);
#endif
+#ifdef CONFIG_QATZIP
+ migration_test_add("/migration/multifd/tcp/plain/qatzip",
+ test_multifd_tcp_qatzip);
+#endif
#ifdef CONFIG_QPL
migration_test_add("/migration/multifd/tcp/plain/qpl",
test_multifd_tcp_qpl);
@@ -4022,8 +3989,10 @@ int main(int argc, char **argv)
if (g_str_equal(arch, "x86_64") && has_kvm && kvm_dirty_ring_supported()) {
migration_test_add("/migration/dirty_ring",
test_precopy_unix_dirty_ring);
- migration_test_add("/migration/vcpu_dirty_limit",
- test_vcpu_dirty_limit);
+ if (qtest_has_machine("pc") && g_test_slow()) {
+ migration_test_add("/migration/vcpu_dirty_limit",
+ test_vcpu_dirty_limit);
+ }
}
ret = g_test_run();
diff --git a/tests/qtest/netdev-socket.c b/tests/qtest/netdev-socket.c
index fc7d119..317af03 100644
--- a/tests/qtest/netdev-socket.c
+++ b/tests/qtest/netdev-socket.c
@@ -204,7 +204,7 @@ static void test_stream_unix_reconnect(void)
qts1 = qtest_initf("-nodefaults -M none "
"-netdev stream,server=false,id=st0,addr.type=unix,"
- "addr.path=%s,reconnect=1", path);
+ "addr.path=%s,reconnect-ms=1000", path);
wait_stream_connected(qts0, "st0", &addr);
g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_UNIX);
diff --git a/tests/qtest/numa-test.c b/tests/qtest/numa-test.c
index ede4189..6d92bae 100644
--- a/tests/qtest/numa-test.c
+++ b/tests/qtest/numa-test.c
@@ -162,7 +162,7 @@ static void pc_numa_cpu(const void *data)
} else if (socket == 1 && core == 1 && thread == 1) {
g_assert_cmpint(node, ==, 1);
} else {
- g_assert(false);
+ g_assert_not_reached();
}
qobject_unref(e);
}
@@ -207,7 +207,7 @@ static void spapr_numa_cpu(const void *data)
} else if (core == 3) {
g_assert_cmpint(node, ==, 1);
} else {
- g_assert(false);
+ g_assert_not_reached();
}
qobject_unref(e);
}
@@ -257,7 +257,7 @@ static void aarch64_numa_cpu(const void *data)
} else if (socket == 1 && cluster == 0 && core == 0 && thread == 0) {
g_assert_cmpint(node, ==, 0);
} else {
- g_assert(false);
+ g_assert_not_reached();
}
qobject_unref(e);
}
@@ -305,7 +305,7 @@ static void loongarch64_numa_cpu(const void *data)
} else if (socket == 1 && core == 0 && thread == 0) {
g_assert_cmpint(node, ==, 0);
} else {
- g_assert(false);
+ g_assert_not_reached();
}
qobject_unref(e);
}
@@ -367,7 +367,7 @@ static void pc_dynamic_cpu_cfg(const void *data)
} else if (socket == 1) {
g_assert_cmpint(node, ==, 0);
} else {
- g_assert(false);
+ g_assert_not_reached();
}
qobject_unref(e);
}
diff --git a/tests/qtest/pnv-spi-seeprom-test.c b/tests/qtest/pnv-spi-seeprom-test.c
new file mode 100644
index 0000000..57f20af
--- /dev/null
+++ b/tests/qtest/pnv-spi-seeprom-test.c
@@ -0,0 +1,110 @@
+/*
+ * QTest testcase for PowerNV 10 Seeprom Communications
+ *
+ * Copyright (c) 2024, IBM Corporation.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <unistd.h>
+#include "qemu/osdep.h"
+#include "libqtest.h"
+#include "qemu/bswap.h"
+#include "hw/ssi/pnv_spi_regs.h"
+#include "pnv-xscom.h"
+
+#define FLASH_SIZE (512 * 1024)
+#define SPIC2_XSCOM_BASE 0xc0040
+
+/* To transmit READ opcode and address */
+#define READ_OP_TDR_DATA 0x0300010000000000
+/*
+ * N1 shift - tx 4 bytes (transmit opcode and address)
+ * N2 shift - tx and rx 8 bytes.
+ */
+#define READ_OP_COUNTER_CONFIG 0x2040000000002b00
+/* SEQ_OP_SELECT_RESPONDER - N1 Shift - N2 Shift * 5 - SEQ_OP_STOP */
+#define READ_OP_SEQUENCER 0x1130404040404010
+
+/* To transmit WREN(Set Write Enable Latch in status0 register) opcode */
+#define WRITE_OP_WREN 0x0600000000000000
+/* To transmit WRITE opcode, address and data */
+#define WRITE_OP_TDR_DATA 0x0300010012345678
+/* N1 shift - tx 8 bytes (transmit opcode, address and data) */
+#define WRITE_OP_COUNTER_CONFIG 0x4000000000002000
+/* SEQ_OP_SELECT_RESPONDER - N1 Shift - SEQ_OP_STOP */
+#define WRITE_OP_SEQUENCER 0x1130100000000000
+
+static void pnv_spi_xscom_write(QTestState *qts, const PnvChip *chip,
+ uint32_t reg, uint64_t val)
+{
+ uint32_t pcba = SPIC2_XSCOM_BASE + reg;
+ qtest_writeq(qts, pnv_xscom_addr(chip, pcba), val);
+}
+
+static uint64_t pnv_spi_xscom_read(QTestState *qts, const PnvChip *chip,
+ uint32_t reg)
+{
+ uint32_t pcba = SPIC2_XSCOM_BASE + reg;
+ return qtest_readq(qts, pnv_xscom_addr(chip, pcba));
+}
+
+static void spi_seeprom_transaction(QTestState *qts, const PnvChip *chip)
+{
+ /* SPI transactions to SEEPROM to read from SEEPROM image */
+ pnv_spi_xscom_write(qts, chip, SPI_CTR_CFG_REG, READ_OP_COUNTER_CONFIG);
+ pnv_spi_xscom_write(qts, chip, SPI_SEQ_OP_REG, READ_OP_SEQUENCER);
+ pnv_spi_xscom_write(qts, chip, SPI_XMIT_DATA_REG, READ_OP_TDR_DATA);
+ pnv_spi_xscom_write(qts, chip, SPI_XMIT_DATA_REG, 0);
+ /* Read 5*8 bytes from SEEPROM at 0x100 */
+ uint64_t rdr_val = pnv_spi_xscom_read(qts, chip, SPI_RCV_DATA_REG);
+ g_test_message("RDR READ = 0x%" PRIx64, rdr_val);
+ rdr_val = pnv_spi_xscom_read(qts, chip, SPI_RCV_DATA_REG);
+ rdr_val = pnv_spi_xscom_read(qts, chip, SPI_RCV_DATA_REG);
+ rdr_val = pnv_spi_xscom_read(qts, chip, SPI_RCV_DATA_REG);
+ rdr_val = pnv_spi_xscom_read(qts, chip, SPI_RCV_DATA_REG);
+ g_test_message("RDR READ = 0x%" PRIx64, rdr_val);
+
+ /* SPI transactions to SEEPROM to write to SEEPROM image */
+ pnv_spi_xscom_write(qts, chip, SPI_CTR_CFG_REG, WRITE_OP_COUNTER_CONFIG);
+ /* Set Write Enable Latch bit of status0 register */
+ pnv_spi_xscom_write(qts, chip, SPI_SEQ_OP_REG, WRITE_OP_SEQUENCER);
+ pnv_spi_xscom_write(qts, chip, SPI_XMIT_DATA_REG, WRITE_OP_WREN);
+ /* write 8 bytes to SEEPROM at 0x100 */
+ pnv_spi_xscom_write(qts, chip, SPI_SEQ_OP_REG, WRITE_OP_SEQUENCER);
+ pnv_spi_xscom_write(qts, chip, SPI_XMIT_DATA_REG, WRITE_OP_TDR_DATA);
+}
+
+static void test_spi_seeprom(const void *data)
+{
+ const PnvChip *chip = data;
+ QTestState *qts = NULL;
+ g_autofree char *tmp_path = NULL;
+ int ret;
+ int fd;
+
+ /* Create a temporary raw image */
+ fd = g_file_open_tmp("qtest-seeprom-XXXXXX", &tmp_path, NULL);
+ g_assert(fd >= 0);
+ ret = ftruncate(fd, FLASH_SIZE);
+ g_assert(ret == 0);
+ close(fd);
+
+ qts = qtest_initf("-machine powernv10 -smp 2,cores=2,"
+ "threads=1 -accel tcg,thread=single -nographic "
+ "-blockdev node-name=pib_spic2,driver=file,"
+ "filename=%s -device 25csm04,bus=pnv-spi-bus.2,cs=0,"
+ "drive=pib_spic2", tmp_path);
+ spi_seeprom_transaction(qts, chip);
+ qtest_quit(qts);
+ unlink(tmp_path);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+ char *tname = g_strdup_printf("pnv-xscom/spi-seeprom/%s",
+ pnv_chips[3].cpu_model);
+ qtest_add_data_func(tname, &pnv_chips[3], test_spi_seeprom);
+ g_free(tname);
+ return g_test_run();
+}
diff --git a/tests/qtest/pnv-xscom.h b/tests/qtest/pnv-xscom.h
index 6f62941..5aa1701 100644
--- a/tests/qtest/pnv-xscom.h
+++ b/tests/qtest/pnv-xscom.h
@@ -56,7 +56,7 @@ static const PnvChip pnv_chips[] = {
.chip_type = PNV_CHIP_POWER10,
.cpu_model = "POWER10",
.xscom_base = 0x000603fc00000000ull,
- .cfam_id = 0x120da04900008000ull,
+ .cfam_id = 0x220da04980000000ull,
.first_core = 0x0,
.num_i2c = 4,
},
diff --git a/tests/qtest/rtl8139-test.c b/tests/qtest/rtl8139-test.c
index eedf90f..55f671f 100644
--- a/tests/qtest/rtl8139-test.c
+++ b/tests/qtest/rtl8139-test.c
@@ -65,7 +65,7 @@ PORT(IntrMask, w, 0x3c)
PORT(IntrStatus, w, 0x3E)
PORT(TimerInt, l, 0x54)
-#define fatal(...) do { g_test_message(__VA_ARGS__); g_assert(0); } while (0)
+#define fatal(...) do { g_test_message(__VA_ARGS__); g_assert_not_reached(); } while (0)
static void test_timer(void)
{
diff --git a/tests/qtest/stm32l4x5.h b/tests/qtest/stm32l4x5.h
new file mode 100644
index 0000000..2d21cc6
--- /dev/null
+++ b/tests/qtest/stm32l4x5.h
@@ -0,0 +1,42 @@
+/*
+ * QTest testcase header for STM32L4X5 :
+ * used for consolidating common objects in stm32l4x5_*-test.c
+ *
+ * Copyright (c) 2024 Arnaud Minier <arnaud.minier@telecom-paris.fr>
+ * Copyright (c) 2024 InĆØs Varhol <ines.varhol@telecom-paris.fr>
+ *
+ * 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 "libqtest.h"
+
+/* copied from clock.h */
+#define CLOCK_PERIOD_1SEC (1000000000llu << 32)
+#define CLOCK_PERIOD_FROM_HZ(hz) (((hz) != 0) ? CLOCK_PERIOD_1SEC / (hz) : 0u)
+/*
+ * MSI (4 MHz) is used as system clock source after startup
+ * from Reset.
+ * AHB, APB1 and APB2 prescalers are set to 1 at reset.
+ */
+#define SYSCLK_PERIOD CLOCK_PERIOD_FROM_HZ(4000000)
+#define RCC_AHB2ENR 0x4002104C
+#define RCC_APB1ENR1 0x40021058
+#define RCC_APB1ENR2 0x4002105C
+#define RCC_APB2ENR 0x40021060
+
+
+static inline uint64_t get_clock_period(QTestState *qts, const char *path)
+{
+ uint64_t clock_period = 0;
+ QDict *r;
+
+ r = qtest_qmp(qts, "{ 'execute': 'qom-get', 'arguments':"
+ " { 'path': %s, 'property': 'qtest-clock-period'} }", path);
+ g_assert_false(qdict_haskey(r, "error"));
+ clock_period = qdict_get_int(r, "return");
+ qobject_unref(r);
+ return clock_period;
+}
+
+
diff --git a/tests/qtest/stm32l4x5_gpio-test.c b/tests/qtest/stm32l4x5_gpio-test.c
index 72a7823..c0686c7 100644
--- a/tests/qtest/stm32l4x5_gpio-test.c
+++ b/tests/qtest/stm32l4x5_gpio-test.c
@@ -10,6 +10,7 @@
#include "qemu/osdep.h"
#include "libqtest-single.h"
+#include "stm32l4x5.h"
#define GPIO_BASE_ADDR 0x48000000
#define GPIO_SIZE 0x400
@@ -505,6 +506,26 @@ static void test_bsrr_brr(const void *data)
gpio_writel(gpio, ODR, reset(gpio, ODR));
}
+static void test_clock_enable(void)
+{
+ /*
+ * For each GPIO, enable its clock in RCC
+ * and check that its clock period changes to SYSCLK_PERIOD
+ */
+ unsigned int gpio_id;
+
+ for (uint32_t gpio = GPIO_A; gpio <= GPIO_H; gpio += GPIO_B - GPIO_A) {
+ gpio_id = get_gpio_id(gpio);
+ g_autofree char *path = g_strdup_printf("/machine/soc/gpio%c/clk",
+ gpio_id + 'a');
+ g_assert_cmpuint(get_clock_period(global_qtest, path), ==, 0);
+ /* Enable the gpio clock */
+ writel(RCC_AHB2ENR, readl(RCC_AHB2ENR) | (0x1 << gpio_id));
+ g_assert_cmpuint(get_clock_period(global_qtest, path), ==,
+ SYSCLK_PERIOD);
+ }
+}
+
int main(int argc, char **argv)
{
int ret;
@@ -556,6 +577,8 @@ int main(int argc, char **argv)
qtest_add_data_func("stm32l4x5/gpio/test_bsrr_brr2",
test_data(GPIO_D, 0),
test_bsrr_brr);
+ qtest_add_func("stm32l4x5/gpio/test_clock_enable",
+ test_clock_enable);
qtest_start("-machine b-l475e-iot01a");
ret = g_test_run();
diff --git a/tests/qtest/stm32l4x5_syscfg-test.c b/tests/qtest/stm32l4x5_syscfg-test.c
index 258417c..d5c71e2 100644
--- a/tests/qtest/stm32l4x5_syscfg-test.c
+++ b/tests/qtest/stm32l4x5_syscfg-test.c
@@ -10,6 +10,7 @@
#include "qemu/osdep.h"
#include "libqtest-single.h"
+#include "stm32l4x5.h"
#define SYSCFG_BASE_ADDR 0x40010000
#define SYSCFG_MEMRMP 0x00
@@ -26,7 +27,9 @@
#define INVALID_ADDR 0x2C
/* SoC forwards GPIOs to SysCfg */
-#define SYSCFG "/machine/soc"
+#define SOC "/machine/soc"
+#define SYSCFG "/machine/soc/syscfg"
+#define SYSCFG_CLK "/machine/soc/syscfg/clk"
#define EXTI "/machine/soc/exti"
static void syscfg_writel(unsigned int offset, uint32_t value)
@@ -41,7 +44,7 @@ static uint32_t syscfg_readl(unsigned int offset)
static void syscfg_set_irq(int num, int level)
{
- qtest_set_irq_in(global_qtest, SYSCFG, NULL, num, level);
+ qtest_set_irq_in(global_qtest, SOC, NULL, num, level);
}
static void system_reset(void)
@@ -301,6 +304,17 @@ static void test_irq_gpio_multiplexer(void)
syscfg_writel(SYSCFG_EXTICR1, 0x00000000);
}
+static void test_clock_enable(void)
+{
+ g_assert_cmpuint(get_clock_period(global_qtest, SYSCFG_CLK), ==, 0);
+
+ /* Enable SYSCFG clock */
+ writel(RCC_APB2ENR, readl(RCC_APB2ENR) | (0x1 << 0));
+
+ g_assert_cmpuint(get_clock_period(global_qtest, SYSCFG_CLK), ==,
+ SYSCLK_PERIOD);
+}
+
int main(int argc, char **argv)
{
int ret;
@@ -325,6 +339,8 @@ int main(int argc, char **argv)
test_irq_pin_multiplexer);
qtest_add_func("stm32l4x5/syscfg/test_irq_gpio_multiplexer",
test_irq_gpio_multiplexer);
+ qtest_add_func("stm32l4x5/syscfg/test_clock_enable",
+ test_clock_enable);
qtest_start("-machine b-l475e-iot01a");
ret = g_test_run();
diff --git a/tests/qtest/stm32l4x5_usart-test.c b/tests/qtest/stm32l4x5_usart-test.c
index 8902518..927bab6 100644
--- a/tests/qtest/stm32l4x5_usart-test.c
+++ b/tests/qtest/stm32l4x5_usart-test.c
@@ -12,6 +12,7 @@
#include "libqtest.h"
#include "hw/misc/stm32l4x5_rcc_internals.h"
#include "hw/registerfields.h"
+#include "stm32l4x5.h"
#define RCC_BASE_ADDR 0x40021000
/* Use USART 1 ADDR, assume the others work the same */
@@ -36,6 +37,8 @@ REG32(GTPR, 0x10)
REG32(RTOR, 0x14)
REG32(RQR, 0x18)
REG32(ISR, 0x1C)
+ FIELD(ISR, REACK, 22, 1)
+ FIELD(ISR, TEACK, 21, 1)
FIELD(ISR, TXE, 7, 1)
FIELD(ISR, RXNE, 5, 1)
FIELD(ISR, ORE, 3, 1)
@@ -191,7 +194,7 @@ static void init_uart(QTestState *qts)
/* Enable the transmitter, the receiver and the USART. */
qtest_writel(qts, (USART1_BASE_ADDR + A_CR1),
- R_CR1_UE_MASK | R_CR1_RE_MASK | R_CR1_TE_MASK);
+ cr1 | R_CR1_UE_MASK | R_CR1_RE_MASK | R_CR1_TE_MASK);
}
static void test_write_read(void)
@@ -202,6 +205,8 @@ static void test_write_read(void)
qtest_writel(qts, USART1_BASE_ADDR + A_TDR, 0xFFFFFFFF);
const uint32_t tdr = qtest_readl(qts, USART1_BASE_ADDR + A_TDR);
g_assert_cmpuint(tdr, ==, 0x000001FF);
+
+ qtest_quit(qts);
}
static void test_receive_char(void)
@@ -296,6 +301,63 @@ static void test_send_str(void)
qtest_quit(qts);
}
+static void test_ack(void)
+{
+ uint32_t cr1;
+ uint32_t isr;
+ QTestState *qts = qtest_init("-M b-l475e-iot01a");
+
+ init_uart(qts);
+
+ cr1 = qtest_readl(qts, (USART1_BASE_ADDR + A_CR1));
+
+ /* Disable the transmitter and receiver. */
+ qtest_writel(qts, (USART1_BASE_ADDR + A_CR1),
+ cr1 & ~(R_CR1_RE_MASK | R_CR1_TE_MASK));
+
+ /* Test ISR ACK for transmitter and receiver disabled */
+ isr = qtest_readl(qts, (USART1_BASE_ADDR + A_ISR));
+ g_assert_false(isr & R_ISR_TEACK_MASK);
+ g_assert_false(isr & R_ISR_REACK_MASK);
+
+ /* Enable the transmitter and receiver. */
+ qtest_writel(qts, (USART1_BASE_ADDR + A_CR1),
+ cr1 | (R_CR1_RE_MASK | R_CR1_TE_MASK));
+
+ /* Test ISR ACK for transmitter and receiver disabled */
+ isr = qtest_readl(qts, (USART1_BASE_ADDR + A_ISR));
+ g_assert_true(isr & R_ISR_TEACK_MASK);
+ g_assert_true(isr & R_ISR_REACK_MASK);
+
+ qtest_quit(qts);
+}
+
+static void check_clock(QTestState *qts, const char *path, uint32_t rcc_reg,
+ uint32_t reg_offset)
+{
+ g_assert_cmpuint(get_clock_period(qts, path), ==, 0);
+ qtest_writel(qts, rcc_reg, qtest_readl(qts, rcc_reg) | (0x1 << reg_offset));
+ g_assert_cmpuint(get_clock_period(qts, path), ==, SYSCLK_PERIOD);
+}
+
+static void test_clock_enable(void)
+{
+ /*
+ * For each USART device, enable its clock in RCC
+ * and check that its clock frequency is SYSCLK_PERIOD
+ */
+ QTestState *qts = qtest_init("-M b-l475e-iot01a");
+
+ check_clock(qts, "machine/soc/usart[0]/clk", RCC_APB2ENR, 14);
+ check_clock(qts, "machine/soc/usart[1]/clk", RCC_APB1ENR1, 17);
+ check_clock(qts, "machine/soc/usart[2]/clk", RCC_APB1ENR1, 18);
+ check_clock(qts, "machine/soc/uart[0]/clk", RCC_APB1ENR1, 19);
+ check_clock(qts, "machine/soc/uart[1]/clk", RCC_APB1ENR1, 20);
+ check_clock(qts, "machine/soc/lpuart1/clk", RCC_APB1ENR2, 0);
+
+ qtest_quit(qts);
+}
+
int main(int argc, char **argv)
{
int ret;
@@ -308,6 +370,8 @@ int main(int argc, char **argv)
qtest_add_func("stm32l4x5/usart/send_char", test_send_char);
qtest_add_func("stm32l4x5/usart/receive_str", test_receive_str);
qtest_add_func("stm32l4x5/usart/send_str", test_send_str);
+ qtest_add_func("stm32l4x5/usart/ack", test_ack);
+ qtest_add_func("stm32l4x5/usart/clock_enable", test_clock_enable);
ret = g_test_run();
return ret;
diff --git a/tests/qtest/tmp105-test.c b/tests/qtest/tmp105-test.c
index 3678646..85ad4ee 100644
--- a/tests/qtest/tmp105-test.c
+++ b/tests/qtest/tmp105-test.c
@@ -100,9 +100,9 @@ static void send_and_receive(void *obj, void *data, QGuestAllocator *alloc)
g_assert_cmphex(value, ==, 0x14f0);
i2c_set16(i2cdev, TMP105_REG_T_LOW, 0x1234);
- g_assert_cmphex(i2c_get16(i2cdev, TMP105_REG_T_LOW), ==, 0x1234);
+ g_assert_cmphex(i2c_get16(i2cdev, TMP105_REG_T_LOW), ==, 0x1230);
i2c_set16(i2cdev, TMP105_REG_T_HIGH, 0x4231);
- g_assert_cmphex(i2c_get16(i2cdev, TMP105_REG_T_HIGH), ==, 0x4231);
+ g_assert_cmphex(i2c_get16(i2cdev, TMP105_REG_T_HIGH), ==, 0x4230);
}
static void tmp105_register_nodes(void)
diff --git a/tests/qtest/tpm-tests.c b/tests/qtest/tpm-tests.c
index fb94496..197714f 100644
--- a/tests/qtest/tpm-tests.c
+++ b/tests/qtest/tpm-tests.c
@@ -114,7 +114,7 @@ void tpm_test_swtpm_migration_test(const char *src_tpm_path,
sizeof(tpm_pcrread_resp));
tpm_util_migrate(src_qemu, uri);
- tpm_util_wait_for_migration_complete(src_qemu);
+ tpm_util_wait_for_migration_complete(dst_qemu);
tpm_util_pcrread(dst_qemu, tx, tpm_pcrread_resp,
sizeof(tpm_pcrread_resp));
diff --git a/tests/qtest/ufs-test.c b/tests/qtest/ufs-test.c
index 82ec3f0..60199ab 100644
--- a/tests/qtest/ufs-test.c
+++ b/tests/qtest/ufs-test.c
@@ -119,6 +119,7 @@ static void ufs_send_nop_out(QUfs *ufs, uint8_t slot,
static void ufs_send_query(QUfs *ufs, uint8_t slot, uint8_t query_function,
uint8_t query_opcode, uint8_t idn, uint8_t index,
+ uint8_t selector, uint32_t attr_value,
UtpTransferReqDesc *utrd_out, UtpUpiuRsp *rsp_out)
{
/* Build up utp transfer request descriptor */
@@ -136,13 +137,16 @@ static void ufs_send_query(QUfs *ufs, uint8_t slot, uint8_t query_function,
req_upiu.header.query_func = query_function;
req_upiu.header.task_tag = slot;
/*
- * QEMU UFS does not currently support Write descriptor and Write attribute,
+ * QEMU UFS does not currently support Write descriptor,
* so the value of data_segment_length is always 0.
*/
req_upiu.header.data_segment_length = 0;
req_upiu.qr.opcode = query_opcode;
req_upiu.qr.idn = idn;
req_upiu.qr.index = index;
+ req_upiu.qr.selector = selector;
+ req_upiu.qr.value = attr_value;
+ req_upiu.qr.length = UFS_QUERY_DESC_MAX_SIZE;
qtest_memwrite(ufs->dev.bus->qts, req_upiu_addr, &req_upiu,
sizeof(req_upiu));
@@ -344,7 +348,7 @@ static void ufs_init(QUfs *ufs, QGuestAllocator *alloc)
/* Set fDeviceInit flag via query request */
ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
UFS_UPIU_QUERY_OPCODE_SET_FLAG,
- UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, &utrd, &rsp_upiu);
+ UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, 0, 0, &utrd, &rsp_upiu);
g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
/* Wait for device to reset */
@@ -353,7 +357,8 @@ static void ufs_init(QUfs *ufs, QGuestAllocator *alloc)
qtest_clock_step(ufs->dev.bus->qts, 100);
ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
UFS_UPIU_QUERY_OPCODE_READ_FLAG,
- UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, &utrd, &rsp_upiu);
+ UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, 0, 0, &utrd,
+ &rsp_upiu);
} while (be32_to_cpu(rsp_upiu.qr.value) != 0 &&
g_get_monotonic_time() < end_time);
g_assert_cmpuint(be32_to_cpu(rsp_upiu.qr.value), ==, 0);
@@ -534,6 +539,373 @@ static void ufstest_read_write(void *obj, void *data, QGuestAllocator *alloc)
ufs_exit(ufs, alloc);
}
+static void ufstest_query_flag_request(void *obj, void *data,
+ QGuestAllocator *alloc)
+{
+ QUfs *ufs = obj;
+
+ UtpTransferReqDesc utrd;
+ UtpUpiuRsp rsp_upiu;
+ ufs_init(ufs, alloc);
+
+ /* Read read-only flag */
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_FLAG,
+ UFS_QUERY_FLAG_IDN_FDEVICEINIT, 0, 0, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.opcode, ==, UFS_UPIU_QUERY_OPCODE_READ_FLAG);
+ g_assert_cmpuint(rsp_upiu.qr.idn, ==, UFS_QUERY_FLAG_IDN_FDEVICEINIT);
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0));
+
+ /* Flag Set, Clear, Toggle Test with fDeviceLifeSpanModeEn */
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_FLAG,
+ UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, &utrd,
+ &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0));
+
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_SET_FLAG,
+ UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, &utrd,
+ &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(1));
+
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_CLEAR_FLAG,
+ UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, &utrd,
+ &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0));
+
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_TOGGLE_FLAG,
+ UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, &utrd,
+ &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(1));
+
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_TOGGLE_FLAG,
+ UFS_QUERY_FLAG_IDN_LIFE_SPAN_MODE_ENABLE, 0, 0, 0, &utrd,
+ &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, be32_to_cpu(0));
+
+ /* Read Write-only Flag (Intended Failure) */
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_FLAG,
+ UFS_QUERY_FLAG_IDN_PURGE_ENABLE, 0, 0, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
+ UFS_OCS_INVALID_CMD_TABLE_ATTR);
+ g_assert_cmpuint(rsp_upiu.header.response, ==,
+ UFS_QUERY_RESULT_NOT_READABLE);
+
+ /* Write Read-Only Flag (Intended Failure) */
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_SET_FLAG, UFS_QUERY_FLAG_IDN_BUSY_RTC,
+ 0, 0, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
+ UFS_OCS_INVALID_CMD_TABLE_ATTR);
+ g_assert_cmpuint(rsp_upiu.header.response, ==,
+ UFS_QUERY_RESULT_NOT_WRITEABLE);
+
+ ufs_exit(ufs, alloc);
+}
+
+static void ufstest_query_attr_request(void *obj, void *data,
+ QGuestAllocator *alloc)
+{
+ QUfs *ufs = obj;
+
+ UtpTransferReqDesc utrd;
+ UtpUpiuRsp rsp_upiu;
+ ufs_init(ufs, alloc);
+
+ /* Read Readable Attributes*/
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
+ UFS_QUERY_ATTR_IDN_BOOT_LU_EN, 0, 0, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.opcode, ==, UFS_UPIU_QUERY_OPCODE_READ_ATTR);
+ g_assert_cmpuint(rsp_upiu.qr.idn, ==, UFS_QUERY_ATTR_IDN_BOOT_LU_EN);
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
+
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
+ UFS_QUERY_ATTR_IDN_BKOPS_STATUS, 0, 0, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
+
+ /* Write Writable Attributes & Read Again */
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
+ UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0x03, &utrd,
+ &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x03));
+
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
+ UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0x07, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x07));
+
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
+ UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &utrd,
+ &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x03));
+
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
+ UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x07));
+
+ /* Write Invalid Value (Intended Error) */
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
+ UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0x10, &utrd,
+ &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
+ UFS_OCS_INVALID_CMD_TABLE_ATTR);
+ g_assert_cmpuint(rsp_upiu.header.response, ==,
+ UFS_QUERY_RESULT_INVALID_VALUE);
+
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
+ UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &utrd,
+ &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x03));
+
+ /* Read Write-Only Attribute (Intended Error) */
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
+ UFS_QUERY_ATTR_IDN_SECONDS_PASSED, 0, 0, 0, &utrd,
+ &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
+ UFS_OCS_INVALID_CMD_TABLE_ATTR);
+ g_assert_cmpuint(rsp_upiu.header.response, ==,
+ UFS_QUERY_RESULT_NOT_READABLE);
+
+ /* Write Read-Only Attribute (Intended Error) */
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
+ UFS_QUERY_ATTR_IDN_POWER_MODE, 0, 0, 0x01, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
+ UFS_OCS_INVALID_CMD_TABLE_ATTR);
+ g_assert_cmpuint(rsp_upiu.header.response, ==,
+ UFS_QUERY_RESULT_NOT_WRITEABLE);
+
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
+ UFS_QUERY_ATTR_IDN_POWER_MODE, 0, 0, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
+
+ /* Reset Written Attributes */
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
+ UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &utrd,
+ &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
+
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_WRITE_ATTR,
+ UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
+
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
+ UFS_QUERY_ATTR_IDN_ACTIVE_ICC_LVL, 0, 0, 0, &utrd,
+ &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
+
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_ATTR,
+ UFS_QUERY_ATTR_IDN_EE_CONTROL, 0, 0, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.value, ==, cpu_to_be32(0x00));
+
+ ufs_exit(ufs, alloc);
+}
+
+static void ufstest_query_desc_request(void *obj, void *data,
+ QGuestAllocator *alloc)
+{
+ QUfs *ufs = obj;
+
+ UtpTransferReqDesc utrd;
+ UtpUpiuRsp rsp_upiu;
+ ufs_init(ufs, alloc);
+
+ /* Write Descriptor is not supported yet */
+
+ /* Read Device Descriptor */
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_DEVICE,
+ 0, 0, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.opcode, ==, UFS_UPIU_QUERY_OPCODE_READ_DESC);
+ g_assert_cmpuint(rsp_upiu.qr.idn, ==, UFS_QUERY_DESC_IDN_DEVICE);
+ g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(DeviceDescriptor));
+ g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_DEVICE);
+
+ /* Read Configuration Descriptor is not supported yet*/
+
+ /* Read Unit Descriptor */
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_UNIT, 0,
+ 0, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(UnitDescriptor));
+ g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_UNIT);
+ g_assert_cmpuint(rsp_upiu.qr.data[2], ==, 0);
+
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_UNIT, 1,
+ 0, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(UnitDescriptor));
+ g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_UNIT);
+ g_assert_cmpuint(rsp_upiu.qr.data[2], ==, 1);
+
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_UNIT,
+ UFS_UPIU_RPMB_WLUN, 0, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(RpmbUnitDescriptor));
+ g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_UNIT);
+ g_assert_cmpuint(rsp_upiu.qr.data[2], ==, UFS_UPIU_RPMB_WLUN);
+
+ /* Read Interconnect Descriptor */
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC,
+ UFS_QUERY_DESC_IDN_INTERCONNECT, 0, 0, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(InterconnectDescriptor));
+ g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_INTERCONNECT);
+
+ /* Read String Descriptor */
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_STRING,
+ 0, 0, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 0x12);
+ g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_STRING);
+
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_STRING,
+ 1, 0, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 0x22);
+ g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_STRING);
+
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_STRING,
+ 4, 0, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.data[0], ==, 0x0a);
+ g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_STRING);
+
+ /* Read Geometry Descriptor */
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_GEOMETRY,
+ 0, 0, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(GeometryDescriptor));
+ g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_GEOMETRY);
+
+ /* Read Power Descriptor */
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_POWER, 0,
+ 0, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.data[0], ==,
+ sizeof(PowerParametersDescriptor));
+ g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_POWER);
+
+ /* Read Health Descriptor */
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_HEALTH,
+ 0, 0, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==, UFS_OCS_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.header.response, ==, UFS_COMMAND_RESULT_SUCCESS);
+ g_assert_cmpuint(rsp_upiu.qr.data[0], ==, sizeof(DeviceHealthDescriptor));
+ g_assert_cmpuint(rsp_upiu.qr.data[1], ==, UFS_QUERY_DESC_IDN_HEALTH);
+
+ /* Invalid Index (Intended Failure) */
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_UNIT, 4,
+ 0, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
+ UFS_OCS_INVALID_CMD_TABLE_ATTR);
+ g_assert_cmpuint(rsp_upiu.header.response, ==,
+ UFS_QUERY_RESULT_INVALID_INDEX);
+
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_STRING,
+ 5, 0, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
+ UFS_OCS_INVALID_CMD_TABLE_ATTR);
+ g_assert_cmpuint(rsp_upiu.header.response, ==,
+ UFS_QUERY_RESULT_INVALID_INDEX);
+
+ /* Invalid Selector (Intended Failure) */
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_DEVICE,
+ 0, 1, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
+ UFS_OCS_INVALID_CMD_TABLE_ATTR);
+ g_assert_cmpuint(rsp_upiu.header.response, ==,
+ UFS_QUERY_RESULT_INVALID_SELECTOR);
+
+ ufs_send_query(ufs, 0, UFS_UPIU_QUERY_FUNC_STANDARD_READ_REQUEST,
+ UFS_UPIU_QUERY_OPCODE_READ_DESC, UFS_QUERY_DESC_IDN_STRING,
+ 0, 1, 0, &utrd, &rsp_upiu);
+ g_assert_cmpuint(le32_to_cpu(utrd.header.dword_2), ==,
+ UFS_OCS_INVALID_CMD_TABLE_ATTR);
+ g_assert_cmpuint(rsp_upiu.header.response, ==,
+ UFS_QUERY_RESULT_INVALID_SELECTOR);
+
+ ufs_exit(ufs, alloc);
+}
+
static void drive_destroy(void *path)
{
unlink(path);
@@ -601,6 +973,12 @@ static void ufs_register_nodes(void)
}
qos_add_test("init", "ufs", ufstest_init, NULL);
qos_add_test("read-write", "ufs", ufstest_read_write, &io_test_opts);
+ qos_add_test("flag read-write", "ufs",
+ ufstest_query_flag_request, &io_test_opts);
+ qos_add_test("attr read-write", "ufs",
+ ufstest_query_attr_request, &io_test_opts);
+ qos_add_test("desc read-write", "ufs",
+ ufstest_query_desc_request, &io_test_opts);
}
libqos_init(ufs_register_nodes);
diff --git a/tests/qtest/vhost-user-test.c b/tests/qtest/vhost-user-test.c
index d607500..8948fb8 100644
--- a/tests/qtest/vhost-user-test.c
+++ b/tests/qtest/vhost-user-test.c
@@ -920,7 +920,7 @@ static void wait_for_rings_started(TestServer *s, size_t count)
static inline void test_server_connect(TestServer *server)
{
- test_server_create_chr(server, ",reconnect=1");
+ test_server_create_chr(server, ",reconnect-ms=1000");
}
static gboolean
diff --git a/tests/tcg/Makefile.target b/tests/tcg/Makefile.target
index cb8cfeb..9722145 100644
--- a/tests/tcg/Makefile.target
+++ b/tests/tcg/Makefile.target
@@ -90,6 +90,7 @@ CFLAGS=
LDFLAGS=
QEMU_OPTS=
+CHECK_PLUGIN_OUTPUT_COMMAND=
# If TCG debugging, or TCI is enabled things are a lot slower
@@ -102,9 +103,14 @@ ifeq ($(filter %-softmmu, $(TARGET)),)
# then the target. If there are common tests shared between
# sub-targets (e.g. ARM & AArch64) then it is up to
# $(TARGET_NAME)/Makefile.target to include the common parent
-# architecture in its VPATH.
+# architecture in its VPATH. However some targets are so minimal we
+# can't even build the multiarch tests.
+ifneq ($(filter $(TARGET_NAME),aarch64_be),)
+-include $(SRC_PATH)/tests/tcg/$(TARGET_NAME)/Makefile.target
+else
-include $(SRC_PATH)/tests/tcg/multiarch/Makefile.target
-include $(SRC_PATH)/tests/tcg/$(TARGET_NAME)/Makefile.target
+endif
# Add the common build options
CFLAGS+=-Wall -Werror -O0 -g -fno-strict-aliasing
@@ -115,7 +121,7 @@ endif
%: %.c
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
%: %.S
- $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -Wa,--noexecstack $< -o $@ $(LDFLAGS)
else
# For system targets we include a different Makefile fragment as the
# build options for bare programs are usually pretty different. They
@@ -142,8 +148,8 @@ RUN_TESTS=$(patsubst %,run-%, $(TESTS))
# If plugins exist also include those in the tests
ifeq ($(CONFIG_PLUGIN),y)
-PLUGIN_SRC=$(SRC_PATH)/tests/plugin
-PLUGIN_LIB=../../plugin
+PLUGIN_SRC=$(SRC_PATH)/tests/tcg/plugins
+PLUGIN_LIB=../plugins
VPATH+=$(PLUGIN_LIB)
PLUGINS=$(patsubst %.c, lib%.so, $(notdir $(wildcard $(PLUGIN_SRC)/*.c)))
@@ -152,10 +158,11 @@ PLUGINS=$(patsubst %.c, lib%.so, $(notdir $(wildcard $(PLUGIN_SRC)/*.c)))
# only expand MULTIARCH_TESTS which are common on most of our targets
# to avoid an exponential explosion as new tests are added. We also
# add some special helpers the run-plugin- rules can use below.
+# In more, extra tests can be added using ADDITIONAL_PLUGINS_TESTS variable.
ifneq ($(MULTIARCH_TESTS),)
$(foreach p,$(PLUGINS), \
- $(foreach t,$(MULTIARCH_TESTS),\
+ $(foreach t,$(MULTIARCH_TESTS) $(ADDITIONAL_PLUGINS_TESTS),\
$(eval run-plugin-$(t)-with-$(p): $t $p) \
$(eval RUN_TESTS+=run-plugin-$(t)-with-$(p))))
endif # MULTIARCH_TESTS
@@ -179,6 +186,10 @@ run-plugin-%:
-plugin $(PLUGIN_LIB)/$(call extract-plugin,$@)$(PLUGIN_ARGS) \
-d plugin -D $*.pout \
$(call strip-plugin,$<))
+ $(if $(CHECK_PLUGIN_OUTPUT_COMMAND), \
+ $(call quiet-command, $(CHECK_PLUGIN_OUTPUT_COMMAND) $*.pout, \
+ TEST, check plugin $(call extract-plugin,$@) output \
+ with $(call strip-plugin,$<)))
else
run-%: %
$(call run-test, $<, \
@@ -193,6 +204,10 @@ run-plugin-%:
-plugin $(PLUGIN_LIB)/$(call extract-plugin,$@)$(PLUGIN_ARGS) \
-d plugin -D $*.pout \
$(QEMU_OPTS) $(call strip-plugin,$<))
+ $(if $(CHECK_PLUGIN_OUTPUT_COMMAND), \
+ $(call quiet-command, $(CHECK_PLUGIN_OUTPUT_COMMAND) $*.pout, \
+ TEST, check plugin $(call extract-plugin,$@) output \
+ with $(call strip-plugin,$<)))
endif
gdb-%: %
diff --git a/tests/tcg/README b/tests/tcg/README
index 706bb18..6d08ca5 100644
--- a/tests/tcg/README
+++ b/tests/tcg/README
@@ -1,9 +1,14 @@
-This directory contains various interesting guest programs for
-regression testing. Tests are either multi-arch, meaning they can be
-built for all guest architectures that support linux-user executable,
-or they are architecture specific.
-
-CRIS
-====
-The testsuite for CRIS is in tests/tcg/cris. You can run it
-with "make test-cris".
+This directory contains various interesting guest binaries for
+regression testing the Tiny Code Generator doing system and user-mode
+emulation.
+
+The multiarch directory contains shared code for tests that can be
+built for all guest architectures. Architecture specific code can be
+found in their respective directories.
+
+System mode tests will be under the "system" subdirectories.
+
+GDB scripts for exercising the gdbstub on specific tests will be found
+under the "gdbstb" subdirectories.
+
+See the developer guide for more instructions on "make check-tcg"
diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/Makefile.softmmu-target
index dd6d595..d08d9b0 100644
--- a/tests/tcg/aarch64/Makefile.softmmu-target
+++ b/tests/tcg/aarch64/Makefile.softmmu-target
@@ -2,14 +2,22 @@
# Aarch64 system tests
#
-AARCH64_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/aarch64/system
+AARCH64_SRC=$(SRC_PATH)/tests/tcg/aarch64
+AARCH64_SYSTEM_SRC=$(AARCH64_SRC)/system
+
VPATH+=$(AARCH64_SYSTEM_SRC)
# These objects provide the basic boot code and helper functions for all tests
CRT_OBJS=boot.o
-AARCH64_TEST_SRCS=$(wildcard $(AARCH64_SYSTEM_SRC)/*.c)
-AARCH64_TESTS = $(patsubst $(AARCH64_SYSTEM_SRC)/%.c, %, $(AARCH64_TEST_SRCS))
+AARCH64_TEST_C_SRCS=$(wildcard $(AARCH64_SYSTEM_SRC)/*.c)
+AARCH64_TEST_S_SRCS=$(AARCH64_SYSTEM_SRC)/mte.S
+
+AARCH64_C_TESTS = $(patsubst $(AARCH64_SYSTEM_SRC)/%.c, %, $(AARCH64_TEST_C_SRCS))
+AARCH64_S_TESTS = $(patsubst $(AARCH64_SYSTEM_SRC)/%.S, %, $(AARCH64_TEST_S_SRCS))
+
+AARCH64_TESTS = $(AARCH64_C_TESTS)
+AARCH64_TESTS += $(AARCH64_S_TESTS)
CRT_PATH=$(AARCH64_SYSTEM_SRC)
LINK_SCRIPT=$(AARCH64_SYSTEM_SRC)/kernel.ld
@@ -21,14 +29,15 @@ LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
config-cc.mak: Makefile
$(quiet-@)( \
- $(call cc-option,-march=armv8.3-a, CROSS_CC_HAS_ARMV8_3)) 3> config-cc.mak
+ $(call cc-option,-march=armv8.3-a, CROSS_CC_HAS_ARMV8_3); \
+ $(call cc-option,-march=armv8.5-a+memtag, CROSS_CC_HAS_ARMV8_MTE)) 3> config-cc.mak
-include config-cc.mak
# building head blobs
.PRECIOUS: $(CRT_OBJS)
%.o: $(CRT_PATH)/%.S
- $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -x assembler-with-cpp -c $< -o $@
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -x assembler-with-cpp -Wa,--noexecstack -c $< -o $@
# Build and link the tests
%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
@@ -88,3 +97,35 @@ pauth-3:
run-pauth-3:
$(call skip-test, "RUN of pauth-3", "not built")
endif
+
+ifneq ($(CROSS_CC_HAS_ARMV8_MTE),)
+QEMU_MTE_ENABLED_MACHINE=-M virt,mte=on -cpu max -display none
+QEMU_OPTS_WITH_MTE_ON = $(QEMU_MTE_ENABLED_MACHINE) $(QEMU_BASE_ARGS) -kernel
+mte: CFLAGS+=-march=armv8.5-a+memtag
+mte: mte.S $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
+
+run-mte: QEMU_OPTS=$(QEMU_OPTS_WITH_MTE_ON)
+run-mte: mte
+
+ifeq ($(GDB_SUPPORTS_MTE_IN_BAREMETAL),y)
+run-gdbstub-mte: QEMU_OPTS=$(QEMU_OPTS_WITH_MTE_ON)
+run-gdbstub-mte: mte
+ $(call run-test, $@, $(GDB_SCRIPT) \
+ --output run-gdbstub-mte.out \
+ --gdb $(GDB) \
+ --qemu $(QEMU) --qargs "-chardev null$(COMMA)id=output $(QEMU_OPTS)" \
+ --bin $< --test $(AARCH64_SRC)/gdbstub/test-mte.py -- --mode=system, \
+ gdbstub MTE support)
+
+EXTRA_RUNS += run-gdbstub-mte
+else # !GDB_SUPPORTS_MTE_IN_BAREMETAL
+run-gdbstub-mte:
+ $(call skip-test "RUN of gdbstub-mte", "GDB does not support MTE in baremetal!")
+endif
+else # !CROSS_CC_HAS_ARMV8_MTE
+mte:
+ $(call skip-test, "BUILD of $@", "missing compiler support")
+run-mte:
+ $(call skip-test, "RUN of mte", "not build")
+endif
diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
index 8cc62eb..9efe2f8 100644
--- a/tests/tcg/aarch64/Makefile.target
+++ b/tests/tcg/aarch64/Makefile.target
@@ -138,7 +138,8 @@ run-gdbstub-mte: mte-8
$(call run-test, $@, $(GDB_SCRIPT) \
--gdb $(GDB) \
--qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
- --bin $< --test $(AARCH64_SRC)/gdbstub/test-mte.py, \
+ --bin $< --test $(AARCH64_SRC)/gdbstub/test-mte.py \
+ -- --mode=user, \
gdbstub MTE support)
EXTRA_RUNS += run-gdbstub-mte
diff --git a/tests/tcg/aarch64/gdbstub/test-mte.py b/tests/tcg/aarch64/gdbstub/test-mte.py
index 2db0663..9ad98e7 100644
--- a/tests/tcg/aarch64/gdbstub/test-mte.py
+++ b/tests/tcg/aarch64/gdbstub/test-mte.py
@@ -1,34 +1,59 @@
from __future__ import print_function
#
# Test GDB memory-tag commands that exercise the stubs for the qIsAddressTagged,
-# qMemTag, and QMemTag packets. Logical tag-only commands rely on local
-# operations, hence don't exercise any stub.
+# qMemTag, and QMemTag packets, which are used for manipulating allocation tags.
+# Logical tags-related commands rely on local operations, hence don't exercise
+# any stub and so are not used in this test.
#
-# The test consists in breaking just after a atag() call (which sets the
-# allocation tag -- see mte-8.c for details) and setting/getting tags in
-# different memory locations and ranges starting at the address of the array
-# 'a'.
+# The test consists in breaking just after a tag is set in a specific memory
+# chunk, and then using the GDB 'memory-tagging' subcommands to set/get tags in
+# different memory locations and ranges in the MTE-enabled memory chunk.
#
# This is launched via tests/guest-debug/run-test.py
#
-import gdb
+try:
+ import gdb
+except ModuleNotFoundError:
+ from sys import exit
+ exit("This script must be launched via tests/guest-debug/run-test.py!")
import re
-from test_gdbstub import main, report
+from sys import argv
+from test_gdbstub import arg_parser, main, report
-PATTERN_0 = "Memory tags for address 0x[0-9a-f]+ match \(0x[0-9a-f]+\)."
-PATTERN_1 = ".*(0x[0-9a-f]+)"
+PATTERN_0 = r"Memory tags for address 0x[0-9a-f]+ match \(0x[0-9a-f]+\)."
+PATTERN_1 = r".*(0x[0-9a-f]+)"
def run_test():
- gdb.execute("break 95", False, True)
+ p = arg_parser(prog="test-mte.py", description="TCG MTE tests.")
+ p.add_argument("--mode", help="Run test for QEMU system or user mode.",
+ required=True, choices=['system','user'])
+
+ args = p.parse_args(args=argv)
+
+ if args.mode == "system":
+ # Break address: where to break before performing the tests
+ # See mte.S for details about this label.
+ ba = "main_end"
+ # Tagged address: the start of the MTE-enabled memory chunk to be tested
+ # 'tagged_addr' (x1) is a pointer to the MTE-enabled page. See mte.S.
+ ta = "$x1"
+ else: # mode="user"
+ # Line 95 in mte-8.c
+ ba = "95"
+ # 'a' array. See mte-8.c
+ ta = "a"
+
+ gdb.execute(f"break {ba}", False, True)
gdb.execute("continue", False, True)
+
try:
- # Test if we can check correctly that the allocation tag for
- # array 'a' matches the logical tag after atag() is called.
- co = gdb.execute("memory-tag check a", False, True)
+ # Test if we can check correctly that the allocation tag for the address
+ # in {ta} matches the logical tag in {ta}.
+ co = gdb.execute(f"memory-tag check {ta}", False, True)
tags_match = re.findall(PATTERN_0, co, re.MULTILINE)
if tags_match:
report(True, f"{tags_match[0]}")
@@ -39,20 +64,20 @@ def run_test():
# tags rely on local operation and so don't exercise any stub.
# Set the allocation tag for the first granule (16 bytes) of
- # address starting at 'a' address to a known value, i.e. 0x04.
- gdb.execute("memory-tag set-allocation-tag a 1 04", False, True)
+ # address starting at {ta} address to a known value, i.e. 0x04.
+ gdb.execute(f"memory-tag set-allocation-tag {ta} 1 04", False, True)
# Then set the allocation tag for the second granule to a known
# value, i.e. 0x06. This tests that contiguous tag granules are
- # set correct and don't run over each other.
- gdb.execute("memory-tag set-allocation-tag a+16 1 06", False, True)
+ # set correctly and don't run over each other.
+ gdb.execute(f"memory-tag set-allocation-tag {ta}+16 1 06", False, True)
# Read the known values back and check if they remain the same.
- co = gdb.execute("memory-tag print-allocation-tag a", False, True)
+ co = gdb.execute(f"memory-tag print-allocation-tag {ta}", False, True)
first_tag = re.match(PATTERN_1, co)[1]
- co = gdb.execute("memory-tag print-allocation-tag a+16", False, True)
+ co = gdb.execute(f"memory-tag print-allocation-tag {ta}+16", False, True)
second_tag = re.match(PATTERN_1, co)[1]
if first_tag == "0x4" and second_tag == "0x6":
@@ -61,15 +86,15 @@ def run_test():
report(False, "Can't set/print allocation tags!")
# Now test fill pattern by setting a whole page with a pattern.
- gdb.execute("memory-tag set-allocation-tag a 4096 0a0b", False, True)
+ gdb.execute(f"memory-tag set-allocation-tag {ta} 4096 0a0b", False, True)
# And read back the tags of the last two granules in page so
# we also test if the pattern is set correctly up to the end of
# the page.
- co = gdb.execute("memory-tag print-allocation-tag a+4096-32", False, True)
+ co = gdb.execute(f"memory-tag print-allocation-tag {ta}+4096-32", False, True)
tag = re.match(PATTERN_1, co)[1]
- co = gdb.execute("memory-tag print-allocation-tag a+4096-16", False, True)
+ co = gdb.execute(f"memory-tag print-allocation-tag {ta}+4096-16", False, True)
last_tag = re.match(PATTERN_1, co)[1]
if tag == "0xa" and last_tag == "0xb":
@@ -78,8 +103,8 @@ def run_test():
report(False, "Fill pattern failed!")
except gdb.error:
- # This usually happens because a GDB version that does not
- # support memory tagging was used to run the test.
+ # This usually happens because a GDB version that does not support
+ # memory tagging was used to run the test.
report(False, "'memory-tag' command failed!")
diff --git a/tests/tcg/aarch64/system/boot.S b/tests/tcg/aarch64/system/boot.S
index 501685d..4eb1b35 100644
--- a/tests/tcg/aarch64/system/boot.S
+++ b/tests/tcg/aarch64/system/boot.S
@@ -135,6 +135,17 @@ __start:
orr x1, x1, x3
str x1, [x2] /* 2nd 2mb (.data & .bss)*/
+ /* Third block: at 'mte_page', set in kernel.ld */
+ adrp x1, mte_page
+ add x1, x1, :lo12:mte_page
+ bic x1, x1, #(1 << 21) - 1
+ and x4, x1, x5
+ add x2, x0, x4, lsr #(21 - 3)
+ /* attr(AF, NX, block, AttrIndx=Attr1) */
+ ldr x3, =(3 << 53) | 0x401 | (1 << 2)
+ orr x1, x1, x3
+ str x1, [x2]
+
/* Setup/enable the MMU. */
/*
diff --git a/tests/tcg/aarch64/system/kernel.ld b/tests/tcg/aarch64/system/kernel.ld
index 7b3a76d..aef043e 100644
--- a/tests/tcg/aarch64/system/kernel.ld
+++ b/tests/tcg/aarch64/system/kernel.ld
@@ -1,23 +1,32 @@
ENTRY(__start)
-SECTIONS
-{
- /* virt machine, RAM starts at 1gb */
- . = (1 << 30);
+MEMORY {
+ /* On virt machine RAM starts at 1 GiB. */
+
+ /* Align text and rodata to the 1st 2 MiB chunk. */
+ TXT (rx) : ORIGIN = 1 << 30, LENGTH = 2M
+ /* Align r/w data to the 2nd 2 MiB chunk. */
+ DAT (rw) : ORIGIN = (1 << 30) + 2M, LENGTH = 2M
+ /* Align the MTE-enabled page to the 3rd 2 MiB chunk. */
+ TAG (rw) : ORIGIN = (1 << 30) + 4M, LENGTH = 2M
+}
+
+SECTIONS {
.text : {
*(.text)
- }
- .rodata : {
*(.rodata)
- }
- /* align r/w section to next 2mb */
- . = ALIGN(1 << 21);
+ } >TXT
.data : {
*(.data)
- }
- .bss : {
*(.bss)
- }
+ } >DAT
+ .tag : {
+ /*
+ * Symbol 'mte_page' is used in boot.S to setup the PTE and in the mte.S
+ * test as the address that the MTE instructions operate on.
+ */
+ mte_page = .;
+ } >TAG
/DISCARD/ : {
*(.ARM.attributes)
}
diff --git a/tests/tcg/aarch64/system/mte.S b/tests/tcg/aarch64/system/mte.S
new file mode 100644
index 0000000..b611240
--- /dev/null
+++ b/tests/tcg/aarch64/system/mte.S
@@ -0,0 +1,109 @@
+/*
+ * Code to help test the MTE gdbstubs in system mode.
+ *
+ * Copyright (c) 2024 Linaro Limited
+ *
+ * Author: Gustavo Romero <gustavo.romero@linaro.org>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#define addr x0 /* Ptr to the start of the MTE-enabled page. */
+#define tagged_addr x1 /* 'addr' ptr with a random-generated tag added. */
+#define tmp0 x2 /* Scratch register. */
+#define tmp1 x3 /* Scratch register. */
+#define tmp2 x4 /* Scratch register. */
+#define tmp3 x5 /* Sctatch register. */
+
+ .file "mte.S"
+
+ .text
+ .align 4
+
+ .globl main
+ .type main, @function
+
+main:
+ /*
+ * Set MAIR_EL1 (Memory Attribute Index Register). In boot.S, the
+ * attribute index for .mte_page is set to point to MAILR_EL field Attr1
+ * (AttrIndx=Attr1), so set Attr1 as Tagged Normal (MTE) to enable MTE
+ * on this page.
+ *
+ * Attr1 = 0xF0 => Tagged Normal (MTE)
+ */
+ mrs tmp0, mair_el1
+ orr tmp0, tmp0, (0xF0 << 8)
+ msr mair_el1, tmp0
+
+ /*
+ * Set TCR_EL1 (Translation Control Registers) to ignore the top byte
+ * in the translated addresses so it can be used to keep the tags.
+ *
+ * TBI0[37] = 0b1 => Top Byte ignored and used for tagged addresses
+ */
+ mrs tmp1, tcr_el1
+ orr tmp1, tmp1, (1 << 37)
+ msr tcr_el1, tmp1
+
+ /*
+ * Set SCTLR_EL1 (System Control Register) to enable the use of MTE
+ * insns., like stg & friends, and to enable synchronous exception in
+ * case of a tag mismatch, i.e., when the logical tag in 'tagged_addr'
+ * is different from the allocation tag related to 'addr' address.
+ *
+ * ATA[43] = 0b1 => Enable access to allocation tags at EL1
+ * TCF[41:40] = 0b01 => Tag Check Faults cause a synchronous exception
+ *
+ */
+ mrs tmp2, sctlr_el1
+ mov tmp3, (1 << 43) | (1 << 40)
+ orr tmp2, tmp2, tmp3
+ msr sctlr_el1, tmp2
+
+ isb
+
+ /*
+ * MTE-enabled page resides at the 3rd 2MB chunk in the second 1GB
+ * block, i.e., at 0x40400000 address. See .mte_page section in boot.S
+ * and kernel.ld (where the address is effectively computed).
+ *
+ * Load .mte_page address into 'addr' register.
+ */
+ adrp addr, mte_page
+ add addr, addr, :lo12:mte_page
+
+ /*
+ * Set GCR for random tag generation. 0xA5 is just a random value to set
+ * GCR != 0 so the tag generated by 'irg' insn. is not zero, which is
+ * more interesting for the tests than when tag is zero.
+ */
+ mov tmp0, 0xA5
+ msr gcr_el1, tmp0
+
+ /*
+ * Generate a logical tag, add it to 'addr' address and put it into
+ * 'tagged_addr'.
+ */
+ irg tagged_addr, addr
+
+ /*
+ * Store the generated tag to memory region pointed to by 'addr', i.e.
+ * set the allocation tag for granule at 'addr'. The tag is extracted
+ * by stg from tagged_addr pointer.
+ */
+ stg tagged_addr, [addr]
+
+ /*
+ * Store a random value (0xdeadbeef) to tagged_addr address. This must
+ * not cause any Tag Check Fault since logical tag in tagged_addr and
+ * allocation tag associated with the memory pointed by tagged_addr are
+ * set the same, otherwise something is off and the test fails -- an
+ * exception is generated.
+ */
+ ldr tmp1, =0xdeadbeef
+ str tmp1, [tagged_addr]
+
+ /* This label is used by GDB Python script test-mte.py. */
+main_end:
+ ret
diff --git a/tests/tcg/aarch64_be/Makefile.target b/tests/tcg/aarch64_be/Makefile.target
new file mode 100644
index 0000000..cbe5fa0
--- /dev/null
+++ b/tests/tcg/aarch64_be/Makefile.target
@@ -0,0 +1,17 @@
+# -*- Mode: makefile -*-
+#
+# A super basic AArch64 BE makefile. As we don't have any big-endian
+# libc available the best we can do is a basic Hello World.
+
+AARCH64BE_SRC=$(SRC_PATH)/tests/tcg/aarch64_be
+VPATH += $(AARCH64BE_SRC)
+
+AARCH64BE_TEST_SRCS=$(notdir $(wildcard $(AARCH64BE_SRC)/*.c))
+AARCH64BE_TESTS=$(AARCH64BE_TEST_SRCS:.c=)
+#MULTIARCH_TESTS = $(MULTIARCH_SRCS:.c=)
+
+# We need to specify big-endian cflags
+CFLAGS +=-mbig-endian -ffreestanding
+LDFLAGS +=-nostdlib
+
+TESTS += $(AARCH64BE_TESTS)
diff --git a/tests/tcg/aarch64_be/hello.c b/tests/tcg/aarch64_be/hello.c
new file mode 100644
index 0000000..a9b2ab4
--- /dev/null
+++ b/tests/tcg/aarch64_be/hello.c
@@ -0,0 +1,35 @@
+/*
+ * Non-libc syscall hello world for Aarch64 BE
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#define __NR_write 64
+#define __NR_exit 93
+
+int write(int fd, char *buf, int len)
+{
+ register int x0 __asm__("x0") = fd;
+ register char *x1 __asm__("x1") = buf;
+ register int x2 __asm__("x2") = len;
+ register int x8 __asm__("x8") = __NR_write;
+
+ asm volatile("svc #0" : : "r"(x0), "r"(x1), "r"(x2), "r"(x8));
+
+ return len;
+}
+
+void exit(int ret)
+{
+ register int x0 __asm__("x0") = ret;
+ register int x8 __asm__("x8") = __NR_exit;
+
+ asm volatile("svc #0" : : "r"(x0), "r"(x8));
+ __builtin_unreachable();
+}
+
+void _start(void)
+{
+ write(1, "Hello World\n", 12);
+ exit(0);
+}
diff --git a/tests/tcg/alpha/Makefile.softmmu-target b/tests/tcg/alpha/Makefile.softmmu-target
index 09193a6..a944102 100644
--- a/tests/tcg/alpha/Makefile.softmmu-target
+++ b/tests/tcg/alpha/Makefile.softmmu-target
@@ -22,13 +22,13 @@ LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
.PRECIOUS: $(CRT_OBJS)
%.o: $(CRT_PATH)/%.S
- $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -x assembler-with-cpp -c $< -o $@
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -x assembler-with-cpp -Wa,--noexecstack -c $< -o $@
# Build and link the tests
%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
-memory: CFLAGS+=-DCHECK_UNALIGNED=0
+memory: CFLAGS+=-DCHECK_UNALIGNED=0 -mbwx
# Running
QEMU_OPTS+=-serial chardev:output -kernel
diff --git a/tests/tcg/alpha/Makefile.target b/tests/tcg/alpha/Makefile.target
index fdd7ddf..36d8ed1 100644
--- a/tests/tcg/alpha/Makefile.target
+++ b/tests/tcg/alpha/Makefile.target
@@ -12,4 +12,7 @@ test-cmov: EXTRA_CFLAGS=-DTEST_CMOV
test-cmov: test-cond.c
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
+# Force generation of byte read/write
+test-plugin-mem-access: CFLAGS+=-mbwx
+
run-test-cmov: test-cmov
diff --git a/tests/tcg/arm/Makefile.softmmu-target b/tests/tcg/arm/Makefile.softmmu-target
index 547063c..b66074b 100644
--- a/tests/tcg/arm/Makefile.softmmu-target
+++ b/tests/tcg/arm/Makefile.softmmu-target
@@ -36,7 +36,7 @@ LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
.PRECIOUS: $(CRT_OBJS)
%.o: $(ARM_SRC)/%.S
- $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -x assembler-with-cpp -c $< -o $@
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -x assembler-with-cpp -Wa,--noexecstack -c $< -o $@
# Build and link the tests
%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
diff --git a/tests/tcg/arm/Makefile.target b/tests/tcg/arm/Makefile.target
index 8e28719..06ddf3e 100644
--- a/tests/tcg/arm/Makefile.target
+++ b/tests/tcg/arm/Makefile.target
@@ -25,7 +25,7 @@ ARM_TESTS += test-arm-iwmmxt
# Clang assembler does not support IWMXT, so use the external assembler.
test-arm-iwmmxt: CFLAGS += -marm -march=iwmmxt -mabi=aapcs -mfpu=fpv4-sp-d16 $(CROSS_CC_HAS_FNIA)
test-arm-iwmmxt: test-arm-iwmmxt.S
- $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
+ $(CC) $(CFLAGS) -Wa,--noexecstack $< -o $@ $(LDFLAGS)
# Float-convert Tests
ARM_TESTS += fcvt
diff --git a/tests/tcg/cris/.gdbinit b/tests/tcg/cris/.gdbinit
deleted file mode 100644
index 5e8c1d3..0000000
--- a/tests/tcg/cris/.gdbinit
+++ /dev/null
@@ -1,11 +0,0 @@
-b main
-b _fail
-b exit
-display /i $pc
-display /x $srp
-display /x $r0
-display /x $r1
-display /x $r2
-display /x $r3
-display /x $r4
-display /t $ccs
diff --git a/tests/tcg/cris/Makefile.target b/tests/tcg/cris/Makefile.target
deleted file mode 100644
index 713e2a5..0000000
--- a/tests/tcg/cris/Makefile.target
+++ /dev/null
@@ -1,62 +0,0 @@
-# -*- Mode: makefile -*-
-#
-# Cris tests
-#
-# Currently we can only build the "bare" tests with the docker
-# supplied cross-compiler.
-#
-
-CRIS_SRC = $(SRC_PATH)/tests/tcg/cris/bare
-CRIS_ALL = $(wildcard $(CRIS_SRC)/*.s)
-CRIS_TESTS = $(patsubst $(CRIS_SRC)/%.s, %, $(CRIS_ALL))
-# Filter out common blobs and broken tests
-CRIS_BROKEN_TESTS = crt check_jsr
-# upstream GCC doesn't support v32
-CRIS_BROKEN_TESTS += check_mcp check_mulv32 check_addiv32 check_movpmv32
-CRIS_BROKEN_TESTS += check_movprv32 check_clearfv32 check_movemrv32 check_bas
-CRIS_BROKEN_TESTS += check_lapc check_movei
-# no sure why
-CRIS_BROKEN_TESTS += check_scc check_xarith
-
-CRIS_USABLE_TESTS = $(filter-out $(CRIS_BROKEN_TESTS), $(CRIS_TESTS))
-CRIS_RUNS = $(patsubst %, run-%, $(CRIS_USABLE_TESTS))
-
-# override the list of tests, as we can't build the multiarch tests
-TESTS = $(CRIS_USABLE_TESTS)
-EXTRA_RUNS =
-VPATH = $(CRIS_SRC)
-
-AS = $(CC) -x assembler-with-cpp
-LD = $(CC)
-
-# we rely on GCC inline:ing the stuff we tell it to in many places here.
-CFLAGS = -Winline -Wall -g -O2 -static -fno-stack-protector
-NOSTDFLAGS = -nostartfiles -nostdlib
-ASFLAGS += -mcpu=v10 -g -Wa,-I,$(SRC_PATH)/tests/tcg/cris/bare
-CRT_FILES = crt.o sys.o
-
-# stop make deleting crt files if build fails
-.PRECIOUS: $(CRT_FILES)
-
-%.o: %.c
- $(CC) -c $< -o $@
-
-%.o: %.s
- $(AS) $(ASFLAGS) -c $< -o $@
-
-%: %.s $(CRT_FILES)
- $(CC) $(ASFLAGS) $< -o $@ $(LDFLAGS) $(NOSTDFLAGS) $(CRT_FILES)
-
-# The default CPU breaks (possibly as it's max?) so force crisv17
-QEMU_OPTS=-cpu crisv17
-
-# Additional runners to run under GNU SIM
-CRIS_RUNS_ON_SIM=$(patsubst %, %-on-sim, $(CRIS_RUNS))
-SIMG:=cris-axis-linux-gnu-run
-
-# e.g.: make -f ../../tests/tcg/Makefile run-check_orm-on-sim
-run-%-on-sim:
- $(call run-test, $<, $(SIMG) $<)
-
-# We don't currently support the multiarch tests
-undefine MULTIARCH_TESTS
diff --git a/tests/tcg/cris/README b/tests/tcg/cris/README
deleted file mode 100644
index 2e65a76..0000000
--- a/tests/tcg/cris/README
+++ /dev/null
@@ -1 +0,0 @@
-Test-suite for the cris port. Heavily based on the test-suite for the CRIS port of sim by Hans-Peter Nilsson.
diff --git a/tests/tcg/cris/bare/check_addcv17.s b/tests/tcg/cris/bare/check_addcv17.s
deleted file mode 100644
index 52ef7a9..0000000
--- a/tests/tcg/cris/bare/check_addcv17.s
+++ /dev/null
@@ -1,65 +0,0 @@
-# mach: crisv17
-
- .include "testutils.inc"
-
- .macro addc Rs Rd inc=0
-# Create the instruction manually since there is no assembler support yet
- .word (\Rd << 12) | \Rs | (\inc << 10) | 0x09a0
- .endm
-
- start
-
- .data
-mem1:
- .dword 0x0
-mem2:
- .dword 0x12345678
-
- .text
- move.d mem1,r4
- clearf nzvc
- addc 4 3
- test_cc 0 1 0 0
- checkr3 0
-
- move.d mem1,r4
- clearf nzvc
- ax
- addc 4 3
- test_cc 0 0 0 0
- checkr3 0
-
- move.d mem1,r4
- clearf nzvc
- setf c
- addc 4 3
- test_cc 0 0 0 0
- checkr3 1
-
- move.d mem2,r4
- moveq 2, r3
- clearf nzvc
- setf c
- addc 4 3
- test_cc 0 0 0 0
- checkr3 1234567b
-
- move.d mem2,r5
- clearf nzvc
- cmp.d r4,r5
- test_cc 0 1 0 0
-
- move.d mem2,r4
- moveq 2, r3
- clearf nzvc
- addc 4 3 inc=1
- test_cc 0 0 0 0
- checkr3 1234567a
-
- move.d mem2,r5
- clearf nzvc
- addq 4,r5
- cmp.d r4,r5
- test_cc 0 1 0 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_addi.s b/tests/tcg/cris/bare/check_addi.s
deleted file mode 100644
index a00dec0..0000000
--- a/tests/tcg/cris/bare/check_addi.s
+++ /dev/null
@@ -1,57 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 0\n1\n2\n4\nbe02460f\n69d035a6\nc16c14d4\n
-
- .include "testutils.inc"
- start
- moveq 0,r3
- moveq 0,r4
- clearf zcvn
- addi r4.b,r3
- test_cc 0 0 0 0
- checkr3 0
-
- moveq 0,r3
- moveq 1,r4
- setf zcvn
- addi r4.b,r3
- test_cc 1 1 1 1
- checkr3 1
-
- moveq 0,r3
- moveq 1,r4
- setf cv
- clearf zn
- addi r4.w,r3
- test_cc 0 0 1 1
- checkr3 2
-
- moveq 0,r3
- moveq 1,r4
- clearf cv
- setf zn
- addi r4.d,r3
- test_cc 1 1 0 0
- checkr3 4
-
- move.d 0x12345678,r3
- move.d 0xabcdef97,r4
- clearf cn
- setf zv
- addi r4.b,r3
- test_cc 0 1 1 0
- checkr3 be02460f
-
- move.d 0x12345678,r3
- move.d 0xabcdef97,r4
- setf cn
- clearf zv
- addi r4.w,r3
- test_cc 1 0 0 1
- checkr3 69d035a6
-
- move.d 0x12345678,r3
- move.d 0xabcdef97,r4
- addi r4.d,r3
- checkr3 c16c14d4
-
- quit
diff --git a/tests/tcg/cris/bare/check_addiv32.s b/tests/tcg/cris/bare/check_addiv32.s
deleted file mode 100644
index 20ba25d..0000000
--- a/tests/tcg/cris/bare/check_addiv32.s
+++ /dev/null
@@ -1,62 +0,0 @@
-# mach: crisv32
-# output: 4455aa77\n4455aa77\nee19ccff\nff22\n4455aa77\nff224455\n55aa77ff\n
-
- .include "testutils.inc"
- .data
-x:
- .dword 0x55aa77ff
- .dword 0xccff2244
- .dword 0x88ccee19
-
- start
- setf cv
- moveq -1,r0
- move.d x-32768,r5
- move.d 32769,r6
- addi r6.b,r5,acr
- test_cc 0 0 1 1
- move.d [acr],r3
- checkr3 4455aa77
-
- addu.w 32771,r5
- setf znvc
- moveq -1,r8
- addi r8.w,r5,acr
- test_cc 1 1 1 1
- move.d [acr],r3
- checkr3 4455aa77
-
- moveq 5,r10
- clearf znvc
- addi r10.b,acr,acr
- test_cc 0 0 0 0
- move.d [acr],r3
- checkr3 ee19ccff
-
- subq 1,r5
- move.d r5,r8
- subq 1,r8
- moveq 1,r9
- addi r9.d,r8,acr
- test_cc 0 0 0 0
- movu.w [acr],r3
- checkr3 ff22
-
- moveq -2,r11
- addi r11.w,acr,acr
- move.d [acr],r3
- checkr3 4455aa77
-
- moveq 5,r9
- addi r9.d,acr,acr
- subq 18,acr
- move.d [acr],r3
- checkr3 ff224455
-
- move.d -76789888/4,r12
- addi r12.d,r5,acr
- add.d 76789886,acr
- move.d [acr],r3
- checkr3 55aa77ff
-
- quit
diff --git a/tests/tcg/cris/bare/check_addm.s b/tests/tcg/cris/bare/check_addm.s
deleted file mode 100644
index efece9f..0000000
--- a/tests/tcg/cris/bare/check_addm.s
+++ /dev/null
@@ -1,96 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n781344d0\n
-
- .include "testutils.inc"
- .data
-x:
- .dword 2,-1,0xffff,-1,0x5432f789
- .word 2,-1,0xffff,0xf789
- .byte 2,0xff,0x89
- .byte 0x7e
-
- start
- moveq -1,r3
- move.d x,r5
- add.d [r5+],r3
- test_cc 0 0 0 1
- checkr3 1
-
- moveq 2,r3
- add.d [r5],r3
- test_cc 0 0 0 1
- addq 4,r5
- checkr3 1
-
- move.d 0xffff,r3
- add.d [r5+],r3
- test_cc 0 0 0 0
- checkr3 1fffe
-
- moveq -1,r3
- add.d [r5+],r3
- test_cc 1 0 0 1
- checkr3 fffffffe
-
- move.d 0x78134452,r3
- add.d [r5+],r3
- test_cc 1 0 1 0
- checkr3 cc463bdb
-
- moveq -1,r3
- add.w [r5+],r3
- test_cc 0 0 0 1
- checkr3 ffff0001
-
- moveq 2,r3
- add.w [r5+],r3
- test_cc 0 0 0 1
- checkr3 1
-
- move.d 0xffff,r3
- add.w [r5],r3
- test_cc 1 0 0 1
- checkr3 fffe
-
- move.d 0xfedaffff,r3
- add.w [r5+],r3
- test_cc 1 0 0 1
- checkr3 fedafffe
-
- move.d 0x78134452,r3
- add.w [r5+],r3
- test_cc 0 0 0 1
- checkr3 78133bdb
-
- moveq -1,r3
- add.b [r5],r3
- test_cc 0 0 0 1
- addq 1,r5
- checkr3 ffffff01
-
- moveq 2,r3
- add.b [r5],r3
- test_cc 0 0 0 1
- checkr3 1
-
- move.d 0xff,r3
- add.b [r5],r3
- test_cc 1 0 0 1
- checkr3 fe
-
- move.d 0xfeda49ff,r3
- add.b [r5+],r3
- test_cc 1 0 0 1
- checkr3 feda49fe
-
- move.d 0x78134452,r3
- add.b [r5+],r3
- test_cc 1 0 0 0
- checkr3 781344db
-
- move.d 0x78134452,r3
- add.b [r5],r3
- test_cc 1 0 1 0
- checkr3 781344d0
-
- quit
diff --git a/tests/tcg/cris/bare/check_addq.s b/tests/tcg/cris/bare/check_addq.s
deleted file mode 100644
index e6f874f..0000000
--- a/tests/tcg/cris/bare/check_addq.s
+++ /dev/null
@@ -1,47 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: ffffffff\n0\n1\n100\n10000\n47\n67\na6\n80000001\n
-
- .include "testutils.inc"
- start
- moveq -2,r3
- addq 1,r3
- test_cc 1 0 0 0
- checkr3 ffffffff
-
- addq 1,r3
- test_cc 0 1 0 1
- checkr3 0
-
- addq 1,r3
- test_cc 0 0 0 0
- checkr3 1
-
- move.d 0xff,r3
- addq 1,r3
- test_cc 0 0 0 0
- checkr3 100
-
- move.d 0xffff,r3
- addq 1,r3
- test_cc 0 0 0 0
- checkr3 10000
-
- move.d 0x42,r3
- addq 5,r3
- test_cc 0 0 0 0
- checkr3 47
-
- addq 32,r3
- test_cc 0 0 0 0
- checkr3 67
-
- addq 63,r3
- test_cc 0 0 0 0
- checkr3 a6
-
- move.d 0x7ffffffe,r3
- addq 3,r3
- test_cc 1 0 1 0
- checkr3 80000001
-
- quit
diff --git a/tests/tcg/cris/bare/check_addr.s b/tests/tcg/cris/bare/check_addr.s
deleted file mode 100644
index 7f55cdc..0000000
--- a/tests/tcg/cris/bare/check_addr.s
+++ /dev/null
@@ -1,96 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- moveq 2,r4
- add.d r4,r3
- test_cc 0 0 0 1
- checkr3 1
-
- moveq 2,r3
- moveq -1,r4
- add.d r4,r3
- test_cc 0 0 0 1
- checkr3 1
-
- move.d 0xffff,r4
- move.d r4,r3
- add.d r4,r3
- test_cc 0 0 0 0
- checkr3 1fffe
-
- moveq -1,r4
- move.d r4,r3
- add.d r4,r3
- test_cc 1 0 0 1
- checkr3 fffffffe
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- add.d r4,r3
- test_cc 1 0 1 0
- checkr3 cc463bdb
-
- moveq -1,r3
- moveq 2,r4
- add.w r4,r3
- test_cc 0 0 0 1
- checkr3 ffff0001
-
- moveq 2,r3
- moveq -1,r4
- add.w r4,r3
- test_cc 0 0 0 1
- checkr3 1
-
- move.d 0xffff,r4
- move.d r4,r3
- add.w r4,r3
- test_cc 1 0 0 1
- checkr3 fffe
-
- move.d 0xfedaffff,r4
- move.d r4,r3
- add.w r4,r3
- test_cc 1 0 0 1
- checkr3 fedafffe
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- add.w r4,r3
- test_cc 0 0 0 1
- checkr3 78133bdb
-
- moveq -1,r3
- moveq 2,r4
- add.b r4,r3
- test_cc 0 0 0 1
- checkr3 ffffff01
-
- moveq 2,r3
- moveq -1,r4
- add.b r4,r3
- test_cc 0 0 0 1
- checkr3 1
-
- move.d 0xff,r4
- move.d r4,r3
- add.b r4,r3
- test_cc 1 0 0 1
- checkr3 fe
-
- move.d 0xfeda49ff,r4
- move.d r4,r3
- add.b r4,r3
- test_cc 1 0 0 1
- checkr3 feda49fe
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- add.b r4,r3
- test_cc 1 0 0 0
- checkr3 781344db
-
- quit
diff --git a/tests/tcg/cris/bare/check_addxc.s b/tests/tcg/cris/bare/check_addxc.s
deleted file mode 100644
index 09c8355..0000000
--- a/tests/tcg/cris/bare/check_addxc.s
+++ /dev/null
@@ -1,91 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 1\n1\n101\n10001\n100fe\n1fffe\nfffe\nfffe\nfffffffe\nfe\nfffffffe\n781344db\n781343db\n78143bdb\n78133bdb\n800000ed\n0\n
-
- .include "testutils.inc"
- start
- moveq 2,r3
- adds.b 0xff,r3
- test_cc 0 0 0 1
- checkr3 1
-
- moveq 2,r3
- adds.w 0xffff,r3
- test_cc 0 0 0 1
- checkr3 1
-
- moveq 2,r3
- addu.b 0xff,r3
- checkr3 101
-
- moveq 2,r3
- move.d 0xffffffff,r4
- addu.w -1,r3
- test_cc 0 0 0 0
- checkr3 10001
-
- move.d 0xffff,r3
- addu.b -1,r3
- test_cc 0 0 0 0
- checkr3 100fe
-
- move.d 0xffff,r3
- addu.w -1,r3
- test_cc 0 0 0 0
- checkr3 1fffe
-
- move.d 0xffff,r3
- adds.b 0xff,r3
- test_cc 0 0 0 1
- checkr3 fffe
-
- move.d 0xffff,r3
- adds.w 0xffff,r3
- test_cc 0 0 0 1
- checkr3 fffe
-
- moveq -1,r3
- adds.b 0xff,r3
- test_cc 1 0 0 1
- checkr3 fffffffe
-
- moveq -1,r3
- adds.w 0xff,r3
- test_cc 0 0 0 1
- checkr3 fe
-
- moveq -1,r3
- adds.w 0xffff,r3
- test_cc 1 0 0 1
- checkr3 fffffffe
-
- move.d 0x78134452,r3
- addu.b 0x89,r3
- test_cc 0 0 0 0
- checkr3 781344db
-
- move.d 0x78134452,r3
- adds.b 0x89,r3
- test_cc 0 0 0 1
- checkr3 781343db
-
- move.d 0x78134452,r3
- addu.w 0xf789,r3
- test_cc 0 0 0 0
- checkr3 78143bdb
-
- move.d 0x78134452,r3
- adds.w 0xf789,r3
- test_cc 0 0 0 1
- checkr3 78133bdb
-
- move.d 0x7fffffee,r3
- addu.b 0xff,r3
- test_cc 1 0 1 0
- checkr3 800000ed
-
- move.d 0x1,r3
- adds.w 0xffff,r3
- test_cc 0 1 0 1
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_addxm.s b/tests/tcg/cris/bare/check_addxm.s
deleted file mode 100644
index 7563494..0000000
--- a/tests/tcg/cris/bare/check_addxm.s
+++ /dev/null
@@ -1,106 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 1\n1\n101\n10001\n100fe\n1fffe\nfffe\nfffe\nfffffffe\nfe\nfffffffe\n781344db\n781343db\n78143bdb\n78133bdb\n800000ed\n0\n
-
- .include "testutils.inc"
- .data
-x:
- .byte 0xff
- .word 0xffff
- .word 0xff
- .word 0xffff
- .byte 0x89
- .word 0xf789
- .byte 0xff
- .word 0xffff
-
- start
- moveq 2,r3
- move.d x,r5
- adds.b [r5+],r3
- test_cc 0 0 0 1
- checkr3 1
-
- moveq 2,r3
- adds.w [r5+],r3
- test_cc 0 0 0 1
- checkr3 1
-
- moveq 2,r3
- subq 3,r5
- addu.b [r5+],r3
- test_cc 0 0 0 0
- checkr3 101
-
- moveq 2,r3
- addu.w [r5+],r3
- subq 3,r5
- test_cc 0 0 0 0
- checkr3 10001
-
- move.d 0xffff,r3
- addu.b [r5],r3
- test_cc 0 0 0 0
- checkr3 100fe
-
- move.d 0xffff,r3
- addu.w [r5],r3
- test_cc 0 0 0 0
- checkr3 1fffe
-
- move.d 0xffff,r3
- adds.b [r5],r3
- test_cc 0 0 0 1
- checkr3 fffe
-
- move.d 0xffff,r3
- adds.w [r5],r3
- test_cc 0 0 0 1
- checkr3 fffe
-
- moveq -1,r3
- adds.b [r5],r3
- test_cc 1 0 0 1
- addq 3,r5
- checkr3 fffffffe
-
- moveq -1,r3
- adds.w [r5+],r3
- test_cc 0 0 0 1
- checkr3 fe
-
- moveq -1,r3
- adds.w [r5+],r3
- test_cc 1 0 0 1
- checkr3 fffffffe
-
- move.d 0x78134452,r3
- addu.b [r5],r3
- test_cc 0 0 0 0
- checkr3 781344db
-
- move.d 0x78134452,r3
- adds.b [r5+],r3
- test_cc 0 0 0 1
- checkr3 781343db
-
- move.d 0x78134452,r3
- addu.w [r5],r3
- test_cc 0 0 0 0
- checkr3 78143bdb
-
- move.d 0x78134452,r3
- adds.w [r5+],r3
- test_cc 0 0 0 1
- checkr3 78133bdb
-
- move.d 0x7fffffee,r3
- addu.b [r5+],r3
- test_cc 1 0 1 0
- checkr3 800000ed
-
- move.d 0x1,r3
- adds.w [r5+],r3
- test_cc 0 1 0 1
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_addxr.s b/tests/tcg/cris/bare/check_addxr.s
deleted file mode 100644
index 7f55cdc..0000000
--- a/tests/tcg/cris/bare/check_addxr.s
+++ /dev/null
@@ -1,96 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- moveq 2,r4
- add.d r4,r3
- test_cc 0 0 0 1
- checkr3 1
-
- moveq 2,r3
- moveq -1,r4
- add.d r4,r3
- test_cc 0 0 0 1
- checkr3 1
-
- move.d 0xffff,r4
- move.d r4,r3
- add.d r4,r3
- test_cc 0 0 0 0
- checkr3 1fffe
-
- moveq -1,r4
- move.d r4,r3
- add.d r4,r3
- test_cc 1 0 0 1
- checkr3 fffffffe
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- add.d r4,r3
- test_cc 1 0 1 0
- checkr3 cc463bdb
-
- moveq -1,r3
- moveq 2,r4
- add.w r4,r3
- test_cc 0 0 0 1
- checkr3 ffff0001
-
- moveq 2,r3
- moveq -1,r4
- add.w r4,r3
- test_cc 0 0 0 1
- checkr3 1
-
- move.d 0xffff,r4
- move.d r4,r3
- add.w r4,r3
- test_cc 1 0 0 1
- checkr3 fffe
-
- move.d 0xfedaffff,r4
- move.d r4,r3
- add.w r4,r3
- test_cc 1 0 0 1
- checkr3 fedafffe
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- add.w r4,r3
- test_cc 0 0 0 1
- checkr3 78133bdb
-
- moveq -1,r3
- moveq 2,r4
- add.b r4,r3
- test_cc 0 0 0 1
- checkr3 ffffff01
-
- moveq 2,r3
- moveq -1,r4
- add.b r4,r3
- test_cc 0 0 0 1
- checkr3 1
-
- move.d 0xff,r4
- move.d r4,r3
- add.b r4,r3
- test_cc 1 0 0 1
- checkr3 fe
-
- move.d 0xfeda49ff,r4
- move.d r4,r3
- add.b r4,r3
- test_cc 1 0 0 1
- checkr3 feda49fe
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- add.b r4,r3
- test_cc 1 0 0 0
- checkr3 781344db
-
- quit
diff --git a/tests/tcg/cris/bare/check_andc.s b/tests/tcg/cris/bare/check_andc.s
deleted file mode 100644
index a947b77..0000000
--- a/tests/tcg/cris/bare/check_andc.s
+++ /dev/null
@@ -1,80 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 2\n2\nffff\nffffffff\n50124400\nffff0002\n2\nfffff\nfedaff0f\n78134400\nffffff02\n2\nf02\n78134401\n78134400\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- and.d 2,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq 2,r3
- and.d -1,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xffff,r3
- and.d 0xffff,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- moveq -1,r3
- and.d -1,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x78134452,r3
- and.d 0x5432f789,r3
- test_move_cc 0 0 0 0
- checkr3 50124400
-
- moveq -1,r3
- and.w 2,r3
- test_move_cc 0 0 0 0
- checkr3 ffff0002
-
- moveq 2,r3
- and.w -1,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xfffff,r3
- and.w 0xffff,r3
- test_move_cc 1 0 0 0
- checkr3 fffff
-
- move.d 0xfedaffaf,r3
- and.w 0xff5f,r3
- test_move_cc 1 0 0 0
- checkr3 fedaff0f
-
- move.d 0x78134452,r3
- and.w 0xf789,r3
- test_move_cc 0 0 0 0
- checkr3 78134400
-
- moveq -1,r3
- and.b 2,r3
- test_move_cc 0 0 0 0
- checkr3 ffffff02
-
- moveq 2,r3
- and.b -1,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xfa7,r3
- and.b 0x5a,r3
- test_move_cc 0 0 0 0
- checkr3 f02
-
- move.d 0x78134453,r3
- and.b 0x89,r3
- test_move_cc 0 0 0 0
- checkr3 78134401
-
- and.b 0,r3
- test_move_cc 0 1 0 0
- checkr3 78134400
-
- quit
diff --git a/tests/tcg/cris/bare/check_andm.s b/tests/tcg/cris/bare/check_andm.s
deleted file mode 100644
index 9385886..0000000
--- a/tests/tcg/cris/bare/check_andm.s
+++ /dev/null
@@ -1,90 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 2\n2\nffff\nffffffff\n50124400\nffff0002\n2\nfffff\nfedaff0f\n78134400\nffffff02\n2\nf02\n78134401\n78134400\n
-
- .include "testutils.inc"
- .data
-x:
- .dword 2,-1,0xffff,-1,0x5432f789
- .word 2,-1,0xffff,0xff5f,0xf789
- .byte 2,-1,0x5a,0x89,0
-
- start
- moveq -1,r3
- move.d x,r5
- and.d [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq 2,r3
- and.d [r5],r3
- test_move_cc 0 0 0 0
- addq 4,r5
- checkr3 2
-
- move.d 0xffff,r3
- and.d [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- moveq -1,r3
- and.d [r5+],r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x78134452,r3
- and.d [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 50124400
-
- moveq -1,r3
- and.w [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 ffff0002
-
- moveq 2,r3
- and.w [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xfffff,r3
- and.w [r5],r3
- test_move_cc 1 0 0 0
- addq 2,r5
- checkr3 fffff
-
- move.d 0xfedaffaf,r3
- and.w [r5+],r3
- test_move_cc 1 0 0 0
- checkr3 fedaff0f
-
- move.d 0x78134452,r3
- and.w [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 78134400
-
- moveq -1,r3
- and.b [r5],r3
- test_move_cc 0 0 0 0
- addq 1,r5
- checkr3 ffffff02
-
- moveq 2,r3
- and.b [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xfa7,r3
- and.b [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 f02
-
- move.d 0x78134453,r3
- and.b [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 78134401
-
- and.b [r5],r3
- test_move_cc 0 1 0 0
- checkr3 78134400
-
- quit
diff --git a/tests/tcg/cris/bare/check_andq.s b/tests/tcg/cris/bare/check_andq.s
deleted file mode 100644
index 55aa7b0..0000000
--- a/tests/tcg/cris/bare/check_andq.s
+++ /dev/null
@@ -1,46 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 2\n2\nffff\nffffffff\n1f\nffffffe0\n78134452\n0\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- andq 2,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq 2,r3
- andq -1,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xffff,r3
- andq -1,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- moveq -1,r3
- andq -1,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- andq 31,r3
- test_move_cc 0 0 0 0
- checkr3 1f
-
- moveq -1,r3
- andq -32,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffe0
-
- move.d 0x78134457,r3
- andq -14,r3
- test_move_cc 0 0 0 0
- checkr3 78134452
-
- moveq 0,r3
- andq -14,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_andr.s b/tests/tcg/cris/bare/check_andr.s
deleted file mode 100644
index 61aa1dc..0000000
--- a/tests/tcg/cris/bare/check_andr.s
+++ /dev/null
@@ -1,95 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 2\n2\nffff\nffffffff\n50124400\nffff0002\n2\nfffff\nfedaff0f\n78134400\nffffff02\n2\nf02\n78134401\n78134400\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- moveq 2,r4
- and.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq 2,r3
- moveq -1,r4
- and.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xffff,r4
- move.d r4,r3
- and.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- moveq -1,r4
- move.d r4,r3
- and.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- and.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 50124400
-
- moveq -1,r3
- moveq 2,r4
- and.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffff0002
-
- moveq 2,r3
- moveq -1,r4
- and.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xfffff,r3
- move.d 0xffff,r4
- and.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 fffff
-
- move.d 0xfedaffaf,r3
- move.d 0xff5f,r4
- and.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 fedaff0f
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- and.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 78134400
-
- moveq -1,r3
- moveq 2,r4
- and.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffffff02
-
- moveq 2,r3
- moveq -1,r4
- and.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0x5a,r4
- move.d 0xfa7,r3
- and.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 f02
-
- move.d 0x5432f789,r4
- move.d 0x78134453,r3
- and.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 78134401
-
- moveq 0,r7
- and.b r7,r3
- test_move_cc 0 1 0 0
- checkr3 78134400
-
- quit
diff --git a/tests/tcg/cris/bare/check_asr.s b/tests/tcg/cris/bare/check_asr.s
deleted file mode 100644
index 0a02ae6..0000000
--- a/tests/tcg/cris/bare/check_asr.s
+++ /dev/null
@@ -1,230 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: ffffffff\n1\nffffffff\nffffffff\n5a67f\nffffffff\nffffffff\nffffffff\nf699fc67\nffffffff\n1\nffffffff\nffffffff\n5a67f\nda67ffff\nda67ffff\nda67ffff\nda67fc67\nffffffff\nffffffff\n1\nffffffff\nffffffff\n5a670007\nda67f1ff\nda67f1ff\nda67f1ff\nda67f1e7\nffffffff\nffffffff\n1\nffffffff\nffffffff\nffffffff\n5a67f1ff\n5a67f1f9\n0\n5a670000\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- asrq 0,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- asrq 1,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
- moveq -1,r3
- asrq 31,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- asrq 15,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x5a67f19f,r3
- asrq 12,r3
- test_move_cc 0 0 0 0
- checkr3 5a67f
-
- move.d 0xda67f19f,r3
- move.d 31,r4
- asr.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0xda67f19f,r3
- move.d 32,r4
- asr.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0xda67f19f,r3
- move.d 33,r4
- asr.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0xda67f19f,r3
- move.d 66,r4
- asr.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 f699fc67
-
- moveq -1,r3
- moveq 0,r4
- asr.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- moveq 1,r4
- asr.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
- moveq -1,r3
- moveq 31,r4
- asr.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 15,r4
- asr.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x5a67f19f,r3
- moveq 12,r4
- asr.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 5a67f
-
- move.d 0xda67f19f,r3
- move.d 31,r4
- asr.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 da67ffff
-
- move.d 0xda67f19f,r3
- move.d 32,r4
- asr.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 da67ffff
-
- move.d 0xda67f19f,r3
- move.d 33,r4
- asr.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 da67ffff
-
- move.d 0xda67f19f,r3
- move.d 66,r4
- asr.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 da67fc67
-
- moveq -1,r3
- moveq 0,r4
- asr.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 1,r4
- asr.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- moveq 1,r4
- asr.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
- moveq -1,r3
- moveq 31,r4
- asr.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 15,r4
- asr.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x5a67719f,r3
- moveq 12,r4
- asr.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 5a670007
-
- move.d 0xda67f19f,r3
- move.d 31,r4
- asr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 da67f1ff
-
- move.d 0xda67f19f,r3
- move.d 32,r4
- asr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 da67f1ff
-
- move.d 0xda67f19f,r3
- move.d 33,r4
- asr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 da67f1ff
-
- move.d 0xda67f19f,r3
- move.d 66,r4
- asr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 da67f1e7
-
- moveq -1,r3
- moveq 0,r4
- asr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 1,r4
- asr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- moveq 1,r4
- asr.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
- moveq -1,r3
- moveq 31,r4
- asr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 15,r4
- asr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 7,r4
- asr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
-; FIXME: was wrong.
- move.d 0x5a67f19f,r3
- moveq 12,r4
- asr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 5a67f1ff
-
-; FIXME: was wrong.
- move.d 0x5a67f19f,r3
- moveq 4,r4
- asr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 5a67f1f9
-
- move.d 0x5a67f19f,r3
- asrq 31,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- move.d 0x5a67419f,r3
- moveq 16,r4
- asr.w r4,r3
- test_move_cc 0 1 0 0
- checkr3 5a670000
-
- quit
diff --git a/tests/tcg/cris/bare/check_ba.s b/tests/tcg/cris/bare/check_ba.s
deleted file mode 100644
index 873a408..0000000
--- a/tests/tcg/cris/bare/check_ba.s
+++ /dev/null
@@ -1,93 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: a\n
-
-
- .set smalloffset,0
- .set largeoffset,0
-
-
- .macro fail
- jump _fail
- .endm
-
- .global main
-main:
- moveq 0,$r3
-
-; Short forward branch.
- ba 0f
- addq 1,$r3
- fail
-
-; Max short forward branch.
-1:
- ba 2f
- addq 1,$r3
- fail
-
-; Short backward branch.
-0:
- ba 1b
- addq 1,$r3
- fail
-
- .space 254-2+smalloffset+1b-.,0
- moveq 0,$r3
-
-2:
-; Transit branch (long).
- ba 3f
- addq 1,$r3
- fail
-
- moveq 0,$r3
-4:
-; Long forward branch.
- ba 5f
- addq 1,$r3
- fail
-
- .space 256-2-smalloffset+4b-.,0
-
- moveq 0,$r3
-
-; Max short backward branch.
-3:
- ba 4b
- addq 1,$r3
- fail
-
-5:
-; Max long forward branch.
- ba 6f
- addq 1,$r3
- fail
-
- .space 32766+largeoffset-2+5b-.,0
-
- moveq 0,$r3
-6:
-; Transit branch.
- ba 7f
- addq 1,$r3
- fail
-
- moveq 0,$r3
-9:
- jsr pass
- nop
-
-; Transit branch.
- moveq 0,$r3
-7:
- ba 8f
- addq 1,$r3
- fail
-
- .space 32768-largeoffset+9b-.,0
-
-8:
-; Max long backward branch.
- ba 9b
- addq 1,$r3
- fail
diff --git a/tests/tcg/cris/bare/check_bas.s b/tests/tcg/cris/bare/check_bas.s
deleted file mode 100644
index 11929d4..0000000
--- a/tests/tcg/cris/bare/check_bas.s
+++ /dev/null
@@ -1,102 +0,0 @@
-# mach: crisv32
-# output: 0\n0\n0\nfb349abc\n0\n12124243\n0\n0\neab5baad\n0\nefb37832\n
-
- .include "testutils.inc"
- start
-x:
- setf zncv
- bsr 0f
- nop
-0:
- test_cc 1 1 1 1
- move srp,r3
- sub.d 0b,r3
- checkr3 0
-
- bas 1f,mof
- moveq 0,r0
-6:
- nop
- quit
-
-2:
- move srp,r3
- sub.d 3f,r3
- checkr3 0
- move srp,r4
- subq 4,r4
- move.d [r4],r3
- checkr3 fb349abc
-
- basc 4f,mof
- nop
- .dword 0x12124243
-7:
- nop
- quit
-
-8:
- move mof,r3
- sub.d 7f,r3
- checkr3 0
-
- move mof,r4
- subq 4,r4
- move.d [r4],r3
- checkr3 eab5baad
-
- jasc 9f,mof
- nop
- .dword 0xefb37832
-0:
- quit
-
- quit
-9:
- move mof,r3
- sub.d 0b,r3
- checkr3 0
-
- move mof,r4
- subq 4,r4
- move.d [r4],r3
- checkr3 efb37832
-
- quit
-
-4:
- move mof,r3
- sub.d 7b,r3
- checkr3 0
- move mof,r4
- subq 4,r4
- move.d [r4],r3
- checkr3 12124243
- basc 5f,bz
- moveq 0,r3
- .dword 0x7634aeba
- quit
-
- .space 32770,0
-1:
- move mof,r3
- sub.d 6b,r3
- checkr3 0
-
- bsrc 2b
- nop
- .dword 0xfb349abc
-3:
-
- quit
-
-5:
- move mof,r3
- sub.d 7b,r3
- checkr3 0
- move.d 8b,r6
- jasc r6,mof
- nop
- .dword 0xeab5baad
-7:
- quit
diff --git a/tests/tcg/cris/bare/check_bcc.s b/tests/tcg/cris/bare/check_bcc.s
deleted file mode 100644
index c57ffa6..0000000
--- a/tests/tcg/cris/bare/check_bcc.s
+++ /dev/null
@@ -1,197 +0,0 @@
- .global main
- .type main, @function
-main:
- clearf nzvc
- setf nzv
- bcc 0f
- addq 1, $r3
- jump dofail
-
-0:
- clearf nzvc
- setf nzv
- bcs dofail
- addq 1,$r3
-
- clearf nzvc
- setf ncv
- bne 1f
- addq 1, $r3
-
-fail:
-dofail:
- jump _fail
-
-1:
- clearf nzvc
- setf ncv
- beq dofail
- addq 1,$r3
-
- clearf nzvc
- setf ncz
- bvc 2f
- addq 1,$r3
- jump dofail
-
-2:
- clearf nzvc
- setf ncz
- bvs dofail
- addq 1,$r3
-
- clearf nzvc
- setf vcz
- bpl 3f
- addq 1,$r3
- jump fail
-3:
- clearf nzvc
- setf vcz
- bmi dofail
- addq 1,$r3
-
- clearf nzvc
- setf nv
- bls dofail
- addq 1,$r3
-
- clearf nzvc
- setf nv
- bhi 4f
- addq 1,$r3
- jump dofail
-
-4:
- clearf nzvc
- setf zc
- bge 5f
- addq 1,$r3
- jump dofail
-
-5:
- clearf nzvc
- setf zc
- blt dofail
- addq 1,$r3
-
- clearf nzvc
- setf c
- bgt 6f
- addq 1,$r3
- jump fail
-
-6:
- clearf nzvc
- setf c
- ble dofail
- addq 1,$r3
-
-;;;;;;;;;;
-
- setf nzvc
- clearf nzv
- bcc dofail
- addq 1,$r3
-
- setf nzvc
- clearf nzv
- bcs 0f
- addq 1,$r3
- jump fail
-
-0:
- setf nzvc
- clearf ncv
- bne dofail
- addq 1,$r3
-
- setf nzvc
- clearf ncv
- beq 1f
- addq 1,$r3
- jump fail
-
-1:
- setf nzvc
- clearf ncz
- bvc dofail
- addq 1,$r3
-
- setf nzvc
- clearf ncz
- bvs 2f
- addq 1,$r3
- jump fail
-
-2:
- setf nzvc
- clearf vcz
- bpl dofail
- addq 1,$r3
-
- setf nzvc
- clearf vcz
- bmi 3f
- addq 1,$r3
- jump fail
-
-3:
- setf nzvc
- clearf nv
- bls 4f
- addq 1,$r3
- jump fail
-
-4:
- setf nzvc
- clearf nv
- bhi dofail
- addq 1,$r3
-
- setf zvc
- clearf nzc
- bge dofail
- addq 1,$r3
-
- setf nzc
- clearf vzc
- blt 5f
- addq 1,$r3
- jump fail
-
-5:
- setf nzvc
- clearf c
- bgt dofail
- addq 1,$r3
-
- setf nzvc
- clearf c
- ble 6f
- addq 1,$r3
- jump fail
-
-6:
- ; do a forward branch.
- ba 2f
- nop
- .fill 100
-1:
- ba 3f
- nop
- .fill 800
-2:
- ba 1b
- nop
- .fill 1024
-3:
-
- moveq 31, $r0
-1: bne 1b
- subq 1, $r0
-
- jsr pass
- moveq 0, $r10
- ret
- nop
diff --git a/tests/tcg/cris/bare/check_boundc.s b/tests/tcg/cris/bare/check_boundc.s
deleted file mode 100644
index fb9e5bc..0000000
--- a/tests/tcg/cris/bare/check_boundc.s
+++ /dev/null
@@ -1,101 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 2\n2\nffff\nffffffff\n5432f789\n2\nffff\n2\nffff\nffff\nf789\n2\n2\nff\nff\nff\n89\n0\nff\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- moveq 2,r4
- bound.d 2,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq 2,r3
- bound.d 0xffffffff,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xffff,r3
- bound.d 0xffff,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- moveq -1,r3
- bound.d 0xffffffff,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x78134452,r3
- bound.d 0x5432f789,r3
- test_move_cc 0 0 0 0
- checkr3 5432f789
-
- moveq -1,r3
- bound.w 2,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq -1,r3
- bound.w 0xffff,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- moveq 2,r3
- bound.w 0xffff,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xffff,r3
- bound.w 0xffff,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- move.d 0xfedaffff,r3
- bound.w 0xffff,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- move.d 0x78134452,r3
- bound.w 0xf789,r3
- test_move_cc 0 0 0 0
- checkr3 f789
-
- moveq -1,r3
- bound.b 2,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq 2,r3
- bound.b 0xff,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq -1,r3
- bound.b 0xff,r3
- test_move_cc 0 0 0 0
- checkr3 ff
-
- move.d 0xff,r3
- bound.b 0xff,r3
- test_move_cc 0 0 0 0
- checkr3 ff
-
- move.d 0xfeda49ff,r3
- bound.b 0xff,r3
- test_move_cc 0 0 0 0
- checkr3 ff
-
- move.d 0x78134452,r3
- bound.b 0x89,r3
- test_move_cc 0 0 0 0
- checkr3 89
-
- bound.w 0,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- move.d 0xffff,r3
- bound.b -1,r3
- test_move_cc 0 0 0 0
- checkr3 ff
-
- quit
diff --git a/tests/tcg/cris/bare/check_boundr.s b/tests/tcg/cris/bare/check_boundr.s
deleted file mode 100644
index 5c50cc5..0000000
--- a/tests/tcg/cris/bare/check_boundr.s
+++ /dev/null
@@ -1,125 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 2\n2\nffff\nffffffff\n5432f789\n2\n2\nffff\nffff\nffff\nf789\n2\n2\nff\nff\n89\nfeda4953\nfeda4962\n0\n0\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- moveq 2,r4
- bound.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq 2,r3
- moveq -1,r4
- bound.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xffff,r4
- move.d r4,r3
- bound.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- moveq -1,r4
- move.d r4,r3
- bound.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- bound.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 5432f789
-
- moveq -1,r3
- moveq 2,r4
- bound.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq 2,r3
- moveq -1,r4
- bound.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq -1,r3
- bound.w r3,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- move.d 0xffff,r4
- move.d r4,r3
- bound.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- move.d 0xfedaffff,r4
- move.d r4,r3
- bound.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- bound.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 f789
-
- moveq -1,r3
- moveq 2,r4
- bound.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- moveq 2,r3
- moveq -1,r4
- bound.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 2
-
- move.d 0xff,r4
- move.d r4,r3
- bound.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 ff
-
- move.d 0xfeda49ff,r4
- move.d r4,r3
- bound.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 ff
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- bound.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 89
-
- move.d 0xfeda4956,r3
- move.d 0xfeda4953,r4
- bound.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 feda4953
-
- move.d 0xfeda4962,r3
- move.d 0xfeda4963,r4
- bound.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 feda4962
-
- move.d 0xfeda4956,r3
- move.d 0,r4
- bound.d r4,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- move.d 0xfeda4956,r4
- move.d 0,r3
- bound.d r4,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_btst.s b/tests/tcg/cris/bare/check_btst.s
deleted file mode 100644
index 485deb2..0000000
--- a/tests/tcg/cris/bare/check_btst.s
+++ /dev/null
@@ -1,96 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 1111\n
-
- .include "testutils.inc"
- start
- clearf nzvc
- moveq -1,r3
- .if 1 ;..asm.arch.cris.v32
- .else
- setf vc
- .endif
- btstq 0,r3
- test_cc 1 0 0 0
-
- moveq 2,r3
- btstq 1,r3
- test_cc 1 0 0 0
-
- moveq 4,r3
- btstq 1,r3
- test_cc 0 1 0 0
-
- moveq -1,r3
- btstq 31,r3
- test_cc 1 0 0 0
-
- move.d 0x5a67f19f,r3
- btstq 12,r3
- test_cc 1 0 0 0
-
- move.d 0xda67f19f,r3
- move.d 29,r4
- btst r4,r3
- test_cc 0 0 0 0
-
- move.d 0xda67f19f,r3
- move.d 32,r4
- btst r4,r3
- test_cc 1 0 0 0
-
- move.d 0xda67f191,r3
- move.d 33,r4
- btst r4,r3
- test_cc 0 0 0 0
-
- moveq -1,r3
- moveq 0,r4
- btst r4,r3
- test_cc 1 0 0 0
-
- moveq 2,r3
- moveq 1,r4
- btst r4,r3
- test_cc 1 0 0 0
-
- moveq -1,r3
- moveq 31,r4
- btst r4,r3
- test_cc 1 0 0 0
-
- moveq 4,r3
- btstq 1,r3
- test_cc 0 1 0 0
-
- moveq -1,r3
- moveq 15,r4
- btst r4,r3
- test_cc 1 0 0 0
-
- move.d 0x5a67f19f,r3
- moveq 12,r4
- btst r4,r3
- test_cc 1 0 0 0
-
- move.d 0x5a678000,r3
- moveq 11,r4
- btst r4,r3
- test_cc 0 1 0 0
-
- move.d 0x5a67f19f,r3
- btst r3,r3
- test_cc 0 0 0 0
-
- move.d 0x1111,r3
- checkr3 1111
-
- ; check that X gets cleared and that only the NZ flags are touched.
- ;; move.d 0xff, $r0
- ;; move $r0, $ccs
- ;; btst r3,r3
- ;; move $ccs, $r0
- ;; and.d 0xff, $r0
- ;; cmp.d 0xe3, $r0
- ;; test_cc 0 1 0 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_clearfv32.s b/tests/tcg/cris/bare/check_clearfv32.s
deleted file mode 100644
index 4e91360..0000000
--- a/tests/tcg/cris/bare/check_clearfv32.s
+++ /dev/null
@@ -1,19 +0,0 @@
-# mach: crisv32
-# output: ef\nef\n
-
-; Check that "clearf x" doesn't trivially fail.
-
- .include "testutils.inc"
- start
- setf puixnzvc
- clearf x ; Actually, x would be cleared by almost-all other insns.
- move ccs,r3
- and.d 0xff, $r3
- checkr3 ef
-
- setf puixnzvc
- moveq 0, $r3 ; moveq should only clear the xflag.
- move ccs,r3
- and.d 0xff, $r3
- checkr3 ef
- quit
diff --git a/tests/tcg/cris/bare/check_clrjmp1.s b/tests/tcg/cris/bare/check_clrjmp1.s
deleted file mode 100644
index 45a7005..0000000
--- a/tests/tcg/cris/bare/check_clrjmp1.s
+++ /dev/null
@@ -1,36 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: ffffff00\n
-
-; A bug resulting in a non-effectual clear.b discovered running the GCC
-; testsuite; jump actually wrote to p0.
-
- .include "testutils.inc"
-
- start
- jump 1f
- nop
- .p2align 8
-1:
- move.d y,r4
-
- .if 0 ;0 == ..asm.arch.cris.v32
-; There was a bug causing this insn to set special register p0
-; (byte-clear) to 8 (low 8 bits of location after insn).
- jump [r4+]
- .endif
-
-1:
- move.d 0f,r4
-
-; The corresponding bug would cause this insn too, to set p0.
- jump r4
- nop
- quit
-0:
- moveq -1,r3
- clear.b r3
- checkr3 ffffff00
- quit
-
-y:
- .dword 1b
diff --git a/tests/tcg/cris/bare/check_cmp-2.s b/tests/tcg/cris/bare/check_cmp-2.s
deleted file mode 100644
index 414d370..0000000
--- a/tests/tcg/cris/bare/check_cmp-2.s
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-.include "testutils.inc"
-
- start
-
- move.d 4294967283, $r0
- move.d $r0, $r10
- cmp.d $r0, $r10
- beq 1f
- move.d $r10, $r3
- fail
-1:
- pass
- quit
diff --git a/tests/tcg/cris/bare/check_cmpc.s b/tests/tcg/cris/bare/check_cmpc.s
deleted file mode 100644
index 267c9ba..0000000
--- a/tests/tcg/cris/bare/check_cmpc.s
+++ /dev/null
@@ -1,86 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: ffffffff\n2\nffff\nffffffff\n78134452\nffffffff\n2\nffff\nfedaffff\n78134452\nffffffff\n2\nff\nfeda49ff\n78134452\n85649282\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- cmp.d -2,r3
- test_cc 0 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- cmp.d 1,r3
- test_cc 0 0 0 0
- checkr3 2
-
- move.d 0xffff,r3
- cmp.d -0xffff,r3
- test_cc 0 0 0 1
- checkr3 ffff
-
- moveq -1,r3
- cmp.d 1,r3
- test_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x78134452,r3
- cmp.d -0x5432f789,r3
- test_cc 1 0 1 1
- checkr3 78134452
-
- moveq -1,r3
- cmp.w -2,r3
- test_cc 0 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- cmp.w 1,r3
- test_cc 0 0 0 0
- checkr3 2
-
- move.d 0xffff,r3
- cmp.w 1,r3
- test_cc 1 0 0 0
- checkr3 ffff
-
- move.d 0xfedaffff,r3
- cmp.w 1,r3
- test_cc 1 0 0 0
- checkr3 fedaffff
-
- move.d 0x78134452,r3
- cmp.w 0x877,r3
- test_cc 0 0 0 0
- checkr3 78134452
-
- moveq -1,r3
- cmp.b -2,r3
- test_cc 0 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- cmp.b 1,r3
- test_cc 0 0 0 0
- checkr3 2
-
- move.d 0xff,r3
- cmp.b 1,r3
- test_cc 1 0 0 0
- checkr3 ff
-
- move.d 0xfeda49ff,r3
- cmp.b 1,r3
- test_cc 1 0 0 0
- checkr3 feda49ff
-
- move.d 0x78134452,r3
- cmp.b 0x77,r3
- test_cc 1 0 0 1
- checkr3 78134452
-
- move.d 0x85649282,r3
- cmp.b 0x82,r3
- test_cc 0 1 0 0
- checkr3 85649282
-
- quit
diff --git a/tests/tcg/cris/bare/check_cmpm.s b/tests/tcg/cris/bare/check_cmpm.s
deleted file mode 100644
index e4dde15..0000000
--- a/tests/tcg/cris/bare/check_cmpm.s
+++ /dev/null
@@ -1,96 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: ffffffff\n2\nffff\nffffffff\n78134452\nffffffff\n2\nffff\nfedaffff\n78134452\nffffffff\n2\nff\nfeda49ff\n78134452\n85649222\n
-
- .include "testutils.inc"
- .data
-x:
- .dword -2,1,-0xffff,1,-0x5432f789
- .word -2,1,1,0x877
- .byte -2,1,0x77
- .byte 0x22
-
- start
- moveq -1,r3
- move.d x,r5
- cmp.d [r5+],r3
- test_cc 0 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- cmp.d [r5],r3
- test_cc 0 0 0 0
- addq 4,r5
- checkr3 2
-
- move.d 0xffff,r3
- cmp.d [r5+],r3
- test_cc 0 0 0 1
- checkr3 ffff
-
- moveq -1,r3
- cmp.d [r5+],r3
- test_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x78134452,r3
- cmp.d [r5+],r3
- test_cc 1 0 1 1
- checkr3 78134452
-
- moveq -1,r3
- cmp.w [r5+],r3
- test_cc 0 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- cmp.w [r5+],r3
- test_cc 0 0 0 0
- checkr3 2
-
- move.d 0xffff,r3
- cmp.w [r5],r3
- test_cc 1 0 0 0
- checkr3 ffff
-
- move.d 0xfedaffff,r3
- cmp.w [r5+],r3
- test_cc 1 0 0 0
- checkr3 fedaffff
-
- move.d 0x78134452,r3
- cmp.w [r5+],r3
- test_cc 0 0 0 0
- checkr3 78134452
-
- moveq -1,r3
- cmp.b [r5],r3
- test_cc 0 0 0 0
- addq 1,r5
- checkr3 ffffffff
-
- moveq 2,r3
- cmp.b [r5],r3
- test_cc 0 0 0 0
- checkr3 2
-
- move.d 0xff,r3
- cmp.b [r5],r3
- test_cc 1 0 0 0
- checkr3 ff
-
- move.d 0xfeda49ff,r3
- cmp.b [r5+],r3
- test_cc 1 0 0 0
- checkr3 feda49ff
-
- move.d 0x78134452,r3
- cmp.b [r5+],r3
- test_cc 1 0 0 1
- checkr3 78134452
-
- move.d 0x85649222,r3
- cmp.b [r5],r3
- test_cc 0 1 0 0
- checkr3 85649222
-
- quit
diff --git a/tests/tcg/cris/bare/check_cmpq.s b/tests/tcg/cris/bare/check_cmpq.s
deleted file mode 100644
index 5469141..0000000
--- a/tests/tcg/cris/bare/check_cmpq.s
+++ /dev/null
@@ -1,75 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: 1\n1\n1\n1f\n1f\nffffffe1\nffffffe1\nffffffe0\n0\n0\nffffffff\nffffffff\n10000\n100\n5678900\n
-
- .include "testutils.inc"
- start
- moveq 1,r3
- cmpq 1,r3
- test_cc 0 1 0 0
- checkr3 1
-
- cmpq -1,r3
- test_cc 0 0 0 1
- checkr3 1
-
- cmpq 31,r3
- test_cc 1 0 0 1
- checkr3 1
-
- moveq 31,r3
- cmpq 31,r3
- test_cc 0 1 0 0
- checkr3 1f
-
- cmpq -31,r3
- test_cc 0 0 0 1
- checkr3 1f
-
- movs.b -31,r3
- cmpq -31,r3
- test_cc 0 1 0 0
- checkr3 ffffffe1
-
- cmpq -32,r3
- test_cc 0 0 0 0
- checkr3 ffffffe1
-
- movs.b -32,r3
- cmpq -32,r3
- test_cc 0 1 0 0
- checkr3 ffffffe0
-
- moveq 0,r3
- cmpq 1,r3
- test_cc 1 0 0 1
- checkr3 0
-
- cmpq -32,r3
- test_cc 0 0 0 1
- checkr3 0
-
- moveq -1,r3
- cmpq 1,r3
- test_cc 1 0 0 0
- checkr3 ffffffff
-
- cmpq -1,r3
- test_cc 0 1 0 0
- checkr3 ffffffff
-
- move.d 0x10000,r3
- cmpq 1,r3
- test_cc 0 0 0 0
- checkr3 10000
-
- move.d 0x100,r3
- cmpq 1,r3
- test_cc 0 0 0 0
- checkr3 100
-
- move.d 0x5678900,r3
- cmpq 7,r3
- test_cc 0 0 0 0
- checkr3 5678900
-
- quit
diff --git a/tests/tcg/cris/bare/check_cmpr.s b/tests/tcg/cris/bare/check_cmpr.s
deleted file mode 100644
index b30af7a..0000000
--- a/tests/tcg/cris/bare/check_cmpr.s
+++ /dev/null
@@ -1,102 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: ffffffff\n2\nffff\nffffffff\n78134452\nffffffff\n2\nffff\nfedaffff\n78134452\nffffffff\n2\nff\nfeda49ff\n78134452\n85649222\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- moveq -2,r4
- cmp.d r4,r3
- test_cc 0 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- moveq 1,r4
- cmp.d r4,r3
- test_cc 0 0 0 0
- checkr3 2
-
- move.d 0xffff,r3
- move.d -0xffff,r4
- cmp.d r4,r3
- test_cc 0 0 0 1
- checkr3 ffff
-
- moveq 1,r4
- moveq -1,r3
- cmp.d r4,r3
- test_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d -0x5432f789,r4
- move.d 0x78134452,r3
- cmp.d r4,r3
- test_cc 1 0 1 1
- checkr3 78134452
-
- moveq -1,r3
- moveq -2,r4
- cmp.w r4,r3
- test_cc 0 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- moveq 1,r4
- cmp.w r4,r3
- test_cc 0 0 0 0
- checkr3 2
-
- move.d 0xffff,r3
- move.d -0xffff,r4
- cmp.w r4,r3
- test_cc 1 0 0 0
- checkr3 ffff
-
- move.d 0xfedaffff,r3
- move.d -0xfedaffff,r4
- cmp.w r4,r3
- test_cc 1 0 0 0
- checkr3 fedaffff
-
- move.d -0x5432f789,r4
- move.d 0x78134452,r3
- cmp.w r4,r3
- test_cc 0 0 0 0
- checkr3 78134452
-
- moveq -1,r3
- moveq -2,r4
- cmp.b r4,r3
- test_cc 0 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- moveq 1,r4
- cmp.b r4,r3
- test_cc 0 0 0 0
- checkr3 2
-
- move.d -0xff,r4
- move.d 0xff,r3
- cmp.b r4,r3
- test_cc 1 0 0 0
- checkr3 ff
-
- move.d -0xfeda49ff,r4
- move.d 0xfeda49ff,r3
- cmp.b r4,r3
- test_cc 1 0 0 0
- checkr3 feda49ff
-
- move.d -0x5432f789,r4
- move.d 0x78134452,r3
- cmp.b r4,r3
- test_cc 1 0 0 1
- checkr3 78134452
-
- move.d 0x85649222,r3
- move.d 0x77445622,r4
- cmp.b r4,r3
- test_cc 0 1 0 0
- checkr3 85649222
-
- quit
diff --git a/tests/tcg/cris/bare/check_cmpxc.s b/tests/tcg/cris/bare/check_cmpxc.s
deleted file mode 100644
index b237a93..0000000
--- a/tests/tcg/cris/bare/check_cmpxc.s
+++ /dev/null
@@ -1,92 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 2\n2\n2\n2\nffff\nffff\nffff\nffff\nffffffff\nffffffff\nffffffff\n78134452\n78134452\n78134452\n78134452\n4452\n80000032\n
-
- .include "testutils.inc"
- start
- moveq 2,r3
- cmps.b 0xff,r3
- test_cc 0 0 0 1
- checkr3 2
-
- moveq 2,r3
- cmps.w 0xffff,r3
- test_cc 0 0 0 1
- checkr3 2
-
- moveq 2,r3
- cmpu.b 0xff,r3
- test_cc 1 0 0 1
- checkr3 2
-
- moveq 2,r3
- move.d 0xffffffff,r4
- cmpu.w -1,r3
- test_cc 1 0 0 1
- checkr3 2
-
- move.d 0xffff,r3
- cmpu.b -1,r3
- test_cc 0 0 0 0
- checkr3 ffff
-
- move.d 0xffff,r3
- cmpu.w -1,r3
- test_cc 0 1 0 0
- checkr3 ffff
-
- move.d 0xffff,r3
- cmps.b 0xff,r3
- test_cc 0 0 0 1
- checkr3 ffff
-
- move.d 0xffff,r3
- cmps.w 0xffff,r3
- test_cc 0 0 0 1
- checkr3 ffff
-
- moveq -1,r3
- cmps.b 0xff,r3
- test_cc 0 1 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- cmps.w 0xff,r3
- test_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- cmps.w 0xffff,r3
- test_cc 0 1 0 0
- checkr3 ffffffff
-
- move.d 0x78134452,r3
- cmpu.b 0x89,r3
- test_cc 0 0 0 0
- checkr3 78134452
-
- move.d 0x78134452,r3
- cmps.b 0x89,r3
- test_cc 0 0 0 1
- checkr3 78134452
-
- move.d 0x78134452,r3
- cmpu.w 0xf789,r3
- test_cc 0 0 0 0
- checkr3 78134452
-
- move.d 0x78134452,r3
- cmps.w 0xf789,r3
- test_cc 0 0 0 1
- checkr3 78134452
-
- move.d 0x4452,r3
- cmps.w 0x8002,r3
- test_cc 0 0 0 1
- checkr3 4452
-
- move.d 0x80000032,r3
- cmpu.w 0x764,r3
- test_cc 0 0 1 0
- checkr3 80000032
-
- quit
diff --git a/tests/tcg/cris/bare/check_cmpxm.s b/tests/tcg/cris/bare/check_cmpxm.s
deleted file mode 100644
index 87ea5bf..0000000
--- a/tests/tcg/cris/bare/check_cmpxm.s
+++ /dev/null
@@ -1,106 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 2\n2\n2\n2\nffff\nffff\nffff\nffff\nffffffff\nffffffff\nffffffff\n78134452\n78134452\n78134452\n78134452\n4452\n80000032\n
-
- .include "testutils.inc"
- .data
-x:
- .byte 0xff
- .word 0xffff
- .word 0xff
- .word 0xffff
- .byte 0x89
- .word 0xf789
- .word 0x8002
- .word 0x764
-
- start
- moveq 2,r3
- move.d x,r5
- cmps.b [r5+],r3
- test_cc 0 0 0 1
- checkr3 2
-
- moveq 2,r3
- cmps.w [r5+],r3
- test_cc 0 0 0 1
- checkr3 2
-
- moveq 2,r3
- subq 3,r5
- cmpu.b [r5+],r3
- test_cc 1 0 0 1
- checkr3 2
-
- moveq 2,r3
- cmpu.w [r5+],r3
- test_cc 1 0 0 1
- subq 3,r5
- checkr3 2
-
- move.d 0xffff,r3
- cmpu.b [r5],r3
- test_cc 0 0 0 0
- checkr3 ffff
-
- move.d 0xffff,r3
- cmpu.w [r5],r3
- test_cc 0 1 0 0
- checkr3 ffff
-
- move.d 0xffff,r3
- cmps.b [r5],r3
- test_cc 0 0 0 1
- checkr3 ffff
-
- move.d 0xffff,r3
- cmps.w [r5],r3
- test_cc 0 0 0 1
- checkr3 ffff
-
- moveq -1,r3
- cmps.b [r5],r3
- test_cc 0 1 0 0
- addq 3,r5
- checkr3 ffffffff
-
- moveq -1,r3
- cmps.w [r5+],r3
- test_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- cmps.w [r5+],r3
- test_cc 0 1 0 0
- checkr3 ffffffff
-
- move.d 0x78134452,r3
- cmpu.b [r5],r3
- test_cc 0 0 0 0
- checkr3 78134452
-
- move.d 0x78134452,r3
- cmps.b [r5+],r3
- test_cc 0 0 0 1
- checkr3 78134452
-
- move.d 0x78134452,r3
- cmpu.w [r5],r3
- test_cc 0 0 0 0
- checkr3 78134452
-
- move.d 0x78134452,r3
- cmps.w [r5+],r3
- test_cc 0 0 0 1
- checkr3 78134452
-
- move.d 0x4452,r3
- cmps.w [r5+],r3
- test_cc 0 0 0 1
- checkr3 4452
-
- move.d 0x80000032,r3
- cmpu.w [r5+],r3
- test_cc 0 0 1 0
- checkr3 80000032
-
- quit
diff --git a/tests/tcg/cris/bare/check_dstep.s b/tests/tcg/cris/bare/check_dstep.s
deleted file mode 100644
index bd43b83..0000000
--- a/tests/tcg/cris/bare/check_dstep.s
+++ /dev/null
@@ -1,42 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: fffffffc\n4\nffff\nfffffffe\n9bf3911b\n0\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- moveq 2,r4
- dstep r4,r3
- test_move_cc 1 0 0 0
- checkr3 fffffffc
-
- moveq 2,r3
- moveq -1,r4
- dstep r4,r3
- test_move_cc 0 0 0 0
- checkr3 4
-
- move.d 0xffff,r4
- move.d r4,r3
- dstep r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- moveq -1,r4
- move.d r4,r3
- dstep r4,r3
- test_move_cc 1 0 0 0
- checkr3 fffffffe
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- dstep r4,r3
- test_move_cc 1 0 0 0
- checkr3 9bf3911b
-
- move.d 0xffff,r3
- move.d 0x1fffe,r4
- dstep r4,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_jsr.s b/tests/tcg/cris/bare/check_jsr.s
deleted file mode 100644
index 1060237..0000000
--- a/tests/tcg/cris/bare/check_jsr.s
+++ /dev/null
@@ -1,85 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: 0\n0\n0\n0\n0\n0\n
-
-# Test that jsr Rn and jsr [PC+] work.
-
- .include "testutils.inc"
- start
-x:
- move.d 0f,r6
- setf nzvc
- jsr r6
- .if 1; ..asm.arch.cris.v32
- nop
- .endif
-0:
- test_move_cc 1 1 1 1
- move srp,r3
- sub.d 0b,r3
- checkr3 0
-
- move.d 1f,r0
- setf nzvc
- jsr r0
- .if 1 ; ..asm.arch.cris.v32
- moveq 0,r0
- .endif
-6:
- nop
- quit
-
-2:
- test_move_cc 0 0 0 0
- move srp,r3
- sub.d 3f,r3
- checkr3 0
- jsr 4f
- .if 1 ; ..asm.arch.cris.v32
- nop
- .endif
-7:
- nop
- quit
-
-8:
- move srp,r3
- sub.d 7b,r3
- checkr3 0
- quit
-
-4:
- move srp,r3
- sub.d 7b,r3
- checkr3 0
- move.d 5f,r3
- jump r3
- .if 1; ..asm.arch.cris.v32
- moveq 0,r3
- .endif
- quit
-
- .space 32770,0
-1:
- test_move_cc 1 1 1 1
- move srp,r3
- sub.d 6b,r3
- checkr3 0
-
- clearf cznv
- jsr 2b
- .if 1; ..asm.arch.cris.v32
- nop
- .endif
-3:
-
- quit
-
-5:
- move srp,r3
- sub.d 7b,r3
- checkr3 0
- jump 8b
- .if 1 ; ..asm.arch.cris.v32
- nop
- .endif
- quit
diff --git a/tests/tcg/cris/bare/check_lapc.s b/tests/tcg/cris/bare/check_lapc.s
deleted file mode 100644
index 9a6150b..0000000
--- a/tests/tcg/cris/bare/check_lapc.s
+++ /dev/null
@@ -1,78 +0,0 @@
-# mach: crisv32
-# output: 0\n0\nfffffffa\nfffffffe\nffffffda\n1e\n1e\n0\n
-
-.include "testutils.inc"
-
-; To accommodate dumpr3 with more than one instruction, keep it
-; out of lapc operand ranges and difference calculations.
-
- start
- lapc.d 0f,r3
-0:
- sub.d .,r3
- checkr3 0
-
- lapcq 0f,r3
-0:
- sub.d .,r3
- checkr3 0
-
- lapc.d .,r3
- sub.d .,r3
- checkr3 fffffffa
-
- lapcq .,r3
- sub.d .,r3
- checkr3 fffffffe
-
-0:
- .rept 16
- nop
- .endr
- lapc.d 0b,r3
- sub.d .,r3
- checkr3 ffffffda
-
- setf zcvn
- lapc.d 0f,r3
- test_cc 1 1 1 1
- sub.d .,r3
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
-0:
- checkr3 1e
-0:
- lapcq 0f,r3
- sub.d 0b,r3
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
-0:
- checkr3 1e
- clearf cn
- setf zv
-1:
- lapcq .,r3
- test_cc 0 1 1 0
- sub.d 1b,r3
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_lsl.s b/tests/tcg/cris/bare/check_lsl.s
deleted file mode 100644
index 9e2ddd7..0000000
--- a/tests/tcg/cris/bare/check_lsl.s
+++ /dev/null
@@ -1,217 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: ffffffff\n4\n80000000\nffff8000\n7f19f000\n80000000\n0\n0\n699fc67c\nffffffff\n4\n80000000\nffff8000\n7f19f000\nda670000\nda670000\nda670000\nda67c67c\nffffffff\nfffafffe\n4\nffff0000\nffff8000\n5a67f000\nda67f100\nda67f100\nda67f100\nda67f17c\nfff3faff\nfff3fafe\n4\nffffff00\nffffff00\nffffff80\n5a67f100\n5a67f1f0\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- lslq 0,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- lslq 1,r3
- test_move_cc 0 0 0 0
- checkr3 4
-
- moveq -1,r3
- lslq 31,r3
- test_move_cc 1 0 0 0
- checkr3 80000000
-
- moveq -1,r3
- lslq 15,r3
- test_move_cc 1 0 0 0
- checkr3 ffff8000
-
- move.d 0x5a67f19f,r3
- lslq 12,r3
- test_move_cc 0 0 0 0
- checkr3 7f19f000
-
- move.d 0xda67f19f,r3
- move.d 31,r4
- lsl.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 80000000
-
- move.d 0xda67f19f,r3
- move.d 32,r4
- lsl.d r4,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- move.d 0xda67f19f,r3
- move.d 33,r4
- lsl.d r4,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- move.d 0xda67f19f,r3
- move.d 66,r4
- lsl.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 699fc67c
-
- moveq -1,r3
- moveq 0,r4
- lsl.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- moveq 1,r4
- lsl.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 4
-
- moveq -1,r3
- moveq 31,r4
- lsl.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 80000000
-
- moveq -1,r3
- moveq 15,r4
- lsl.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffff8000
-
- move.d 0x5a67f19f,r3
- moveq 12,r4
- lsl.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 7f19f000
-
- move.d 0xda67f19f,r3
- move.d 31,r4
- lsl.w r4,r3
- test_move_cc 0 1 0 0
- checkr3 da670000
-
- move.d 0xda67f19f,r3
- move.d 32,r4
- lsl.w r4,r3
- test_move_cc 0 1 0 0
- checkr3 da670000
-
- move.d 0xda67f19f,r3
- move.d 33,r4
- lsl.w r4,r3
- test_move_cc 0 1 0 0
- checkr3 da670000
-
- move.d 0xda67f19f,r3
- move.d 66,r4
- lsl.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 da67c67c
-
- moveq -1,r3
- moveq 0,r4
- lsl.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0xfffaffff,r3
- moveq 1,r4
- lsl.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 fffafffe
-
- moveq 2,r3
- moveq 1,r4
- lsl.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 4
-
- moveq -1,r3
- moveq 31,r4
- lsl.w r4,r3
- test_move_cc 0 1 0 0
- checkr3 ffff0000
-
- moveq -1,r3
- moveq 15,r4
- lsl.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffff8000
-
- move.d 0x5a67f19f,r3
- moveq 12,r4
- lsl.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 5a67f000
-
- move.d 0xda67f19f,r3
- move.d 31,r4
- lsl.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 da67f100
-
- move.d 0xda67f19f,r3
- move.d 32,r4
- lsl.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 da67f100
-
- move.d 0xda67f19f,r3
- move.d 33,r4
- lsl.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 da67f100
-
- move.d 0xda67f19f,r3
- move.d 66,r4
- lsl.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 da67f17c
-
- move.d 0xfff3faff,r3
- moveq 0,r4
- lsl.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 fff3faff
-
- move.d 0xfff3faff,r3
- moveq 1,r4
- lsl.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 fff3fafe
-
- moveq 2,r3
- moveq 1,r4
- lsl.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 4
-
- moveq -1,r3
- moveq 31,r4
- lsl.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 ffffff00
-
- moveq -1,r3
- moveq 15,r4
- lsl.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 ffffff00
-
- moveq -1,r3
- moveq 7,r4
- lsl.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffff80
-
- move.d 0x5a67f19f,r3
- moveq 12,r4
- lsl.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 5a67f100
-
- move.d 0x5a67f19f,r3
- moveq 4,r4
- lsl.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 5a67f1f0
-
- quit
diff --git a/tests/tcg/cris/bare/check_lsr.s b/tests/tcg/cris/bare/check_lsr.s
deleted file mode 100644
index 18fdbef..0000000
--- a/tests/tcg/cris/bare/check_lsr.s
+++ /dev/null
@@ -1,218 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: ffffffff\n1\n1\n1ffff\n5a67f\n1\n0\n0\n3699fc67\nffffffff\n1\n1\n1ffff\n5a67f\nda670000\nda670000\nda670000\nda673c67\nffffffff\nffff7fff\n1\nffff0000\nffff0001\n5a67000f\nda67f100\nda67f100\nda67f100\nda67f127\nffffffff\nffffff7f\n1\nffffff00\nffffff00\nffffff01\n5a67f100\n5a67f109\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- lsrq 0,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- lsrq 1,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
- moveq -1,r3
- lsrq 31,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
- moveq -1,r3
- lsrq 15,r3
- test_move_cc 0 0 0 0
- checkr3 1ffff
-
- move.d 0x5a67f19f,r3
- lsrq 12,r3
- test_move_cc 0 0 0 0
- checkr3 5a67f
-
- move.d 0xda67f19f,r3
- move.d 31,r4
- lsr.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
- move.d 0xda67f19f,r3
- move.d 32,r4
- lsr.d r4,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- move.d 0xda67f19f,r3
- move.d 33,r4
- lsr.d r4,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- move.d 0xda67f19f,r3
- move.d 66,r4
- lsr.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 3699fc67
-
- moveq -1,r3
- moveq 0,r4
- lsr.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq 2,r3
- moveq 1,r4
- lsr.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
- moveq -1,r3
- moveq 31,r4
- lsr.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
- moveq -1,r3
- moveq 15,r4
- lsr.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 1ffff
-
- move.d 0x5a67f19f,r3
- moveq 12,r4
- lsr.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 5a67f
-
- move.d 0xda67f19f,r3
- move.d 31,r4
- lsr.w r4,r3
- test_move_cc 0 1 0 0
- checkr3 da670000
-
- move.d 0xda67f19f,r3
- move.d 32,r4
- lsr.w r4,r3
- test_move_cc 0 1 0 0
- checkr3 da670000
-
- move.d 0xda67f19f,r3
- move.d 33,r4
- lsr.w r4,r3
- test_move_cc 0 1 0 0
- checkr3 da670000
-
- move.d 0xda67f19f,r3
- move.d 66,r4
- lsr.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 da673c67
-
- moveq -1,r3
- moveq 0,r4
- lsr.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 1,r4
- lsr.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffff7fff
-
- moveq 2,r3
- moveq 1,r4
- lsr.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
-;; FIXME: this was wrong. Z should be set.
- moveq -1,r3
- moveq 31,r4
- lsr.w r4,r3
- test_move_cc 0 1 0 0
- checkr3 ffff0000
-
- moveq -1,r3
- moveq 15,r4
- lsr.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffff0001
-
- move.d 0x5a67f19f,r3
- moveq 12,r4
- lsr.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 5a67000f
-
- move.d 0xda67f19f,r3
- move.d 31,r4
- lsr.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 da67f100
-
- move.d 0xda67f19f,r3
- move.d 32,r4
- lsr.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 da67f100
-
- move.d 0xda67f19f,r3
- move.d 33,r4
- lsr.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 da67f100
-
- move.d 0xda67f19f,r3
- move.d 66,r4
- lsr.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 da67f127
-
- moveq -1,r3
- moveq 0,r4
- lsr.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 1,r4
- lsr.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffffff7f
-
- moveq 2,r3
- moveq 1,r4
- lsr.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
- moveq -1,r3
- moveq 31,r4
- lsr.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 ffffff00
-
- moveq -1,r3
- moveq 15,r4
- lsr.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 ffffff00
-
- moveq -1,r3
- moveq 7,r4
- lsr.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffffff01
-
- move.d 0x5a67f19f,r3
- moveq 12,r4
- lsr.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 5a67f100
-
- move.d 0x5a67f19f,r3
- moveq 4,r4
- lsr.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 5a67f109
-
- quit
diff --git a/tests/tcg/cris/bare/check_mcp.s b/tests/tcg/cris/bare/check_mcp.s
deleted file mode 100644
index e65ccdd..0000000
--- a/tests/tcg/cris/bare/check_mcp.s
+++ /dev/null
@@ -1,49 +0,0 @@
-# mach: crisv32
-# output: fffffffe\n1\n1ffff\nfffffffe\ncc463bdc\n4c463bdc\n0\n
-
- .include "testutils.inc"
- start
-
-; Set R, clear C.
- move 0x100,ccs
- moveq -5,r3
- move 2,mof
- mcp mof,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
-
- moveq 2,r3
- move -1,srp
- mcp srp,r3
- test_cc 0 0 0 0
- checkr3 1
-
- move 0xffff,srp
- move srp,r3
- mcp srp,r3
- test_cc 0 0 0 0
- checkr3 1ffff
-
- move -1,mof
- move mof,r3
- mcp mof,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
-
- move 0x5432f789,mof
- move.d 0x78134452,r3
- mcp mof,r3
- test_cc 1 0 1 0
- checkr3 cc463bdc
-
- move 0x80000000,srp
- mcp srp,r3
- test_cc 0 0 1 0
- checkr3 4c463bdc
-
- move 0xb3b9c423,srp
- mcp srp,r3
- test_cc 0 1 0 0
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_movdelsr1.s b/tests/tcg/cris/bare/check_movdelsr1.s
deleted file mode 100644
index 300cc87..0000000
--- a/tests/tcg/cris/bare/check_movdelsr1.s
+++ /dev/null
@@ -1,33 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: aa117acd\n
-# output: eeaabb42\n
-
-; Bug with move to special register in delay slot, due to
-; special flush-insn-cache simulator use. Ordinary move worked;
-; special register caused branch to fail.
-
- .include "testutils.inc"
- start
- move -1,srp
-
- move.d 0xaa117acd,r1
- moveq 3,r9
- cmpq 1,r9
- bhi 0f
- move.d r1,r3
-
- fail
-0:
- checkr3 aa117acd
-
- move.d 0xeeaabb42,r1
- moveq 3,r9
- cmpq 1,r9
- bhi 0f
- move r1,srp
-
- fail
-0:
- move srp,r3
- checkr3 eeaabb42
- quit
diff --git a/tests/tcg/cris/bare/check_movecr.s b/tests/tcg/cris/bare/check_movecr.s
deleted file mode 100644
index da8ec26..0000000
--- a/tests/tcg/cris/bare/check_movecr.s
+++ /dev/null
@@ -1,37 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: ffffff42\n94\nffff4321\n9234\n76543210\n76540000\n
-
-; Move constant byte, word, dword to register. Check that no extension is
-; performed, that only part of the register is set.
-
- .include "testutils.inc"
- startnostack
- moveq -1,r3
- move.b 0x42,r3
- test_move_cc 0 0 0 0
- checkr3 ffffff42
-
- moveq 0,r3
- move.b 0x94,r3
- test_move_cc 1 0 0 0
- checkr3 94
-
- moveq -1,r3
- move.w 0x4321,r3
- test_move_cc 0 0 0 0
- checkr3 ffff4321
-
- moveq 0,r3
- move.w 0x9234,r3
- test_move_cc 1 0 0 0
- checkr3 9234
-
- move.d 0x76543210,r3
- test_move_cc 0 0 0 0
- checkr3 76543210
-
- move.w 0,r3
- test_move_cc 0 1 0 0
- checkr3 76540000
-
- quit
diff --git a/tests/tcg/cris/bare/check_movei.s b/tests/tcg/cris/bare/check_movei.s
deleted file mode 100644
index bbfa633..0000000
--- a/tests/tcg/cris/bare/check_movei.s
+++ /dev/null
@@ -1,50 +0,0 @@
-# mach: crisv32
-# output: fffffffe\n
-# output: fffffffe\n
-
-; Check basic integral-write semantics regarding flags.
-
- .include "testutils.inc"
- start
-
- move.d 0, $r3
-; A write that works. Check that flags are set correspondingly.
- move.d d,r4
- ;; store to bring it into the tlb with the right prot bits
- move.d r3,[r4]
- moveq -2,r5
- setf c
- clearf p
- move.d [r4],r3
- ax
- move.d r5,[r4]
- move.d [r4],r3
-
- bcc 0f
- nop
- fail
-
-0:
- checkr3 fffffffe
-
-; A write that fails; check flags too.
- move.d d,r4
- moveq 23,r5
- setf p
- clearf c
- move.d [r4],r3
- ax
- move.d r5,[r4]
- move.d [r4],r3
-
- bcs 0f
- nop
- fail
-
-0:
- checkr3 fffffffe
- quit
-
- .data
-d:
- .dword 42424242
diff --git a/tests/tcg/cris/bare/check_movemr.s b/tests/tcg/cris/bare/check_movemr.s
deleted file mode 100644
index 88489de..0000000
--- a/tests/tcg/cris/bare/check_movemr.s
+++ /dev/null
@@ -1,78 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: 12345678\n10234567\n12345678\n12344567\n12344523\n76543210\nffffffaa\naa\n9911\nffff9911\n78\n56\n3456\n6712\n
-
- .include "testutils.inc"
- start
-
- .data
-mem1:
- .dword 0x12345678
-mem2:
- .word 0x4567
-mem3:
- .byte 0x23
- .dword 0x76543210
- .byte 0xaa,0x11,0x99
-
- .text
- move.d mem1,r2
- move.d [r2],r3
- test_move_cc 0 0 0 0
- checkr3 12345678
-
- move.d mem2,r3
- move.d [r3],r3
- test_move_cc 0 0 0 0
- checkr3 10234567
-
- move.d mem1,r2
- move.d [r2+],r3
- test_move_cc 0 0 0 0
- checkr3 12345678
-
- move.w [r2+],r3
- test_move_cc 0 0 0 0
- checkr3 12344567
-
- move.b [r2+],r3
- test_move_cc 0 0 0 0
- checkr3 12344523
-
- move.d [r2+],r3
- test_move_cc 0 0 0 0
- checkr3 76543210
-
- movs.b [r2],r3
- test_move_cc 1 0 0 0
- checkr3 ffffffaa
-
- movu.b [r2+],r3
- test_move_cc 0 0 0 0
- checkr3 aa
-
- movu.w [r2],r3
- test_move_cc 0 0 0 0
- checkr3 9911
-
- movs.w [r2+],r3
- test_move_cc 1 0 0 0
- checkr3 ffff9911
-
- move.d mem1,r13
- movs.b [r13+],r3
- test_move_cc 0 0 0 0
- checkr3 78
-
- movu.b [r13],r3
- test_move_cc 0 0 0 0
- checkr3 56
-
- movs.w [r13+],r3
- test_move_cc 0 0 0 0
- checkr3 3456
-
- movu.w [r13+],r3
- test_move_cc 0 0 0 0
- checkr3 6712
-
- quit
diff --git a/tests/tcg/cris/bare/check_movemrv32.s b/tests/tcg/cris/bare/check_movemrv32.s
deleted file mode 100644
index 53950ab..0000000
--- a/tests/tcg/cris/bare/check_movemrv32.s
+++ /dev/null
@@ -1,96 +0,0 @@
-# mach: crisv32
-# output: 15\n7\n2\nffff1234\nb\n16\nf\n2\nffffffef\nf\nffff1234\nf\nfffffff4\nd\nfffffff2\n10\nfffffff2\nd\n
-
- .include "testutils.inc"
- .data
-x:
- .dword 8,9,10,11
-y:
- .dword -12,13,-14,15,16
-
- start
- moveq 7,r0
- moveq 2,r1
- move.d 0xffff1234,r2
- moveq 21,r3
- move.d x,r4
- setf zcvn
- movem r2,[r4+]
- test_cc 1 1 1 1
- subq 12,r4
-
- checkr3 15
-
- move.d [r4+],r3
- checkr3 7
-
- move.d [r4+],r3
- checkr3 2
-
- move.d [r4+],r3
- checkr3 ffff1234
-
- move.d [r4+],r3
- checkr3 b
-
- subq 16,r4
- moveq 22,r0
- moveq 15,r1
- clearf zcvn
- movem r0,[r4]
- test_cc 0 0 0 0
- move.d [r4+],r3
- checkr3 16
-
- move.d r1,r3
- checkr3 f
-
- move.d [r4+],r3
- checkr3 2
-
- subq 8,r4
- moveq 10,r2
- moveq -17,r0
- clearf zc
- setf vn
- movem r1,[r4]
- test_cc 1 0 1 0
- move.d [r4+],r3
- checkr3 ffffffef
-
- move.d [r4+],r3
- checkr3 f
-
- move.d [r4+],r3
- checkr3 ffff1234
-
- move.d y,r4
- setf zc
- clearf vn
- movem [r4+],r3
- test_cc 0 1 0 1
- checkr3 f
-
- move.d r0,r3
- checkr3 fffffff4
-
- move.d r1,r3
- checkr3 d
-
- move.d r2,r3
- checkr3 fffffff2
-
- move.d [r4],r3
- checkr3 10
-
- subq 8,r4
- setf zcvn
- movem [r4+],r0
- test_cc 1 1 1 1
- move.d r0,r3
- checkr3 fffffff2
-
- move.d r1,r3
- checkr3 d
-
- quit
diff --git a/tests/tcg/cris/bare/check_mover.s b/tests/tcg/cris/bare/check_mover.s
deleted file mode 100644
index b4db595..0000000
--- a/tests/tcg/cris/bare/check_mover.s
+++ /dev/null
@@ -1,28 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: ffffff05\nffff0005\n5\nffffff00\n
-
-; Move between registers. Check that just the subreg is copied.
-
- .include "testutils.inc"
- startnostack
- moveq -30,r3
- moveq 5,r4
- move.b r4,r3
- test_move_cc 0 0 0 0 ; FIXME
- checkr3 ffffff05
-
- move.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffff0005
-
- move.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 5
-
- moveq -1,r3
- moveq 0,r4
- move.b r4,r3
- test_move_cc 0 1 0 0
- checkr3 ffffff00
-
- quit
diff --git a/tests/tcg/cris/bare/check_moverm.s b/tests/tcg/cris/bare/check_moverm.s
deleted file mode 100644
index eabc958..0000000
--- a/tests/tcg/cris/bare/check_moverm.s
+++ /dev/null
@@ -1,45 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: 7823fec2\n10231879\n102318fe\n
-
- .include "testutils.inc"
- start
-
- .data
-mem1:
- .dword 0x12345678
-mem2:
- .word 0x4567
-mem3:
- .byte 0x23
- .dword 0x76543210
- .byte 0xaa,0x11,0x99
-
- .text
- move.d mem1,r2
- move.d 0x7823fec2,r4
- setf nzvc
- move.d r4,[r2+]
- test_cc 1 1 1 1
- subq 4,r2
- move.d [r2],r3
- checkr3 7823fec2
-
- move.d mem2,r3
- move.d 0x45231879,r4
- clearf nzvc
- move.w r4,[r3]
- test_cc 0 0 0 0
- move.d [r3],r3
- checkr3 10231879
-
- move.d mem2,r2
- moveq -2,r4
- clearf nc
- setf zv
- move.b r4,[r2+]
- test_cc 0 1 1 0
- subq 1,r2
- move.d [r2],r3
- checkr3 102318fe
-
- quit
diff --git a/tests/tcg/cris/bare/check_movmp.s b/tests/tcg/cris/bare/check_movmp.s
deleted file mode 100644
index 7fc11f0..0000000
--- a/tests/tcg/cris/bare/check_movmp.s
+++ /dev/null
@@ -1,131 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: ffffff00\nffff0000\n0\nffffff00\nffff0000\n0\nffffff00\nffff0000\n0\nbb113344\n664433aa\ncc557788\nabcde012\nabcde000\n77880000\n0\n
-
-# Test generic "move Ps,[]" and "move [],Pd" insns; the ones with
-# functionality common to all models.
-
- .include "testutils.inc"
- start
-
- .data
-filler:
- .byte 0xaa
- .word 0x4433
- .dword 0x55778866
- .byte 0xcc
-
- .text
-; Test that writing to zero-registers is a nop
- .if 0
- ; We used to just ignore the writes, but now an error is emitted. We
- ; keep the test-code but disabled, in case we need to change this again.
- move 0xaa,p0
- move 0x4433,p4
- move 0x55774433,p8
- .endif
-
- moveq -1,r3
- setf zcvn
- clear.b r3
- test_cc 1 1 1 1
- checkr3 ffffff00
-
- moveq -1,r3
- clearf zcvn
- clear.w r3
- test_cc 0 0 0 0
- checkr3 ffff0000
-
- moveq -1,r3
- clear.d r3
- checkr3 0
-
-; "Write" using ordinary memory references too.
- .if 0 ; See ".if 0" above.
- move.d filler,r6
- move [r6],p0
- move [r6],p4
- move [r6],p8
- .endif
-
-# ffffff00\nffff0000\n0\nffffff00\nffff0000\n0\nbb113344\n664433aa\ncc557788\nabcde012\nabcde000\n77880000\n0\n
-
- moveq -1,r3
- clear.b r3
- checkr3 ffffff00
-
- moveq -1,r3
- clear.w r3
- checkr3 ffff0000
-
- moveq -1,r3
- clear.d r3
- checkr3 0
-
-; And postincremented.
- .if 0 ; See ".if 0" above.
- move [r6+],p0
- move [r6+],p4
- move [r6+],p8
- .endif
-
-# ffffff00\nffff0000\n0\nbb113344\n664433aa\ncc557788\nabcde012\nabcde000\n77880000\n0\n
-
- moveq -1,r3
- clear.b r3
- checkr3 ffffff00
-
- moveq -1,r3
- clear.w r3
- checkr3 ffff0000
-
- moveq -1,r3
- clear.d r3
- checkr3 0
-
-; Now see that we can write to the registers too.
-# bb113344\n664433aa\ncc557788\nabcde012\nabcde000\n77880000\n0\n
-; [PC+]
- move.d filler,r9
- move 0xbb113344,srp
- move srp,r3
- checkr3 bb113344
-
-; [R+]
- move [r9+],srp
- move srp,r3
- checkr3 664433aa
-
-; [R]
- move [r9],srp
- move srp,r3
- checkr3 cc557788
-
-; And check writing to memory, clear and srp.
-
- move.d filler,r9
- move 0xabcde012,srp
- setf zcvn
- move srp,[r9+]
- test_cc 1 1 1 1
- subq 4,r9
- move.d [r9],r3
- checkr3 abcde012
-
- clearf zcvn
- clear.b [r9]
- test_cc 0 0 0 0
- move.d [r9],r3
- checkr3 abcde000
-
- addq 2,r9
- clear.w [r9+]
- subq 2,r9
- move.d [r9],r3
- checkr3 77880000
-
- clear.d [r9]
- move.d [r9],r3
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_movpmv32.s b/tests/tcg/cris/bare/check_movpmv32.s
deleted file mode 100644
index daf0970..0000000
--- a/tests/tcg/cris/bare/check_movpmv32.s
+++ /dev/null
@@ -1,35 +0,0 @@
-# mach: crisv32
-# output: 11223320\nbb113344\naa557711\n
-
-# Test v32-specific special registers. FIXME: more registers.
-
- .include "testutils.inc"
- start
- .data
-store:
- .dword 0x11223344
- .dword 0x77665544
-
- .text
- moveq -1,r3
- move.d store,r4
- move vr,[r4]
- move [r4+],mof
- move mof,r3
- checkr3 11223320
-
- moveq -1,r3
- clearf zcvn
- move 0xbb113344,mof
- test_cc 0 0 0 0
- move mof,r3
- checkr3 bb113344
-
- setf zcvn
- move 0xaa557711,mof
- test_cc 1 1 1 1
- move mof,[r4]
- move.d [r4],r3
- checkr3 aa557711
-
- quit
diff --git a/tests/tcg/cris/bare/check_movpr.s b/tests/tcg/cris/bare/check_movpr.s
deleted file mode 100644
index eef9bdb..0000000
--- a/tests/tcg/cris/bare/check_movpr.s
+++ /dev/null
@@ -1,28 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: ffffff00\nffff0000\n0\nbb113344\n
-
-# Test generic "move Ps,Rd" and "move Rs,Pd" insns; the ones with
-# functionality common to all models.
-
- .include "testutils.inc"
- start
- moveq -1,r3
- clear.b r3
- checkr3 ffffff00
-
- moveq -1,r3
- clear.w r3
- checkr3 ffff0000
-
- moveq -1,r3
- clear.d r3
- checkr3 0
-
- moveq -1,r3
- move.d 0xbb113344,r4
- setf zcvn
- move r4,srp
- move srp,r3
- test_cc 1 1 1 1
- checkr3 bb113344
- quit
diff --git a/tests/tcg/cris/bare/check_movprv32.s b/tests/tcg/cris/bare/check_movprv32.s
deleted file mode 100644
index d0d90e1..0000000
--- a/tests/tcg/cris/bare/check_movprv32.s
+++ /dev/null
@@ -1,21 +0,0 @@
-# mach: crisv32
-# output: ffffff20\nbb113344\n
-
-# Test v32-specific special registers. FIXME: more registers.
-
- .include "testutils.inc"
- start
- moveq -1,r3
- setf zcvn
- move vr,r3
- test_cc 1 1 1 1
- checkr3 ffffff20
-
- moveq -1,r3
- move.d 0xbb113344,r4
- clearf cvnz
- move r4,mof
- test_cc 0 0 0 0
- move mof,r3
- checkr3 bb113344
- quit
diff --git a/tests/tcg/cris/bare/check_movscr.s b/tests/tcg/cris/bare/check_movscr.s
deleted file mode 100644
index 53c8ce6..0000000
--- a/tests/tcg/cris/bare/check_movscr.s
+++ /dev/null
@@ -1,29 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: 42\nffffff85\n7685\nffff8765\n0\n
-
-; Move constant byte, word, dword to register. Check that sign-extension
-; is performed.
-
- .include "testutils.inc"
- start
- moveq -1,r3
- movs.b 0x42,r3
- checkr3 42
-
- movs.b 0x85,r3
- test_move_cc 1 0 0 0
- checkr3 ffffff85
-
- movs.w 0x7685,r3
- test_move_cc 0 0 0 0
- checkr3 7685
-
- movs.w 0x8765,r3
- test_move_cc 1 0 0 0
- checkr3 ffff8765
-
- movs.w 0,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_movsm.s b/tests/tcg/cris/bare/check_movsm.s
deleted file mode 100644
index 7074336..0000000
--- a/tests/tcg/cris/bare/check_movsm.s
+++ /dev/null
@@ -1,44 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: 5\nfffffff5\n5\nfffffff5\n0\n
-
-; Movs between registers. Check that sign-extension is performed and the
-; full register is set.
-
- .include "testutils.inc"
-
- .data
-x:
- .byte 5,-11
- .word 5,-11
- .word 0
-
- start
- move.d x,r5
-
- moveq -1,r3
- movs.b [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 5
-
- moveq 0,r3
- movs.b [r5],r3
- test_move_cc 1 0 0 0
- addq 1,r5
- checkr3 fffffff5
-
- moveq -1,r3
- movs.w [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 5
-
- moveq 0,r3
- movs.w [r5],r3
- test_move_cc 1 0 0 0
- addq 2,r5
- checkr3 fffffff5
-
- movs.w [r5],r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_movsr.s b/tests/tcg/cris/bare/check_movsr.s
deleted file mode 100644
index d1889a7..0000000
--- a/tests/tcg/cris/bare/check_movsr.s
+++ /dev/null
@@ -1,46 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: 5\nfffffff5\n5\nfffffff5\n0\n
-
-; Movs between registers. Check that sign-extension is performed and the
-; full register is set.
-
- .include "testutils.inc"
- start
- moveq -1,r5
- moveq 5,r4
- move.b r4,r5
- moveq -1,r3
- movs.b r5,r3
- test_move_cc 0 0 0 0
- checkr3 5
-
- moveq 0,r5
- moveq -11,r4
- move.b r4,r5
- moveq 0,r3
- movs.b r5,r3
- test_move_cc 1 0 0 0
- checkr3 fffffff5
-
- moveq -1,r5
- moveq 5,r4
- move.w r4,r5
- moveq -1,r3
- movs.w r5,r3
- test_move_cc 0 0 0 0
- checkr3 5
-
- moveq 0,r5
- moveq -11,r4
- move.w r4,r5
- moveq 0,r3
- movs.w r5,r3
- test_move_cc 1 0 0 0
- checkr3 fffffff5
-
- moveq 0,r5
- movs.b r5,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_movucr.s b/tests/tcg/cris/bare/check_movucr.s
deleted file mode 100644
index 7c8487d..0000000
--- a/tests/tcg/cris/bare/check_movucr.s
+++ /dev/null
@@ -1,33 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: 42\n85\n7685\n8765\n0\n
-
-; Move constant byte, word, dword to register. Check that zero-extension
-; is performed.
-
- .include "testutils.inc"
- start
- moveq -1,r3
- movu.b 0x42,r3
- test_move_cc 0 0 0 0
- checkr3 42
-
- moveq -1,r3
- movu.b 0x85,r3
- test_move_cc 0 0 0 0
- checkr3 85
-
- moveq -1,r3
- movu.w 0x7685,r3
- test_move_cc 0 0 0 0
- checkr3 7685
-
- moveq -1,r3
- movu.w 0x8765,r3
- test_move_cc 0 0 0 0
- checkr3 8765
-
- movu.b 0,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_movum.s b/tests/tcg/cris/bare/check_movum.s
deleted file mode 100644
index 038e539..0000000
--- a/tests/tcg/cris/bare/check_movum.s
+++ /dev/null
@@ -1,40 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: 5\nf5\n5\nfff5\n0\n
-
-; Movu between registers. Check that zero-extension is performed and the
-; full register is set.
-
- .include "testutils.inc"
-
- .data
-x:
- .byte 5,-11
- .word 5,-11
- .word 0
-
- start
- move.d x,r5
-
- movu.b [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 5
-
- movu.b [r5],r3
- test_move_cc 0 0 0 0
- addq 1,r5
- checkr3 f5
-
- movu.w [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 5
-
- movu.w [r5],r3
- test_move_cc 0 0 0 0
- addq 2,r5
- checkr3 fff5
-
- movu.w [r5],r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_movur.s b/tests/tcg/cris/bare/check_movur.s
deleted file mode 100644
index 3ecf475..0000000
--- a/tests/tcg/cris/bare/check_movur.s
+++ /dev/null
@@ -1,45 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: 5\nf5\n5\nfff5\n0\n
-
-; Movu between registers. Check that zero-extension is performed and the
-; full register is set.
-
- .include "testutils.inc"
- start
- moveq -1,r5
- moveq 5,r4
- move.b r4,r5
- moveq -1,r3
- movu.b r5,r3
- test_move_cc 0 0 0 0
- checkr3 5
-
- moveq 0,r5
- moveq -11,r4
- move.b r4,r5
- moveq -1,r3
- movu.b r5,r3
- test_move_cc 0 0 0 0
- checkr3 f5
-
- moveq -1,r5
- moveq 5,r4
- move.w r4,r5
- moveq -1,r3
- movu.w r5,r3
- test_move_cc 0 0 0 0
- checkr3 5
-
- moveq 0,r5
- moveq -11,r4
- move.w r4,r5
- moveq -1,r3
- movu.w r5,r3
- test_move_cc 0 0 0 0
- checkr3 fff5
-
- movu.w 0,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_mulv32.s b/tests/tcg/cris/bare/check_mulv32.s
deleted file mode 100644
index f379358..0000000
--- a/tests/tcg/cris/bare/check_mulv32.s
+++ /dev/null
@@ -1,51 +0,0 @@
-# mach: crisv32
-# output: fffffffe\n
-# output: ffffffff\n
-# output: fffffffe\n
-# output: 1\n
-# output: fffffffe\n
-# output: ffffffff\n
-# output: fffffffe\n
-# output: 1\n
-
-; Check that carry is not modified on v32.
-
- .include "testutils.inc"
- start
- moveq -1,r3
- moveq 2,r4
- setf c
- muls.d r4,r3
- test_cc 1 0 0 1
- checkr3 fffffffe
- move mof,r3
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 2,r4
- setf c
- mulu.d r4,r3
- test_cc 0 0 1 1
- checkr3 fffffffe
- move mof,r3
- checkr3 1
-
- moveq -1,r3
- moveq 2,r4
- clearf c
- muls.d r4,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
- move mof,r3
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 2,r4
- clearf c
- mulu.d r4,r3
- test_cc 0 0 1 0
- checkr3 fffffffe
- move mof,r3
- checkr3 1
-
- quit
diff --git a/tests/tcg/cris/bare/check_mulx.s b/tests/tcg/cris/bare/check_mulx.s
deleted file mode 100644
index a7a1f82..0000000
--- a/tests/tcg/cris/bare/check_mulx.s
+++ /dev/null
@@ -1,257 +0,0 @@
-# mach: crisv10 crisv32
-# output: fffffffe\nffffffff\nfffffffe\n1\nfffffffe\nffffffff\nfffffffe\n1\nfffe0001\n0\nfffe0001\n0\n1\n0\n1\nfffffffe\n193eade2\n277e3a49\n193eade2\n277e3a49\nfffffffe\nffffffff\n1fffe\n0\nfffffffe\nffffffff\n1fffe\n0\n1\n0\nfffe0001\n0\nfdbdade2\nffffffff\n420fade2\n0\nfffffffe\nffffffff\n1fe\n0\nfffffffe\nffffffff\n1fe\n0\n1\n0\nfe01\n0\n1\n0\nfe01\n0\nffffd9e2\nffffffff\n2be2\n0\n0\n0\n0\n0\n
-
- .include "testutils.inc"
- start
-
- .align 4
- moveq -1,r3
- moveq 2,r4
- muls.d r4,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
- move mof,r3
- checkr3 ffffffff
-
- .align 4
- moveq -1,r3
- moveq 2,r4
- mulu.d r4,r3
- test_cc 0 0 1 0
- checkr3 fffffffe
- move mof,r3
- checkr3 1
-
- .align 4
- moveq 2,r3
- moveq -1,r4
- muls.d r4,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
- move mof,r3
- checkr3 ffffffff
-
- .align 4
- moveq 2,r3
- moveq -1,r4
- mulu.d r4,r3
- test_cc 0 0 1 0
- checkr3 fffffffe
- move mof,r3
- checkr3 1
-
- move.d 0xffff,r4
- move.d r4,r3
- muls.d r4,r3
- test_cc 0 0 1 0
- checkr3 fffe0001
- move mof,r3
- checkr3 0
-
- move.d 0xffff,r4
- move.d r4,r3
- mulu.d r4,r3
- test_cc 0 0 0 0
- checkr3 fffe0001
- move mof,r3
- checkr3 0
-
- moveq -1,r4
- move.d r4,r3
- muls.d r4,r3
- test_cc 0 0 0 0
- checkr3 1
- move mof,r3
- checkr3 0
-
- moveq -1,r4
- move.d r4,r3
- mulu.d r4,r3
- test_cc 1 0 1 0
- checkr3 1
- move mof,r3
- checkr3 fffffffe
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- muls.d r4,r3
- test_cc 0 0 1 0
- checkr3 193eade2
- move mof,r3
- checkr3 277e3a49
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- mulu.d r4,r3
- test_cc 0 0 1 0
- checkr3 193eade2
- move mof,r3
- checkr3 277e3a49
-
- move.d 0xffff,r3
- moveq 2,r4
- muls.w r4,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
- move mof,r3
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 2,r4
- mulu.w r4,r3
- test_cc 0 0 0 0
- checkr3 1fffe
- move mof,r3
- checkr3 0
- nop
-
- moveq 2,r3
- move.d 0xffff,r4
- muls.w r4,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
- move mof,r3
- checkr3 ffffffff
-
- moveq 2,r3
- moveq -1,r4
- mulu.w r4,r3
- test_cc 0 0 0 0
- checkr3 1fffe
- move mof,r3
- checkr3 0
-
- move.d 0xffff,r4
- move.d r4,r3
- muls.w r4,r3
- test_cc 0 0 0 0
- checkr3 1
- move mof,r3
- checkr3 0
-
- moveq -1,r4
- move.d r4,r3
- mulu.w r4,r3
- test_cc 0 0 0 0
- checkr3 fffe0001
- move mof,r3
- checkr3 0
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- muls.w r4,r3
- test_cc 1 0 0 0
- checkr3 fdbdade2
- move mof,r3
- checkr3 ffffffff
- nop
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- mulu.w r4,r3
- test_cc 0 0 0 0
- checkr3 420fade2
- move mof,r3
- checkr3 0
- nop
-
- move.d 0xff,r3
- moveq 2,r4
- muls.b r4,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
- move mof,r3
- checkr3 ffffffff
-
- moveq -1,r3
- moveq 2,r4
- mulu.b r4,r3
- test_cc 0 0 0 0
- checkr3 1fe
- move mof,r3
- checkr3 0
-
- moveq 2,r3
- moveq -1,r4
- muls.b r4,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
- move mof,r3
- checkr3 ffffffff
-
- moveq 2,r3
- moveq -1,r4
- mulu.b r4,r3
- test_cc 0 0 0 0
- checkr3 1fe
- move mof,r3
- checkr3 0
-
- move.d 0xff,r4
- move.d r4,r3
- muls.b r4,r3
- test_cc 0 0 0 0
- checkr3 1
- move mof,r3
- checkr3 0
- nop
-
- moveq -1,r4
- move.d r4,r3
- mulu.b r4,r3
- test_cc 0 0 0 0
- checkr3 fe01
- move mof,r3
- checkr3 0
- nop
-
- move.d 0xfeda49ff,r4
- move.d r4,r3
- muls.b r4,r3
- test_cc 0 0 0 0
- checkr3 1
- move mof,r3
- checkr3 0
- nop
-
- move.d 0xfeda49ff,r4
- move.d r4,r3
- mulu.b r4,r3
- test_cc 0 0 0 0
- checkr3 fe01
- move mof,r3
- checkr3 0
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- muls.b r4,r3
- test_cc 1 0 0 0
- checkr3 ffffd9e2
- move mof,r3
- checkr3 ffffffff
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- mulu.b r4,r3
- test_cc 0 0 0 0
- checkr3 2be2
- move mof,r3
- checkr3 0
-
- moveq 0,r3
- move.d 0xf87f4aeb,r4
- muls.d r4,r3
- test_cc 0 1 0 0
- checkr3 0
- move mof,r3
- checkr3 0
-
- move.d 0xf87f4aeb,r3
- moveq 0,r4
- mulu.d r4,r3
- test_cc 0 1 0 0
- checkr3 0
- move mof,r3
- checkr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_neg.s b/tests/tcg/cris/bare/check_neg.s
deleted file mode 100644
index 963c4b6..0000000
--- a/tests/tcg/cris/bare/check_neg.s
+++ /dev/null
@@ -1,104 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: ffffffff\nffffffff\n0\n80000000\n1\nba987655\nffff\nffff\n0\n89ab8000\nffff0001\n45677655\nff\nff\n0\n89abae80\nffffff01\n45678955\n
-
- .include "testutils.inc"
- start
- moveq 0,r3
- moveq 1,r4
- neg.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq 1,r3
- moveq 0,r4
- neg.d r3,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
-;; FIXME: this was wrong.
- moveq 0,r3
- neg.d r3,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- move.d 0x80000000,r3
- neg.d r3,r3
- test_move_cc 1 0 0 0
- checkr3 80000000
-
- moveq -1,r3
- neg.d r3,r3
- test_move_cc 0 0 0 0
- checkr3 1
-
- move.d 0x456789ab,r3
- neg.d r3,r3
- test_move_cc 1 0 0 0
- checkr3 ba987655
-
- moveq 0,r3
- moveq 1,r4
- neg.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffff
-
- moveq 1,r3
- moveq 0,r4
- neg.w r3,r3
- test_move_cc 1 0 0 0
- checkr3 ffff
-
- moveq 0,r3
- neg.w r3,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- move.d 0x89ab8000,r3
- neg.w r3,r3
- test_move_cc 1 0 0 0
- checkr3 89ab8000
-
- moveq -1,r3
- neg.w r3,r3
- test_move_cc 0 0 0 0
- checkr3 ffff0001
-
- move.d 0x456789ab,r3
- neg.w r3,r3
- test_move_cc 0 0 0 0
- checkr3 45677655
-
- moveq 0,r3
- moveq 1,r4
- neg.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 ff
-
- moveq 1,r3
- moveq 0,r4
- neg.b r3,r3
- test_move_cc 1 0 0 0
- checkr3 ff
-
- moveq 0,r3
- neg.b r3,r3
- test_move_cc 0 1 0 0
- checkr3 0
-
-;; FIXME: was wrong.
- move.d 0x89abae80,r3
- neg.b r3,r3
- test_move_cc 1 0 0 1
- checkr3 89abae80
-
- moveq -1,r3
- neg.b r3,r3
- test_move_cc 0 0 0 0
- checkr3 ffffff01
-
- move.d 0x456789ab,r3
- neg.b r3,r3
- test_move_cc 0 0 0 0
- checkr3 45678955
-
- quit
diff --git a/tests/tcg/cris/bare/check_not.s b/tests/tcg/cris/bare/check_not.s
deleted file mode 100644
index 33bcf15..0000000
--- a/tests/tcg/cris/bare/check_not.s
+++ /dev/null
@@ -1,31 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: fffffffe\nfffffffd\nffff0f00\n0\n87ecbbad\n
-
- .include "testutils.inc"
- start
- moveq 1,r3
- not r3
- test_move_cc 1 0 0 0
- checkr3 fffffffe
-
- moveq 2,r3
- not r3
- test_move_cc 1 0 0 0
- checkr3 fffffffd
-
- move.d 0xf0ff,r3
- not r3
- test_move_cc 1 0 0 0
- checkr3 ffff0f00
-
- moveq -1,r3
- not r3
- test_move_cc 0 1 0 0
- checkr3 0
-
- move.d 0x78134452,r3
- not r3
- test_move_cc 1 0 0 0
- checkr3 87ecbbad
-
- quit
diff --git a/tests/tcg/cris/bare/check_orc.s b/tests/tcg/cris/bare/check_orc.s
deleted file mode 100644
index c733f03..0000000
--- a/tests/tcg/cris/bare/check_orc.s
+++ /dev/null
@@ -1,71 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 3\n3\nffff\nffffffff\n7c33f7db\nffff0003\n3\nfedaffff\n7813f7db\n3\n3\nfeb\n781344db\n
-
- .include "testutils.inc"
- start
- moveq 1,r3
- or.d 2,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- moveq 2,r3
- or.d 1,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- move.d 0xf0ff,r3
- or.d 0xff0f,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- moveq -1,r3
- or.d -1,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x78134452,r3
- or.d 0x5432f789,r3
- test_move_cc 0 0 0 0
- checkr3 7c33f7db
-
- move.d 0xffff0001,r3
- or.w 2,r3
- test_move_cc 0 0 0 0
- checkr3 ffff0003
-
- moveq 2,r3
- or.w 1,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- move.d 0xfedaffaf,r3
- or.w 0xff5f,r3
- test_move_cc 1 0 0 0
- checkr3 fedaffff
-
- move.d 0x78134452,r3
- or.w 0xf789,r3
- test_move_cc 1 0 0 0
- checkr3 7813f7db
-
- moveq 1,r3
- or.b 2,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- moveq 2,r3
- or.b 1,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- move.d 0xfa3,r3
- or.b 0x4a,r3
- test_move_cc 1 0 0 0
- checkr3 feb
-
- move.d 0x78134453,r3
- or.b 0x89,r3
- test_move_cc 1 0 0 0
- checkr3 781344db
-
- quit
diff --git a/tests/tcg/cris/bare/check_orm.s b/tests/tcg/cris/bare/check_orm.s
deleted file mode 100644
index ee723a6..0000000
--- a/tests/tcg/cris/bare/check_orm.s
+++ /dev/null
@@ -1,75 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 3\n3\nffff\nffffffff\n7c33f7db\nffff0003\n3\nfedaffff\n7813f7db\n3\n3\nfeb\n781344db\n
-
- .include "testutils.inc"
- .data
-x:
- .dword 2,1,0xff0f,-1,0x5432f789
- .word 2,1,0xff5f,0xf789
- .byte 2,1,0x4a,0x89
-
- start
- moveq 1,r3
- move.d x,r5
- or.d [r5+],r3
- checkr3 3
-
- moveq 2,r3
- or.d [r5],r3
- addq 4,r5
- checkr3 3
-
- move.d 0xf0ff,r3
- or.d [r5+],r3
- checkr3 ffff
-
- moveq -1,r3
- or.d [r5+],r3
- checkr3 ffffffff
-
- move.d 0x78134452,r3
- or.d [r5+],r3
- checkr3 7c33f7db
-
- move.d 0xffff0001,r3
- or.w [r5+],r3
- checkr3 ffff0003
-
- moveq 2,r3
- or.w [r5],r3
- addq 2,r5
- test_move_cc 0 0 0 0
- checkr3 3
-
- move.d 0xfedaffaf,r3
- or.w [r5+],r3
- test_move_cc 1 0 0 0
- checkr3 fedaffff
-
- move.d 0x78134452,r3
- or.w [r5+],r3
- test_move_cc 1 0 0 0
- checkr3 7813f7db
-
- moveq 1,r3
- or.b [r5+],r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- moveq 2,r3
- or.b [r5],r3
- addq 1,r5
- test_move_cc 0 0 0 0
- checkr3 3
-
- move.d 0xfa3,r3
- or.b [r5+],r3
- test_move_cc 1 0 0 0
- checkr3 feb
-
- move.d 0x78134453,r3
- or.b [r5],r3
- test_move_cc 1 0 0 0
- checkr3 781344db
-
- quit
diff --git a/tests/tcg/cris/bare/check_orq.s b/tests/tcg/cris/bare/check_orq.s
deleted file mode 100644
index 5060edc..0000000
--- a/tests/tcg/cris/bare/check_orq.s
+++ /dev/null
@@ -1,41 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 3\n3\nffffffff\nffffffff\n1f\nffffffe0\n7813445e\n
-
- .include "testutils.inc"
- start
- moveq 1,r3
- orq 2,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- moveq 2,r3
- orq 1,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- move.d 0xf0ff,r3
- orq -1,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq 0,r3
- orq -1,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- moveq 0,r3
- orq 31,r3
- test_move_cc 0 0 0 0
- checkr3 1f
-
- moveq 0,r3
- orq -32,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffe0
-
- move.d 0x78134452,r3
- orq 12,r3
- test_move_cc 0 0 0 0
- checkr3 7813445e
-
- quit
diff --git a/tests/tcg/cris/bare/check_orr.s b/tests/tcg/cris/bare/check_orr.s
deleted file mode 100644
index a514c11..0000000
--- a/tests/tcg/cris/bare/check_orr.s
+++ /dev/null
@@ -1,84 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 3\n3\nffff\nffffffff\n7c33f7db\nffff0003\n3\nfedaffff\n7813f7db\n3\n3\nfeb\n781344db\n
-
- .include "testutils.inc"
- start
- moveq 1,r3
- moveq 2,r4
- or.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- moveq 2,r3
- moveq 1,r4
- or.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- move.d 0xff0f,r4
- move.d 0xf0ff,r3
- or.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffff
-
- moveq -1,r4
- move.d r4,r3
- or.d r4,r3
- test_move_cc 1 0 0 0
- checkr3 ffffffff
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- or.d r4,r3
- test_move_cc 0 0 0 0
- checkr3 7c33f7db
-
- move.d 0xffff0001,r3
- moveq 2,r4
- or.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 ffff0003
-
- moveq 2,r3
- move.d 0xffff0001,r4
- or.w r4,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- move.d 0xfedaffaf,r3
- move.d 0xffffff5f,r4
- or.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 fedaffff
-
- move.d 0x5432f789,r4
- move.d 0x78134452,r3
- or.w r4,r3
- test_move_cc 1 0 0 0
- checkr3 7813f7db
-
- moveq 1,r3
- move.d 0xffffff02,r4
- or.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- moveq 2,r3
- moveq 1,r4
- or.b r4,r3
- test_move_cc 0 0 0 0
- checkr3 3
-
- move.d 0x4a,r4
- move.d 0xfa3,r3
- or.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 feb
-
- move.d 0x5432f789,r4
- move.d 0x78134453,r3
- or.b r4,r3
- test_move_cc 1 0 0 0
- checkr3 781344db
-
- quit
diff --git a/tests/tcg/cris/bare/check_ret.s b/tests/tcg/cris/bare/check_ret.s
deleted file mode 100644
index b44fb25..0000000
--- a/tests/tcg/cris/bare/check_ret.s
+++ /dev/null
@@ -1,25 +0,0 @@
-# mach: crisv3 crisv8 crisv10
-# output: 3\n
-
-# Test that ret works.
-
- .include "testutils.inc"
- start
-x:
- moveq 0,r3
- jsr z
-w:
- quit
-y:
- addq 1,r3
- checkr3 3
- quit
-
-z:
- addq 1,r3
- move srp,r2
- add.d y-w,r2
- move r2,srp
- ret
- addq 1,r3
- quit
diff --git a/tests/tcg/cris/bare/check_scc.s b/tests/tcg/cris/bare/check_scc.s
deleted file mode 100644
index 4a8674c..0000000
--- a/tests/tcg/cris/bare/check_scc.s
+++ /dev/null
@@ -1,95 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 1\n0\n1\n0\n1\n0\n1\n0\n0\n1\n1\n0\n1\n0\n1\n0\n1\n0\n0\n1\n0\n1\n1\n0\n1\n0\n0\n1\n1\n0\n1\n1\n0\n
-
- .include "testutils.inc"
-
- .macro lcheckr3 v
- move $ccs, $r9
- checkr3 \v
- move $r9, $ccs
- .endm
-
- start
- clearf nzvc
- scc r3
- lcheckr3 1
- scs r3
- lcheckr3 0
- sne r3
- lcheckr3 1
- seq r3
- lcheckr3 0
- svc r3
- lcheckr3 1
- svs r3
- lcheckr3 0
- spl r3
- lcheckr3 1
- smi r3
- lcheckr3 0
- sls r3
- lcheckr3 0
- shi r3
- lcheckr3 1
- sge r3
- lcheckr3 1
- slt r3
- lcheckr3 0
- sgt r3
- lcheckr3 1
- sle r3
- lcheckr3 0
- sa r3
- lcheckr3 1
- setf nzvc
- scc r3
- lcheckr3 0
- scs r3
- lcheckr3 1
- sne r3
- lcheckr3 0
- svc r3
- lcheckr3 0
- svs r3
- lcheckr3 1
- spl r3
- lcheckr3 0
- smi r3
- lcheckr3 1
- sls r3
- lcheckr3 1
- shi r3
- lcheckr3 0
- sge r3
- lcheckr3 1
- slt r3
- lcheckr3 0
- sgt r3
- lcheckr3 0
- sle r3
- lcheckr3 1
- sa r3
- lcheckr3 1
- clearf n
- sge r3
- lcheckr3 0
- slt r3
- lcheckr3 1
-
- .if 1 ;..asm.arch.cris.v32
- setf p
- ssb r3
- .else
- moveq 1,r3
- .endif
- lcheckr3 1
-
- .if 1 ;..asm.arch.cris.v32
- clearf p
- ssb r3
- .else
- moveq 0,r3
- .endif
- lcheckr3 0
-
- quit
diff --git a/tests/tcg/cris/bare/check_subc.s b/tests/tcg/cris/bare/check_subc.s
deleted file mode 100644
index e34b544..0000000
--- a/tests/tcg/cris/bare/check_subc.s
+++ /dev/null
@@ -1,87 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n85649200\n
-
- .include "testutils.inc"
- start
-
- moveq -1,r3
- sub.d -2,r3
- test_cc 0 0 0 0
- checkr3 1
-
- moveq 2,r3
- sub.d 1,r3
- test_cc 0 0 0 0
- checkr3 1
-
- move.d 0xffff,r3
- sub.d -0xffff,r3
- test_cc 0 0 0 1
- checkr3 1fffe
-
- moveq -1,r3
- sub.d 1,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
-
- move.d 0x78134452,r3
- sub.d -0x5432f789,r3
- test_cc 1 0 1 1
- checkr3 cc463bdb
-
- moveq -1,r3
- sub.w -2,r3
- test_cc 0 0 0 0
- checkr3 ffff0001
-
- moveq 2,r3
- sub.w 1,r3
- test_cc 0 0 0 0
- checkr3 1
-
- move.d 0xffff,r3
- sub.w 1,r3
- test_cc 1 0 0 0
- checkr3 fffe
-
- move.d 0xfedaffff,r3
- sub.w 1,r3
- test_cc 1 0 0 0
- checkr3 fedafffe
-
- move.d 0x78134452,r3
- sub.w 0x877,r3
- test_cc 0 0 0 0
- checkr3 78133bdb
-
- moveq -1,r3
- sub.b -2,r3
- test_cc 0 0 0 0
- checkr3 ffffff01
-
- moveq 2,r3
- sub.b 1,r3
- test_cc 0 0 0 0
- checkr3 1
-
- move.d 0xff,r3
- sub.b 1,r3
- test_cc 1 0 0 0
- checkr3 fe
-
- move.d 0xfeda49ff,r3
- sub.b 1,r3
- test_cc 1 0 0 0
- checkr3 feda49fe
-
- move.d 0x78134452,r3
- sub.b 0x77,r3
- test_cc 1 0 0 1
- checkr3 781344db
-
- move.d 0x85649282,r3
- sub.b 0x82,r3
- test_cc 0 1 0 0
- checkr3 85649200
-
- quit
diff --git a/tests/tcg/cris/bare/check_subm.s b/tests/tcg/cris/bare/check_subm.s
deleted file mode 100644
index e07ea02..0000000
--- a/tests/tcg/cris/bare/check_subm.s
+++ /dev/null
@@ -1,96 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n85649200\n
-
- .include "testutils.inc"
- .data
-x:
- .dword -2,1,-0xffff,1,-0x5432f789
- .word -2,1,1,0x877
- .byte -2,1,0x77
- .byte 0x22
-
- start
- moveq -1,r3
- move.d x,r5
- sub.d [r5+],r3
- test_cc 0 0 0 0
- checkr3 1
-
- moveq 2,r3
- sub.d [r5],r3
- test_cc 0 0 0 0
- addq 4,r5
- checkr3 1
-
- move.d 0xffff,r3
- sub.d [r5+],r3
- test_cc 0 0 0 1
- checkr3 1fffe
-
- moveq -1,r3
- sub.d [r5+],r3
- test_cc 1 0 0 0
- checkr3 fffffffe
-
- move.d 0x78134452,r3
- sub.d [r5+],r3
- test_cc 1 0 1 1
- checkr3 cc463bdb
-
- moveq -1,r3
- sub.w [r5+],r3
- test_cc 0 0 0 0
- checkr3 ffff0001
-
- moveq 2,r3
- sub.w [r5+],r3
- test_cc 0 0 0 0
- checkr3 1
-
- move.d 0xffff,r3
- sub.w [r5],r3
- test_cc 1 0 0 0
- checkr3 fffe
-
- move.d 0xfedaffff,r3
- sub.w [r5+],r3
- test_cc 1 0 0 0
- checkr3 fedafffe
-
- move.d 0x78134452,r3
- sub.w [r5+],r3
- test_cc 0 0 0 0
- checkr3 78133bdb
-
- moveq -1,r3
- sub.b [r5],r3
- test_cc 0 0 0 0
- addq 1,r5
- checkr3 ffffff01
-
- moveq 2,r3
- sub.b [r5],r3
- test_cc 0 0 0 0
- checkr3 1
-
- move.d 0xff,r3
- sub.b [r5],r3
- test_cc 1 0 0 0
- checkr3 fe
-
- move.d 0xfeda49ff,r3
- sub.b [r5+],r3
- test_cc 1 0 0 0
- checkr3 feda49fe
-
- move.d 0x78134452,r3
- sub.b [r5+],r3
- test_cc 1 0 0 1
- checkr3 781344db
-
- move.d 0x85649222,r3
- sub.b [r5],r3
- test_cc 0 1 0 0
- checkr3 85649200
-
- quit
diff --git a/tests/tcg/cris/bare/check_subq.s b/tests/tcg/cris/bare/check_subq.s
deleted file mode 100644
index 9e34fa3..0000000
--- a/tests/tcg/cris/bare/check_subq.s
+++ /dev/null
@@ -1,52 +0,0 @@
-# mach: crisv3 crisv8 crisv10 crisv32
-# output: 0\nffffffff\nfffffffe\nffff\nff\n56788f9\n56788d9\n567889a\n0\n7ffffffc\n
-
- .include "testutils.inc"
- start
- moveq 1,r3
- subq 1,r3
- test_cc 0 1 0 0
- checkr3 0
-
- subq 1,r3
- test_cc 1 0 0 1
- checkr3 ffffffff
-
- subq 1,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
-
- move.d 0x10000,r3
- subq 1,r3
- test_cc 0 0 0 0
- checkr3 ffff
-
- move.d 0x100,r3
- subq 1,r3
- test_cc 0 0 0 0
- checkr3 ff
-
- move.d 0x5678900,r3
- subq 7,r3
- test_cc 0 0 0 0
- checkr3 56788f9
-
- subq 32,r3
- test_cc 0 0 0 0
- checkr3 56788d9
-
- subq 63,r3
- test_cc 0 0 0 0
- checkr3 567889a
-
- move.d 34,r3
- subq 34,r3
- test_cc 0 1 0 0
- checkr3 0
-
- move.d 0x80000024,r3
- subq 40,r3
- test_cc 0 0 1 0
- checkr3 7ffffffc
-
- quit
diff --git a/tests/tcg/cris/bare/check_subr.s b/tests/tcg/cris/bare/check_subr.s
deleted file mode 100644
index 742fbc8..0000000
--- a/tests/tcg/cris/bare/check_subr.s
+++ /dev/null
@@ -1,102 +0,0 @@
-# mach: crisv0 crisv3 crisv8 crisv10 crisv32
-# output: 1\n1\n1fffe\nfffffffe\ncc463bdb\nffff0001\n1\nfffe\nfedafffe\n78133bdb\nffffff01\n1\nfe\nfeda49fe\n781344db\n85649200\n
-
- .include "testutils.inc"
- start
- moveq -1,r3
- moveq -2,r4
- sub.d r4,r3
- test_cc 0 0 0 0
- checkr3 1
-
- moveq 2,r3
- moveq 1,r4
- sub.d r4,r3
- test_cc 0 0 0 0
- checkr3 1
-
- move.d 0xffff,r3
- move.d -0xffff,r4
- sub.d r4,r3
- test_cc 0 0 0 1
- checkr3 1fffe
-
- moveq 1,r4
- moveq -1,r3
- sub.d r4,r3
- test_cc 1 0 0 0
- checkr3 fffffffe
-
- move.d -0x5432f789,r4
- move.d 0x78134452,r3
- sub.d r4,r3
- test_cc 1 0 1 1
- checkr3 cc463bdb
-
- moveq -1,r3
- moveq -2,r4
- sub.w r4,r3
- test_cc 0 0 0 0
- checkr3 ffff0001
-
- moveq 2,r3
- moveq 1,r4
- sub.w r4,r3
- test_cc 0 0 0 0
- checkr3 1
-
- move.d 0xffff,r3
- move.d -0xffff,r4
- sub.w r4,r3
- test_cc 1 0 0 0
- checkr3 fffe
-
- move.d 0xfedaffff,r3
- move.d -0xfedaffff,r4
- sub.w r4,r3
- test_cc 1 0 0 0
- checkr3 fedafffe
-
- move.d -0x5432f789,r4
- move.d 0x78134452,r3
- sub.w r4,r3
- test_cc 0 0 0 0
- checkr3 78133bdb
-
- moveq -1,r3
- moveq -2,r4
- sub.b r4,r3
- test_cc 0 0 0 0
- checkr3 ffffff01
-
- moveq 2,r3
- moveq 1,r4
- sub.b r4,r3
- test_cc 0 0 0 0
- checkr3 1
-
- move.d -0xff,r4
- move.d 0xff,r3
- sub.b r4,r3
- test_cc 1 0 0 0
- checkr3 fe
-
- move.d -0xfeda49ff,r4
- move.d 0xfeda49ff,r3
- sub.b r4,r3
- test_cc 1 0 0 0
- checkr3 feda49fe
-
- move.d -0x5432f789,r4
- move.d 0x78134452,r3
- sub.b r4,r3
- test_cc 1 0 0 1
- checkr3 781344db
-
- move.d 0x85649222,r3
- move.d 0x77445622,r4
- sub.b r4,r3
- test_cc 0 1 0 0
- checkr3 85649200
-
- quit
diff --git a/tests/tcg/cris/bare/check_xarith.s b/tests/tcg/cris/bare/check_xarith.s
deleted file mode 100644
index 80038b2..0000000
--- a/tests/tcg/cris/bare/check_xarith.s
+++ /dev/null
@@ -1,72 +0,0 @@
-
-.include "testutils.inc"
-
- start
-
- moveq -1, $r0
- moveq 0, $r1
- addq 1, $r0
- ax
- addq 0, $r1
-
- move.d $r0, $r3
- checkr3 0
- move.d $r1, $r3
- checkr3 1
-
- move.d 0, $r0
- moveq -1, $r1
- subq 1, $r0
- ax
- subq 0, $r1
-
- move.d $r0, $r3
- checkr3 ffffffff
- move.d $r1, $r3
- checkr3 fffffffe
-
-
- moveq -1, $r0
- moveq -1, $r1
- cmpq -1, $r0
- ax
- cmpq -1, $r1
- beq 1f
- nop
- fail
-1:
- cmpq 0, $r0
- ax
- cmpq -1, $r1
- bne 1f
- nop
- fail
-1:
-
- ;; test for broken X sequence, run it several times.
- moveq 8, $r0
-1:
- moveq 0, $r3
- move.d $r0, $r1
- andq 1, $r1
- lslq 4, $r1
- moveq 1, $r2
- or.d $r1, $r2
- ba 2f
- move $r2, $ccs
-2:
- addq 0, $r3
- move.d $r0, $r4
- move.d $r1, $r5
- move.d $r2, $r6
- move.d $r3, $r7
- lsrq 4, $r1
- move.d $r1, $r8
- xor $r1, $r3
- checkr3 0
- subq 1, $r0
- bne 1b
- nop
-
- pass
- quit
diff --git a/tests/tcg/cris/bare/crt.s b/tests/tcg/cris/bare/crt.s
deleted file mode 100644
index af027d7..0000000
--- a/tests/tcg/cris/bare/crt.s
+++ /dev/null
@@ -1,13 +0,0 @@
- .data
-_stack_start:
- .space 8192, 0
-_stack_end:
- .text
- .global _start
-_start:
- move.d _stack_end, $sp
- jsr main
- nop
- moveq 0, $r10
- jump exit
- nop
diff --git a/tests/tcg/cris/bare/sys.c b/tests/tcg/cris/bare/sys.c
deleted file mode 100644
index 1644eec..0000000
--- a/tests/tcg/cris/bare/sys.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Helper functions for CRIS system tests
- *
- * There is no libc and only a limited set of headers.
- */
-
-#include <stddef.h>
-
-void exit(int status)
-{
- register unsigned int callno asm ("r9") = 1; /* NR_exit */
-
- asm volatile ("break 13\n"
- : /* no outputs */
- : "r" (callno)
- : "memory");
- while (1) {
- /* do nothing */
- };
-}
-
-size_t write(int fd, const void *buf, size_t count)
-{
- register unsigned int callno asm ("r9") = 4; /* NR_write */
- register unsigned int r10 asm ("r10") = fd;
- register const void *r11 asm ("r11") = buf;
- register size_t r12 asm ("r12") = count;
- register unsigned int r asm ("r10");
-
- asm volatile ("break 13\n"
- : "=r" (r)
- : "r" (callno), "0" (r10), "r" (r11), "r" (r12)
- : "memory");
-
- return r;
-}
-
-static inline int mystrlen(char *s)
-{
- int i = 0;
- while (s[i]) {
- i++;
- }
- return i;
-}
-
-
-void pass(void)
-{
- char s[] = "passed.\n";
- write(1, s, sizeof(s) - 1);
- exit(0);
-}
-
-void _fail(char *reason)
-{
- char s[] = "\nfailed: ";
- int len = mystrlen(reason);
- write(1, s, sizeof(s) - 1);
- write(1, reason, len);
- write(1, "\n", 1);
- exit(1);
-}
diff --git a/tests/tcg/cris/bare/testutils.inc b/tests/tcg/cris/bare/testutils.inc
deleted file mode 100644
index aa1641b..0000000
--- a/tests/tcg/cris/bare/testutils.inc
+++ /dev/null
@@ -1,117 +0,0 @@
- .syntax no_register_prefix
-
- .macro start
- .text
- .global main
-main:
- .endm
-
- .macro quit
- jump pass
- nop
- .endm
-
- .macro pass
- jump pass
- nop
- .endm
-
- .macro startnostack
- start
- .endm
-
- .macro fail
- .data
-99:
- .asciz " checkr3 failed\n"
- .text
- move.d 99b, $r10
- jsr _fail
- nop
- .endm
-
- .macro checkr3 val
- cmp.d 0x\val, $r3
- beq 100f
- nop
- .data
-99:
- .asciz "checkr3 failed\n"
- .text
- move.d 99b, $r10
- jsr _fail
- nop
-100:
- .endm
-
-; Test the condition codes
- .macro test_cc N Z V C
- .if \N
- bpl 9f
- nop
- .else
- bmi 9f
- nop
- .endif
- .if \Z
- bne 9f
- nop
- .else
- beq 9f
- nop
- .endif
- .if \V
- bvc 9f
- nop
- .else
- bvs 9f
- nop
- .endif
- .if \C
- bcc 9f
- nop
- .else
- bcs 9f
- nop
- .endif
- ba 8f
- nop
-9:
- .data
-99:
- .asciz "test_move_cc failed\n"
- .text
- move.d 99b, $r10
- jsr _fail
- nop
-8:
- .endm
-
-
- .macro test_move_cc N Z V C
- .if \N
- bpl 9f
- nop
- .else
- bmi 9f
- nop
- .endif
- .if \Z
- bne 9f
- nop
- .else
- beq 9f
- nop
- .endif
- ba 8f
- nop
-9:
- .data
-99:
- .asciz "test_move_cc failed\n"
- .text
- move.d 99b, $r10
- jsr _fail
- nop
-8:
- .endm
diff --git a/tests/tcg/cris/libc/check_abs.c b/tests/tcg/cris/libc/check_abs.c
deleted file mode 100644
index 08b67b6..0000000
--- a/tests/tcg/cris/libc/check_abs.c
+++ /dev/null
@@ -1,40 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-#include "crisutils.h"
-
-static always_inline int cris_abs(int n)
-{
- int r;
- asm ("abs\t%1, %0\n" : "=r" (r) : "r" (n));
- return r;
-}
-
-static always_inline void
-verify_abs(int val, int res,
- const int n, const int z, const int v, const int c)
-{
- int r;
-
- cris_tst_cc_init();
- r = cris_abs(val);
- cris_tst_cc(n, z, v, c);
- if (r != res)
- err();
-}
-
-int main(void)
-{
- verify_abs(-1, 1, 0, 0, 0, 0);
- verify_abs(0x80000000, 0x80000000, 1, 0, 0, 0);
- verify_abs(0x7fffffff, 0x7fffffff, 0, 0, 0, 0);
- verify_abs(42, 42, 0, 0, 0, 0);
- verify_abs(1, 1, 0, 0, 0, 0);
- verify_abs(0xffff, 0xffff, 0, 0, 0, 0);
- verify_abs(0xffff, 0xffff, 0, 0, 0, 0);
- verify_abs(-31, 0x1f, 0, 0, 0, 0);
- verify_abs(0, 0, 0, 1, 0, 0);
- pass();
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_addc.c b/tests/tcg/cris/libc/check_addc.c
deleted file mode 100644
index fc3fb1f..0000000
--- a/tests/tcg/cris/libc/check_addc.c
+++ /dev/null
@@ -1,58 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-#include "crisutils.h"
-
-static always_inline int cris_addc(int a, const int b)
-{
- asm ("addc\t%1, %0\n" : "+r" (a) : "r" (b));
- return a;
-}
-
-#define verify_addc(a, b, res, n, z, v, c) \
-{ \
- int r; \
- r = cris_addc((a), (b)); \
- cris_tst_cc((n), (z), (v), (c)); \
- if (r != (res)) \
- err(); \
-}
-
-int main(void)
-{
- cris_tst_cc_init();
- asm volatile ("clearf cz");
- verify_addc(0, 0, 0, 0, 0, 0, 0);
-
- cris_tst_cc_init();
- asm volatile ("setf z");
- verify_addc(0, 0, 0, 0, 1, 0, 0);
-
- cris_tst_cc_init();
- asm volatile ("setf cz");
- verify_addc(0, 0, 1, 0, 0, 0, 0);
- cris_tst_cc_init();
- asm volatile ("clearf c");
- verify_addc(-1, 2, 1, 0, 0, 0, 1);
-
- cris_tst_cc_init();
- asm volatile ("clearf nzv");
- asm volatile ("setf c");
- verify_addc(-1, 2, 2, 0, 0, 0, 1);
-
- cris_tst_cc_init();
- asm volatile ("setf c");
- verify_addc(0xffff, 0xffff, 0x1ffff, 0, 0, 0, 0);
-
- cris_tst_cc_init();
- asm volatile ("clearf nzvc");
- verify_addc(-1, -1, 0xfffffffe, 1, 0, 0, 1);
-
- cris_tst_cc_init();
- asm volatile ("setf c");
- verify_addc(0x78134452, 0x5432f789, 0xcc463bdc, 1, 0, 1, 0);
-
- pass();
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_addcm.c b/tests/tcg/cris/libc/check_addcm.c
deleted file mode 100644
index b355ba1..0000000
--- a/tests/tcg/cris/libc/check_addcm.c
+++ /dev/null
@@ -1,85 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-#include "crisutils.h"
-
-/* need to avoid acr as source here. */
-static always_inline int cris_addc_m(int a, const int *b)
-{
- asm volatile ("addc [%1], %0\n" : "+r" (a) : "r" (b));
- return a;
-}
-
-/* 'b' is a crisv32 constrain to avoid postinc with $acr. */
-static always_inline int cris_addc_pi_m(int a, int **b)
-{
- asm volatile ("addc [%1+], %0\n" : "+r" (a), "+b" (*b));
- return a;
-}
-
-#define verify_addc_m(a, b, res, n, z, v, c) \
-{ \
- int r; \
- r = cris_addc_m((a), (b)); \
- cris_tst_cc((n), (z), (v), (c)); \
- if (r != (res)) \
- err(); \
-}
-
-#define verify_addc_pi_m(a, b, res, n, z, v, c) \
-{ \
- int r; \
- r = cris_addc_pi_m((a), (b)); \
- cris_tst_cc((n), (z), (v), (c)); \
- if (r != (res)) \
- err(); \
-}
-
-int x[] = { 0, 0, 2, -1, 0xffff, -1, 0x5432f789};
-
-int main(void)
-{
- int *p = (void *)&x[0];
-#if 1
- cris_tst_cc_init();
- asm volatile ("clearf cz");
- verify_addc_m(0, p, 0, 0, 0, 0, 0);
-
- cris_tst_cc_init();
- asm volatile ("setf z");
- verify_addc_m(0, p, 0, 0, 1, 0, 0);
-
- cris_tst_cc_init();
- asm volatile ("setf c");
- verify_addc_m(0, p, 1, 0, 0, 0, 0);
-
- cris_tst_cc_init();
- asm volatile ("clearf c");
- verify_addc_pi_m(0, &p, 0, 0, 1, 0, 0);
-
- p = &x[1];
- cris_tst_cc_init();
- asm volatile ("setf c");
- verify_addc_pi_m(0, &p, 1, 0, 0, 0, 0);
-
- if (p != &x[2])
- err();
-
- cris_tst_cc_init();
- asm volatile ("clearf c");
- verify_addc_pi_m(-1, &p, 1, 0, 0, 0, 1);
-
- if (p != &x[3])
- err();
-#endif
- p = &x[3];
- /* TODO: investigate why this one fails. */
- cris_tst_cc_init();
- asm volatile ("setf c");
- verify_addc_m(2, p, 2, 0, 0, 0, 1);
- p += 4;
-
- pass();
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_addo.c b/tests/tcg/cris/libc/check_addo.c
deleted file mode 100644
index 4235e5f..0000000
--- a/tests/tcg/cris/libc/check_addo.c
+++ /dev/null
@@ -1,125 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-#include "crisutils.h"
-
-/* this would be better to do in asm, it's an orgy in GCC inline asm now. */
-
-#define cris_addo_b(o, v) \
- asm volatile ("addo.b\t[%0], %1, $acr\n" : : "r" (o), "r" (v) : "acr");
-#define cris_addo_w(o, v) \
- asm volatile ("addo.w\t[%0], %1, $acr\n" : : "r" (o), "r" (v) : "acr");
-#define cris_addo_d(o, v) \
- asm volatile ("addo.d\t[%0], %1, $acr\n" : : "r" (o), "r" (v) : "acr");
-#define cris_addo_pi_b(o, v) \
- asm volatile ("addo.b\t[%0+], %1, $acr\n" \
- : "+b" (o): "r" (v) : "acr");
-#define cris_addo_pi_w(o, v) \
- asm volatile ("addo.w\t[%0+], %1, $acr\n" \
- : "+b" (o): "r" (v) : "acr");
-#define cris_addo_pi_d(o, v) \
- asm volatile ("addo.d\t[%0+], %1, $acr\n" \
- : "+b" (o): "r" (v) : "acr");
-
-struct {
- uint32_t v1;
- uint16_t v2;
- uint32_t v3;
- uint8_t v4;
- uint8_t v5;
- uint16_t v6;
- uint32_t v7;
-} y = {
- 32769,
- -1,
- 5,
- 3, -4,
- 2,
- -76789887
-};
-
-static int x[3] = {0x55aa77ff, 0xccff2244, 0x88ccee19};
-
-int main(void)
-{
- int *r;
- unsigned char *t, *p;
-
- /* Note, this test-case will trig an unaligned access, partly
- to x[0] and to [x1]. */
- t = (unsigned char *)x;
- t -= 32768;
- p = (unsigned char *) &y.v1;
- mb(); /* don't reorder anything beyond here. */
- cris_tst_cc_init();
- asm volatile ("setf\tzvnc\n");
- cris_addo_pi_d(p, t);
- cris_tst_cc(1, 1, 1, 1);
- asm volatile ("move.d\t$acr, %0\n" : "=r" (r));
- if (*r != 0x4455aa77)
- err();
-
-
- t += 32770;
- mb(); /* don't reorder anything beyond here. */
- cris_tst_cc_init();
- asm volatile ("setf\tzvnc\n");
- cris_addo_pi_w(p, t);
- cris_tst_cc(1, 1, 1, 1);
- asm volatile ("move.d\t$acr, %0\n" : "=r" (r));
- if (*r != 0x4455aa77)
- err();
-
- mb(); /* don't reorder anything beyond here. */
- cris_tst_cc_init();
- asm volatile ("setf\tzvnc\n");
- cris_addo_d(p, r);
- cris_tst_cc(1, 1, 1, 1);
- p += 4;
- asm volatile ("move.d\t$acr, %0\n" : "=r" (r));
- if (*r != 0xee19ccff)
- err();
-
- mb(); /* don't reorder anything beyond here. */
- cris_tst_cc_init();
- asm volatile ("setf\tzvnc\n");
- cris_addo_pi_b(p, t);
- cris_tst_cc(0, 0, 0, 0);
- asm volatile ("move.d\t$acr, %0\n" : "=r" (r));
- if (*(uint16_t*)r != 0xff22)
- err();
-
- mb(); /* don't reorder anything beyond here. */
- cris_tst_cc_init();
- asm volatile ("setf\tzvnc\n");
- cris_addo_b(p, r);
- cris_tst_cc(1, 1, 1, 1);
- p += 1;
- asm volatile ("move.d\t$acr, %0\n" : "=r" (r));
- if (*r != 0x4455aa77)
- err();
-
- mb(); /* don't reorder anything beyond here. */
- cris_tst_cc_init();
- asm volatile ("setf\tzvnc\n");
- cris_addo_w(p, r);
- cris_tst_cc(1, 1, 1, 1);
- p += 2;
- asm volatile ("move.d\t$acr, %0\n" : "=r" (r));
- if (*r != 0xff224455)
- err();
-
- mb(); /* don't reorder anything beyond here. */
- cris_tst_cc_init();
- asm volatile ("setf\tzvnc\n");
- cris_addo_pi_d(p, t);
- cris_tst_cc(0, 0, 0, 0);
- asm volatile ("move.d\t$acr, %0\n" : "=r" (r));
- r = (void*)(((char *)r) + 76789885);
- if (*r != 0x55aa77ff)
- err();
-
- pass();
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_addoq.c b/tests/tcg/cris/libc/check_addoq.c
deleted file mode 100644
index ed509e2..0000000
--- a/tests/tcg/cris/libc/check_addoq.c
+++ /dev/null
@@ -1,44 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-#include "crisutils.h"
-
-/* this would be better to do in asm, it's an orgy in GCC inline asm now. */
-
-/* ACR will be clobbered. */
-#define cris_addoq(o, v) \
- asm volatile ("addoq\t%1, %0, $acr\n" : : "r" (v), "i" (o) : "acr");
-
-
-int main(void)
-{
- int x[3] = {0x55aa77ff, 0xccff2244, 0x88ccee19};
- int *p, *t = x + 1;
-
- cris_tst_cc_init();
- asm volatile ("setf\tzvnc\n");
- cris_addoq(0, t);
- cris_tst_cc(1, 1, 1, 1);
- asm volatile ("move.d\t$acr, %0\n" : "=r" (p));
- if (*p != 0xccff2244)
- err();
-
- cris_tst_cc_init();
- asm volatile ("setf\tzvnc\n");
- cris_addoq(4, t);
- cris_tst_cc(0, 0, 0, 0);
- asm volatile ("move.d\t$acr, %0\n" : "=r" (p));
- if (*p != 0x88ccee19)
- err();
-
- cris_tst_cc_init();
- asm volatile ("clearf\tzvnc\n");
- cris_addoq(-8, t + 1);
- cris_tst_cc(0, 0, 0, 0);
- asm volatile ("move.d\t$acr, %0\n" : "=r" (p));
- if (*p != 0x55aa77ff)
- err();
- pass();
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_bound.c b/tests/tcg/cris/libc/check_bound.c
deleted file mode 100644
index d956ab9..0000000
--- a/tests/tcg/cris/libc/check_bound.c
+++ /dev/null
@@ -1,142 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-#include "crisutils.h"
-
-static always_inline int cris_bound_b(int v, int b)
-{
- int r = v;
- asm ("bound.b\t%1, %0\n" : "+r" (r) : "ri" (b));
- return r;
-}
-
-static always_inline int cris_bound_w(int v, int b)
-{
- int r = v;
- asm ("bound.w\t%1, %0\n" : "+r" (r) : "ri" (b));
- return r;
-}
-
-static always_inline int cris_bound_d(int v, int b)
-{
- int r = v;
- asm ("bound.d\t%1, %0\n" : "+r" (r) : "ri" (b));
- return r;
-}
-
-int main(void)
-{
- int r;
-
- cris_tst_cc_init();
- r = cris_bound_d(-1, 2);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 2)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_d(2, 0xffffffff);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 2)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_d(0xffff, 0xffff);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 0xffff)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_d(-1, 0xffffffff);
- cris_tst_cc(1, 0, 0, 0);
- if (r != 0xffffffff)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_d(0x78134452, 0x5432f789);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 0x5432f789)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_w(-1, 2);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 2)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_w(-1, 0xffff);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 0xffff)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_w(2, 0xffff);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 2)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_w(0xfedaffff, 0xffff);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 0xffff)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_w(0x78134452, 0xf789);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 0xf789)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_b(-1, 2);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 2)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_b(2, 0xff);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 2)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_b(-1, 0xff);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 0xff)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_b(0xff, 0xff);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 0xff)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_b(0xfeda49ff, 0xff);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 0xff)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_b(0x78134452, 0x89);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 0x89)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_w(0x78134452, 0);
- cris_tst_cc(0, 1, 0, 0);
- if (r != 0)
- err();
-
- cris_tst_cc_init();
- r = cris_bound_b(0xffff, -1);
- cris_tst_cc(0, 0, 0, 0);
- if (r != 0xff)
- err();
-
- pass();
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_ftag.c b/tests/tcg/cris/libc/check_ftag.c
deleted file mode 100644
index aaa5c97..0000000
--- a/tests/tcg/cris/libc/check_ftag.c
+++ /dev/null
@@ -1,37 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-#include "crisutils.h"
-
-static always_inline void cris_ftag_i(unsigned int x)
-{
- register unsigned int v asm("$r10") = x;
- asm ("ftagi\t[%0]\n" : : "r" (v) );
-}
-static always_inline void cris_ftag_d(unsigned int x)
-{
- register unsigned int v asm("$r10") = x;
- asm ("ftagd\t[%0]\n" : : "r" (v) );
-}
-static always_inline void cris_fidx_i(unsigned int x)
-{
- register unsigned int v asm("$r10") = x;
- asm ("fidxi\t[%0]\n" : : "r" (v) );
-}
-static always_inline void cris_fidx_d(unsigned int x)
-{
- register unsigned int v asm("$r10") = x;
- asm ("fidxd\t[%0]\n" : : "r" (v) );
-}
-
-
-int main(void)
-{
- cris_ftag_i(0);
- cris_ftag_d(0);
- cris_fidx_i(0);
- cris_fidx_d(0);
- pass();
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_gcctorture_pr28634-1.c b/tests/tcg/cris/libc/check_gcctorture_pr28634-1.c
deleted file mode 100644
index 45ecd15..0000000
--- a/tests/tcg/cris/libc/check_gcctorture_pr28634-1.c
+++ /dev/null
@@ -1,15 +0,0 @@
-/* PR rtl-optimization/28634. On targets with delayed branches,
- dbr_schedule could do the next iteration's addition in the
- branch delay slot, then subtract the value again if the branch
- wasn't taken. This can lead to rounding errors. */
-int x = -1;
-int y = 1;
-int
-main (void)
-{
- while (y > 0)
- y += x;
- if (y != x + 1)
- abort ();
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_gcctorture_pr28634.c b/tests/tcg/cris/libc/check_gcctorture_pr28634.c
deleted file mode 100644
index a0c5254..0000000
--- a/tests/tcg/cris/libc/check_gcctorture_pr28634.c
+++ /dev/null
@@ -1,15 +0,0 @@
-/* PR rtl-optimization/28634. On targets with delayed branches,
- dbr_schedule could do the next iteration's addition in the
- branch delay slot, then subtract the value again if the branch
- wasn't taken. This can lead to rounding errors. */
-double x = -0x1.0p53;
-double y = 1;
-int
-main (void)
-{
- while (y > 0)
- y += x;
- if (y != x + 1)
- abort ();
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_glibc_kernelversion.c b/tests/tcg/cris/libc/check_glibc_kernelversion.c
deleted file mode 100644
index 7aada89..0000000
--- a/tests/tcg/cris/libc/check_glibc_kernelversion.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Check the lz insn.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-
-#define __LINUX_KERNEL_VERSION 131584
-
-#define DL_SYSDEP_OSCHECK(FATAL) \
- do { \
- /* Test whether the kernel is new enough. This test is only \
- performed if the library is not compiled to run on all \
- kernels. */ \
- if (__LINUX_KERNEL_VERSION > 0) \
- { \
- char bufmem[64]; \
- char *buf = bufmem; \
- unsigned int version; \
- int parts; \
- char *cp; \
- struct utsname uts; \
- \
- /* Try the uname syscall */ \
- if (__uname (&uts)) \
- { \
- /* This was not successful. Now try reading the /proc \
- filesystem. */ \
- ssize_t reslen; \
- int fd = __open ("/proc/sys/kernel/osrelease", O_RDONLY); \
- if (fd == -1 \
- || (reslen = __read (fd, bufmem, sizeof (bufmem))) <= 0) \
- /* This also didn't work. We give up since we cannot \
- make sure the library can actually work. */ \
- FATAL ("FATAL: cannot determine library version\n"); \
- __close (fd); \
- buf[MIN (reslen, (ssize_t) sizeof (bufmem) - 1)] = '\0'; \
- } \
- else \
- buf = uts.release; \
- \
- /* Now convert it into a number. The string consists of at most \
- three parts. */ \
- version = 0; \
- parts = 0; \
- cp = buf; \
- while ((*cp >= '0') && (*cp <= '9')) \
- { \
- unsigned int here = *cp++ - '0'; \
- \
- while ((*cp >= '0') && (*cp <= '9')) \
- { \
- here *= 10; \
- here += *cp++ - '0'; \
- } \
- \
- ++parts; \
- version <<= 8; \
- version |= here; \
- \
- if (*cp++ != '.') \
- /* Another part following? */ \
- break; \
- } \
- \
- if (parts < 3) \
- version <<= 8 * (3 - parts); \
- \
- /* Now we can test with the required version. */ \
- if (version < __LINUX_KERNEL_VERSION) \
- /* Not sufficient. */ \
- FATAL ("FATAL: kernel too old\n"); \
- \
- _dl_osversion = version; \
- } \
- } while (0)
-
-int main(void)
-{
- char bufmem[64] = "2.6.22";
- char *buf = bufmem;
- unsigned int version;
- int parts;
- char *cp;
-
- version = 0;
- parts = 0;
- cp = buf;
- while ((*cp >= '0') && (*cp <= '9'))
- {
- unsigned int here = *cp++ - '0';
-
- while ((*cp >= '0') && (*cp <= '9'))
- {
- here *= 10;
- here += *cp++ - '0';
- }
-
- ++parts;
- version <<= 8;
- version |= here;
-
- if (*cp++ != '.')
- /* Another part following? */
- break;
- }
-
- if (parts < 3)
- version <<= 8 * (3 - parts);
- if (version < __LINUX_KERNEL_VERSION)
- err();
- pass();
- exit(0);
-}
diff --git a/tests/tcg/cris/libc/check_hello.c b/tests/tcg/cris/libc/check_hello.c
deleted file mode 100644
index fb403ba..0000000
--- a/tests/tcg/cris/libc/check_hello.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-int main ()
-{
- printf ("pass\n");
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_int64.c b/tests/tcg/cris/libc/check_int64.c
deleted file mode 100644
index 69caec1..0000000
--- a/tests/tcg/cris/libc/check_int64.c
+++ /dev/null
@@ -1,47 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-#include "crisutils.h"
-
-
-static always_inline int64_t add64(const int64_t a, const int64_t b)
-{
- return a + b;
-}
-
-static always_inline int64_t sub64(const int64_t a, const int64_t b)
-{
- return a - b;
-}
-
-int main(void)
-{
- int64_t a = 1;
- int64_t b = 2;
-
- /* FIXME: add some tests. */
- a = add64(a, b);
- if (a != 3)
- err();
-
- a = sub64(a, b);
- if (a != 1)
- err();
-
- a = add64(a, -4);
- if (a != -3)
- err();
-
- a = add64(a, 3);
- if (a != 0)
- err();
-
- a = 0;
- a = sub64(a, 1);
- if (a != -1)
- err();
-
- pass();
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_lz.c b/tests/tcg/cris/libc/check_lz.c
deleted file mode 100644
index bf051a6..0000000
--- a/tests/tcg/cris/libc/check_lz.c
+++ /dev/null
@@ -1,49 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-
-static always_inline int cris_lz(int x)
-{
- int r;
- asm ("lz\t%1, %0\n" : "=r" (r) : "r" (x));
- return r;
-}
-
-void check_lz(void)
-{
- int i;
-
- if (cris_lz(0) != 32)
- err();
- if (cris_lz(1) != 31)
- err();
- if (cris_lz(2) != 30)
- err();
- if (cris_lz(4) != 29)
- err();
- if (cris_lz(8) != 28)
- err();
-
- /* try all positions with a single bit. */
- for (i = 1; i < 32; i++) {
- if (cris_lz(1 << (i-1)) != (32 - i))
- err();
- }
-
- /* try all positions with all bits. */
- for (i = 1; i < 32; i++) {
- /* split up this computation to clarify it. */
- uint32_t val;
- val = (unsigned int)-1 >> (32 - i);
- if (cris_lz(val) != (32 - i))
- err();
- }
-}
-
-int main(void)
-{
- check_lz();
- pass();
- exit(0);
-}
diff --git a/tests/tcg/cris/libc/check_mapbrk.c b/tests/tcg/cris/libc/check_mapbrk.c
deleted file mode 100644
index 1aff762..0000000
--- a/tests/tcg/cris/libc/check_mapbrk.c
+++ /dev/null
@@ -1,39 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-
-/* Basic sanity check that syscalls to implement malloc (brk, mmap2,
- munmap) are trivially functional. */
-
-int main ()
-{
- void *p1, *p2, *p3, *p4, *p5, *p6;
-
- if ((p1 = malloc (8100)) == NULL
- || (p2 = malloc (16300)) == NULL
- || (p3 = malloc (4000)) == NULL
- || (p4 = malloc (500)) == NULL
- || (p5 = malloc (1023*1024)) == NULL
- || (p6 = malloc (8191*1024)) == NULL)
- {
- printf ("fail\n");
- exit (1);
- }
-
- free (p1);
- free (p2);
- free (p3);
- free (p4);
- free (p5);
- free (p6);
-
- p1 = malloc (64000);
- if (p1 == NULL)
- {
- printf ("fail\n");
- exit (1);
- }
- free (p1);
-
- printf ("pass\n");
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_mmap1.c b/tests/tcg/cris/libc/check_mmap1.c
deleted file mode 100644
index b803f0c..0000000
--- a/tests/tcg/cris/libc/check_mmap1.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-#notarget: cris*-*-elf
-*/
-
-#define _GNU_SOURCE
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/mman.h>
-
-int main (int argc, char *argv[])
-{
- int fd = open (argv[0], O_RDONLY);
- struct stat sb;
- int size;
- void *a;
- const char *str = "a string you'll only find in the program";
-
- if (fd == -1)
- {
- perror ("open");
- abort ();
- }
-
- if (fstat (fd, &sb) < 0)
- {
- perror ("fstat");
- abort ();
- }
-
- size = sb.st_size;
-
- /* We want to test mmapping a size that isn't exactly a page. */
- if ((size & 8191) == 0)
- size--;
-
- a = mmap (NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
-
- if (memmem (a, size, str, strlen (str) + 1) == NULL)
- abort ();
-
- printf ("pass\n");
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_mmap2.c b/tests/tcg/cris/libc/check_mmap2.c
deleted file mode 100644
index 35139a0..0000000
--- a/tests/tcg/cris/libc/check_mmap2.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-#notarget: cris*-*-elf
-*/
-
-#define _GNU_SOURCE
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/mman.h>
-
-int main (int argc, char *argv[])
-{
- int fd = open (argv[0], O_RDONLY);
- struct stat sb;
- int size;
- void *a;
- const char *str = "a string you'll only find in the program";
-
- if (fd == -1)
- {
- perror ("open");
- abort ();
- }
-
- if (fstat (fd, &sb) < 0)
- {
- perror ("fstat");
- abort ();
- }
-
- size = sb.st_size;
-
- /* We want to test mmapping a size that isn't exactly a page. */
- if ((size & 8191) == 0)
- size--;
-
- a = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0);
-
- if (memmem (a, size, str, strlen (str) + 1) == NULL)
- abort ();
-
- printf ("pass\n");
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_mmap3.c b/tests/tcg/cris/libc/check_mmap3.c
deleted file mode 100644
index cb890ef..0000000
--- a/tests/tcg/cris/libc/check_mmap3.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
-#notarget: cris*-*-elf
-*/
-
-#define _GNU_SOURCE
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <sys/mman.h>
-
-int main (int argc, char *argv[])
-{
- volatile unsigned char *a;
-
- /* Check that we can map a non-multiple of a page and still get a full page. */
- a = mmap (NULL, 0x4c, PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (a == NULL || a == (unsigned char *) -1)
- abort ();
-
- a[0] = 0xbe;
- a[8191] = 0xef;
- memset ((char *) a + 1, 0, 8190);
-
- if (a[0] != 0xbe || a[8191] != 0xef)
- abort ();
-
- printf ("pass\n");
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_moveq.c b/tests/tcg/cris/libc/check_moveq.c
deleted file mode 100644
index 80f2dff..0000000
--- a/tests/tcg/cris/libc/check_moveq.c
+++ /dev/null
@@ -1,51 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-#include "crisutils.h"
-
-#define cris_moveq(dst, src) \
- asm volatile ("moveq %1, %0\n" : "=r" (dst) : "i" (src));
-
-
-
-int main(void)
-{
- int t;
-
- cris_tst_cc_init();
- asm volatile ("setf\tzvnc\n");
- cris_moveq(t, 10);
- cris_tst_cc(1, 1, 1, 1);
- if (t != 10)
- err();
-
- /* make sure moveq doesn't clobber the zflag. */
- cris_tst_cc_init();
- asm volatile ("setf vnc\n");
- asm volatile ("clearf z\n");
- cris_moveq(t, 0);
- cris_tst_cc(1, 0, 1, 1);
- if (t != 0)
- err();
-
- /* make sure moveq doesn't clobber the nflag.
- Also check large immediates */
- cris_tst_cc_init();
- asm volatile ("setf zvc\n");
- asm volatile ("clearf n\n");
- cris_moveq(t, -31);
- cris_tst_cc(0, 1, 1, 1);
- if (t != -31)
- err();
-
- cris_tst_cc_init();
- asm volatile ("setf nzvc\n");
- cris_moveq(t, 31);
- cris_tst_cc(1, 1, 1, 1);
- if (t != 31)
- err();
-
- pass();
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_openpf1.c b/tests/tcg/cris/libc/check_openpf1.c
deleted file mode 100644
index 251d26e..0000000
--- a/tests/tcg/cris/libc/check_openpf1.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Check that --sysroot is applied to open(2).
-#sim: --sysroot=@exedir@
-
- We assume, with EXE being the name of the executable:
- - The simulator executes with cwd the same directory where the executable
- is located (so argv[0] contains a plain filename without directory
- components).
- - There's no /EXE on the host file system. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-int main (int argc, char *argv[])
-{
- char *fnam = argv[0];
- FILE *f;
- if (argv[0][0] != '/')
- {
- fnam = malloc (strlen (argv[0]) + 2);
- if (fnam == NULL)
- abort ();
- strcpy (fnam, "/");
- strcat (fnam, argv[0]);
- }
-
- f = fopen (fnam, "rb");
- if (f == NULL)
- abort ();
- fclose(f);
-
- /* Cover another execution path. */
- if (fopen ("/nonexistent", "rb") != NULL
- || errno != ENOENT)
- abort ();
- printf ("pass\n");
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_openpf2.c b/tests/tcg/cris/libc/check_openpf2.c
deleted file mode 100644
index 5d56189..0000000
--- a/tests/tcg/cris/libc/check_openpf2.c
+++ /dev/null
@@ -1,16 +0,0 @@
-/* Check that the simulator has chdir:ed to the --sysroot argument
-#sim: --sysroot=@srcdir@
- (or that --sysroot is applied to relative file paths). */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-int main (int argc, char *argv[])
-{
- FILE *f = fopen ("check_openpf2.c", "rb");
- if (f == NULL)
- abort ();
- fclose(f);
- printf ("pass\n");
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_openpf3.c b/tests/tcg/cris/libc/check_openpf3.c
deleted file mode 100644
index 557adee..0000000
--- a/tests/tcg/cris/libc/check_openpf3.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Basic file operations (rename, unlink); once without sysroot. We
- also test that the simulator has chdir:ed to PREFIX, when defined. */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#ifndef PREFIX
-#define PREFIX
-#endif
-
-void err (const char *s)
-{
- perror (s);
- abort ();
-}
-
-int main (int argc, char *argv[])
-{
- FILE *f;
- struct stat buf;
-
- unlink (PREFIX "testfoo2.tmp");
-
- f = fopen ("testfoo1.tmp", "w");
- if (f == NULL)
- err ("open");
- fclose (f);
-
- if (rename (PREFIX "testfoo1.tmp", PREFIX "testfoo2.tmp") != 0)
- err ("rename");
-
- if (stat (PREFIX "testfoo2.tmp", &buf) != 0
- || !S_ISREG (buf.st_mode))
- err ("stat 1");
-
- if (stat ("testfoo2.tmp", &buf) != 0
- || !S_ISREG (buf.st_mode))
- err ("stat 2");
-
- if (unlink (PREFIX "testfoo2.tmp") != 0)
- err ("unlink");
-
- printf ("pass\n");
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_openpf5.c b/tests/tcg/cris/libc/check_openpf5.c
deleted file mode 100644
index 1f86ea2..0000000
--- a/tests/tcg/cris/libc/check_openpf5.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/* Check that TRT happens when error on too many opened files.
-#notarget: cris*-*-elf
-#sim: --sysroot=@exedir@
-*/
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <string.h>
-
-int main (int argc, char *argv[])
-{
- int i;
- int filemax;
-
-#ifdef OPEN_MAX
- filemax = OPEN_MAX;
-#else
- filemax = sysconf (_SC_OPEN_MAX);
-#endif
-
- char *fn = malloc (strlen (argv[0]) + 2);
- if (fn == NULL)
- abort ();
- strcpy (fn, "/");
- strcat (fn, argv[0]);
-
- for (i = 0; i < filemax + 1; i++)
- {
- if (open (fn, O_RDONLY) < 0)
- {
- /* Shouldn't happen too early. */
- if (i < filemax - 3 - 1)
- {
- fprintf (stderr, "i: %d\n", i);
- abort ();
- }
- if (errno != EMFILE)
- {
- perror ("open");
- abort ();
- }
- goto ok;
- }
- }
- abort ();
-
-ok:
- printf ("pass\n");
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_settls1.c b/tests/tcg/cris/libc/check_settls1.c
deleted file mode 100644
index 3abc3a9..0000000
--- a/tests/tcg/cris/libc/check_settls1.c
+++ /dev/null
@@ -1,45 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include <sys/syscall.h>
-
-#ifndef SYS_set_thread_area
-#define SYS_set_thread_area 243
-#endif
-
-int main (void)
-{
- unsigned long tp, old_tp;
- int ret;
-
- asm volatile ("move $pid,%0" : "=r" (old_tp));
- old_tp &= ~0xff;
-
- ret = syscall (SYS_set_thread_area, 0xf0);
- if (ret != -1 || errno != EINVAL) {
- syscall (SYS_set_thread_area, old_tp);
- perror ("Invalid thread area accepted:");
- abort();
- }
-
- ret = syscall (SYS_set_thread_area, 0xeddeed00);
- if (ret != 0) {
- perror ("Valid thread area not accepted: ");
- abort ();
- }
-
- asm volatile ("move $pid,%0" : "=r" (tp));
- tp &= ~0xff;
- syscall (SYS_set_thread_area, old_tp);
-
- if (tp != 0xeddeed00) {
- * (volatile int *) 0 = 0;
- perror ("tls2");
- abort ();
- }
-
- printf ("pass\n");
- return EXIT_SUCCESS;
-}
diff --git a/tests/tcg/cris/libc/check_sigalrm.c b/tests/tcg/cris/libc/check_sigalrm.c
deleted file mode 100644
index 39fa8d9..0000000
--- a/tests/tcg/cris/libc/check_sigalrm.c
+++ /dev/null
@@ -1,26 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <unistd.h>
-
-#define MAGIC (0xdeadbeef)
-
-int s = 0;
-void sighandler(int sig)
-{
- s = MAGIC;
-}
-
-int main(int argc, char **argv)
-{
- int p;
-
- p = getpid();
- signal(SIGALRM, sighandler);
- kill(p, SIGALRM);
- if (s != MAGIC)
- return EXIT_FAILURE;
-
- printf ("passed\n");
- return EXIT_SUCCESS;
-}
diff --git a/tests/tcg/cris/libc/check_stat1.c b/tests/tcg/cris/libc/check_stat1.c
deleted file mode 100644
index 2e2cae5..0000000
--- a/tests/tcg/cris/libc/check_stat1.c
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-int main (void)
-{
- struct stat buf;
-
- if (stat (".", &buf) != 0
- || !S_ISDIR (buf.st_mode))
- abort ();
- printf ("pass\n");
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_stat2.c b/tests/tcg/cris/libc/check_stat2.c
deleted file mode 100644
index e36172e..0000000
--- a/tests/tcg/cris/libc/check_stat2.c
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
-#notarget: cris*-*-elf
-*/
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-int main (void)
-{
- struct stat buf;
-
- if (lstat (".", &buf) != 0
- || !S_ISDIR (buf.st_mode))
- abort ();
- printf ("pass\n");
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_stat3.c b/tests/tcg/cris/libc/check_stat3.c
deleted file mode 100644
index 36a9d5d..0000000
--- a/tests/tcg/cris/libc/check_stat3.c
+++ /dev/null
@@ -1,25 +0,0 @@
-/* Simulator options:
-#sim: --sysroot=@exedir@
-*/
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-int main (int argc, char *argv[])
-{
- char path[1024] = "/";
- struct stat buf;
-
- strncat(path, argv[0], sizeof(path) - 2);
- if (stat (".", &buf) != 0
- || !S_ISDIR (buf.st_mode))
- abort ();
- if (stat (path, &buf) != 0
- || !S_ISREG (buf.st_mode))
- abort ();
- printf ("pass\n");
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_stat4.c b/tests/tcg/cris/libc/check_stat4.c
deleted file mode 100644
index 04f21fe..0000000
--- a/tests/tcg/cris/libc/check_stat4.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Simulator options:
-#notarget: cris*-*-elf
-#sim: --sysroot=@exedir@
-*/
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-int main (int argc, char *argv[])
-{
- char path[1024] = "/";
- struct stat buf;
-
- strncat(path, argv[0], sizeof(path) - 2);
- if (lstat (".", &buf) != 0
- || !S_ISDIR (buf.st_mode))
- abort ();
- if (lstat (path, &buf) != 0
- || !S_ISREG (buf.st_mode))
- abort ();
- printf ("pass\n");
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/check_swap.c b/tests/tcg/cris/libc/check_swap.c
deleted file mode 100644
index 9a68c1e..0000000
--- a/tests/tcg/cris/libc/check_swap.c
+++ /dev/null
@@ -1,76 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "sys.h"
-#include "crisutils.h"
-
-#define N 8
-#define W 4
-#define B 2
-#define R 1
-
-static always_inline int cris_swap(const int mode, int x)
-{
- switch (mode)
- {
- case N: asm ("swapn\t%0\n" : "+r" (x) : "0" (x)); break;
- case W: asm ("swapw\t%0\n" : "+r" (x) : "0" (x)); break;
- case B: asm ("swapb\t%0\n" : "+r" (x) : "0" (x)); break;
- case R: asm ("swapr\t%0\n" : "+r" (x) : "0" (x)); break;
- case B|R: asm ("swapbr\t%0\n" : "+r" (x) : "0" (x)); break;
- case W|R: asm ("swapwr\t%0\n" : "+r" (x) : "0" (x)); break;
- case W|B: asm ("swapwb\t%0\n" : "+r" (x) : "0" (x)); break;
- case W|B|R: asm ("swapwbr\t%0\n" : "+r" (x) : "0" (x)); break;
- case N|R: asm ("swapnr\t%0\n" : "+r" (x) : "0" (x)); break;
- case N|B: asm ("swapnb\t%0\n" : "+r" (x) : "0" (x)); break;
- case N|B|R: asm ("swapnbr\t%0\n" : "+r" (x) : "0" (x)); break;
- case N|W: asm ("swapnw\t%0\n" : "+r" (x) : "0" (x)); break;
- default:
- err();
- break;
- }
- return x;
-}
-
-/* Made this a macro to be able to pick up the location of the errors. */
-#define verify_swap(mode, val, expected, n, z) \
-do { \
- int r; \
- cris_tst_cc_init(); \
- r = cris_swap(mode, val); \
- cris_tst_mov_cc(n, z); \
- if (r != expected) \
- err(); \
-} while(0)
-
-void check_swap(void)
-{
- /* Some of these numbers are borrowed from GDB's cris sim
- testsuite. */
- if (cris_swap(N, 0) != 0xffffffff)
- err();
- if (cris_swap(W, 0x12345678) != 0x56781234)
- err();
- if (cris_swap(B, 0x12345678) != 0x34127856)
- err();
-
- verify_swap(R, 0x78134452, 0x1ec8224a, 0, 0);
- verify_swap(B, 0x78134452, 0x13785244, 0, 0);
- verify_swap(B|R, 0x78134452, 0xc81e4a22, 1, 0);
- verify_swap(W, 0x78134452, 0x44527813, 0, 0);
- verify_swap(W|R, 0x78134452, 0x224a1ec8, 0, 0);
- verify_swap(W|B|R, 0x78134452, 0x4a22c81e, 0, 0);
- verify_swap(N, 0x78134452, 0x87ecbbad, 1, 0);
- verify_swap(N|R, 0x78134452, 0xe137ddb5, 1, 0);
- verify_swap(N|B, 0x78134452, 0xec87adbb, 1, 0);
- verify_swap(N|B|R, 0x78134452, 0x37e1b5dd, 0, 0);
- verify_swap(N|W, 0x78134452, 0xbbad87ec, 1, 0);
- verify_swap(N|B|R, 0xffffffff, 0, 0, 1);
-}
-
-int main(void)
-{
- check_swap();
- pass();
- return 0;
-}
diff --git a/tests/tcg/cris/libc/check_time2.c b/tests/tcg/cris/libc/check_time2.c
deleted file mode 100644
index 20b69b4..0000000
--- a/tests/tcg/cris/libc/check_time2.c
+++ /dev/null
@@ -1,18 +0,0 @@
-/* CB_SYS_time doesn't implement the Linux time syscall; the return
- value isn't written to the argument. */
-
-#include <time.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-int
-main (void)
-{
- time_t x = (time_t) -1;
- time_t t = time (&x);
-
- if (t == (time_t) -1 || t != x)
- abort ();
- printf ("pass\n");
- exit (0);
-}
diff --git a/tests/tcg/cris/libc/crisutils.h b/tests/tcg/cris/libc/crisutils.h
deleted file mode 100644
index bbbe6c5..0000000
--- a/tests/tcg/cris/libc/crisutils.h
+++ /dev/null
@@ -1,76 +0,0 @@
-#ifndef CRISUTILS_H
-#define CRISUTILS_H 1
-
-static char *tst_cc_loc = NULL;
-
-#define cris_tst_cc_init() \
-do { tst_cc_loc = "test_cc failed at " CURRENT_LOCATION; } while(0)
-
-/* We need a real symbol to signal error. */
-void _err(void) {
- if (!tst_cc_loc)
- tst_cc_loc = "tst_cc_failed\n";
- _fail(tst_cc_loc);
-}
-
-static always_inline void cris_tst_cc_n1(void)
-{
- asm volatile ("bpl _err\n"
- "nop\n");
-}
-static always_inline void cris_tst_cc_n0(void)
-{
- asm volatile ("bmi _err\n"
- "nop\n");
-}
-
-static always_inline void cris_tst_cc_z1(void)
-{
- asm volatile ("bne _err\n"
- "nop\n");
-}
-static always_inline void cris_tst_cc_z0(void)
-{
- asm volatile ("beq _err\n"
- "nop\n");
-}
-static always_inline void cris_tst_cc_v1(void)
-{
- asm volatile ("bvc _err\n"
- "nop\n");
-}
-static always_inline void cris_tst_cc_v0(void)
-{
- asm volatile ("bvs _err\n"
- "nop\n");
-}
-
-static always_inline void cris_tst_cc_c1(void)
-{
- asm volatile ("bcc _err\n"
- "nop\n");
-}
-static always_inline void cris_tst_cc_c0(void)
-{
- asm volatile ("bcs _err\n"
- "nop\n");
-}
-
-static always_inline void cris_tst_mov_cc(int n, int z)
-{
- if (n) cris_tst_cc_n1(); else cris_tst_cc_n0();
- if (z) cris_tst_cc_z1(); else cris_tst_cc_z0();
- asm volatile ("" : : "g" (_err));
-}
-
-static always_inline void cris_tst_cc(const int n, const int z,
- const int v, const int c)
-{
- if (n) cris_tst_cc_n1(); else cris_tst_cc_n0();
- if (z) cris_tst_cc_z1(); else cris_tst_cc_z0();
- if (v) cris_tst_cc_v1(); else cris_tst_cc_v0();
- if (c) cris_tst_cc_c1(); else cris_tst_cc_c0();
- asm volatile ("" : : "g" (_err));
-}
-
-#endif
diff --git a/tests/tcg/cris/libc/sys.h b/tests/tcg/cris/libc/sys.h
deleted file mode 100644
index 3dd47bb..0000000
--- a/tests/tcg/cris/libc/sys.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#include <unistd.h>
-
-#define STRINGIFY(x) #x
-#define TOSTRING(x) STRINGIFY(x)
-
-#define always_inline inline __attribute__((always_inline))
-
-#define CURRENT_LOCATION __FILE__ ":" TOSTRING(__LINE__)
-
-#define err() \
-{ \
- _fail("at " CURRENT_LOCATION " "); \
-}
-
-#define mb() asm volatile ("" : : : "memory")
-
-void pass(void);
-void _fail(char *reason);
diff --git a/tests/tcg/hexagon/usr.c b/tests/tcg/hexagon/usr.c
index 92bc86a..f0b23d3 100644
--- a/tests/tcg/hexagon/usr.c
+++ b/tests/tcg/hexagon/usr.c
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2022-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ * Copyright(c) 2022-2024 Qualcomm Innovation Center, Inc. All Rights Reserved.
*
* 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
@@ -1007,6 +1007,11 @@ int main()
TEST_P_OP_R(conv_sf2d_chop, SF_QNaN, 0xffffffffffffffffULL, USR_FPINVF);
TEST_P_OP_R(conv_sf2d_chop, SF_SNaN, 0xffffffffffffffffULL, USR_FPINVF);
+ TEST_R_OP_R(conv_sf2uw, SF_zero_neg, 0, USR_CLEAR);
+ TEST_R_OP_R(conv_sf2uw_chop, SF_zero_neg, 0, USR_CLEAR);
+ TEST_P_OP_R(conv_sf2ud, SF_zero_neg, 0, USR_CLEAR);
+ TEST_P_OP_R(conv_sf2ud_chop, SF_zero_neg, 0, USR_CLEAR);
+
TEST_R_OP_P(conv_df2sf, DF_QNaN, SF_HEX_NaN, USR_CLEAR);
TEST_R_OP_P(conv_df2sf, DF_SNaN, SF_HEX_NaN, USR_FPINVF);
TEST_R_OP_P(conv_df2uw, DF_QNaN, 0xffffffff, USR_FPINVF);
@@ -1020,6 +1025,11 @@ int main()
TEST_R_OP_P(conv_df2uw_chop, DF_QNaN, 0xffffffff, USR_FPINVF);
TEST_R_OP_P(conv_df2uw_chop, DF_SNaN, 0xffffffff, USR_FPINVF);
+ TEST_R_OP_P(conv_df2uw, DF_zero_neg, 0, USR_CLEAR);
+ TEST_R_OP_P(conv_df2uw_chop, DF_zero_neg, 0, USR_CLEAR);
+ TEST_P_OP_P(conv_df2ud, DF_zero_neg, 0, USR_CLEAR);
+ TEST_P_OP_P(conv_df2ud_chop, DF_zero_neg, 0, USR_CLEAR);
+
/* Test for typo in HELPER(conv_df2uw_chop) */
TEST_R_OP_P(conv_df2uw_chop, 0xffffff7f00000001ULL, 0xffffffff, USR_FPINVF);
diff --git a/tests/tcg/i386/Makefile.softmmu-target b/tests/tcg/i386/Makefile.softmmu-target
index 5266f23..4096a1c 100644
--- a/tests/tcg/i386/Makefile.softmmu-target
+++ b/tests/tcg/i386/Makefile.softmmu-target
@@ -25,7 +25,7 @@ EXTRA_RUNS+=$(MULTIARCH_RUNS)
.PRECIOUS: $(CRT_OBJS)
%.o: $(CRT_PATH)/%.S
- $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -Wa,--noexecstack -c $< -o $@
# Build and link the tests
%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
diff --git a/tests/tcg/loongarch64/Makefile.softmmu-target b/tests/tcg/loongarch64/Makefile.softmmu-target
index 908f3a8..6d4a20f 100644
--- a/tests/tcg/loongarch64/Makefile.softmmu-target
+++ b/tests/tcg/loongarch64/Makefile.softmmu-target
@@ -16,13 +16,13 @@ LINK_SCRIPT=$(LOONGARCH64_SYSTEM_SRC)/kernel.ld
LDFLAGS=-Wl,-T$(LINK_SCRIPT)
TESTS+=$(LOONGARCH64_TESTS) $(MULTIARCH_TESTS)
CFLAGS+=-nostdlib -g -O1 -march=loongarch64 -mabi=lp64d $(MINILIB_INC)
-LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
+LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc -Wl,--no-warn-rwx-segments
# building head blobs
.PRECIOUS: $(CRT_OBJS)
%.o: $(CRT_PATH)/%.S
- $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -x assembler-with-cpp -c $< -o $@
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -x assembler-with-cpp -Wa,--noexecstack -c $< -o $@
# Build and link the tests
%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
diff --git a/tests/tcg/loongarch64/system/regdef.h b/tests/tcg/loongarch64/system/regdef.h
index faa09b2..b586b4e 100644
--- a/tests/tcg/loongarch64/system/regdef.h
+++ b/tests/tcg/loongarch64/system/regdef.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021 Loongson Technology Corporation Limited
*/
diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target
index 5e3391e..78b83d5 100644
--- a/tests/tcg/multiarch/Makefile.target
+++ b/tests/tcg/multiarch/Makefile.target
@@ -170,5 +170,16 @@ run-plugin-semiconsole-with-%:
TESTS += semihosting semiconsole
endif
+# Test plugin memory access instrumentation
+run-plugin-test-plugin-mem-access-with-libmem.so: \
+ PLUGIN_ARGS=$(COMMA)print-accesses=true
+run-plugin-test-plugin-mem-access-with-libmem.so: \
+ CHECK_PLUGIN_OUTPUT_COMMAND= \
+ $(SRC_PATH)/tests/tcg/multiarch/check-plugin-output.sh \
+ $(QEMU) $<
+
+test-plugin-mem-access: CFLAGS+=-pthread -O0
+test-plugin-mem-access: LDFLAGS+=-pthread -O0
+
# Update TESTS
TESTS += $(MULTIARCH_TESTS)
diff --git a/tests/tcg/multiarch/check-plugin-output.sh b/tests/tcg/multiarch/check-plugin-output.sh
new file mode 100755
index 0000000..80607f0
--- /dev/null
+++ b/tests/tcg/multiarch/check-plugin-output.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+
+# This script runs a given executable using qemu, and compare its standard
+# output with an expected plugin output.
+# Each line of output is searched (as a regexp) in the expected plugin output.
+
+set -euo pipefail
+
+die()
+{
+ echo "$@" 1>&2
+ exit 1
+}
+
+check()
+{
+ file=$1
+ pattern=$2
+ grep "$pattern" "$file" > /dev/null || die "\"$pattern\" not found in $file"
+}
+
+[ $# -eq 3 ] || die "usage: qemu_bin exe plugin_out_file"
+
+qemu_bin=$1; shift
+exe=$1;shift
+plugin_out=$1; shift
+
+expected()
+{
+ $qemu_bin $exe ||
+ die "running $exe failed"
+}
+
+expected | while read line; do
+ check "$plugin_out" "$line"
+done
diff --git a/tests/tcg/multiarch/gdbstub/test-proc-mappings.py b/tests/tcg/multiarch/gdbstub/test-proc-mappings.py
index 564613f..0f687f3 100644
--- a/tests/tcg/multiarch/gdbstub/test-proc-mappings.py
+++ b/tests/tcg/multiarch/gdbstub/test-proc-mappings.py
@@ -8,17 +8,12 @@ from test_gdbstub import main, report
def run_test():
"""Run through the tests one by one"""
- try:
- mappings = gdb.execute("info proc mappings", False, True)
- except gdb.error as exc:
- exc_str = str(exc)
- if "Not supported on this target." in exc_str:
- # Detect failures due to an outstanding issue with how GDB handles
- # the x86_64 QEMU's target.xml, which does not contain the
- # definition of orig_rax. Skip the test in this case.
- print("SKIP: {}".format(exc_str))
- return
- raise
+ if gdb.selected_inferior().architecture().name() == "m68k":
+ # m68k GDB supports only GDB_OSABI_SVR4, but GDB_OSABI_LINUX is
+ # required for the info proc support (see set_gdbarch_info_proc()).
+ print("SKIP: m68k GDB does not support GDB_OSABI_LINUX")
+ exit(0)
+ mappings = gdb.execute("info proc mappings", False, True)
report(isinstance(mappings, str), "Fetched the mappings from the inferior")
# Broken with host page size > guest page size
# report("/sha1" in mappings, "Found the test binary name in the mappings")
diff --git a/tests/tcg/multiarch/system/Makefile.softmmu-target b/tests/tcg/multiarch/system/Makefile.softmmu-target
index 32dc0f9..07be001 100644
--- a/tests/tcg/multiarch/system/Makefile.softmmu-target
+++ b/tests/tcg/multiarch/system/Makefile.softmmu-target
@@ -65,3 +65,9 @@ endif
MULTIARCH_RUNS += run-gdbstub-memory run-gdbstub-interrupt \
run-gdbstub-untimely-packet run-gdbstub-registers
+
+# Test plugin memory access instrumentation
+run-plugin-memory-with-libmem.so: \
+ PLUGIN_ARGS=$(COMMA)region-summary=true
+run-plugin-memory-with-libmem.so: \
+ CHECK_PLUGIN_OUTPUT_COMMAND=$(MULTIARCH_SYSTEM_SRC)/validate-memory-counts.py $@.out
diff --git a/tests/tcg/multiarch/system/memory.c b/tests/tcg/multiarch/system/memory.c
index 6eb2eb1..65a6038 100644
--- a/tests/tcg/multiarch/system/memory.c
+++ b/tests/tcg/multiarch/system/memory.c
@@ -14,26 +14,35 @@
#include <stdint.h>
#include <stdbool.h>
+#include <inttypes.h>
#include <minilib.h>
#ifndef CHECK_UNALIGNED
# error "Target does not specify CHECK_UNALIGNED"
#endif
+uint32_t test_read_count;
+uint32_t test_write_count;
+
#define MEM_PAGE_SIZE 4096 /* nominal 4k "pages" */
#define TEST_SIZE (MEM_PAGE_SIZE * 4) /* 4 pages */
#define ARRAY_SIZE(x) ((sizeof(x) / sizeof((x)[0])))
-__attribute__((aligned(MEM_PAGE_SIZE)))
+__attribute__((aligned(TEST_SIZE)))
static uint8_t test_data[TEST_SIZE];
typedef void (*init_ufn) (int offset);
typedef bool (*read_ufn) (int offset);
typedef bool (*read_sfn) (int offset, bool nf);
-static void pdot(int count)
+static void pdot(int count, bool write)
{
+ if (write) {
+ test_write_count++;
+ } else {
+ test_read_count++;
+ }
if (count % 128 == 0) {
ml_printf(".");
}
@@ -63,12 +72,14 @@ static void init_test_data_u8(int unused_offset)
int i;
(void)(unused_offset);
- ml_printf("Filling test area with u8:");
+ ml_printf("Filling test area with u8 (%p):", ptr);
+
for (i = 0; i < TEST_SIZE; i++) {
*ptr++ = BYTE_NEXT(count);
- pdot(i);
+ pdot(i, true);
}
- ml_printf("done\n");
+
+ ml_printf("done %d @ %p\n", i, ptr);
}
/*
@@ -91,10 +102,11 @@ static void init_test_data_s8(bool neg_first)
neg_first ? "neg first" : "pos first");
for (i = 0; i < TEST_SIZE / 2; i++) {
*ptr++ = get_byte(i, neg_first);
+ pdot(i, true);
*ptr++ = get_byte(i, !neg_first);
- pdot(i);
+ pdot(i, true);
}
- ml_printf("done\n");
+ ml_printf("done %d @ %p\n", i * 2, ptr);
}
/*
@@ -105,9 +117,19 @@ static void reset_start_data(int offset)
{
uint32_t *ptr = (uint32_t *) &test_data[0];
int i;
+
+ if (!offset) {
+ return;
+ }
+
+ ml_printf("Flushing %d bytes from %p: ", offset, ptr);
+
for (i = 0; i < offset; i++) {
*ptr++ = 0;
+ pdot(i, true);
}
+
+ ml_printf("done %d @ %p\n", i, ptr);
}
static void init_test_data_u16(int offset)
@@ -117,17 +139,17 @@ static void init_test_data_u16(int offset)
const int max = (TEST_SIZE - offset) / sizeof(word);
int i;
- ml_printf("Filling test area with u16 (offset %d, %p):", offset, ptr);
-
reset_start_data(offset);
+ ml_printf("Filling test area with u16 (offset %d, %p):", offset, ptr);
+
for (i = 0; i < max; i++) {
uint16_t low = BYTE_NEXT(count), high = BYTE_NEXT(count);
word = BYTE_SHIFT(high, 1) | BYTE_SHIFT(low, 0);
*ptr++ = word;
- pdot(i);
+ pdot(i, true);
}
- ml_printf("done @ %p\n", ptr);
+ ml_printf("done %d @ %p\n", i, ptr);
}
static void init_test_data_u32(int offset)
@@ -137,21 +159,22 @@ static void init_test_data_u32(int offset)
const int max = (TEST_SIZE - offset) / sizeof(word);
int i;
- ml_printf("Filling test area with u32 (offset %d, %p):", offset, ptr);
-
reset_start_data(offset);
+ ml_printf("Filling test area with u32 (offset %d, %p):", offset, ptr);
+
for (i = 0; i < max; i++) {
uint32_t b4 = BYTE_NEXT(count), b3 = BYTE_NEXT(count);
uint32_t b2 = BYTE_NEXT(count), b1 = BYTE_NEXT(count);
word = BYTE_SHIFT(b1, 3) | BYTE_SHIFT(b2, 2) | BYTE_SHIFT(b3, 1) |
BYTE_SHIFT(b4, 0);
*ptr++ = word;
- pdot(i);
+ pdot(i, true);
}
- ml_printf("done @ %p\n", ptr);
+ ml_printf("done %d @ %p\n", i, ptr);
}
+#if __SIZEOF_POINTER__ >= 8
static void init_test_data_u64(int offset)
{
uint8_t count = 0;
@@ -159,10 +182,10 @@ static void init_test_data_u64(int offset)
const int max = (TEST_SIZE - offset) / sizeof(word);
int i;
- ml_printf("Filling test area with u64 (offset %d, %p):", offset, ptr);
-
reset_start_data(offset);
+ ml_printf("Filling test area with u64 (offset %d, %p):", offset, ptr);
+
for (i = 0; i < max; i++) {
uint64_t b8 = BYTE_NEXT(count), b7 = BYTE_NEXT(count);
uint64_t b6 = BYTE_NEXT(count), b5 = BYTE_NEXT(count);
@@ -172,10 +195,11 @@ static void init_test_data_u64(int offset)
BYTE_SHIFT(b4, 4) | BYTE_SHIFT(b5, 3) | BYTE_SHIFT(b6, 2) |
BYTE_SHIFT(b7, 1) | BYTE_SHIFT(b8, 0);
*ptr++ = word;
- pdot(i);
+ pdot(i, true);
}
- ml_printf("done @ %p\n", ptr);
+ ml_printf("done %d @ %p\n", i, ptr);
}
+#endif
static bool read_test_data_u16(int offset)
{
@@ -194,11 +218,11 @@ static bool read_test_data_u16(int offset)
ml_printf("Error %d < %d\n", high, low);
return false;
} else {
- pdot(i);
+ pdot(i, false);
}
}
- ml_printf("done @ %p\n", ptr);
+ ml_printf("done %d @ %p\n", i, ptr);
return true;
}
@@ -236,13 +260,14 @@ static bool read_test_data_u32(int offset)
ml_printf("Error %d, %d, %d, %d", b1, b2, b3, b4);
return false;
} else {
- pdot(i);
+ pdot(i, false);
}
}
- ml_printf("done @ %p\n", ptr);
+ ml_printf("done %d @ %p\n", i, ptr);
return true;
}
+#if __SIZEOF_POINTER__ >= 8
static bool read_test_data_u64(int offset)
{
uint64_t word, *ptr = (uint64_t *)&test_data[offset];
@@ -290,17 +315,22 @@ static bool read_test_data_u64(int offset)
b1, b2, b3, b4, b5, b6, b7, b8);
return false;
} else {
- pdot(i);
+ pdot(i, false);
}
}
- ml_printf("done @ %p\n", ptr);
+ ml_printf("done %d @ %p\n", i, ptr);
return true;
}
+#endif
/* Read the test data and verify at various offsets */
-read_ufn read_ufns[] = { read_test_data_u16,
- read_test_data_u32,
- read_test_data_u64 };
+read_ufn read_ufns[] = {
+ read_test_data_u16,
+ read_test_data_u32,
+#if __SIZEOF_POINTER__ >= 8
+ read_test_data_u64
+#endif
+};
bool do_unsigned_reads(int start_off)
{
@@ -357,15 +387,17 @@ static bool read_test_data_s8(int offset, bool neg_first)
second = *ptr++;
if (neg_first && first < 0 && second > 0) {
- pdot(i);
+ pdot(i, false);
+ pdot(i, false);
} else if (!neg_first && first > 0 && second < 0) {
- pdot(i);
+ pdot(i, false);
+ pdot(i, false);
} else {
ml_printf("Error %d %c %d\n", first, neg_first ? '<' : '>', second);
return false;
}
}
- ml_printf("done @ %p\n", ptr);
+ ml_printf("done %d @ %p\n", i * 2, ptr);
return true;
}
@@ -390,15 +422,15 @@ static bool read_test_data_s16(int offset, bool neg_first)
int32_t data = *ptr++;
if (neg_first && data < 0) {
- pdot(i);
+ pdot(i, false);
} else if (!neg_first && data > 0) {
- pdot(i);
+ pdot(i, false);
} else {
ml_printf("Error %d %c 0\n", data, neg_first ? '<' : '>');
return false;
}
}
- ml_printf("done @ %p\n", ptr);
+ ml_printf("done %d @ %p\n", i, ptr);
return true;
}
@@ -423,15 +455,15 @@ static bool read_test_data_s32(int offset, bool neg_first)
int64_t data = *ptr++;
if (neg_first && data < 0) {
- pdot(i);
+ pdot(i, false);
} else if (!neg_first && data > 0) {
- pdot(i);
+ pdot(i, false);
} else {
ml_printf("Error %d %c 0\n", data, neg_first ? '<' : '>');
return false;
}
}
- ml_printf("done @ %p\n", ptr);
+ ml_printf("done %d @ %p\n", i, ptr);
return true;
}
@@ -465,16 +497,23 @@ bool do_signed_reads(bool neg_first)
return ok;
}
-init_ufn init_ufns[] = { init_test_data_u8,
- init_test_data_u16,
- init_test_data_u32,
- init_test_data_u64 };
+init_ufn init_ufns[] = {
+ init_test_data_u8,
+ init_test_data_u16,
+ init_test_data_u32,
+#if __SIZEOF_POINTER__ >= 8
+ init_test_data_u64
+#endif
+};
int main(void)
{
int i;
bool ok = true;
+ ml_printf("Test data start: 0x%"PRIxPTR"\n", &test_data[0]);
+ ml_printf("Test data end: 0x%"PRIxPTR"\n", &test_data[TEST_SIZE]);
+
/* Run through the unsigned tests first */
for (i = 0; i < ARRAY_SIZE(init_ufns) && ok; i++) {
ok = do_unsigned_test(init_ufns[i]);
@@ -490,6 +529,8 @@ int main(void)
ok = do_signed_reads(true);
}
+ ml_printf("Test data read: %"PRId32"\n", test_read_count);
+ ml_printf("Test data write: %"PRId32"\n", test_write_count);
ml_printf("Test complete: %s\n", ok ? "PASSED" : "FAILED");
return ok ? 0 : -1;
}
diff --git a/tests/tcg/multiarch/system/validate-memory-counts.py b/tests/tcg/multiarch/system/validate-memory-counts.py
new file mode 100755
index 0000000..5b8bbf3
--- /dev/null
+++ b/tests/tcg/multiarch/system/validate-memory-counts.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python3
+#
+# validate-memory-counts.py: check we instrumented memory properly
+#
+# This program takes two inputs:
+# - the mem plugin output
+# - the memory binary output
+#
+# Copyright (C) 2024 Linaro Ltd
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import sys
+from argparse import ArgumentParser
+
+def extract_counts(path):
+ """
+ Load the output from path and extract the lines containing:
+
+ Test data start: 0x40214000
+ Test data end: 0x40218001
+ Test data read: 2522280
+ Test data write: 262111
+
+ From the stream of data. Extract the values for use in the
+ validation function.
+ """
+ start_address = None
+ end_address = None
+ read_count = 0
+ write_count = 0
+ with open(path, 'r') as f:
+ for line in f:
+ if line.startswith("Test data start:"):
+ start_address = int(line.split(':')[1].strip(), 16)
+ elif line.startswith("Test data end:"):
+ end_address = int(line.split(':')[1].strip(), 16)
+ elif line.startswith("Test data read:"):
+ read_count = int(line.split(':')[1].strip())
+ elif line.startswith("Test data write:"):
+ write_count = int(line.split(':')[1].strip())
+ return start_address, end_address, read_count, write_count
+
+
+def parse_plugin_output(path, start, end):
+ """
+ Load the plugin output from path in the form of:
+
+ Region Base, Reads, Writes, Seen all
+ 0x0000000040004000, 31093, 0, false
+ 0x0000000040214000, 2522280, 278579, true
+ 0x0000000040000000, 137398, 0, false
+ 0x0000000040210000, 54727397, 33721956, false
+
+ And extract the ranges that match test data start and end and
+ return the results.
+ """
+ total_reads = 0
+ total_writes = 0
+ seen_all = False
+
+ with open(path, 'r') as f:
+ next(f) # Skip the header
+ for line in f:
+
+ if line.startswith("Region Base"):
+ continue
+
+ parts = line.strip().split(', ')
+ if len(parts) != 4:
+ continue
+
+ region_base = int(parts[0], 16)
+ reads = int(parts[1])
+ writes = int(parts[2])
+
+ if start <= region_base < end: # Checking if within range
+ total_reads += reads
+ total_writes += writes
+ seen_all = parts[3] == "true"
+
+ return total_reads, total_writes, seen_all
+
+def main() -> None:
+ """
+ Process the arguments, injest the program and plugin out and
+ verify they match up and report if they do not.
+ """
+ parser = ArgumentParser(description="Validate memory instrumentation")
+ parser.add_argument('test_output',
+ help="The output from the test itself")
+ parser.add_argument('plugin_output',
+ help="The output from memory plugin")
+ parser.add_argument('--bss-cleared',
+ action='store_true',
+ help='Assume bss was cleared (and adjusts counts).')
+
+ args = parser.parse_args()
+
+ # Extract counts from memory binary
+ start, end, exp_reads, exp_writes = extract_counts(args.test_output)
+
+ # Some targets clear BSS before running but the test doesn't know
+ # that so we adjust it by the size of the test region.
+ if args.bss_cleared:
+ exp_writes += 16384
+
+ if start is None or end is None:
+ print("Failed to test_data boundaries from output.")
+ sys.exit(1)
+
+ # Parse plugin output
+ preads, pwrites, seen_all = parse_plugin_output(args.plugin_output,
+ start, end)
+
+ if not seen_all:
+ print("Fail: didn't instrument all accesses to test_data.")
+ sys.exit(1)
+
+ # Compare and report
+ if preads == exp_reads and pwrites == exp_writes:
+ sys.exit(0)
+ else:
+ print("Fail: The memory reads and writes count does not match.")
+ print(f"Expected Reads: {exp_reads}, Actual Reads: {preads}")
+ print(f"Expected Writes: {exp_writes}, Actual Writes: {pwrites}")
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/tcg/multiarch/test-plugin-mem-access.c b/tests/tcg/multiarch/test-plugin-mem-access.c
new file mode 100644
index 0000000..057b9aa
--- /dev/null
+++ b/tests/tcg/multiarch/test-plugin-mem-access.c
@@ -0,0 +1,177 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Check if we detect all memory accesses expected using plugin API.
+ * Used in conjunction with ./check-plugin-mem-access.sh check script.
+ * Output of this program is the list of patterns expected in plugin output.
+ *
+ * 8,16,32 load/store are tested for all arch.
+ * 64,128 load/store are tested for aarch64/x64.
+ * atomic operations (8,16,32,64) are tested for x64 only.
+ */
+
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#if defined(__x86_64__)
+#include <emmintrin.h>
+#elif defined(__aarch64__)
+#include <arm_neon.h>
+#endif /* __x86_64__ */
+
+static void *data;
+
+/* ,store_u8,.*,8,store,0xf1 */
+#define PRINT_EXPECTED(function, type, value, action) \
+do { \
+ printf(",%s,.*,%d,%s,%s\n", \
+ #function, (int) sizeof(type) * 8, action, value); \
+} \
+while (0)
+
+#define DEFINE_STORE(name, type, value) \
+ \
+static void print_expected_store_##name(void) \
+{ \
+ PRINT_EXPECTED(store_##name, type, #value, "store"); \
+} \
+ \
+static void store_##name(void) \
+{ \
+ *((type *)data) = value; \
+ print_expected_store_##name(); \
+}
+
+#define DEFINE_ATOMIC_OP(name, type, value) \
+ \
+static void print_expected_atomic_op_##name(void) \
+{ \
+ PRINT_EXPECTED(atomic_op_##name, type, "0x0*42", "load"); \
+ PRINT_EXPECTED(atomic_op_##name, type, #value, "store"); \
+} \
+ \
+static void atomic_op_##name(void) \
+{ \
+ *((type *)data) = 0x42; \
+ __sync_val_compare_and_swap((type *)data, 0x42, value); \
+ print_expected_atomic_op_##name(); \
+}
+
+#define DEFINE_LOAD(name, type, value) \
+ \
+static void print_expected_load_##name(void) \
+{ \
+ PRINT_EXPECTED(load_##name, type, #value, "load"); \
+} \
+ \
+static void load_##name(void) \
+{ \
+ \
+ /* volatile forces load to be generated. */ \
+ volatile type src = *((type *) data); \
+ volatile type dest = src; \
+ (void)src, (void)dest; \
+ print_expected_load_##name(); \
+}
+
+DEFINE_STORE(u8, uint8_t, 0xf1)
+DEFINE_LOAD(u8, uint8_t, 0xf1)
+DEFINE_STORE(u16, uint16_t, 0xf123)
+DEFINE_LOAD(u16, uint16_t, 0xf123)
+DEFINE_STORE(u32, uint32_t, 0xff112233)
+DEFINE_LOAD(u32, uint32_t, 0xff112233)
+
+#if defined(__x86_64__) || defined(__aarch64__)
+DEFINE_STORE(u64, uint64_t, 0xf123456789abcdef)
+DEFINE_LOAD(u64, uint64_t, 0xf123456789abcdef)
+
+static void print_expected_store_u128(void)
+{
+ PRINT_EXPECTED(store_u128, __int128,
+ "0xf122334455667788f123456789abcdef", "store");
+}
+
+static void store_u128(void)
+{
+#ifdef __x86_64__
+ _mm_store_si128(data, _mm_set_epi32(0xf1223344, 0x55667788,
+ 0xf1234567, 0x89abcdef));
+#else
+ const uint32_t init[4] = {0x89abcdef, 0xf1234567, 0x55667788, 0xf1223344};
+ uint32x4_t vec = vld1q_u32(init);
+ vst1q_u32(data, vec);
+#endif /* __x86_64__ */
+ print_expected_store_u128();
+}
+
+static void print_expected_load_u128(void)
+{
+ PRINT_EXPECTED(load_u128, __int128,
+ "0xf122334455667788f123456789abcdef", "load");
+}
+
+static void load_u128(void)
+{
+#ifdef __x86_64__
+ __m128i var = _mm_load_si128(data);
+#else
+ uint32x4_t var = vld1q_u32(data);
+#endif
+ (void) var;
+ print_expected_load_u128();
+}
+#endif /* __x86_64__ || __aarch64__ */
+
+#if defined(__x86_64__)
+DEFINE_ATOMIC_OP(u8, uint8_t, 0xf1)
+DEFINE_ATOMIC_OP(u16, uint16_t, 0xf123)
+DEFINE_ATOMIC_OP(u32, uint32_t, 0xff112233)
+DEFINE_ATOMIC_OP(u64, uint64_t, 0xf123456789abcdef)
+#endif /* __x86_64__ */
+
+static void *f(void *p)
+{
+ return NULL;
+}
+
+int main(void)
+{
+ /*
+ * We force creation of a second thread to enable cpu flag CF_PARALLEL.
+ * This will generate atomic operations when needed.
+ */
+ pthread_t thread;
+ pthread_create(&thread, NULL, &f, NULL);
+ pthread_join(thread, NULL);
+
+ /* allocate storage up to 128 bits */
+ data = malloc(16);
+
+ store_u8();
+ load_u8();
+
+ store_u16();
+ load_u16();
+
+ store_u32();
+ load_u32();
+
+#if defined(__x86_64__) || defined(__aarch64__)
+ store_u64();
+ load_u64();
+
+ store_u128();
+ load_u128();
+#endif /* __x86_64__ || __aarch64__ */
+
+#if defined(__x86_64__)
+ atomic_op_u8();
+ atomic_op_u16();
+ atomic_op_u32();
+ atomic_op_u64();
+#endif /* __x86_64__ */
+
+ free(data);
+}
diff --git a/tests/plugin/bb.c b/tests/tcg/plugins/bb.c
index 36776de..36776de 100644
--- a/tests/plugin/bb.c
+++ b/tests/tcg/plugins/bb.c
diff --git a/tests/plugin/empty.c b/tests/tcg/plugins/empty.c
index 8fa6bac..8fa6bac 100644
--- a/tests/plugin/empty.c
+++ b/tests/tcg/plugins/empty.c
diff --git a/tests/plugin/inline.c b/tests/tcg/plugins/inline.c
index cd63827..73dde99 100644
--- a/tests/plugin/inline.c
+++ b/tests/tcg/plugins/inline.c
@@ -71,10 +71,12 @@ static void stats_insn(void)
const uint64_t cond_track_left = qemu_plugin_u64_sum(insn_cond_track_count);
const uint64_t conditional =
cond_num_trigger * cond_trigger_limit + cond_track_left;
- printf("insn: %" PRIu64 "\n", expected);
- printf("insn: %" PRIu64 " (per vcpu)\n", per_vcpu);
- printf("insn: %" PRIu64 " (per vcpu inline)\n", inl_per_vcpu);
- printf("insn: %" PRIu64 " (cond cb)\n", conditional);
+ g_autoptr(GString) stats = g_string_new("");
+ g_string_append_printf(stats, "insn: %" PRIu64 "\n", expected);
+ g_string_append_printf(stats, "insn: %" PRIu64 " (per vcpu)\n", per_vcpu);
+ g_string_append_printf(stats, "insn: %" PRIu64 " (per vcpu inline)\n", inl_per_vcpu);
+ g_string_append_printf(stats, "insn: %" PRIu64 " (cond cb)\n", conditional);
+ qemu_plugin_outs(stats->str);
g_assert(expected > 0);
g_assert(per_vcpu == expected);
g_assert(inl_per_vcpu == expected);
@@ -91,10 +93,12 @@ static void stats_tb(void)
const uint64_t cond_track_left = qemu_plugin_u64_sum(tb_cond_track_count);
const uint64_t conditional =
cond_num_trigger * cond_trigger_limit + cond_track_left;
- printf("tb: %" PRIu64 "\n", expected);
- printf("tb: %" PRIu64 " (per vcpu)\n", per_vcpu);
- printf("tb: %" PRIu64 " (per vcpu inline)\n", inl_per_vcpu);
- printf("tb: %" PRIu64 " (conditional cb)\n", conditional);
+ g_autoptr(GString) stats = g_string_new("");
+ g_string_append_printf(stats, "tb: %" PRIu64 "\n", expected);
+ g_string_append_printf(stats, "tb: %" PRIu64 " (per vcpu)\n", per_vcpu);
+ g_string_append_printf(stats, "tb: %" PRIu64 " (per vcpu inline)\n", inl_per_vcpu);
+ g_string_append_printf(stats, "tb: %" PRIu64 " (conditional cb)\n", conditional);
+ qemu_plugin_outs(stats->str);
g_assert(expected > 0);
g_assert(per_vcpu == expected);
g_assert(inl_per_vcpu == expected);
@@ -107,9 +111,11 @@ static void stats_mem(void)
const uint64_t per_vcpu = qemu_plugin_u64_sum(count_mem);
const uint64_t inl_per_vcpu =
qemu_plugin_u64_sum(count_mem_inline);
- printf("mem: %" PRIu64 "\n", expected);
- printf("mem: %" PRIu64 " (per vcpu)\n", per_vcpu);
- printf("mem: %" PRIu64 " (per vcpu inline)\n", inl_per_vcpu);
+ g_autoptr(GString) stats = g_string_new("");
+ g_string_append_printf(stats, "mem: %" PRIu64 "\n", expected);
+ g_string_append_printf(stats, "mem: %" PRIu64 " (per vcpu)\n", per_vcpu);
+ g_string_append_printf(stats, "mem: %" PRIu64 " (per vcpu inline)\n", inl_per_vcpu);
+ qemu_plugin_outs(stats->str);
g_assert(expected > 0);
g_assert(per_vcpu == expected);
g_assert(inl_per_vcpu == expected);
@@ -118,6 +124,7 @@ static void stats_mem(void)
static void plugin_exit(qemu_plugin_id_t id, void *udata)
{
const unsigned int num_cpus = qemu_plugin_num_vcpus();
+ g_autoptr(GString) stats = g_string_new("");
g_assert(num_cpus == max_cpu_index + 1);
for (int i = 0; i < num_cpus ; ++i) {
@@ -135,20 +142,21 @@ static void plugin_exit(qemu_plugin_id_t id, void *udata)
qemu_plugin_u64_get(insn_cond_num_trigger, i);
const uint64_t insn_cond_left =
qemu_plugin_u64_get(insn_cond_track_count, i);
- printf("cpu %d: tb (%" PRIu64 ", %" PRIu64
- ", %" PRIu64 " * %" PRIu64 " + %" PRIu64
- ") | "
- "insn (%" PRIu64 ", %" PRIu64
- ", %" PRIu64 " * %" PRIu64 " + %" PRIu64
- ") | "
- "mem (%" PRIu64 ", %" PRIu64 ")"
- "\n",
- i,
- tb, tb_inline,
- tb_cond_trigger, cond_trigger_limit, tb_cond_left,
- insn, insn_inline,
- insn_cond_trigger, cond_trigger_limit, insn_cond_left,
- mem, mem_inline);
+ g_string_printf(stats, "cpu %d: tb (%" PRIu64 ", %" PRIu64
+ ", %" PRIu64 " * %" PRIu64 " + %" PRIu64
+ ") | "
+ "insn (%" PRIu64 ", %" PRIu64
+ ", %" PRIu64 " * %" PRIu64 " + %" PRIu64
+ ") | "
+ "mem (%" PRIu64 ", %" PRIu64 ")"
+ "\n",
+ i,
+ tb, tb_inline,
+ tb_cond_trigger, cond_trigger_limit, tb_cond_left,
+ insn, insn_inline,
+ insn_cond_trigger, cond_trigger_limit, insn_cond_left,
+ mem, mem_inline);
+ qemu_plugin_outs(stats->str);
g_assert(tb == tb_inline);
g_assert(insn == insn_inline);
g_assert(mem == mem_inline);
diff --git a/tests/plugin/insn.c b/tests/tcg/plugins/insn.c
index baf2d07..baf2d07 100644
--- a/tests/plugin/insn.c
+++ b/tests/tcg/plugins/insn.c
diff --git a/tests/tcg/plugins/mem.c b/tests/tcg/plugins/mem.c
new file mode 100644
index 0000000..b0fa8a9
--- /dev/null
+++ b/tests/tcg/plugins/mem.c
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2018, Emilio G. Cota <cota@braap.org>
+ *
+ * License: GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include <inttypes.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <glib.h>
+
+/*
+ * plugins should not include anything from QEMU aside from the
+ * API header. However as this is a test plugin to exercise the
+ * internals of QEMU and we want to avoid needless code duplication we
+ * do so here. bswap.h is pretty self-contained although it needs a
+ * few things provided by compiler.h.
+ */
+#include <compiler.h>
+#include <bswap.h>
+#include <qemu-plugin.h>
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
+
+typedef struct {
+ uint64_t mem_count;
+ uint64_t io_count;
+} CPUCount;
+
+typedef struct {
+ uint64_t vaddr;
+ const char *sym;
+} InsnInfo;
+
+/*
+ * For the "memory" system test we need to track accesses to
+ * individual regions. We mirror the data written to the region and
+ * then check when it is read that it matches up.
+ *
+ * We do this as regions rather than pages to save on complications
+ * with page crossing and the fact the test only cares about the
+ * test_data region.
+ */
+static uint64_t region_size = 4096 * 4;
+static uint64_t region_mask;
+
+typedef struct {
+ uint64_t region_address;
+ uint64_t reads;
+ uint64_t writes;
+ uint8_t *data;
+ /* Did we see every write and read with correct values? */
+ bool seen_all;
+} RegionInfo;
+
+static struct qemu_plugin_scoreboard *counts;
+static qemu_plugin_u64 mem_count;
+static qemu_plugin_u64 io_count;
+static bool do_inline, do_callback, do_print_accesses, do_region_summary;
+static bool do_haddr;
+static enum qemu_plugin_mem_rw rw = QEMU_PLUGIN_MEM_RW;
+
+
+static GMutex lock;
+static GHashTable *regions;
+
+static gint addr_order(gconstpointer a, gconstpointer b)
+{
+ RegionInfo *na = (RegionInfo *) a;
+ RegionInfo *nb = (RegionInfo *) b;
+
+ return na->region_address > nb->region_address ? 1 : -1;
+}
+
+
+static void plugin_exit(qemu_plugin_id_t id, void *p)
+{
+ g_autoptr(GString) out = g_string_new("");
+
+ if (do_inline || do_callback) {
+ g_string_printf(out, "mem accesses: %" PRIu64 "\n",
+ qemu_plugin_u64_sum(mem_count));
+ }
+ if (do_haddr) {
+ g_string_append_printf(out, "io accesses: %" PRIu64 "\n",
+ qemu_plugin_u64_sum(io_count));
+ }
+ qemu_plugin_outs(out->str);
+
+
+ if (do_region_summary) {
+ GList *counts = g_hash_table_get_values(regions);
+
+ counts = g_list_sort(counts, addr_order);
+
+ g_string_printf(out, "Region Base, Reads, Writes, Seen all\n");
+
+ if (counts && g_list_next(counts)) {
+ for (/* counts */; counts; counts = counts->next) {
+ RegionInfo *ri = (RegionInfo *) counts->data;
+
+ g_string_append_printf(out,
+ "0x%016"PRIx64", "
+ "%"PRId64", %"PRId64", %s\n",
+ ri->region_address,
+ ri->reads,
+ ri->writes,
+ ri->seen_all ? "true" : "false");
+ }
+ }
+ qemu_plugin_outs(out->str);
+ }
+
+ qemu_plugin_scoreboard_free(counts);
+}
+
+/*
+ * Update the region tracking info for the access. We split up accesses
+ * that span regions even though the plugin infrastructure will deliver
+ * it as a single access.
+ */
+static void update_region_info(uint64_t region, uint64_t offset,
+ qemu_plugin_meminfo_t meminfo,
+ qemu_plugin_mem_value value,
+ unsigned size)
+{
+ bool be = qemu_plugin_mem_is_big_endian(meminfo);
+ bool is_store = qemu_plugin_mem_is_store(meminfo);
+ RegionInfo *ri;
+ bool unseen_data = false;
+
+ g_assert(offset + size <= region_size);
+
+ g_mutex_lock(&lock);
+ ri = (RegionInfo *) g_hash_table_lookup(regions, GUINT_TO_POINTER(region));
+
+ if (!ri) {
+ ri = g_new0(RegionInfo, 1);
+ ri->region_address = region;
+ ri->data = g_malloc0(region_size);
+ ri->seen_all = true;
+ g_hash_table_insert(regions, GUINT_TO_POINTER(region), (gpointer) ri);
+ }
+
+ if (is_store) {
+ ri->writes++;
+ } else {
+ ri->reads++;
+ }
+
+ switch (value.type) {
+ case QEMU_PLUGIN_MEM_VALUE_U8:
+ if (is_store) {
+ ri->data[offset] = value.data.u8;
+ } else if (ri->data[offset] != value.data.u8) {
+ unseen_data = true;
+ }
+ break;
+ case QEMU_PLUGIN_MEM_VALUE_U16:
+ {
+ uint16_t *p = (uint16_t *) &ri->data[offset];
+ if (is_store) {
+ if (be) {
+ stw_be_p(p, value.data.u16);
+ } else {
+ stw_le_p(p, value.data.u16);
+ }
+ } else {
+ uint16_t val = be ? lduw_be_p(p) : lduw_le_p(p);
+ unseen_data = val != value.data.u16;
+ }
+ break;
+ }
+ case QEMU_PLUGIN_MEM_VALUE_U32:
+ {
+ uint32_t *p = (uint32_t *) &ri->data[offset];
+ if (is_store) {
+ if (be) {
+ stl_be_p(p, value.data.u32);
+ } else {
+ stl_le_p(p, value.data.u32);
+ }
+ } else {
+ uint32_t val = be ? ldl_be_p(p) : ldl_le_p(p);
+ unseen_data = val != value.data.u32;
+ }
+ break;
+ }
+ case QEMU_PLUGIN_MEM_VALUE_U64:
+ {
+ uint64_t *p = (uint64_t *) &ri->data[offset];
+ if (is_store) {
+ if (be) {
+ stq_be_p(p, value.data.u64);
+ } else {
+ stq_le_p(p, value.data.u64);
+ }
+ } else {
+ uint64_t val = be ? ldq_be_p(p) : ldq_le_p(p);
+ unseen_data = val != value.data.u64;
+ }
+ break;
+ }
+ case QEMU_PLUGIN_MEM_VALUE_U128:
+ /* non in test so skip */
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ /*
+ * This is expected for regions initialised by QEMU (.text etc) but we
+ * expect to see all data read and written to the test_data region
+ * of the memory test.
+ */
+ if (unseen_data && ri->seen_all) {
+ g_autoptr(GString) error = g_string_new("Warning: ");
+ g_string_append_printf(error, "0x%016"PRIx64":%"PRId64
+ " read an un-instrumented value\n",
+ region, offset);
+ qemu_plugin_outs(error->str);
+ ri->seen_all = false;
+ }
+
+ g_mutex_unlock(&lock);
+}
+
+static void vcpu_mem(unsigned int cpu_index, qemu_plugin_meminfo_t meminfo,
+ uint64_t vaddr, void *udata)
+{
+ if (do_haddr) {
+ struct qemu_plugin_hwaddr *hwaddr;
+ hwaddr = qemu_plugin_get_hwaddr(meminfo, vaddr);
+ if (qemu_plugin_hwaddr_is_io(hwaddr)) {
+ qemu_plugin_u64_add(io_count, cpu_index, 1);
+ } else {
+ qemu_plugin_u64_add(mem_count, cpu_index, 1);
+ }
+ } else {
+ qemu_plugin_u64_add(mem_count, cpu_index, 1);
+ }
+
+ if (do_region_summary) {
+ uint64_t region = vaddr & ~region_mask;
+ uint64_t offset = vaddr & region_mask;
+ qemu_plugin_mem_value value = qemu_plugin_mem_get_value(meminfo);
+ unsigned size = 1 << qemu_plugin_mem_size_shift(meminfo);
+
+ update_region_info(region, offset, meminfo, value, size);
+ }
+}
+
+static void print_access(unsigned int cpu_index, qemu_plugin_meminfo_t meminfo,
+ uint64_t vaddr, void *udata)
+{
+ InsnInfo *insn_info = udata;
+ unsigned size = 8 << qemu_plugin_mem_size_shift(meminfo);
+ const char *type = qemu_plugin_mem_is_store(meminfo) ? "store" : "load";
+ qemu_plugin_mem_value value = qemu_plugin_mem_get_value(meminfo);
+ uint64_t hwaddr =
+ qemu_plugin_hwaddr_phys_addr(qemu_plugin_get_hwaddr(meminfo, vaddr));
+ g_autoptr(GString) out = g_string_new("");
+ g_string_printf(out,
+ "0x%"PRIx64",%s,0x%"PRIx64",0x%"PRIx64",%d,%s,",
+ insn_info->vaddr, insn_info->sym,
+ vaddr, hwaddr, size, type);
+ switch (value.type) {
+ case QEMU_PLUGIN_MEM_VALUE_U8:
+ g_string_append_printf(out, "0x%02"PRIx8, value.data.u8);
+ break;
+ case QEMU_PLUGIN_MEM_VALUE_U16:
+ g_string_append_printf(out, "0x%04"PRIx16, value.data.u16);
+ break;
+ case QEMU_PLUGIN_MEM_VALUE_U32:
+ g_string_append_printf(out, "0x%08"PRIx32, value.data.u32);
+ break;
+ case QEMU_PLUGIN_MEM_VALUE_U64:
+ g_string_append_printf(out, "0x%016"PRIx64, value.data.u64);
+ break;
+ case QEMU_PLUGIN_MEM_VALUE_U128:
+ g_string_append_printf(out, "0x%016"PRIx64"%016"PRIx64,
+ value.data.u128.high, value.data.u128.low);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ g_string_append_printf(out, "\n");
+ qemu_plugin_outs(out->str);
+}
+
+static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb)
+{
+ size_t n = qemu_plugin_tb_n_insns(tb);
+ size_t i;
+
+ for (i = 0; i < n; i++) {
+ struct qemu_plugin_insn *insn = qemu_plugin_tb_get_insn(tb, i);
+
+ if (do_inline) {
+ qemu_plugin_register_vcpu_mem_inline_per_vcpu(
+ insn, rw,
+ QEMU_PLUGIN_INLINE_ADD_U64,
+ mem_count, 1);
+ }
+ if (do_callback || do_region_summary) {
+ qemu_plugin_register_vcpu_mem_cb(insn, vcpu_mem,
+ QEMU_PLUGIN_CB_NO_REGS,
+ rw, NULL);
+ }
+ if (do_print_accesses) {
+ /* we leak this pointer, to avoid locking to keep track of it */
+ InsnInfo *insn_info = g_malloc(sizeof(InsnInfo));
+ const char *sym = qemu_plugin_insn_symbol(insn);
+ insn_info->sym = sym ? sym : "";
+ insn_info->vaddr = qemu_plugin_insn_vaddr(insn);
+ qemu_plugin_register_vcpu_mem_cb(insn, print_access,
+ QEMU_PLUGIN_CB_NO_REGS,
+ rw, (void *) insn_info);
+ }
+ }
+}
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
+ const qemu_info_t *info,
+ int argc, char **argv)
+{
+
+ for (int i = 0; i < argc; i++) {
+ char *opt = argv[i];
+ g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
+
+ if (g_strcmp0(tokens[0], "haddr") == 0) {
+ if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_haddr)) {
+ fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
+ return -1;
+ }
+ } else if (g_strcmp0(tokens[0], "track") == 0) {
+ if (g_strcmp0(tokens[1], "r") == 0) {
+ rw = QEMU_PLUGIN_MEM_R;
+ } else if (g_strcmp0(tokens[1], "w") == 0) {
+ rw = QEMU_PLUGIN_MEM_W;
+ } else if (g_strcmp0(tokens[1], "rw") == 0) {
+ rw = QEMU_PLUGIN_MEM_RW;
+ } else {
+ fprintf(stderr, "invalid value for argument track: %s\n", opt);
+ return -1;
+ }
+ } else if (g_strcmp0(tokens[0], "inline") == 0) {
+ if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_inline)) {
+ fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
+ return -1;
+ }
+ } else if (g_strcmp0(tokens[0], "callback") == 0) {
+ if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_callback)) {
+ fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
+ return -1;
+ }
+ } else if (g_strcmp0(tokens[0], "print-accesses") == 0) {
+ if (!qemu_plugin_bool_parse(tokens[0], tokens[1],
+ &do_print_accesses)) {
+ fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
+ return -1;
+ }
+ } else if (g_strcmp0(tokens[0], "region-summary") == 0) {
+ if (!qemu_plugin_bool_parse(tokens[0], tokens[1],
+ &do_region_summary)) {
+ fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
+ return -1;
+ }
+ } else {
+ fprintf(stderr, "option parsing failed: %s\n", opt);
+ return -1;
+ }
+ }
+
+ if (do_inline && do_callback) {
+ fprintf(stderr,
+ "can't enable inline and callback counting at the same time\n");
+ return -1;
+ }
+
+ if (do_print_accesses) {
+ g_autoptr(GString) out = g_string_new("");
+ g_string_printf(out,
+ "insn_vaddr,insn_symbol,mem_vaddr,mem_hwaddr,"
+ "access_size,access_type,mem_value\n");
+ qemu_plugin_outs(out->str);
+ }
+
+ if (do_region_summary) {
+ region_mask = (region_size - 1);
+ regions = g_hash_table_new(NULL, g_direct_equal);
+ }
+
+ counts = qemu_plugin_scoreboard_new(sizeof(CPUCount));
+ mem_count = qemu_plugin_scoreboard_u64_in_struct(
+ counts, CPUCount, mem_count);
+ io_count = qemu_plugin_scoreboard_u64_in_struct(counts, CPUCount, io_count);
+ qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans);
+ qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
+ return 0;
+}
diff --git a/tests/plugin/meson.build b/tests/tcg/plugins/meson.build
index 9eece5b..f847849 100644
--- a/tests/plugin/meson.build
+++ b/tests/tcg/plugins/meson.build
@@ -2,15 +2,15 @@ t = []
if get_option('plugins')
foreach i : ['bb', 'empty', 'inline', 'insn', 'mem', 'syscall']
if host_os == 'windows'
- t += shared_module(i, files(i + '.c') + '../../contrib/plugins/win32_linker.c',
- include_directories: '../../include/qemu',
+ t += shared_module(i, files(i + '.c') + '../../../contrib/plugins/win32_linker.c',
+ include_directories: '../../../include/qemu',
link_depends: [win32_qemu_plugin_api_lib],
link_args: ['-Lplugins', '-lqemu_plugin_api'],
dependencies: glib)
else
t += shared_module(i, files(i + '.c'),
- include_directories: '../../include/qemu',
+ include_directories: '../../../include/qemu',
dependencies: glib)
endif
endforeach
diff --git a/tests/plugin/syscall.c b/tests/tcg/plugins/syscall.c
index 72e1a5b..ff45217 100644
--- a/tests/plugin/syscall.c
+++ b/tests/tcg/plugins/syscall.c
@@ -22,8 +22,56 @@ typedef struct {
int64_t errors;
} SyscallStats;
+struct SyscallInfo {
+ const char *name;
+ int64_t write_sysno;
+};
+
+static const struct SyscallInfo arch_syscall_info[] = {
+ { "aarch64", 64 },
+ { "aarch64_be", 64 },
+ { "alpha", 4 },
+ { "arm", 4 },
+ { "armeb", 4 },
+ { "avr", -1 },
+ { "hexagon", 64 },
+ { "hppa", -1 },
+ { "i386", 4 },
+ { "loongarch64", -1 },
+ { "m68k", 4 },
+ { "microblaze", 4 },
+ { "microblazeel", 4 },
+ { "mips", 1 },
+ { "mips64", 1 },
+ { "mips64el", 1 },
+ { "mipsel", 1 },
+ { "mipsn32", 1 },
+ { "mipsn32el", 1 },
+ { "or1k", -1 },
+ { "ppc", 4 },
+ { "ppc64", 4 },
+ { "ppc64le", 4 },
+ { "riscv32", 64 },
+ { "riscv64", 64 },
+ { "rx", -1 },
+ { "s390x", -1 },
+ { "sh4", -1 },
+ { "sh4eb", -1 },
+ { "sparc", 4 },
+ { "sparc32plus", 4 },
+ { "sparc64", 4 },
+ { "tricore", -1 },
+ { "x86_64", 1 },
+ { "xtensa", 13 },
+ { "xtensaeb", 13 },
+ { NULL, -1 },
+};
+
static GMutex lock;
static GHashTable *statistics;
+static GByteArray *memory_buffer;
+static bool do_log_writes;
+static int64_t write_sysno = -1;
static SyscallStats *get_or_create_entry(int64_t num)
{
@@ -39,6 +87,44 @@ static SyscallStats *get_or_create_entry(int64_t num)
return entry;
}
+/*
+ * Hex-dump a GByteArray to the QEMU plugin output in the format:
+ * 61 63 63 65 6c 09 09 20 20 20 66 70 75 09 09 09 | accel.....fpu...
+ * 20 6d 6f 64 75 6c 65 2d 63 6f 6d 6d 6f 6e 2e 63 | .module-common.c
+ */
+static void hexdump(const GByteArray *data)
+{
+ g_autoptr(GString) out = g_string_new("");
+
+ for (guint index = 0; index < data->len; index += 16) {
+ for (guint col = 0; col < 16; col++) {
+ if (index + col < data->len) {
+ g_string_append_printf(out, "%02x ", data->data[index + col]);
+ } else {
+ g_string_append(out, " ");
+ }
+ }
+
+ g_string_append(out, " | ");
+
+ for (guint col = 0; col < 16; col++) {
+ if (index + col >= data->len) {
+ break;
+ }
+
+ if (g_ascii_isgraph(data->data[index + col])) {
+ g_string_append_printf(out, "%c", data->data[index + col]);
+ } else {
+ g_string_append(out, ".");
+ }
+ }
+
+ g_string_append(out, "\n");
+ }
+
+ qemu_plugin_outs(out->str);
+}
+
static void vcpu_syscall(qemu_plugin_id_t id, unsigned int vcpu_index,
int64_t num, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5,
@@ -54,6 +140,14 @@ static void vcpu_syscall(qemu_plugin_id_t id, unsigned int vcpu_index,
g_autofree gchar *out = g_strdup_printf("syscall #%" PRIi64 "\n", num);
qemu_plugin_outs(out);
}
+
+ if (do_log_writes && num == write_sysno) {
+ if (qemu_plugin_read_memory_vaddr(a2, memory_buffer, a3)) {
+ hexdump(memory_buffer);
+ } else {
+ fprintf(stderr, "Error reading memory from vaddr %"PRIu64"\n", a2);
+ }
+ }
}
static void vcpu_syscall_ret(qemu_plugin_id_t id, unsigned int vcpu_idx,
@@ -127,6 +221,10 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_print)) {
fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
}
+ } else if (g_strcmp0(tokens[0], "log_writes") == 0) {
+ if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_log_writes)) {
+ fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
+ }
} else {
fprintf(stderr, "unsupported argument: %s\n", argv[i]);
return -1;
@@ -137,6 +235,24 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
statistics = g_hash_table_new_full(NULL, g_direct_equal, NULL, g_free);
}
+ if (do_log_writes) {
+ for (const struct SyscallInfo *syscall_info = arch_syscall_info;
+ syscall_info->name != NULL; syscall_info++) {
+
+ if (g_strcmp0(syscall_info->name, info->target_name) == 0) {
+ write_sysno = syscall_info->write_sysno;
+ break;
+ }
+ }
+
+ if (write_sysno == -1) {
+ fprintf(stderr, "write syscall number not found\n");
+ return -1;
+ }
+
+ memory_buffer = g_byte_array_new();
+ }
+
qemu_plugin_register_vcpu_syscall_cb(id, vcpu_syscall);
qemu_plugin_register_vcpu_syscall_ret_cb(id, vcpu_syscall_ret);
qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
diff --git a/tests/tcg/ppc64/Makefile.target b/tests/tcg/ppc64/Makefile.target
index 8c3e4e4..1940886 100644
--- a/tests/tcg/ppc64/Makefile.target
+++ b/tests/tcg/ppc64/Makefile.target
@@ -11,6 +11,18 @@ config-cc.mak: Makefile
-include config-cc.mak
+# multi-threaded tests are known to fail (e.g., clang-user CI job)
+# See: https://gitlab.com/qemu-project/qemu/-/issues/2456
+run-signals: signals
+ $(call skip-test, $<, "BROKEN (flaky with clang) ")
+run-plugin-signals-with-%:
+ $(call skip-test, $<, "BROKEN (flaky with clang) ")
+
+run-threadcount: threadcount
+ $(call skip-test, $<, "BROKEN (flaky with clang) ")
+run-plugin-threadcount-with-%:
+ $(call skip-test, $<, "BROKEN (flaky with clang) ")
+
ifneq ($(CROSS_CC_HAS_POWER8_VECTOR),)
PPC64_TESTS=bcdsub non_signalling_xscv
endif
@@ -43,4 +55,9 @@ PPC64_TESTS += signal_save_restore_xer
PPC64_TESTS += xxspltw
PPC64_TESTS += test-aes
+# ppc64 ABI uses function descriptors, and thus, QEMU can't find symbol for a
+# given instruction. Thus, we don't check output of mem-access plugin.
+run-plugin-test-plugin-mem-access-with-libmem.so: \
+ CHECK_PLUGIN_OUTPUT_COMMAND=
+
TESTS += $(PPC64_TESTS)
diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/Makefile.softmmu-target
index d5b126e..7c1d44d 100644
--- a/tests/tcg/riscv64/Makefile.softmmu-target
+++ b/tests/tcg/riscv64/Makefile.softmmu-target
@@ -10,7 +10,7 @@ LDFLAGS = -T $(LINK_SCRIPT)
CFLAGS += -g -Og
%.o: %.S
- $(CC) $(CFLAGS) $< -c -o $@
+ $(CC) $(CFLAGS) $< -Wa,--noexecstack -c -o $@
%: %.o $(LINK_SCRIPT)
$(LD) $(LDFLAGS) $< -o $@
diff --git a/tests/tcg/s390x/Makefile.softmmu-target b/tests/tcg/s390x/Makefile.softmmu-target
index 4c8e15e..969bc57 100644
--- a/tests/tcg/s390x/Makefile.softmmu-target
+++ b/tests/tcg/s390x/Makefile.softmmu-target
@@ -1,12 +1,13 @@
S390X_SRC=$(SRC_PATH)/tests/tcg/s390x
VPATH+=$(S390X_SRC)
-QEMU_OPTS+=-action panic=exit-failure -nographic $(EXTFLAGS) -kernel
+# EXTFLAGS can be passed by the user, e.g. to override the --accel
+QEMU_OPTS+=-action panic=exit-failure -nographic -serial chardev:output $(EXTFLAGS) -kernel
LINK_SCRIPT=$(S390X_SRC)/softmmu.ld
-CFLAGS+=-ggdb -O0
+CFLAGS+=-ggdb -O0 -I$(SRC_PATH)/include/hw/s390x/ipl/
LDFLAGS=-nostdlib -static
%.o: %.S
- $(CC) -march=z13 -m64 -c $< -o $@
+ $(CC) -march=z13 -m64 -Wa,--noexecstack -c $< -o $@
%.o: %.c
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -march=z13 -m64 -c $< -o $@
@@ -46,3 +47,8 @@ $(MULTIARCH_TESTS): $(S390X_MULTIARCH_RUNTIME_OBJS)
$(MULTIARCH_TESTS): LDFLAGS += $(S390X_MULTIARCH_RUNTIME_OBJS)
$(MULTIARCH_TESTS): CFLAGS += $(MINILIB_INC)
memory: CFLAGS += -DCHECK_UNALIGNED=0
+
+# s390x clears the BSS section so we need to account for that
+run-plugin-memory-with-libmem.so: \
+ CHECK_PLUGIN_OUTPUT_COMMAND=$(MULTIARCH_SYSTEM_SRC)/validate-memory-counts.py \
+ --bss-cleared $@.out
diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target
index a8f86c9..2dab4f4 100644
--- a/tests/tcg/s390x/Makefile.target
+++ b/tests/tcg/s390x/Makefile.target
@@ -48,6 +48,7 @@ TESTS+=lae
TESTS+=cvd
TESTS+=cvb
TESTS+=ts
+TESTS+=ex-smc
cdsg: CFLAGS+=-pthread
cdsg: LDFLAGS+=-pthread
diff --git a/tests/tcg/s390x/console.c b/tests/tcg/s390x/console.c
index d43ce3f..6c26f04 100644
--- a/tests/tcg/s390x/console.c
+++ b/tests/tcg/s390x/console.c
@@ -4,7 +4,10 @@
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
+
#include "../../../pc-bios/s390-ccw/sclp.c"
+#include "../../../roms/SLOF/lib/libc/string/memset.c"
+#include "../../../roms/SLOF/lib/libc/string/memcpy.c"
void __sys_outc(char c)
{
diff --git a/tests/tcg/s390x/ex-smc.c b/tests/tcg/s390x/ex-smc.c
new file mode 100644
index 0000000..f403640
--- /dev/null
+++ b/tests/tcg/s390x/ex-smc.c
@@ -0,0 +1,57 @@
+/*
+ * Test modifying an EXECUTE target.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <assert.h>
+#include <stdlib.h>
+
+/* Make sure we exercise the same EXECUTE instruction. */
+extern void execute(unsigned char *insn, unsigned char mask,
+ unsigned long *r1_r5);
+asm(".globl execute\n"
+ "execute:\n"
+ "lg %r1,0(%r4)\n"
+ "lg %r5,8(%r4)\n"
+ "ex %r3,0(%r2)\n"
+ "stg %r5,8(%r4)\n"
+ "stg %r1,0(%r4)\n"
+ "br %r14\n");
+
+/* Define an RWX EXECUTE target. */
+extern unsigned char lgfi[];
+asm(".pushsection .rwx,\"awx\",@progbits\n"
+ ".globl lgfi\n"
+ "lgfi: lgfi %r0,0\n"
+ ".popsection\n");
+
+int main(void)
+{
+ unsigned long r1_r5[2];
+
+ /* Create an initial TB. */
+ r1_r5[0] = -1;
+ r1_r5[1] = -1;
+ execute(lgfi, 1 << 4, r1_r5);
+ assert(r1_r5[0] == 0);
+ assert(r1_r5[1] == -1);
+
+ /* Test changing the mask. */
+ execute(lgfi, 5 << 4, r1_r5);
+ assert(r1_r5[0] == 0);
+ assert(r1_r5[1] == 0);
+
+ /* Test changing the target. */
+ lgfi[5] = 42;
+ execute(lgfi, 5 << 4, r1_r5);
+ assert(r1_r5[0] == 0);
+ assert(r1_r5[1] == 42);
+
+ /* Test changing both the mask and the target. */
+ lgfi[5] = 24;
+ execute(lgfi, 1 << 4, r1_r5);
+ assert(r1_r5[0] == 24);
+ assert(r1_r5[1] == 42);
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/tcg/x86_64/Makefile.softmmu-target b/tests/tcg/x86_64/Makefile.softmmu-target
index 1bd763f..ef6bcb4 100644
--- a/tests/tcg/x86_64/Makefile.softmmu-target
+++ b/tests/tcg/x86_64/Makefile.softmmu-target
@@ -25,7 +25,7 @@ EXTRA_RUNS+=$(MULTIARCH_RUNS)
.PRECIOUS: $(CRT_OBJS)
%.o: $(CRT_PATH)/%.S
- $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -Wa,--noexecstack -c $< -o $@
# Build and link the tests
%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
diff --git a/tests/tcg/x86_64/Makefile.target b/tests/tcg/x86_64/Makefile.target
index eda9bd7..d6dff55 100644
--- a/tests/tcg/x86_64/Makefile.target
+++ b/tests/tcg/x86_64/Makefile.target
@@ -16,6 +16,8 @@ X86_64_TESTS += noexec
X86_64_TESTS += cmpxchg
X86_64_TESTS += adox
X86_64_TESTS += test-1648
+X86_64_TESTS += test-2175
+X86_64_TESTS += cross-modifying-code
TESTS=$(MULTIARCH_TESTS) $(X86_64_TESTS) test-x86_64
else
TESTS=$(MULTIARCH_TESTS)
@@ -26,6 +28,9 @@ adox: CFLAGS=-O2
run-test-i386-ssse3: QEMU_OPTS += -cpu max
run-plugin-test-i386-ssse3-%: QEMU_OPTS += -cpu max
+cross-modifying-code: CFLAGS+=-pthread
+cross-modifying-code: LDFLAGS+=-pthread
+
test-x86_64: LDFLAGS+=-lm -lc
test-x86_64: test-i386.c test-i386.h test-i386-shift.h test-i386-muldiv.h
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
diff --git a/tests/tcg/x86_64/cross-modifying-code.c b/tests/tcg/x86_64/cross-modifying-code.c
new file mode 100644
index 0000000..2704df6
--- /dev/null
+++ b/tests/tcg/x86_64/cross-modifying-code.c
@@ -0,0 +1,80 @@
+/*
+ * Test patching code, running in one thread, from another thread.
+ *
+ * Intel SDM calls this "cross-modifying code" and recommends a special
+ * sequence, which requires both threads to cooperate.
+ *
+ * Linux kernel uses a different sequence that does not require cooperation and
+ * involves patching the first byte with int3.
+ *
+ * Finally, there is user-mode software out there that simply uses atomics, and
+ * that seems to be good enough in practice. Test that QEMU has no problems
+ * with this as well.
+ */
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+void add1_or_nop(long *x);
+asm(".pushsection .rwx,\"awx\",@progbits\n"
+ ".globl add1_or_nop\n"
+ /* addq $0x1,(%rdi) */
+ "add1_or_nop: .byte 0x48, 0x83, 0x07, 0x01\n"
+ "ret\n"
+ ".popsection\n");
+
+#define THREAD_WAIT 0
+#define THREAD_PATCH 1
+#define THREAD_STOP 2
+
+static void *thread_func(void *arg)
+{
+ int val = 0x0026748d; /* nop */
+
+ while (true) {
+ switch (__atomic_load_n((int *)arg, __ATOMIC_SEQ_CST)) {
+ case THREAD_WAIT:
+ break;
+ case THREAD_PATCH:
+ val = __atomic_exchange_n((int *)&add1_or_nop, val,
+ __ATOMIC_SEQ_CST);
+ break;
+ case THREAD_STOP:
+ return NULL;
+ default:
+ assert(false);
+ __builtin_unreachable();
+ }
+ }
+}
+
+#define INITIAL 42
+#define COUNT 1000000
+
+int main(void)
+{
+ int command = THREAD_WAIT;
+ pthread_t thread;
+ long x = 0;
+ int err;
+ int i;
+
+ err = pthread_create(&thread, NULL, &thread_func, &command);
+ assert(err == 0);
+
+ __atomic_store_n(&command, THREAD_PATCH, __ATOMIC_SEQ_CST);
+ for (i = 0; i < COUNT; i++) {
+ add1_or_nop(&x);
+ }
+ __atomic_store_n(&command, THREAD_STOP, __ATOMIC_SEQ_CST);
+
+ err = pthread_join(thread, NULL);
+ assert(err == 0);
+
+ assert(x >= INITIAL);
+ assert(x <= INITIAL + COUNT);
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/tcg/x86_64/test-2175.c b/tests/tcg/x86_64/test-2175.c
new file mode 100644
index 0000000..aafd037
--- /dev/null
+++ b/tests/tcg/x86_64/test-2175.c
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* See https://gitlab.com/qemu-project/qemu/-/issues/2185 */
+
+#include <assert.h>
+
+int test_setc(unsigned int x, unsigned int y)
+{
+ asm("blsi %1, %0; setc %b0" : "+r"(x) : "r"(y));
+ return (unsigned char)x;
+}
+
+int test_pushf(unsigned int x, unsigned int y)
+{
+ asm("blsi %1, %0; pushf; pop %q0" : "+r"(x) : "r"(y));
+ return x & 1;
+}
+
+int main()
+{
+ assert(test_setc(1, 0xedbf530a));
+ assert(test_pushf(1, 0xedbf530a));
+ return 0;
+}
+
diff --git a/tests/unit/crypto-tls-psk-helpers.c b/tests/unit/crypto-tls-psk-helpers.c
index c6cc740..36527fd 100644
--- a/tests/unit/crypto-tls-psk-helpers.c
+++ b/tests/unit/crypto-tls-psk-helpers.c
@@ -20,7 +20,6 @@
#include "qemu/osdep.h"
-#include "crypto-tls-x509-helpers.h"
#include "crypto-tls-psk-helpers.h"
#include "qemu/sockets.h"
diff --git a/tests/unit/crypto-tls-x509-helpers.c b/tests/unit/crypto-tls-x509-helpers.c
index e9937f6..2daecc4 100644
--- a/tests/unit/crypto-tls-x509-helpers.c
+++ b/tests/unit/crypto-tls-x509-helpers.c
@@ -20,15 +20,19 @@
#include "qemu/osdep.h"
+#include <libtasn1.h>
+
#include "crypto-tls-x509-helpers.h"
#include "crypto/init.h"
#include "qemu/sockets.h"
+#include "pkix_asn1_tab.c.inc"
+
/*
* This stores some static data that is needed when
* encoding extensions in the x509 certs
*/
-asn1_node pkix_asn1;
+static asn1_node pkix_asn1;
/*
* To avoid consuming random entropy to generate keys,
@@ -131,6 +135,7 @@ void test_tls_init(const char *keyfile)
void test_tls_cleanup(const char *keyfile)
{
asn1_delete_structure(&pkix_asn1);
+ gnutls_x509_privkey_deinit(privkey);
unlink(keyfile);
}
@@ -498,8 +503,7 @@ void test_tls_write_cert_chain(const char *filename,
g_free(buffer);
}
-
-void test_tls_discard_cert(QCryptoTLSTestCertReq *req)
+void test_tls_deinit_cert(QCryptoTLSTestCertReq *req)
{
if (!req->crt) {
return;
@@ -507,6 +511,15 @@ void test_tls_discard_cert(QCryptoTLSTestCertReq *req)
gnutls_x509_crt_deinit(req->crt);
req->crt = NULL;
+}
+
+void test_tls_discard_cert(QCryptoTLSTestCertReq *req)
+{
+ if (!req->crt) {
+ return;
+ }
+
+ test_tls_deinit_cert(req);
if (getenv("QEMU_TEST_DEBUG_CERTS") == NULL) {
unlink(req->filename);
diff --git a/tests/unit/crypto-tls-x509-helpers.h b/tests/unit/crypto-tls-x509-helpers.h
index 247e716..2a0f7c0 100644
--- a/tests/unit/crypto-tls-x509-helpers.h
+++ b/tests/unit/crypto-tls-x509-helpers.h
@@ -23,7 +23,6 @@
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
-#include <libtasn1.h>
#define QCRYPTO_TLS_TEST_CLIENT_NAME "ACME QEMU Client"
@@ -74,6 +73,12 @@ void test_tls_generate_cert(QCryptoTLSTestCertReq *req,
void test_tls_write_cert_chain(const char *filename,
gnutls_x509_crt_t *certs,
size_t ncerts);
+/*
+ * Deinitialize the QCryptoTLSTestCertReq, but don't delete the certificate
+ * file on disk. (The caller is then responsible for doing that themselves.
+ */
+void test_tls_deinit_cert(QCryptoTLSTestCertReq *req);
+/* Deinit the QCryptoTLSTestCertReq, and delete the certificate file */
void test_tls_discard_cert(QCryptoTLSTestCertReq *req);
void test_tls_init(const char *keyfile);
@@ -171,6 +176,4 @@ void test_tls_cleanup(const char *keyfile);
}; \
test_tls_generate_cert(&varname, cavarname.crt)
-extern const asn1_static_node pkix_asn1_tab[];
-
#endif
diff --git a/tests/unit/meson.build b/tests/unit/meson.build
index 26c109c..d5248ae 100644
--- a/tests/unit/meson.build
+++ b/tests/unit/meson.build
@@ -47,6 +47,7 @@ tests = {
'test-logging': [],
'test-qapi-util': [],
'test-interval-tree': [],
+ 'test-fifo': [],
}
if have_system or have_tools
@@ -99,11 +100,11 @@ if have_block
tasn1.found() and \
host_os != 'windows'
tests += {
- 'test-crypto-tlscredsx509': ['crypto-tls-x509-helpers.c', 'pkix_asn1_tab.c',
+ 'test-crypto-tlscredsx509': ['crypto-tls-x509-helpers.c',
tasn1, crypto, gnutls],
- 'test-crypto-tlssession': ['crypto-tls-x509-helpers.c', 'pkix_asn1_tab.c', 'crypto-tls-psk-helpers.c',
+ 'test-crypto-tlssession': ['crypto-tls-x509-helpers.c', 'crypto-tls-psk-helpers.c',
tasn1, crypto, gnutls],
- 'test-io-channel-tls': ['io-channel-helpers.c', 'crypto-tls-x509-helpers.c', 'pkix_asn1_tab.c',
+ 'test-io-channel-tls': ['io-channel-helpers.c', 'crypto-tls-x509-helpers.c',
tasn1, io, crypto, gnutls]}
endif
if pam.found()
@@ -115,15 +116,13 @@ if have_block
if host_os != 'windows'
tests += {
'test-image-locking': [testblock],
- 'test-nested-aio-poll': [testblock],
+ 'test-nested-aio-poll': [],
}
endif
if config_host_data.get('CONFIG_REPLICATION')
tests += {'test-replication': [testblock]}
endif
- if nettle.found() or gcrypt.found()
- tests += {'test-crypto-pbkdf': [io]}
- endif
+ tests += {'test-crypto-pbkdf': [io]}
endif
if have_system
diff --git a/tests/unit/pkix_asn1_tab.c b/tests/unit/pkix_asn1_tab.c.inc
index 8952140..fe29c41 100644
--- a/tests/unit/pkix_asn1_tab.c
+++ b/tests/unit/pkix_asn1_tab.c.inc
@@ -3,10 +3,7 @@
* and is under copyright of various GNUTLS contributors.
*/
-#include "qemu/osdep.h"
-#include "crypto-tls-x509-helpers.h"
-
-const asn1_static_node pkix_asn1_tab[] = {
+static const asn1_static_node pkix_asn1_tab[] = {
{"PKIX1", 536875024, 0},
{0, 1073741836, 0},
{"id-ce", 1879048204, 0},
diff --git a/tests/unit/ptimer-test.c b/tests/unit/ptimer-test.c
index 04b5f4e..0824059 100644
--- a/tests/unit/ptimer-test.c
+++ b/tests/unit/ptimer-test.c
@@ -763,6 +763,33 @@ static void check_oneshot_with_load_0(gconstpointer arg)
ptimer_free(ptimer);
}
+static void check_freq_more_than_1000M(gconstpointer arg)
+{
+ const uint8_t *policy = arg;
+ ptimer_state *ptimer = ptimer_init(ptimer_trigger, NULL, *policy);
+ bool no_round_down = (*policy & PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
+
+ triggered = false;
+
+ ptimer_transaction_begin(ptimer);
+ ptimer_set_freq(ptimer, 2000000000);
+ ptimer_set_limit(ptimer, 8, 1);
+ ptimer_run(ptimer, 1);
+ ptimer_transaction_commit(ptimer);
+
+ qemu_clock_step(3);
+
+ g_assert_cmpuint(ptimer_get_count(ptimer), ==, no_round_down ? 3 : 2);
+ g_assert_false(triggered);
+
+ qemu_clock_step(1);
+
+ g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
+ g_assert_true(triggered);
+
+ ptimer_free(ptimer);
+}
+
static void add_ptimer_tests(uint8_t policy)
{
char policy_name[256] = "";
@@ -857,6 +884,12 @@ static void add_ptimer_tests(uint8_t policy)
policy_name),
g_memdup2(&policy, 1), check_oneshot_with_load_0, g_free);
g_free(tmp);
+
+ g_test_add_data_func_full(
+ tmp = g_strdup_printf("/ptimer/freq_more_than_1000M policy=%s",
+ policy_name),
+ g_memdup2(&policy, 1), check_freq_more_than_1000M, g_free);
+ g_free(tmp);
}
static void add_all_ptimer_policies_comb_tests(void)
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
index 6668804..c112d5b 100644
--- a/tests/unit/test-bdrv-drain.c
+++ b/tests/unit/test-bdrv-drain.c
@@ -722,7 +722,7 @@ static void test_blockjob_common_drain_node(enum drain_type drain_type,
BlockJob *job;
TestBlockJob *tjob;
IOThread *iothread = NULL;
- int ret;
+ int ret = -1;
src = bdrv_new_open_driver(&bdrv_test, "source", BDRV_O_RDWR,
&error_abort);
diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c
index 3766d5d..20ed54f 100644
--- a/tests/unit/test-block-iothread.c
+++ b/tests/unit/test-block-iothread.c
@@ -745,7 +745,7 @@ static void test_propagate_mirror(void)
AioContext *main_ctx = qemu_get_aio_context();
BlockDriverState *src, *target, *filter;
BlockBackend *blk;
- Job *job;
+ Job *job = NULL;
Error *local_err = NULL;
/* Create src and target*/
diff --git a/tests/unit/test-char.c b/tests/unit/test-char.c
index f273ce5..a6e8753 100644
--- a/tests/unit/test-char.c
+++ b/tests/unit/test-char.c
@@ -1,6 +1,7 @@
#include "qemu/osdep.h"
#include <glib/gstdio.h>
+#include "qapi/error.h"
#include "qemu/config-file.h"
#include "qemu/module.h"
#include "qemu/option.h"
@@ -184,6 +185,21 @@ static void char_mux_test(void)
char *data;
FeHandler h1 = { 0, false, 0, false, }, h2 = { 0, false, 0, false, };
CharBackend chr_be1, chr_be2;
+ Error *error = NULL;
+
+ /* Create mux and chardev to be immediately removed */
+ opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label",
+ 1, &error_abort);
+ qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
+ qemu_opt_set(opts, "size", "128", &error_abort);
+ qemu_opt_set(opts, "mux", "on", &error_abort);
+ chr = qemu_chr_new_from_opts(opts, NULL, &error_abort);
+ g_assert_nonnull(chr);
+ qemu_opts_del(opts);
+
+ /* Remove just created mux and chardev */
+ qmp_chardev_remove("mux-label", &error_abort);
+ qmp_chardev_remove("mux-label-base", &error_abort);
opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label",
1, &error_abort);
@@ -334,7 +350,13 @@ static void char_mux_test(void)
g_free(data);
qemu_chr_fe_deinit(&chr_be1, false);
- qemu_chr_fe_deinit(&chr_be2, true);
+
+ qmp_chardev_remove("mux-label", &error);
+ g_assert_cmpstr(error_get_pretty(error), ==, "Chardev 'mux-label' is busy");
+ error_free(error);
+
+ qemu_chr_fe_deinit(&chr_be2, false);
+ qmp_chardev_remove("mux-label", &error_abort);
}
@@ -1523,18 +1545,18 @@ int main(int argc, char **argv)
static CharSocketClientTestConfig client2 ## name = \
{ addr, NULL, true, false, char_socket_event }; \
static CharSocketClientTestConfig client3 ## name = \
- { addr, ",reconnect=1", false, false, char_socket_event }; \
+ { addr, ",reconnect-ms=1000", false, false, char_socket_event }; \
static CharSocketClientTestConfig client4 ## name = \
- { addr, ",reconnect=1", true, false, char_socket_event }; \
+ { addr, ",reconnect-ms=1000", true, false, char_socket_event }; \
static CharSocketClientTestConfig client5 ## name = \
{ addr, NULL, false, true, char_socket_event }; \
static CharSocketClientTestConfig client6 ## name = \
{ addr, NULL, true, true, char_socket_event }; \
static CharSocketClientTestConfig client7 ## name = \
- { addr, ",reconnect=1", true, false, \
+ { addr, ",reconnect-ms=1000", true, false, \
char_socket_event_with_error }; \
static CharSocketClientTestConfig client8 ## name = \
- { addr, ",reconnect=1", false, false, char_socket_event }; \
+ { addr, ",reconnect-ms=1000", false, false, char_socket_event };\
g_test_add_data_func("/char/socket/client/mainloop/" # name, \
&client1 ##name, char_socket_client_test); \
g_test_add_data_func("/char/socket/client/wait-conn/" # name, \
diff --git a/tests/unit/test-crypto-afsplit.c b/tests/unit/test-crypto-afsplit.c
index 00a7c18..45e9046 100644
--- a/tests/unit/test-crypto-afsplit.c
+++ b/tests/unit/test-crypto-afsplit.c
@@ -26,7 +26,7 @@
typedef struct QCryptoAFSplitTestData QCryptoAFSplitTestData;
struct QCryptoAFSplitTestData {
const char *path;
- QCryptoHashAlgorithm hash;
+ QCryptoHashAlgo hash;
uint32_t stripes;
size_t blocklen;
const uint8_t *key;
@@ -36,7 +36,7 @@ struct QCryptoAFSplitTestData {
static QCryptoAFSplitTestData test_data[] = {
{
.path = "/crypto/afsplit/sha256/5",
- .hash = QCRYPTO_HASH_ALG_SHA256,
+ .hash = QCRYPTO_HASH_ALGO_SHA256,
.stripes = 5,
.blocklen = 32,
.key = (const uint8_t *)
@@ -68,7 +68,7 @@ static QCryptoAFSplitTestData test_data[] = {
},
{
.path = "/crypto/afsplit/sha256/5000",
- .hash = QCRYPTO_HASH_ALG_SHA256,
+ .hash = QCRYPTO_HASH_ALGO_SHA256,
.stripes = 5000,
.blocklen = 16,
.key = (const uint8_t *)
@@ -77,7 +77,7 @@ static QCryptoAFSplitTestData test_data[] = {
},
{
.path = "/crypto/afsplit/sha1/1000",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.stripes = 1000,
.blocklen = 32,
.key = (const uint8_t *)
@@ -88,7 +88,7 @@ static QCryptoAFSplitTestData test_data[] = {
},
{
.path = "/crypto/afsplit/sha256/big",
- .hash = QCRYPTO_HASH_ALG_SHA256,
+ .hash = QCRYPTO_HASH_ALGO_SHA256,
.stripes = 1000,
.blocklen = 64,
.key = (const uint8_t *)
diff --git a/tests/unit/test-crypto-akcipher.c b/tests/unit/test-crypto-akcipher.c
index 4f1f421..53c2211 100644
--- a/tests/unit/test-crypto-akcipher.c
+++ b/tests/unit/test-crypto-akcipher.c
@@ -692,7 +692,7 @@ struct QCryptoAkCipherTestData {
static QCryptoRSAKeyTestData rsakey_test_data[] = {
{
.path = "/crypto/akcipher/rsakey-1024-public",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC,
.key = rsa1024_public_key,
.keylen = sizeof(rsa1024_public_key),
.is_valid_key = true,
@@ -700,7 +700,7 @@ static QCryptoRSAKeyTestData rsakey_test_data[] = {
},
{
.path = "/crypto/akcipher/rsakey-1024-private",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE,
.key = rsa1024_private_key,
.keylen = sizeof(rsa1024_private_key),
.is_valid_key = true,
@@ -708,7 +708,7 @@ static QCryptoRSAKeyTestData rsakey_test_data[] = {
},
{
.path = "/crypto/akcipher/rsakey-2048-public",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC,
.key = rsa2048_public_key,
.keylen = sizeof(rsa2048_public_key),
.is_valid_key = true,
@@ -716,7 +716,7 @@ static QCryptoRSAKeyTestData rsakey_test_data[] = {
},
{
.path = "/crypto/akcipher/rsakey-2048-private",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE,
.key = rsa2048_private_key,
.keylen = sizeof(rsa2048_private_key),
.is_valid_key = true,
@@ -724,56 +724,56 @@ static QCryptoRSAKeyTestData rsakey_test_data[] = {
},
{
.path = "/crypto/akcipher/rsakey-public-lack-elem",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC,
.key = rsa_public_key_lack_element,
.keylen = sizeof(rsa_public_key_lack_element),
.is_valid_key = false,
},
{
.path = "/crypto/akcipher/rsakey-private-lack-elem",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE,
.key = rsa_private_key_lack_element,
.keylen = sizeof(rsa_private_key_lack_element),
.is_valid_key = false,
},
{
.path = "/crypto/akcipher/rsakey-public-empty-elem",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC,
.key = rsa_public_key_empty_element,
.keylen = sizeof(rsa_public_key_empty_element),
.is_valid_key = false,
},
{
.path = "/crypto/akcipher/rsakey-private-empty-elem",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE,
.key = rsa_private_key_empty_element,
.keylen = sizeof(rsa_private_key_empty_element),
.is_valid_key = false,
},
{
.path = "/crypto/akcipher/rsakey-public-empty-key",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC,
.key = NULL,
.keylen = 0,
.is_valid_key = false,
},
{
.path = "/crypto/akcipher/rsakey-private-empty-key",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE,
.key = NULL,
.keylen = 0,
.is_valid_key = false,
},
{
.path = "/crypto/akcipher/rsakey-public-invalid-length-val",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC,
.key = rsa_public_key_invalid_length_val,
.keylen = sizeof(rsa_public_key_invalid_length_val),
.is_valid_key = false,
},
{
.path = "/crypto/akcipher/rsakey-public-extra-elem",
- .key_type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
+ .key_type = QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC,
.key = rsa_public_key_extra_elem,
.keylen = sizeof(rsa_public_key_extra_elem),
.is_valid_key = false,
@@ -785,9 +785,9 @@ static QCryptoAkCipherTestData akcipher_test_data[] = {
{
.path = "/crypto/akcipher/rsa1024-raw",
.opt = {
- .alg = QCRYPTO_AKCIPHER_ALG_RSA,
+ .alg = QCRYPTO_AK_CIPHER_ALGO_RSA,
.u.rsa = {
- .padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW,
+ .padding_alg = QCRYPTO_RSA_PADDING_ALGO_RAW,
},
},
.pub_key = rsa1024_public_key,
@@ -805,10 +805,10 @@ static QCryptoAkCipherTestData akcipher_test_data[] = {
{
.path = "/crypto/akcipher/rsa1024-pkcs1",
.opt = {
- .alg = QCRYPTO_AKCIPHER_ALG_RSA,
+ .alg = QCRYPTO_AK_CIPHER_ALGO_RSA,
.u.rsa = {
- .padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1,
- .hash_alg = QCRYPTO_HASH_ALG_SHA1,
+ .padding_alg = QCRYPTO_RSA_PADDING_ALGO_PKCS1,
+ .hash_alg = QCRYPTO_HASH_ALGO_SHA1,
},
},
.pub_key = rsa1024_public_key,
@@ -830,9 +830,9 @@ static QCryptoAkCipherTestData akcipher_test_data[] = {
{
.path = "/crypto/akcipher/rsa2048-raw",
.opt = {
- .alg = QCRYPTO_AKCIPHER_ALG_RSA,
+ .alg = QCRYPTO_AK_CIPHER_ALGO_RSA,
.u.rsa = {
- .padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW,
+ .padding_alg = QCRYPTO_RSA_PADDING_ALGO_RAW,
},
},
.pub_key = rsa2048_public_key,
@@ -850,10 +850,10 @@ static QCryptoAkCipherTestData akcipher_test_data[] = {
{
.path = "/crypto/akcipher/rsa2048-pkcs1",
.opt = {
- .alg = QCRYPTO_AKCIPHER_ALG_RSA,
+ .alg = QCRYPTO_AK_CIPHER_ALGO_RSA,
.u.rsa = {
- .padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1,
- .hash_alg = QCRYPTO_HASH_ALG_SHA1,
+ .padding_alg = QCRYPTO_RSA_PADDING_ALGO_PKCS1,
+ .hash_alg = QCRYPTO_HASH_ALGO_SHA1,
},
},
.pub_key = rsa2048_public_key,
@@ -885,12 +885,12 @@ static void test_akcipher(const void *opaque)
return;
}
pub_key = qcrypto_akcipher_new(&data->opt,
- QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC,
+ QCRYPTO_AK_CIPHER_KEY_TYPE_PUBLIC,
data->pub_key, data->pub_key_len,
&error_abort);
g_assert(pub_key != NULL);
priv_key = qcrypto_akcipher_new(&data->opt,
- QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE,
+ QCRYPTO_AK_CIPHER_KEY_TYPE_PRIVATE,
data->priv_key, data->priv_key_len,
&error_abort);
g_assert(priv_key != NULL);
@@ -944,10 +944,10 @@ static void test_rsakey(const void *opaque)
{
const QCryptoRSAKeyTestData *data = (const QCryptoRSAKeyTestData *)opaque;
QCryptoAkCipherOptions opt = {
- .alg = QCRYPTO_AKCIPHER_ALG_RSA,
+ .alg = QCRYPTO_AK_CIPHER_ALGO_RSA,
.u.rsa = {
- .padding_alg = QCRYPTO_RSA_PADDING_ALG_PKCS1,
- .hash_alg = QCRYPTO_HASH_ALG_SHA1,
+ .padding_alg = QCRYPTO_RSA_PADDING_ALGO_PKCS1,
+ .hash_alg = QCRYPTO_HASH_ALGO_SHA1,
}
};
g_autoptr(QCryptoAkCipher) key = qcrypto_akcipher_new(
diff --git a/tests/unit/test-crypto-block.c b/tests/unit/test-crypto-block.c
index 42cfab6..9217b9a 100644
--- a/tests/unit/test-crypto-block.c
+++ b/tests/unit/test-crypto-block.c
@@ -39,14 +39,14 @@
#endif
static QCryptoBlockCreateOptions qcow_create_opts = {
- .format = Q_CRYPTO_BLOCK_FORMAT_QCOW,
+ .format = QCRYPTO_BLOCK_FORMAT_QCOW,
.u.qcow = {
.key_secret = (char *)"sec0",
},
};
static QCryptoBlockOpenOptions qcow_open_opts = {
- .format = Q_CRYPTO_BLOCK_FORMAT_QCOW,
+ .format = QCRYPTO_BLOCK_FORMAT_QCOW,
.u.qcow = {
.key_secret = (char *)"sec0",
},
@@ -55,7 +55,7 @@ static QCryptoBlockOpenOptions qcow_open_opts = {
#ifdef TEST_LUKS
static QCryptoBlockOpenOptions luks_open_opts = {
- .format = Q_CRYPTO_BLOCK_FORMAT_LUKS,
+ .format = QCRYPTO_BLOCK_FORMAT_LUKS,
.u.luks = {
.key_secret = (char *)"sec0",
},
@@ -64,7 +64,7 @@ static QCryptoBlockOpenOptions luks_open_opts = {
/* Creation with all default values */
static QCryptoBlockCreateOptions luks_create_opts_default = {
- .format = Q_CRYPTO_BLOCK_FORMAT_LUKS,
+ .format = QCRYPTO_BLOCK_FORMAT_LUKS,
.u.luks = {
.key_secret = (char *)"sec0",
},
@@ -73,33 +73,33 @@ static QCryptoBlockCreateOptions luks_create_opts_default = {
/* ...and with explicit values */
static QCryptoBlockCreateOptions luks_create_opts_aes256_cbc_plain64 = {
- .format = Q_CRYPTO_BLOCK_FORMAT_LUKS,
+ .format = QCRYPTO_BLOCK_FORMAT_LUKS,
.u.luks = {
.key_secret = (char *)"sec0",
.has_cipher_alg = true,
- .cipher_alg = QCRYPTO_CIPHER_ALG_AES_256,
+ .cipher_alg = QCRYPTO_CIPHER_ALGO_AES_256,
.has_cipher_mode = true,
.cipher_mode = QCRYPTO_CIPHER_MODE_CBC,
.has_ivgen_alg = true,
- .ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64,
+ .ivgen_alg = QCRYPTO_IV_GEN_ALGO_PLAIN64,
},
};
static QCryptoBlockCreateOptions luks_create_opts_aes256_cbc_essiv = {
- .format = Q_CRYPTO_BLOCK_FORMAT_LUKS,
+ .format = QCRYPTO_BLOCK_FORMAT_LUKS,
.u.luks = {
.key_secret = (char *)"sec0",
.has_cipher_alg = true,
- .cipher_alg = QCRYPTO_CIPHER_ALG_AES_256,
+ .cipher_alg = QCRYPTO_CIPHER_ALGO_AES_256,
.has_cipher_mode = true,
.cipher_mode = QCRYPTO_CIPHER_MODE_CBC,
.has_ivgen_alg = true,
- .ivgen_alg = QCRYPTO_IVGEN_ALG_ESSIV,
+ .ivgen_alg = QCRYPTO_IV_GEN_ALGO_ESSIV,
.has_ivgen_hash_alg = true,
- .ivgen_hash_alg = QCRYPTO_HASH_ALG_SHA256,
+ .ivgen_hash_alg = QCRYPTO_HASH_ALGO_SHA256,
.has_hash_alg = true,
- .hash_alg = QCRYPTO_HASH_ALG_SHA1,
+ .hash_alg = QCRYPTO_HASH_ALGO_SHA1,
},
};
#endif /* TEST_LUKS */
@@ -112,12 +112,12 @@ static struct QCryptoBlockTestData {
bool expect_header;
- QCryptoCipherAlgorithm cipher_alg;
+ QCryptoCipherAlgo cipher_alg;
QCryptoCipherMode cipher_mode;
- QCryptoHashAlgorithm hash_alg;
+ QCryptoHashAlgo hash_alg;
- QCryptoIVGenAlgorithm ivgen_alg;
- QCryptoHashAlgorithm ivgen_hash;
+ QCryptoIVGenAlgo ivgen_alg;
+ QCryptoHashAlgo ivgen_hash;
bool slow;
} test_data[] = {
@@ -128,10 +128,10 @@ static struct QCryptoBlockTestData {
.expect_header = false,
- .cipher_alg = QCRYPTO_CIPHER_ALG_AES_128,
+ .cipher_alg = QCRYPTO_CIPHER_ALGO_AES_128,
.cipher_mode = QCRYPTO_CIPHER_MODE_CBC,
- .ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64,
+ .ivgen_alg = QCRYPTO_IV_GEN_ALGO_PLAIN64,
},
#ifdef TEST_LUKS
{
@@ -141,11 +141,11 @@ static struct QCryptoBlockTestData {
.expect_header = true,
- .cipher_alg = QCRYPTO_CIPHER_ALG_AES_256,
+ .cipher_alg = QCRYPTO_CIPHER_ALGO_AES_256,
.cipher_mode = QCRYPTO_CIPHER_MODE_XTS,
- .hash_alg = QCRYPTO_HASH_ALG_SHA256,
+ .hash_alg = QCRYPTO_HASH_ALGO_SHA256,
- .ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64,
+ .ivgen_alg = QCRYPTO_IV_GEN_ALGO_PLAIN64,
.slow = true,
},
@@ -156,11 +156,11 @@ static struct QCryptoBlockTestData {
.expect_header = true,
- .cipher_alg = QCRYPTO_CIPHER_ALG_AES_256,
+ .cipher_alg = QCRYPTO_CIPHER_ALGO_AES_256,
.cipher_mode = QCRYPTO_CIPHER_MODE_CBC,
- .hash_alg = QCRYPTO_HASH_ALG_SHA256,
+ .hash_alg = QCRYPTO_HASH_ALGO_SHA256,
- .ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64,
+ .ivgen_alg = QCRYPTO_IV_GEN_ALGO_PLAIN64,
.slow = true,
},
@@ -171,12 +171,12 @@ static struct QCryptoBlockTestData {
.expect_header = true,
- .cipher_alg = QCRYPTO_CIPHER_ALG_AES_256,
+ .cipher_alg = QCRYPTO_CIPHER_ALGO_AES_256,
.cipher_mode = QCRYPTO_CIPHER_MODE_CBC,
- .hash_alg = QCRYPTO_HASH_ALG_SHA1,
+ .hash_alg = QCRYPTO_HASH_ALGO_SHA1,
- .ivgen_alg = QCRYPTO_IVGEN_ALG_ESSIV,
- .ivgen_hash = QCRYPTO_HASH_ALG_SHA256,
+ .ivgen_alg = QCRYPTO_IV_GEN_ALGO_ESSIV,
+ .ivgen_hash = QCRYPTO_HASH_ALGO_SHA256,
.slow = true,
},
@@ -572,7 +572,7 @@ int main(int argc, char **argv)
g_assert(qcrypto_init(NULL) == 0);
for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
- if (test_data[i].open_opts->format == Q_CRYPTO_BLOCK_FORMAT_LUKS &&
+ if (test_data[i].open_opts->format == QCRYPTO_BLOCK_FORMAT_LUKS &&
!qcrypto_hash_supports(test_data[i].hash_alg)) {
continue;
}
diff --git a/tests/unit/test-crypto-cipher.c b/tests/unit/test-crypto-cipher.c
index f5152e5..b328b48 100644
--- a/tests/unit/test-crypto-cipher.c
+++ b/tests/unit/test-crypto-cipher.c
@@ -27,7 +27,7 @@
typedef struct QCryptoCipherTestData QCryptoCipherTestData;
struct QCryptoCipherTestData {
const char *path;
- QCryptoCipherAlgorithm alg;
+ QCryptoCipherAlgo alg;
QCryptoCipherMode mode;
const char *key;
const char *plaintext;
@@ -43,7 +43,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* NIST F.1.1 ECB-AES128.Encrypt */
.path = "/crypto/cipher/aes-ecb-128",
- .alg = QCRYPTO_CIPHER_ALG_AES_128,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_128,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "2b7e151628aed2a6abf7158809cf4f3c",
.plaintext =
@@ -60,7 +60,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* NIST F.1.3 ECB-AES192.Encrypt */
.path = "/crypto/cipher/aes-ecb-192",
- .alg = QCRYPTO_CIPHER_ALG_AES_192,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_192,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
.plaintext =
@@ -77,7 +77,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* NIST F.1.5 ECB-AES256.Encrypt */
.path = "/crypto/cipher/aes-ecb-256",
- .alg = QCRYPTO_CIPHER_ALG_AES_256,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_256,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key =
"603deb1015ca71be2b73aef0857d7781"
@@ -96,7 +96,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* NIST F.2.1 CBC-AES128.Encrypt */
.path = "/crypto/cipher/aes-cbc-128",
- .alg = QCRYPTO_CIPHER_ALG_AES_128,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_128,
.mode = QCRYPTO_CIPHER_MODE_CBC,
.key = "2b7e151628aed2a6abf7158809cf4f3c",
.iv = "000102030405060708090a0b0c0d0e0f",
@@ -114,7 +114,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* NIST F.2.3 CBC-AES128.Encrypt */
.path = "/crypto/cipher/aes-cbc-192",
- .alg = QCRYPTO_CIPHER_ALG_AES_192,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_192,
.mode = QCRYPTO_CIPHER_MODE_CBC,
.key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
.iv = "000102030405060708090a0b0c0d0e0f",
@@ -132,7 +132,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* NIST F.2.5 CBC-AES128.Encrypt */
.path = "/crypto/cipher/aes-cbc-256",
- .alg = QCRYPTO_CIPHER_ALG_AES_256,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_256,
.mode = QCRYPTO_CIPHER_MODE_CBC,
.key =
"603deb1015ca71be2b73aef0857d7781"
@@ -156,7 +156,7 @@ static QCryptoCipherTestData test_data[] = {
* ciphertext in ECB and CBC modes
*/
.path = "/crypto/cipher/des-ecb-56-one-block",
- .alg = QCRYPTO_CIPHER_ALG_DES,
+ .alg = QCRYPTO_CIPHER_ALGO_DES,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "80c4a2e691d5b3f7",
.plaintext = "70617373776f7264",
@@ -165,7 +165,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* See previous comment */
.path = "/crypto/cipher/des-cbc-56-one-block",
- .alg = QCRYPTO_CIPHER_ALG_DES,
+ .alg = QCRYPTO_CIPHER_ALGO_DES,
.mode = QCRYPTO_CIPHER_MODE_CBC,
.key = "80c4a2e691d5b3f7",
.iv = "0000000000000000",
@@ -174,7 +174,7 @@ static QCryptoCipherTestData test_data[] = {
},
{
.path = "/crypto/cipher/des-ecb-56",
- .alg = QCRYPTO_CIPHER_ALG_DES,
+ .alg = QCRYPTO_CIPHER_ALGO_DES,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "80c4a2e691d5b3f7",
.plaintext =
@@ -191,7 +191,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* Borrowed from linux-kernel crypto/testmgr.h */
.path = "/crypto/cipher/3des-cbc",
- .alg = QCRYPTO_CIPHER_ALG_3DES,
+ .alg = QCRYPTO_CIPHER_ALGO_3DES,
.mode = QCRYPTO_CIPHER_MODE_CBC,
.key =
"e9c0ff2e760b6424444d995a12d640c0"
@@ -220,7 +220,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* Borrowed from linux-kernel crypto/testmgr.h */
.path = "/crypto/cipher/3des-ecb",
- .alg = QCRYPTO_CIPHER_ALG_3DES,
+ .alg = QCRYPTO_CIPHER_ALGO_3DES,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key =
"0123456789abcdef5555555555555555"
@@ -233,7 +233,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* Borrowed from linux-kernel crypto/testmgr.h */
.path = "/crypto/cipher/3des-ctr",
- .alg = QCRYPTO_CIPHER_ALG_3DES,
+ .alg = QCRYPTO_CIPHER_ALGO_3DES,
.mode = QCRYPTO_CIPHER_MODE_CTR,
.key =
"9cd6f39cb95a67005a67002dceeb2dce"
@@ -308,7 +308,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* RFC 2144, Appendix B.1 */
.path = "/crypto/cipher/cast5-128",
- .alg = QCRYPTO_CIPHER_ALG_CAST5_128,
+ .alg = QCRYPTO_CIPHER_ALGO_CAST5_128,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "0123456712345678234567893456789A",
.plaintext = "0123456789abcdef",
@@ -317,7 +317,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* libgcrypt serpent.c */
.path = "/crypto/cipher/serpent-128",
- .alg = QCRYPTO_CIPHER_ALG_SERPENT_128,
+ .alg = QCRYPTO_CIPHER_ALGO_SERPENT_128,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "00000000000000000000000000000000",
.plaintext = "d29d576fcea3a3a7ed9099f29273d78e",
@@ -326,7 +326,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* libgcrypt serpent.c */
.path = "/crypto/cipher/serpent-192",
- .alg = QCRYPTO_CIPHER_ALG_SERPENT_192,
+ .alg = QCRYPTO_CIPHER_ALGO_SERPENT_192,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "00000000000000000000000000000000"
"0000000000000000",
@@ -336,7 +336,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* libgcrypt serpent.c */
.path = "/crypto/cipher/serpent-256a",
- .alg = QCRYPTO_CIPHER_ALG_SERPENT_256,
+ .alg = QCRYPTO_CIPHER_ALGO_SERPENT_256,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "00000000000000000000000000000000"
"00000000000000000000000000000000",
@@ -346,7 +346,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* libgcrypt serpent.c */
.path = "/crypto/cipher/serpent-256b",
- .alg = QCRYPTO_CIPHER_ALG_SERPENT_256,
+ .alg = QCRYPTO_CIPHER_ALGO_SERPENT_256,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "00000000000000000000000000000000"
"00000000000000000000000000000000",
@@ -356,7 +356,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* Twofish paper "Known Answer Test" */
.path = "/crypto/cipher/twofish-128",
- .alg = QCRYPTO_CIPHER_ALG_TWOFISH_128,
+ .alg = QCRYPTO_CIPHER_ALGO_TWOFISH_128,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "d491db16e7b1c39e86cb086b789f5419",
.plaintext = "019f9809de1711858faac3a3ba20fbc3",
@@ -365,7 +365,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* Twofish paper "Known Answer Test", I=3 */
.path = "/crypto/cipher/twofish-192",
- .alg = QCRYPTO_CIPHER_ALG_TWOFISH_192,
+ .alg = QCRYPTO_CIPHER_ALGO_TWOFISH_192,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "88b2b2706b105e36b446bb6d731a1e88"
"efa71f788965bd44",
@@ -375,7 +375,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* Twofish paper "Known Answer Test", I=4 */
.path = "/crypto/cipher/twofish-256",
- .alg = QCRYPTO_CIPHER_ALG_TWOFISH_256,
+ .alg = QCRYPTO_CIPHER_ALGO_TWOFISH_256,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "d43bb7556ea32e46f2a282b7d45b4e0d"
"57ff739d4dc92c1bd7fc01700cc8216f",
@@ -386,7 +386,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* SM4, GB/T 32907-2016, Appendix A.1 */
.path = "/crypto/cipher/sm4",
- .alg = QCRYPTO_CIPHER_ALG_SM4,
+ .alg = QCRYPTO_CIPHER_ALGO_SM4,
.mode = QCRYPTO_CIPHER_MODE_ECB,
.key = "0123456789abcdeffedcba9876543210",
.plaintext =
@@ -398,7 +398,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* #1 32 byte key, 32 byte PTX */
.path = "/crypto/cipher/aes-xts-128-1",
- .alg = QCRYPTO_CIPHER_ALG_AES_128,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_128,
.mode = QCRYPTO_CIPHER_MODE_XTS,
.key =
"00000000000000000000000000000000"
@@ -415,7 +415,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* #2, 32 byte key, 32 byte PTX */
.path = "/crypto/cipher/aes-xts-128-2",
- .alg = QCRYPTO_CIPHER_ALG_AES_128,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_128,
.mode = QCRYPTO_CIPHER_MODE_XTS,
.key =
"11111111111111111111111111111111"
@@ -432,7 +432,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* #5 from xts.7, 32 byte key, 32 byte PTX */
.path = "/crypto/cipher/aes-xts-128-3",
- .alg = QCRYPTO_CIPHER_ALG_AES_128,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_128,
.mode = QCRYPTO_CIPHER_MODE_XTS,
.key =
"fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0"
@@ -449,7 +449,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* #4, 32 byte key, 512 byte PTX */
.path = "/crypto/cipher/aes-xts-128-4",
- .alg = QCRYPTO_CIPHER_ALG_AES_128,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_128,
.mode = QCRYPTO_CIPHER_MODE_XTS,
.key =
"27182818284590452353602874713526"
@@ -528,7 +528,7 @@ static QCryptoCipherTestData test_data[] = {
* which is incompatible with XTS
*/
.path = "/crypto/cipher/cast5-xts-128",
- .alg = QCRYPTO_CIPHER_ALG_CAST5_128,
+ .alg = QCRYPTO_CIPHER_ALGO_CAST5_128,
.mode = QCRYPTO_CIPHER_MODE_XTS,
.key =
"27182818284590452353602874713526"
@@ -537,7 +537,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* NIST F.5.1 CTR-AES128.Encrypt */
.path = "/crypto/cipher/aes-ctr-128",
- .alg = QCRYPTO_CIPHER_ALG_AES_128,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_128,
.mode = QCRYPTO_CIPHER_MODE_CTR,
.key = "2b7e151628aed2a6abf7158809cf4f3c",
.iv = "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
@@ -555,7 +555,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* NIST F.5.3 CTR-AES192.Encrypt */
.path = "/crypto/cipher/aes-ctr-192",
- .alg = QCRYPTO_CIPHER_ALG_AES_192,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_192,
.mode = QCRYPTO_CIPHER_MODE_CTR,
.key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
.iv = "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
@@ -573,7 +573,7 @@ static QCryptoCipherTestData test_data[] = {
{
/* NIST F.5.5 CTR-AES256.Encrypt */
.path = "/crypto/cipher/aes-ctr-256",
- .alg = QCRYPTO_CIPHER_ALG_AES_256,
+ .alg = QCRYPTO_CIPHER_ALGO_AES_256,
.mode = QCRYPTO_CIPHER_MODE_CTR,
.key = "603deb1015ca71be2b73aef0857d7781"
"1f352c073b6108d72d9810a30914dff4",
@@ -750,7 +750,7 @@ static void test_cipher_null_iv(void)
uint8_t ciphertext[32] = { 0 };
cipher = qcrypto_cipher_new(
- QCRYPTO_CIPHER_ALG_AES_256,
+ QCRYPTO_CIPHER_ALGO_AES_256,
QCRYPTO_CIPHER_MODE_CBC,
key, sizeof(key),
&error_abort);
@@ -779,7 +779,7 @@ static void test_cipher_short_plaintext(void)
int ret;
cipher = qcrypto_cipher_new(
- QCRYPTO_CIPHER_ALG_AES_256,
+ QCRYPTO_CIPHER_ALGO_AES_256,
QCRYPTO_CIPHER_MODE_CBC,
key, sizeof(key),
&error_abort);
@@ -823,7 +823,7 @@ int main(int argc, char **argv)
g_test_add_data_func(test_data[i].path, &test_data[i], test_cipher);
} else {
g_printerr("# skip unsupported %s:%s\n",
- QCryptoCipherAlgorithm_str(test_data[i].alg),
+ QCryptoCipherAlgo_str(test_data[i].alg),
QCryptoCipherMode_str(test_data[i].mode));
}
}
diff --git a/tests/unit/test-crypto-hash.c b/tests/unit/test-crypto-hash.c
index 1f4abb8..76c4699 100644
--- a/tests/unit/test-crypto-hash.c
+++ b/tests/unit/test-crypto-hash.c
@@ -1,6 +1,7 @@
/*
* QEMU Crypto hash algorithms
*
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
* Copyright (c) 2015 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
@@ -55,31 +56,31 @@
#define OUTPUT_RIPEMD160_B64 "89ZY+tP9+ytSyTac8NRBJJ3fqKA="
static const char *expected_outputs[] = {
- [QCRYPTO_HASH_ALG_MD5] = OUTPUT_MD5,
- [QCRYPTO_HASH_ALG_SHA1] = OUTPUT_SHA1,
- [QCRYPTO_HASH_ALG_SHA224] = OUTPUT_SHA224,
- [QCRYPTO_HASH_ALG_SHA256] = OUTPUT_SHA256,
- [QCRYPTO_HASH_ALG_SHA384] = OUTPUT_SHA384,
- [QCRYPTO_HASH_ALG_SHA512] = OUTPUT_SHA512,
- [QCRYPTO_HASH_ALG_RIPEMD160] = OUTPUT_RIPEMD160,
+ [QCRYPTO_HASH_ALGO_MD5] = OUTPUT_MD5,
+ [QCRYPTO_HASH_ALGO_SHA1] = OUTPUT_SHA1,
+ [QCRYPTO_HASH_ALGO_SHA224] = OUTPUT_SHA224,
+ [QCRYPTO_HASH_ALGO_SHA256] = OUTPUT_SHA256,
+ [QCRYPTO_HASH_ALGO_SHA384] = OUTPUT_SHA384,
+ [QCRYPTO_HASH_ALGO_SHA512] = OUTPUT_SHA512,
+ [QCRYPTO_HASH_ALGO_RIPEMD160] = OUTPUT_RIPEMD160,
};
static const char *expected_outputs_b64[] = {
- [QCRYPTO_HASH_ALG_MD5] = OUTPUT_MD5_B64,
- [QCRYPTO_HASH_ALG_SHA1] = OUTPUT_SHA1_B64,
- [QCRYPTO_HASH_ALG_SHA224] = OUTPUT_SHA224_B64,
- [QCRYPTO_HASH_ALG_SHA256] = OUTPUT_SHA256_B64,
- [QCRYPTO_HASH_ALG_SHA384] = OUTPUT_SHA384_B64,
- [QCRYPTO_HASH_ALG_SHA512] = OUTPUT_SHA512_B64,
- [QCRYPTO_HASH_ALG_RIPEMD160] = OUTPUT_RIPEMD160_B64,
+ [QCRYPTO_HASH_ALGO_MD5] = OUTPUT_MD5_B64,
+ [QCRYPTO_HASH_ALGO_SHA1] = OUTPUT_SHA1_B64,
+ [QCRYPTO_HASH_ALGO_SHA224] = OUTPUT_SHA224_B64,
+ [QCRYPTO_HASH_ALGO_SHA256] = OUTPUT_SHA256_B64,
+ [QCRYPTO_HASH_ALGO_SHA384] = OUTPUT_SHA384_B64,
+ [QCRYPTO_HASH_ALGO_SHA512] = OUTPUT_SHA512_B64,
+ [QCRYPTO_HASH_ALGO_RIPEMD160] = OUTPUT_RIPEMD160_B64,
};
static const int expected_lens[] = {
- [QCRYPTO_HASH_ALG_MD5] = 16,
- [QCRYPTO_HASH_ALG_SHA1] = 20,
- [QCRYPTO_HASH_ALG_SHA224] = 28,
- [QCRYPTO_HASH_ALG_SHA256] = 32,
- [QCRYPTO_HASH_ALG_SHA384] = 48,
- [QCRYPTO_HASH_ALG_SHA512] = 64,
- [QCRYPTO_HASH_ALG_RIPEMD160] = 20,
+ [QCRYPTO_HASH_ALGO_MD5] = 16,
+ [QCRYPTO_HASH_ALGO_SHA1] = 20,
+ [QCRYPTO_HASH_ALGO_SHA224] = 28,
+ [QCRYPTO_HASH_ALGO_SHA256] = 32,
+ [QCRYPTO_HASH_ALGO_SHA384] = 48,
+ [QCRYPTO_HASH_ALGO_SHA512] = 64,
+ [QCRYPTO_HASH_ALGO_RIPEMD160] = 20,
};
static const char hex[] = "0123456789abcdef";
@@ -122,7 +123,7 @@ static void test_hash_prealloc(void)
size_t i;
for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) {
- uint8_t *result;
+ uint8_t *result, *origresult;
size_t resultlen;
int ret;
size_t j;
@@ -132,7 +133,7 @@ static void test_hash_prealloc(void)
}
resultlen = expected_lens[i];
- result = g_new0(uint8_t, resultlen);
+ origresult = result = g_new0(uint8_t, resultlen);
ret = qcrypto_hash_bytes(i,
INPUT_TEXT,
@@ -141,7 +142,8 @@ static void test_hash_prealloc(void)
&resultlen,
&error_fatal);
g_assert(ret == 0);
-
+ /* Validate that our pre-allocated pointer was not replaced */
+ g_assert(result == origresult);
g_assert(resultlen == expected_lens[i]);
for (j = 0; j < resultlen; j++) {
g_assert(expected_outputs[i][j * 2] == hex[(result[j] >> 4) & 0xf]);
@@ -241,6 +243,50 @@ static void test_hash_base64(void)
}
}
+static void test_hash_accumulate(void)
+{
+ size_t i;
+
+ for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) {
+ g_autoptr(QCryptoHash) hash = NULL;
+ struct iovec iov[] = {
+ { .iov_base = (char *)INPUT_TEXT1, .iov_len = strlen(INPUT_TEXT1) },
+ { .iov_base = (char *)INPUT_TEXT2, .iov_len = strlen(INPUT_TEXT2) },
+ { .iov_base = (char *)INPUT_TEXT3, .iov_len = strlen(INPUT_TEXT3) },
+ };
+ g_autofree uint8_t *result = NULL;
+ size_t resultlen = 0;
+ int ret;
+ size_t j;
+
+ if (!qcrypto_hash_supports(i)) {
+ continue;
+ }
+
+ hash = qcrypto_hash_new(i, &error_fatal);
+ g_assert(hash != NULL);
+
+ /* Add each iovec to the hash context separately */
+ for (j = 0; j < G_N_ELEMENTS(iov); j++) {
+ ret = qcrypto_hash_updatev(hash,
+ &iov[j], 1,
+ &error_fatal);
+
+ g_assert(ret == 0);
+ }
+
+ ret = qcrypto_hash_finalize_bytes(hash, &result, &resultlen,
+ &error_fatal);
+
+ g_assert(ret == 0);
+ g_assert(resultlen == expected_lens[i]);
+ for (j = 0; j < resultlen; j++) {
+ g_assert(expected_outputs[i][j * 2] == hex[(result[j] >> 4) & 0xf]);
+ g_assert(expected_outputs[i][j * 2 + 1] == hex[result[j] & 0xf]);
+ }
+ }
+}
+
int main(int argc, char **argv)
{
int ret = qcrypto_init(&error_fatal);
@@ -252,5 +298,6 @@ int main(int argc, char **argv)
g_test_add_func("/crypto/hash/prealloc", test_hash_prealloc);
g_test_add_func("/crypto/hash/digest", test_hash_digest);
g_test_add_func("/crypto/hash/base64", test_hash_base64);
+ g_test_add_func("/crypto/hash/accumulate", test_hash_accumulate);
return g_test_run();
}
diff --git a/tests/unit/test-crypto-hmac.c b/tests/unit/test-crypto-hmac.c
index 23eb724..cdb8774 100644
--- a/tests/unit/test-crypto-hmac.c
+++ b/tests/unit/test-crypto-hmac.c
@@ -27,43 +27,43 @@
typedef struct QCryptoHmacTestData QCryptoHmacTestData;
struct QCryptoHmacTestData {
- QCryptoHashAlgorithm alg;
+ QCryptoHashAlgo alg;
const char *hex_digest;
};
static QCryptoHmacTestData test_data[] = {
{
- .alg = QCRYPTO_HASH_ALG_MD5,
+ .alg = QCRYPTO_HASH_ALGO_MD5,
.hex_digest =
"ede9cb83679ba82d88fbeae865b3f8fc",
},
{
- .alg = QCRYPTO_HASH_ALG_SHA1,
+ .alg = QCRYPTO_HASH_ALGO_SHA1,
.hex_digest =
"c7b5a631e3aac975c4ededfcd346e469"
"dbc5f2d1",
},
{
- .alg = QCRYPTO_HASH_ALG_SHA224,
+ .alg = QCRYPTO_HASH_ALGO_SHA224,
.hex_digest =
"5f768179dbb29ca722875d0f461a2e2f"
"597d0210340a84df1a8e9c63",
},
{
- .alg = QCRYPTO_HASH_ALG_SHA256,
+ .alg = QCRYPTO_HASH_ALGO_SHA256,
.hex_digest =
"3798f363c57afa6edaffe39016ca7bad"
"efd1e670afb0e3987194307dec3197db",
},
{
- .alg = QCRYPTO_HASH_ALG_SHA384,
+ .alg = QCRYPTO_HASH_ALGO_SHA384,
.hex_digest =
"d218680a6032d33dccd9882d6a6a7164"
"64f26623be257a9b2919b185294f4a49"
"9e54b190bfd6bc5cedd2cd05c7e65e82",
},
{
- .alg = QCRYPTO_HASH_ALG_SHA512,
+ .alg = QCRYPTO_HASH_ALGO_SHA512,
.hex_digest =
"835a4f5b3750b4c1fccfa88da2f746a4"
"900160c9f18964309bb736c13b59491b"
@@ -71,7 +71,7 @@ static QCryptoHmacTestData test_data[] = {
"94c4ba26862b2dadb59b7ede1d08d53e",
},
{
- .alg = QCRYPTO_HASH_ALG_RIPEMD160,
+ .alg = QCRYPTO_HASH_ALGO_RIPEMD160,
.hex_digest =
"94964ed4c1155b62b668c241d67279e5"
"8a711676",
@@ -126,7 +126,7 @@ static void test_hmac_prealloc(void)
for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
QCryptoHmacTestData *data = &test_data[i];
QCryptoHmac *hmac = NULL;
- uint8_t *result = NULL;
+ uint8_t *result = NULL, *origresult = NULL;
size_t resultlen = 0;
const char *exp_output = NULL;
int ret;
@@ -139,7 +139,7 @@ static void test_hmac_prealloc(void)
exp_output = data->hex_digest;
resultlen = strlen(exp_output) / 2;
- result = g_new0(uint8_t, resultlen);
+ origresult = result = g_new0(uint8_t, resultlen);
hmac = qcrypto_hmac_new(data->alg, (const uint8_t *)KEY,
strlen(KEY), &error_fatal);
@@ -149,6 +149,8 @@ static void test_hmac_prealloc(void)
strlen(INPUT_TEXT), &result,
&resultlen, &error_fatal);
g_assert(ret == 0);
+ /* Validate that our pre-allocated pointer was not replaced */
+ g_assert(result == origresult);
exp_output = data->hex_digest;
for (j = 0; j < resultlen; j++) {
diff --git a/tests/unit/test-crypto-ivgen.c b/tests/unit/test-crypto-ivgen.c
index 29630ed..bc9ffe3 100644
--- a/tests/unit/test-crypto-ivgen.c
+++ b/tests/unit/test-crypto-ivgen.c
@@ -26,9 +26,9 @@
struct QCryptoIVGenTestData {
const char *path;
uint64_t sector;
- QCryptoIVGenAlgorithm ivalg;
- QCryptoHashAlgorithm hashalg;
- QCryptoCipherAlgorithm cipheralg;
+ QCryptoIVGenAlgo ivalg;
+ QCryptoHashAlgo hashalg;
+ QCryptoCipherAlgo cipheralg;
const uint8_t *key;
size_t nkey;
const uint8_t *iv;
@@ -38,7 +38,7 @@ struct QCryptoIVGenTestData {
{
"/crypto/ivgen/plain/1",
.sector = 0x1,
- .ivalg = QCRYPTO_IVGEN_ALG_PLAIN,
+ .ivalg = QCRYPTO_IV_GEN_ALGO_PLAIN,
.iv = (const uint8_t *)"\x01\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.niv = 16,
@@ -47,7 +47,7 @@ struct QCryptoIVGenTestData {
{
"/crypto/ivgen/plain/1f2e3d4c",
.sector = 0x1f2e3d4cULL,
- .ivalg = QCRYPTO_IVGEN_ALG_PLAIN,
+ .ivalg = QCRYPTO_IV_GEN_ALGO_PLAIN,
.iv = (const uint8_t *)"\x4c\x3d\x2e\x1f\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.niv = 16,
@@ -56,7 +56,7 @@ struct QCryptoIVGenTestData {
{
"/crypto/ivgen/plain/1f2e3d4c5b6a7988",
.sector = 0x1f2e3d4c5b6a7988ULL,
- .ivalg = QCRYPTO_IVGEN_ALG_PLAIN,
+ .ivalg = QCRYPTO_IV_GEN_ALGO_PLAIN,
.iv = (const uint8_t *)"\x88\x79\x6a\x5b\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.niv = 16,
@@ -65,7 +65,7 @@ struct QCryptoIVGenTestData {
{
"/crypto/ivgen/plain64/1",
.sector = 0x1,
- .ivalg = QCRYPTO_IVGEN_ALG_PLAIN64,
+ .ivalg = QCRYPTO_IV_GEN_ALGO_PLAIN64,
.iv = (const uint8_t *)"\x01\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.niv = 16,
@@ -74,7 +74,7 @@ struct QCryptoIVGenTestData {
{
"/crypto/ivgen/plain64/1f2e3d4c",
.sector = 0x1f2e3d4cULL,
- .ivalg = QCRYPTO_IVGEN_ALG_PLAIN64,
+ .ivalg = QCRYPTO_IV_GEN_ALGO_PLAIN64,
.iv = (const uint8_t *)"\x4c\x3d\x2e\x1f\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.niv = 16,
@@ -83,7 +83,7 @@ struct QCryptoIVGenTestData {
{
"/crypto/ivgen/plain64/1f2e3d4c5b6a7988",
.sector = 0x1f2e3d4c5b6a7988ULL,
- .ivalg = QCRYPTO_IVGEN_ALG_PLAIN64,
+ .ivalg = QCRYPTO_IV_GEN_ALGO_PLAIN64,
.iv = (const uint8_t *)"\x88\x79\x6a\x5b\x4c\x3d\x2e\x1f"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.niv = 16,
@@ -92,9 +92,9 @@ struct QCryptoIVGenTestData {
{
"/crypto/ivgen/essiv/1",
.sector = 0x1,
- .ivalg = QCRYPTO_IVGEN_ALG_ESSIV,
- .cipheralg = QCRYPTO_CIPHER_ALG_AES_128,
- .hashalg = QCRYPTO_HASH_ALG_SHA256,
+ .ivalg = QCRYPTO_IV_GEN_ALGO_ESSIV,
+ .cipheralg = QCRYPTO_CIPHER_ALGO_AES_128,
+ .hashalg = QCRYPTO_HASH_ALGO_SHA256,
.key = (const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
.nkey = 16,
@@ -106,9 +106,9 @@ struct QCryptoIVGenTestData {
{
"/crypto/ivgen/essiv/1f2e3d4c",
.sector = 0x1f2e3d4cULL,
- .ivalg = QCRYPTO_IVGEN_ALG_ESSIV,
- .cipheralg = QCRYPTO_CIPHER_ALG_AES_128,
- .hashalg = QCRYPTO_HASH_ALG_SHA256,
+ .ivalg = QCRYPTO_IV_GEN_ALGO_ESSIV,
+ .cipheralg = QCRYPTO_CIPHER_ALGO_AES_128,
+ .hashalg = QCRYPTO_HASH_ALGO_SHA256,
.key = (const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
.nkey = 16,
@@ -120,9 +120,9 @@ struct QCryptoIVGenTestData {
{
"/crypto/ivgen/essiv/1f2e3d4c5b6a7988",
.sector = 0x1f2e3d4c5b6a7988ULL,
- .ivalg = QCRYPTO_IVGEN_ALG_ESSIV,
- .cipheralg = QCRYPTO_CIPHER_ALG_AES_128,
- .hashalg = QCRYPTO_HASH_ALG_SHA256,
+ .ivalg = QCRYPTO_IV_GEN_ALGO_ESSIV,
+ .cipheralg = QCRYPTO_CIPHER_ALGO_AES_128,
+ .hashalg = QCRYPTO_HASH_ALGO_SHA256,
.key = (const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
.nkey = 16,
@@ -166,7 +166,7 @@ int main(int argc, char **argv)
size_t i;
g_test_init(&argc, &argv, NULL);
for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
- if (test_data[i].ivalg == QCRYPTO_IVGEN_ALG_ESSIV &&
+ if (test_data[i].ivalg == QCRYPTO_IV_GEN_ALGO_ESSIV &&
!qcrypto_hash_supports(test_data[i].hashalg)) {
continue;
}
diff --git a/tests/unit/test-crypto-pbkdf.c b/tests/unit/test-crypto-pbkdf.c
index 43c417f..12ee808 100644
--- a/tests/unit/test-crypto-pbkdf.c
+++ b/tests/unit/test-crypto-pbkdf.c
@@ -25,14 +25,13 @@
#include <sys/resource.h>
#endif
-#if ((defined(CONFIG_NETTLE) || defined(CONFIG_GCRYPT)) && \
- (defined(_WIN32) || defined(RUSAGE_THREAD)))
+#if defined(_WIN32) || defined(RUSAGE_THREAD) || defined(CONFIG_DARWIN)
#include "crypto/pbkdf.h"
typedef struct QCryptoPbkdfTestData QCryptoPbkdfTestData;
struct QCryptoPbkdfTestData {
const char *path;
- QCryptoHashAlgorithm hash;
+ QCryptoHashAlgo hash;
unsigned int iterations;
const char *key;
size_t nkey;
@@ -53,7 +52,7 @@ static QCryptoPbkdfTestData test_data[] = {
/* RFC 3962 test data */
{
.path = "/crypto/pbkdf/rfc3962/sha1/iter1",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 1,
.key = "password",
.nkey = 8,
@@ -67,7 +66,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/rfc3962/sha1/iter2",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 2,
.key = "password",
.nkey = 8,
@@ -81,7 +80,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/rfc3962/sha1/iter1200a",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 1200,
.key = "password",
.nkey = 8,
@@ -95,7 +94,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/rfc3962/sha1/iter5",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 5,
.key = "password",
.nkey = 8,
@@ -109,7 +108,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/rfc3962/sha1/iter1200b",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 1200,
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
@@ -124,7 +123,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/rfc3962/sha1/iter1200c",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 1200,
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
@@ -139,7 +138,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/rfc3962/sha1/iter50",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 50,
.key = "\360\235\204\236", /* g-clef ("\xf09d849e) */
.nkey = 4,
@@ -155,7 +154,7 @@ static QCryptoPbkdfTestData test_data[] = {
/* RFC-6070 test data */
{
.path = "/crypto/pbkdf/rfc6070/sha1/iter1",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 1,
.key = "password",
.nkey = 8,
@@ -167,7 +166,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/rfc6070/sha1/iter2",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 2,
.key = "password",
.nkey = 8,
@@ -179,7 +178,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/rfc6070/sha1/iter4096",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 4096,
.key = "password",
.nkey = 8,
@@ -191,7 +190,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/rfc6070/sha1/iter16777216",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 16777216,
.key = "password",
.nkey = 8,
@@ -204,7 +203,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/rfc6070/sha1/iter4096a",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 4096,
.key = "passwordPASSWORDpassword",
.nkey = 24,
@@ -217,7 +216,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/rfc6070/sha1/iter4096b",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 4096,
.key = "pass\0word",
.nkey = 9,
@@ -232,7 +231,7 @@ static QCryptoPbkdfTestData test_data[] = {
{
/* empty password test. */
.path = "/crypto/pbkdf/nonrfc/sha1/iter2",
- .hash = QCRYPTO_HASH_ALG_SHA1,
+ .hash = QCRYPTO_HASH_ALGO_SHA1,
.iterations = 2,
.key = "",
.nkey = 0,
@@ -245,7 +244,7 @@ static QCryptoPbkdfTestData test_data[] = {
{
/* Password exceeds block size test */
.path = "/crypto/pbkdf/nonrfc/sha256/iter1200",
- .hash = QCRYPTO_HASH_ALG_SHA256,
+ .hash = QCRYPTO_HASH_ALGO_SHA256,
.iterations = 1200,
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
@@ -260,7 +259,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/nonrfc/sha512/iter1200",
- .hash = QCRYPTO_HASH_ALG_SHA512,
+ .hash = QCRYPTO_HASH_ALGO_SHA512,
.iterations = 1200,
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
@@ -277,7 +276,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/nonrfc/sha224/iter1200",
- .hash = QCRYPTO_HASH_ALG_SHA224,
+ .hash = QCRYPTO_HASH_ALGO_SHA224,
.iterations = 1200,
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
@@ -294,7 +293,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/nonrfc/sha384/iter1200",
- .hash = QCRYPTO_HASH_ALG_SHA384,
+ .hash = QCRYPTO_HASH_ALGO_SHA384,
.iterations = 1200,
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
@@ -311,7 +310,7 @@ static QCryptoPbkdfTestData test_data[] = {
},
{
.path = "/crypto/pbkdf/nonrfc/ripemd160/iter1200",
- .hash = QCRYPTO_HASH_ALG_RIPEMD160,
+ .hash = QCRYPTO_HASH_ALGO_RIPEMD160,
.iterations = 1200,
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
@@ -329,7 +328,7 @@ static QCryptoPbkdfTestData test_data[] = {
#if 0
{
.path = "/crypto/pbkdf/nonrfc/whirlpool/iter1200",
- .hash = QCRYPTO_HASH_ALG_WHIRLPOOL,
+ .hash = QCRYPTO_HASH_ALGO_WHIRLPOOL,
.iterations = 1200,
.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
@@ -394,7 +393,7 @@ static void test_pbkdf(const void *opaque)
}
-static void test_pbkdf_timing(void)
+static void test_pbkdf_timing_sha256(void)
{
uint8_t key[32];
uint8_t salt[32];
@@ -403,7 +402,7 @@ static void test_pbkdf_timing(void)
memset(key, 0x5d, sizeof(key));
memset(salt, 0x7c, sizeof(salt));
- iters = qcrypto_pbkdf2_count_iters(QCRYPTO_HASH_ALG_SHA256,
+ iters = qcrypto_pbkdf2_count_iters(QCRYPTO_HASH_ALGO_SHA256,
key, sizeof(key),
salt, sizeof(salt),
32,
@@ -422,14 +421,18 @@ int main(int argc, char **argv)
g_assert(qcrypto_init(NULL) == 0);
for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
+ if (!qcrypto_pbkdf2_supports(test_data[i].hash)) {
+ continue;
+ }
+
if (!test_data[i].slow ||
g_test_slow()) {
g_test_add_data_func(test_data[i].path, &test_data[i], test_pbkdf);
}
}
- if (g_test_slow()) {
- g_test_add_func("/crypt0/pbkdf/timing", test_pbkdf_timing);
+ if (g_test_slow() && qcrypto_pbkdf2_supports(QCRYPTO_HASH_ALGO_SHA256)) {
+ g_test_add_func("/crypt0/pbkdf/timing/sha256", test_pbkdf_timing_sha256);
}
return g_test_run();
diff --git a/tests/unit/test-crypto-tlssession.c b/tests/unit/test-crypto-tlssession.c
index b12e7b6..3395f73 100644
--- a/tests/unit/test-crypto-tlssession.c
+++ b/tests/unit/test-crypto-tlssession.c
@@ -35,18 +35,40 @@
#define PSKFILE WORKDIR "keys.psk"
#define KEYFILE WORKDIR "key-ctx.pem"
-static ssize_t testWrite(const char *buf, size_t len, void *opaque)
+static ssize_t
+testWrite(const char *buf, size_t len, void *opaque, Error **errp)
{
int *fd = opaque;
+ int ret;
- return write(*fd, buf, len);
+ ret = write(*fd, buf, len);
+ if (ret < 0) {
+ if (errno == EAGAIN) {
+ return QCRYPTO_TLS_SESSION_ERR_BLOCK;
+ } else {
+ error_setg_errno(errp, errno, "unable to write");
+ return -1;
+ }
+ }
+ return ret;
}
-static ssize_t testRead(char *buf, size_t len, void *opaque)
+static ssize_t
+testRead(char *buf, size_t len, void *opaque, Error **errp)
{
int *fd = opaque;
+ int ret;
- return read(*fd, buf, len);
+ ret = read(*fd, buf, len);
+ if (ret < 0) {
+ if (errno == EAGAIN) {
+ return QCRYPTO_TLS_SESSION_ERR_BLOCK;
+ } else {
+ error_setg_errno(errp, errno, "unable to read");
+ return -1;
+ }
+ }
+ return ret;
}
static QCryptoTLSCreds *test_tls_creds_psk_create(
diff --git a/tests/unit/test-fifo.c b/tests/unit/test-fifo.c
new file mode 100644
index 0000000..14153c4
--- /dev/null
+++ b/tests/unit/test-fifo.c
@@ -0,0 +1,449 @@
+/*
+ * Fifo8 tests
+ *
+ * Copyright 2024 Mark Cave-Ayland
+ *
+ * Authors:
+ * Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "migration/vmstate.h"
+#include "qemu/fifo8.h"
+
+const VMStateInfo vmstate_info_uint32;
+const VMStateInfo vmstate_info_buffer;
+
+
+static void test_fifo8_pop_bufptr_wrap(void)
+{
+ Fifo8 fifo;
+ uint8_t data_in1[] = { 0x1, 0x2, 0x3, 0x4 };
+ uint8_t data_in2[] = { 0x5, 0x6, 0x7, 0x8, 0x9, 0xa };
+ const uint8_t *buf;
+ uint32_t count;
+
+ fifo8_create(&fifo, 8);
+ /*
+ * head --v-- tail used = 0
+ * FIFO: [ . . . . . . . . ]
+ */
+
+ fifo8_push_all(&fifo, data_in1, sizeof(data_in1));
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: [ 1 2 3 4 . . . . ]
+ */
+ buf = fifo8_pop_bufptr(&fifo, 2, &count);
+ /*
+ * head --v ]-- tail used = 2
+ * FIFO: [ 1 2 3 4 . . . . ]
+ * buf --^ count = 2
+ */
+ g_assert(count == 2);
+ g_assert(buf[0] == 0x1 && buf[1] == 0x2);
+
+ fifo8_push_all(&fifo, data_in2, sizeof(data_in2));
+ /*
+ * tail --]v-- head used = 8
+ * FIFO: [ 9 a 3 4 5 6 7 8 ]
+ */
+ buf = fifo8_pop_bufptr(&fifo, 8, &count);
+ /*
+ * head --v ]-- tail used = 2
+ * FIFO: [ 9 a 3 4 5 6 7 8 ]
+ * buf --^ count = 6
+ */
+ g_assert(count == 6);
+ g_assert(buf[0] == 0x3 && buf[1] == 0x4 && buf[2] == 0x5 &&
+ buf[3] == 0x6 && buf[4] == 0x7 && buf[5] == 0x8);
+
+ g_assert(fifo8_num_used(&fifo) == 2);
+ fifo8_destroy(&fifo);
+}
+
+static void test_fifo8_pop_bufptr(void)
+{
+ Fifo8 fifo;
+ uint8_t data_in[] = { 0x1, 0x2, 0x3, 0x4 };
+ const uint8_t *buf;
+ uint32_t count;
+
+ fifo8_create(&fifo, 8);
+ /*
+ * head --v-- tail used = 0
+ * FIFO: [ . . . . . . . . ]
+ */
+
+ fifo8_push_all(&fifo, data_in, sizeof(data_in));
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: [ 1 2 3 4 . . . . ]
+ */
+ buf = fifo8_pop_bufptr(&fifo, 2, &count);
+ /*
+ * head --v ]-- tail used = 2
+ * FIFO: [ 1 2 3 4 . . . . ]
+ * buf --^ count = 2
+ */
+ g_assert(count == 2);
+ g_assert(buf[0] == 0x1 && buf[1] == 0x2);
+
+ g_assert(fifo8_num_used(&fifo) == 2);
+ fifo8_destroy(&fifo);
+}
+
+static void test_fifo8_peek_bufptr_wrap(void)
+{
+ Fifo8 fifo;
+ uint8_t data_in1[] = { 0x1, 0x2, 0x3, 0x4 };
+ uint8_t data_in2[] = { 0x5, 0x6, 0x7, 0x8, 0x9, 0xa };
+ const uint8_t *buf;
+ uint32_t count;
+
+ fifo8_create(&fifo, 8);
+ /*
+ * head --v-- tail used = 0
+ * FIFO: { . . . . . . . . }
+ */
+
+ fifo8_push_all(&fifo, data_in1, sizeof(data_in1));
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: { 1 2 3 4 . . . . }
+ */
+ buf = fifo8_peek_bufptr(&fifo, 2, &count);
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: { 1 2 3 4 . . . . }
+ * buf: [ 1 2 ] count = 2
+ */
+ g_assert(count == 2);
+ g_assert(buf[0] == 0x1 && buf[1] == 0x2);
+
+ buf = fifo8_pop_bufptr(&fifo, 2, &count);
+ /*
+ * head --v ]-- tail used = 2
+ * FIFO: { 1 2 3 4 . . . . }
+ * buf: [ 1 2 ] count = 2
+ */
+ g_assert(count == 2);
+ g_assert(buf[0] == 0x1 && buf[1] == 0x2);
+ fifo8_push_all(&fifo, data_in2, sizeof(data_in2));
+ /*
+ * tail ---]v-- head used = 8
+ * FIFO: { 9 a 3 4 5 6 7 8 }
+ */
+
+ buf = fifo8_peek_bufptr(&fifo, 8, &count);
+ /*
+ * tail --]v-- head used = 8
+ * FIFO: { 9 a 3 4 5 6 7 8 }
+ * buf: [ 3 4 5 6 7 8 ] count = 6
+ */
+ g_assert(count == 6);
+ g_assert(buf[0] == 0x3 && buf[1] == 0x4 && buf[2] == 0x5 &&
+ buf[3] == 0x6 && buf[4] == 0x7 && buf[5] == 0x8);
+
+ g_assert(fifo8_num_used(&fifo) == 8);
+ fifo8_destroy(&fifo);
+}
+
+static void test_fifo8_peek_bufptr(void)
+{
+ Fifo8 fifo;
+ uint8_t data_in[] = { 0x1, 0x2, 0x3, 0x4 };
+ const uint8_t *buf;
+ uint32_t count;
+
+ fifo8_create(&fifo, 8);
+ /*
+ * head --v-- tail used = 0
+ * FIFO: { . . . . . . . . }
+ */
+
+ fifo8_push_all(&fifo, data_in, sizeof(data_in));
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: { 1 2 3 4 . . . . }
+ */
+ buf = fifo8_peek_bufptr(&fifo, 2, &count);
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: { 1 2 3 4 . . . . }
+ * buf: [ 1 2 ] count = 2
+ */
+ g_assert(count == 2);
+ g_assert(buf[0] == 0x1 && buf[1] == 0x2);
+
+ g_assert(fifo8_num_used(&fifo) == 4);
+ fifo8_destroy(&fifo);
+}
+
+static void test_fifo8_pop_buf_wrap(void)
+{
+ Fifo8 fifo;
+ uint8_t data_in1[] = { 0x1, 0x2, 0x3, 0x4 };
+ uint8_t data_in2[] = { 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc };
+ uint8_t data_out[4];
+ int count;
+
+ fifo8_create(&fifo, 8);
+ /*
+ * head --v-- tail used = 0
+ * FIFO: { . . . . . . . . }
+ */
+
+ fifo8_push_all(&fifo, data_in1, sizeof(data_in1));
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: { 1 2 3 4 . . . . }
+ */
+ fifo8_pop_buf(&fifo, NULL, 4);
+ /*
+ * tail --]v-- head used = 0
+ * FIFO: [ 1 2 3 4 . . . . ]
+ */
+
+ fifo8_push_all(&fifo, data_in2, sizeof(data_in2));
+ /*
+ * tail --]v-- head used = 8
+ * FIFO: { 9 a b c 5 6 7 8 }
+ */
+ count = fifo8_pop_buf(&fifo, NULL, 4);
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: { 9 a b c 5 6 7 8 }
+ */
+ g_assert(count == 4);
+ count = fifo8_pop_buf(&fifo, data_out, 4);
+ /*
+ * tail --]v-- head used = 0
+ * FIFO: { 9 a b c 5 6 7 8 }
+ */
+ g_assert(count == 4);
+ g_assert(data_out[0] == 0x9 && data_out[1] == 0xa &&
+ data_out[2] == 0xb && data_out[3] == 0xc);
+
+ g_assert(fifo8_num_used(&fifo) == 0);
+ fifo8_destroy(&fifo);
+}
+
+static void test_fifo8_pop_buf(void)
+{
+ Fifo8 fifo;
+ uint8_t data_in[] = { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8 };
+ uint8_t data_out[] = { 0xff, 0xff, 0xff, 0xff };
+ int count;
+
+ fifo8_create(&fifo, 8);
+ /*
+ * head --v-- tail used = 0
+ * FIFO: { . . . . . . . . }
+ */
+
+ fifo8_push_all(&fifo, data_in, sizeof(data_in));
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: { 1 2 3 4 . . . . }
+ */
+ count = fifo8_pop_buf(&fifo, NULL, 4);
+ /*
+ * tail --]v-- head used = 0
+ * FIFO: { 1 2 3 4 . . . . }
+ */
+ g_assert(count == 4);
+ count = fifo8_pop_buf(&fifo, data_out, 4);
+ g_assert(data_out[0] == 0x5 && data_out[1] == 0x6 &&
+ data_out[2] == 0x7 && data_out[3] == 0x8);
+
+ g_assert(fifo8_num_used(&fifo) == 0);
+ fifo8_destroy(&fifo);
+}
+
+static void test_fifo8_peek_buf_wrap(void)
+{
+ Fifo8 fifo;
+ uint8_t data_in1[] = { 0x1, 0x2, 0x3, 0x4 };
+ uint8_t data_in2[] = { 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc };
+ uint8_t data_out[8];
+ int count;
+
+ fifo8_create(&fifo, 8);
+ /*
+ * head --v-- tail used = 0
+ * FIFO: { . . . . . . . . }
+ */
+
+ fifo8_push_all(&fifo, data_in1, sizeof(data_in1));
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: { 1 2 3 4 . . . . }
+ */
+ fifo8_pop_buf(&fifo, NULL, 4);
+ /*
+ * tail --]v-- head used = 0
+ * FIFO: { 1 2 3 4 . . . . }
+ */
+
+ fifo8_push_all(&fifo, data_in2, sizeof(data_in2));
+ /*
+ * tail --]v-- head used = 8
+ * FIFO: { 9 a b c 5 6 7 8 }
+ */
+ count = fifo8_peek_buf(&fifo, NULL, 4);
+ g_assert(count == 4);
+ count = fifo8_peek_buf(&fifo, data_out, 4);
+ /*
+ * tail --]v-- head used = 8
+ * FIFO: { 9 a b c 5 6 7 8 }
+ * buf: [ 5 6 7 8 ] count = 4
+ */
+ g_assert(count == 4);
+ g_assert(data_out[0] == 0x5 && data_out[1] == 0x6 &&
+ data_out[2] == 0x7 && data_out[3] == 0x8);
+
+ count = fifo8_peek_buf(&fifo, data_out, 8);
+ /*
+ * tail --]v-- head used = 8
+ * FIFO: { 9 a b c 5 6 7 8 }
+ * buf: [ 5 6 7 8 9 a b c ] count = 8
+ */
+ g_assert(count == 8);
+ g_assert(data_out[0] == 0x5 && data_out[1] == 0x6 &&
+ data_out[2] == 0x7 && data_out[3] == 0x8);
+ g_assert(data_out[4] == 0x9 && data_out[5] == 0xa &&
+ data_out[6] == 0xb && data_out[7] == 0xc);
+
+ g_assert(fifo8_num_used(&fifo) == 8);
+ fifo8_destroy(&fifo);
+}
+
+static void test_fifo8_peek_buf(void)
+{
+ Fifo8 fifo;
+ uint8_t data_in[] = { 0x1, 0x2, 0x3, 0x4 };
+ uint8_t data_out[] = { 0xff, 0xff, 0xff, 0xff };
+ int count;
+
+ fifo8_create(&fifo, 8);
+ /*
+ * head --v-- tail used = 0
+ * FIFO: { . . . . . . . . }
+ */
+
+ fifo8_push_all(&fifo, data_in, sizeof(data_in));
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: { 1 2 3 4 . . . . }
+ */
+ count = fifo8_peek_buf(&fifo, NULL, 4);
+ g_assert(count == 4);
+
+ g_assert(data_out[0] == 0xff && data_out[1] == 0xff &&
+ data_out[2] == 0xff && data_out[3] == 0xff);
+ count = fifo8_peek_buf(&fifo, data_out, 4);
+ /*
+ * head --v ]-- tail used = 4
+ * FIFO: { 1 2 3 4 . . . . }
+ * buf: [ 1 2 3 4 ] count = 4
+ */
+ g_assert(count == 4);
+ g_assert(data_out[0] == 0x1 && data_out[1] == 0x2 &&
+ data_out[2] == 0x3 && data_out[3] == 0x4);
+
+ g_assert(fifo8_num_used(&fifo) == 4);
+ fifo8_destroy(&fifo);
+}
+
+static void test_fifo8_peek(void)
+{
+ Fifo8 fifo;
+ uint8_t c;
+
+ fifo8_create(&fifo, 8);
+ /*
+ * head --v-- tail used = 0
+ * FIFO: { . . . . . . . . }
+ */
+ fifo8_push(&fifo, 0x1);
+ /*
+ * head --v]-- tail used = 1
+ * FIFO: { 1 . . . . . . . }
+ */
+ fifo8_push(&fifo, 0x2);
+ /*
+ * head --v ]-- tail used = 2
+ * FIFO: { 1 2 . . . . . . }
+ */
+
+ c = fifo8_peek(&fifo);
+ g_assert(c == 0x1);
+ fifo8_pop(&fifo);
+ /*
+ * head --v]-- tail used = 1
+ * FIFO: { 1 2 . . . . . . }
+ */
+ c = fifo8_peek(&fifo);
+ g_assert(c == 0x2);
+
+ g_assert(fifo8_num_used(&fifo) == 1);
+ fifo8_destroy(&fifo);
+}
+
+static void test_fifo8_pushpop(void)
+{
+ Fifo8 fifo;
+ uint8_t c;
+
+ fifo8_create(&fifo, 8);
+ /*
+ * head --v-- tail used = 0
+ * FIFO: { . . . . . . . . }
+ */
+ fifo8_push(&fifo, 0x1);
+ /*
+ * head --v]-- tail used = 1
+ * FIFO: { 1 . . . . . . . }
+ */
+ fifo8_push(&fifo, 0x2);
+ /*
+ * head --v ]-- tail used = 2
+ * FIFO: { 1 2 . . . . . . }
+ */
+
+ c = fifo8_pop(&fifo);
+ /*
+ * head --v]-- tail used = 1
+ * FIFO: { 1 2 . . . . . . }
+ */
+ g_assert(c == 0x1);
+ c = fifo8_pop(&fifo);
+ /*
+ * tail --]v-- head used = 0
+ * FIFO: { 1 2 . . . . . . }
+ */
+ g_assert(c == 0x2);
+
+ g_assert(fifo8_num_used(&fifo) == 0);
+ fifo8_destroy(&fifo);
+}
+
+int main(int argc, char *argv[])
+{
+ g_test_init(&argc, &argv, NULL);
+ g_test_add_func("/fifo8/pushpop", test_fifo8_pushpop);
+ g_test_add_func("/fifo8/peek", test_fifo8_peek);
+ g_test_add_func("/fifo8/peek_buf", test_fifo8_peek_buf);
+ g_test_add_func("/fifo8/peek_buf_wrap", test_fifo8_peek_buf_wrap);
+ g_test_add_func("/fifo8/pop_buf", test_fifo8_pop_buf);
+ g_test_add_func("/fifo8/pop_buf_wrap", test_fifo8_pop_buf_wrap);
+ g_test_add_func("/fifo8/peek_bufptr", test_fifo8_peek_bufptr);
+ g_test_add_func("/fifo8/peek_bufptr_wrap", test_fifo8_peek_bufptr_wrap);
+ g_test_add_func("/fifo8/pop_bufptr", test_fifo8_pop_bufptr);
+ g_test_add_func("/fifo8/pop_bufptr_wrap", test_fifo8_pop_bufptr_wrap);
+ return g_test_run();
+}
diff --git a/tests/unit/test-io-channel-socket.c b/tests/unit/test-io-channel-socket.c
index b964bb2..dc7be96 100644
--- a/tests/unit/test-io-channel-socket.c
+++ b/tests/unit/test-io-channel-socket.c
@@ -506,7 +506,7 @@ static void test_io_channel_unix_listen_cleanup(void)
{
QIOChannelSocket *ioc;
struct sockaddr_un un;
- int sock;
+ int sock, ret = 0;
#define TEST_SOCKET "test-io-channel-socket.sock"
@@ -519,7 +519,9 @@ static void test_io_channel_unix_listen_cleanup(void)
un.sun_family = AF_UNIX;
snprintf(un.sun_path, sizeof(un.sun_path), "%s", TEST_SOCKET);
unlink(TEST_SOCKET);
- bind(sock, (struct sockaddr *)&un, sizeof(un));
+ ret = bind(sock, (struct sockaddr *)&un, sizeof(un));
+ g_assert_cmpint(ret, ==, 0);
+
ioc->fd = sock;
ioc->localAddrLen = sizeof(ioc->localAddr);
getsockname(sock, (struct sockaddr *)&ioc->localAddr,
diff --git a/tests/unit/test-qobject-input-visitor.c b/tests/unit/test-qobject-input-visitor.c
index 024e26c..5479e68 100644
--- a/tests/unit/test-qobject-input-visitor.c
+++ b/tests/unit/test-qobject-input-visitor.c
@@ -720,7 +720,7 @@ static void test_visitor_in_union_in_union(TestInputVisitorData *data,
visit_type_TestUnionInUnion(v, NULL, &tmp, &error_abort);
g_assert_cmpint(tmp->type, ==, TEST_UNION_ENUM_VALUE_A);
- g_assert_cmpint(tmp->u.value_a.type_a, ==, TEST_UNION_ENUMA_VALUE_A1);
+ g_assert_cmpint(tmp->u.value_a.type_a, ==, TEST_UNION_ENUM_A_VALUE_A1);
g_assert_cmpint(tmp->u.value_a.u.value_a1.integer, ==, 2);
g_assert_cmpint(strcmp(tmp->u.value_a.u.value_a1.name, "fish"), ==, 0);
@@ -734,7 +734,7 @@ static void test_visitor_in_union_in_union(TestInputVisitorData *data,
visit_type_TestUnionInUnion(v, NULL, &tmp, &error_abort);
g_assert_cmpint(tmp->type, ==, TEST_UNION_ENUM_VALUE_A);
- g_assert_cmpint(tmp->u.value_a.type_a, ==, TEST_UNION_ENUMA_VALUE_A2);
+ g_assert_cmpint(tmp->u.value_a.type_a, ==, TEST_UNION_ENUM_A_VALUE_A2);
g_assert_cmpint(tmp->u.value_a.u.value_a2.integer, ==, 1729);
g_assert_cmpint(tmp->u.value_a.u.value_a2.size, ==, 87539319);
diff --git a/tests/unit/test-qobject-output-visitor.c b/tests/unit/test-qobject-output-visitor.c
index 1535b3a..3455f3b 100644
--- a/tests/unit/test-qobject-output-visitor.c
+++ b/tests/unit/test-qobject-output-visitor.c
@@ -359,7 +359,7 @@ static void test_visitor_out_union_in_union(TestOutputVisitorData *data,
TestUnionInUnion *tmp = g_new0(TestUnionInUnion, 1);
tmp->type = TEST_UNION_ENUM_VALUE_A;
- tmp->u.value_a.type_a = TEST_UNION_ENUMA_VALUE_A1;
+ tmp->u.value_a.type_a = TEST_UNION_ENUM_A_VALUE_A1;
tmp->u.value_a.u.value_a1.integer = 42;
tmp->u.value_a.u.value_a1.name = g_strdup("fish");
@@ -377,7 +377,7 @@ static void test_visitor_out_union_in_union(TestOutputVisitorData *data,
visitor_reset(data);
tmp = g_new0(TestUnionInUnion, 1);
tmp->type = TEST_UNION_ENUM_VALUE_A;
- tmp->u.value_a.type_a = TEST_UNION_ENUMA_VALUE_A2;
+ tmp->u.value_a.type_a = TEST_UNION_ENUM_A_VALUE_A2;
tmp->u.value_a.u.value_a2.integer = 1729;
tmp->u.value_a.u.value_a2.size = 87539319;
diff --git a/tests/unit/test-xs-node.c b/tests/unit/test-xs-node.c
index ac94e7e..2f447a7 100644
--- a/tests/unit/test-xs-node.c
+++ b/tests/unit/test-xs-node.c
@@ -212,7 +212,7 @@ static void compare_tx(gpointer key, gpointer val, gpointer opaque)
printf("Comparison failure in TX %u after serdes:\n", tx_id);
dump_ref("Original", t1->root, 0);
dump_ref("Deserialised", t2->root, 0);
- g_assert(0);
+ g_assert_not_reached();
}
g_assert(t1->nr_nodes == t2->nr_nodes);
}
@@ -257,7 +257,7 @@ static void check_serdes(XenstoreImplState *s)
printf("Comparison failure in main tree after serdes:\n");
dump_ref("Original", s->root, 0);
dump_ref("Deserialised", s2->root, 0);
- g_assert(0);
+ g_assert_not_reached();
}
nr_transactions1 = g_hash_table_size(s->transactions);
diff --git a/tests/vm/freebsd b/tests/vm/freebsd
index 1247f40..74b3b1e 100755
--- a/tests/vm/freebsd
+++ b/tests/vm/freebsd
@@ -28,8 +28,8 @@ class FreeBSDVM(basevm.BaseVM):
name = "freebsd"
arch = "x86_64"
- link = "https://download.freebsd.org/releases/CI-IMAGES/13.2-RELEASE/amd64/Latest/FreeBSD-13.2-RELEASE-amd64-BASIC-CI.raw.xz"
- csum = "a4fb3b6c7b75dd4d58fb0d75e4caf72844bffe0ca00e66459c028b198ffb3c0e"
+ link = "https://download.freebsd.org/releases/CI-IMAGES/14.1-RELEASE/amd64/Latest/FreeBSD-14.1-RELEASE-amd64-BASIC-CI.raw.xz"
+ csum = "202fe27a05427f0a86d3ebb97712745186f2776ccc4f70d95466dd99a0238ba5"
size = "20G"
BUILD_SCRIPT = """
@@ -39,7 +39,7 @@ class FreeBSDVM(basevm.BaseVM):
mkdir src build; cd src;
tar -xf /dev/vtbd1;
cd ../build;
- ../src/configure --python=python3.9 --extra-ldflags=-L/usr/local/lib \
+ ../src/configure --extra-ldflags=-L/usr/local/lib \
--extra-cflags=-I/usr/local/include {configure_opts};
gmake --output-sync -j{jobs} {target} {verbose};
"""
diff --git a/tests/vm/generated/freebsd.json b/tests/vm/generated/freebsd.json
index 2d5895e..1eb2757 100644
--- a/tests/vm/generated/freebsd.json
+++ b/tests/vm/generated/freebsd.json
@@ -29,6 +29,7 @@
"gmake",
"gnutls",
"gsed",
+ "gtk-vnc",
"gtk3",
"json-c",
"libepoxy",
@@ -51,13 +52,13 @@
"pixman",
"pkgconf",
"png",
- "py39-numpy",
- "py39-pillow",
- "py39-pip",
- "py39-sphinx",
- "py39-sphinx_rtd_theme",
- "py39-tomli",
- "py39-yaml",
+ "py311-numpy",
+ "py311-pillow",
+ "py311-pip",
+ "py311-pyyaml",
+ "py311-sphinx",
+ "py311-sphinx_rtd_theme",
+ "py311-tomli",
"python3",
"rpm2cpio",
"sdl2",
diff --git a/tests/vm/openbsd b/tests/vm/openbsd
index 5e646f7..dfd11c9 100755
--- a/tests/vm/openbsd
+++ b/tests/vm/openbsd
@@ -22,8 +22,8 @@ class OpenBSDVM(basevm.BaseVM):
name = "openbsd"
arch = "x86_64"
- link = "https://cdn.openbsd.org/pub/OpenBSD/7.5/amd64/install75.iso"
- csum = "034435c6e27405d5a7fafb058162943c194eb793dafdc412c08d49bb56b3892a"
+ link = "https://cdn.openbsd.org/pub/OpenBSD/7.6/amd64/install76.iso"
+ csum = "60cba8cb391b50bba8fa10fc768bd0529636f5345d82133c93e22c798d8e5269"
size = "20G"
pkgs = [
# tools
@@ -159,6 +159,7 @@ class OpenBSDVM(basevm.BaseVM):
self.print_step("Installation started now, this will take a while")
self.console_wait_send("Location of sets", "done\n")
+ self.console_wait_send("Time appears wrong. Set to", "\n")
self.console_wait("successfully completed")
self.print_step("Installation finished, rebooting")
diff --git a/tools/i386/qemu-vmsr-helper.c b/tools/i386/qemu-vmsr-helper.c
new file mode 100644
index 0000000..a35dcb8
--- /dev/null
+++ b/tools/i386/qemu-vmsr-helper.c
@@ -0,0 +1,540 @@
+/*
+ * Privileged RAPL MSR helper commands for QEMU
+ *
+ * Copyright (C) 2024 Red Hat, Inc. <aharivel@redhat.com>
+ *
+ * Author: Anthony Harivel <aharivel@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; under version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include <getopt.h>
+#include <stdbool.h>
+#include <sys/ioctl.h>
+#ifdef CONFIG_LIBCAP_NG
+#include <cap-ng.h>
+#endif
+#include <pwd.h>
+#include <grp.h>
+
+#include "qemu/help-texts.h"
+#include "qapi/error.h"
+#include "qemu/cutils.h"
+#include "qemu/main-loop.h"
+#include "qemu/module.h"
+#include "qemu/error-report.h"
+#include "qemu/config-file.h"
+#include "qemu-version.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qemu/log.h"
+#include "qemu/systemd.h"
+#include "io/channel.h"
+#include "io/channel-socket.h"
+#include "trace/control.h"
+#include "qemu-version.h"
+#include "rapl-msr-index.h"
+
+#define MSR_PATH_TEMPLATE "/dev/cpu/%u/msr"
+
+static char *socket_path;
+static char *pidfile;
+static enum { RUNNING, TERMINATE, TERMINATING } state;
+static QIOChannelSocket *server_ioc;
+static int server_watch;
+static int num_active_sockets = 1;
+static bool verbose;
+
+#ifdef CONFIG_LIBCAP_NG
+static int uid = -1;
+static int gid = -1;
+#endif
+
+static void compute_default_paths(void)
+{
+ g_autofree char *state = qemu_get_local_state_dir();
+
+ socket_path = g_build_filename(state, "run", "qemu-vmsr-helper.sock", NULL);
+ pidfile = g_build_filename(state, "run", "qemu-vmsr-helper.pid", NULL);
+}
+
+static int is_intel_processor(void)
+{
+ int result;
+ int ebx, ecx, edx;
+
+ /* Execute CPUID instruction with eax=0 (basic identification) */
+ asm volatile (
+ "cpuid"
+ : "=b" (ebx), "=c" (ecx), "=d" (edx)
+ : "a" (0)
+ );
+
+ /*
+ * Check if processor is "GenuineIntel"
+ * 0x756e6547 = "Genu"
+ * 0x49656e69 = "ineI"
+ * 0x6c65746e = "ntel"
+ */
+ result = (ebx == 0x756e6547) && (edx == 0x49656e69) && (ecx == 0x6c65746e);
+
+ return result;
+}
+
+static int is_rapl_enabled(void)
+{
+ const char *path = "/sys/class/powercap/intel-rapl/enabled";
+ FILE *file = fopen(path, "r");
+ int value = 0;
+
+ if (file != NULL) {
+ if (fscanf(file, "%d", &value) != 1) {
+ error_report("INTEL RAPL not enabled");
+ }
+ fclose(file);
+ } else {
+ error_report("Error opening %s", path);
+ }
+
+ return value;
+}
+
+/*
+ * Check if the TID that request the MSR read
+ * belongs to the peer. It be should a TID of a vCPU.
+ */
+static bool is_tid_present(pid_t pid, pid_t tid)
+{
+ g_autofree char *tidPath = g_strdup_printf("/proc/%d/task/%d", pid, tid);
+
+ /* Check if the TID directory exists within the PID directory */
+ if (access(tidPath, F_OK) == 0) {
+ return true;
+ }
+
+ error_report("Failed to open /proc at %s", tidPath);
+ return false;
+}
+
+/*
+ * Only the RAPL MSR in target/i386/cpu.h are allowed
+ */
+static bool is_msr_allowed(uint32_t reg)
+{
+ switch (reg) {
+ case MSR_RAPL_POWER_UNIT:
+ case MSR_PKG_POWER_LIMIT:
+ case MSR_PKG_ENERGY_STATUS:
+ case MSR_PKG_POWER_INFO:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static uint64_t vmsr_read_msr(uint32_t msr_register, unsigned int cpu_id)
+{
+ int fd;
+ uint64_t result = 0;
+
+ g_autofree char *path = g_strdup_printf(MSR_PATH_TEMPLATE, cpu_id);
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ error_report("Failed to open MSR file at %s", path);
+ return result;
+ }
+
+ if (pread(fd, &result, sizeof(result), msr_register) != sizeof(result)) {
+ error_report("Failed to read MSR");
+ result = 0;
+ }
+
+ close(fd);
+ return result;
+}
+
+static void usage(const char *name)
+{
+ (printf) (
+"Usage: %s [OPTIONS] FILE\n"
+"Virtual RAPL MSR helper program for QEMU\n"
+"\n"
+" -h, --help display this help and exit\n"
+" -V, --version output version information and exit\n"
+"\n"
+" -d, --daemon run in the background\n"
+" -f, --pidfile=PATH PID file when running as a daemon\n"
+" (default '%s')\n"
+" -k, --socket=PATH path to the unix socket\n"
+" (default '%s')\n"
+" -T, --trace [[enable=]<pattern>][,events=<file>][,file=<file>]\n"
+" specify tracing options\n"
+#ifdef CONFIG_LIBCAP_NG
+" -u, --user=USER user to drop privileges to\n"
+" -g, --group=GROUP group to drop privileges to\n"
+#endif
+"\n"
+QEMU_HELP_BOTTOM "\n"
+ , name, pidfile, socket_path);
+}
+
+static void version(const char *name)
+{
+ printf(
+"%s " QEMU_FULL_VERSION "\n"
+"Written by Anthony Harivel.\n"
+"\n"
+QEMU_COPYRIGHT "\n"
+"This is free software; see the source for copying conditions. There is NO\n"
+"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
+ , name);
+}
+
+typedef struct VMSRHelperClient {
+ QIOChannelSocket *ioc;
+ Coroutine *co;
+} VMSRHelperClient;
+
+static void coroutine_fn vh_co_entry(void *opaque)
+{
+ VMSRHelperClient *client = opaque;
+ Error *local_err = NULL;
+ unsigned int peer_pid;
+ uint32_t request[3];
+ uint64_t vmsr;
+ int r;
+
+ qio_channel_set_blocking(QIO_CHANNEL(client->ioc),
+ false, NULL);
+
+ qio_channel_set_follow_coroutine_ctx(QIO_CHANNEL(client->ioc), true);
+
+ /*
+ * Check peer credentials
+ */
+ r = qio_channel_get_peerpid(QIO_CHANNEL(client->ioc),
+ &peer_pid,
+ &local_err);
+ if (r < 0) {
+ goto out;
+ }
+
+ for (;;) {
+ /*
+ * Read the requested MSR
+ * Only RAPL MSR in rapl-msr-index.h is allowed
+ */
+ r = qio_channel_read_all_eof(QIO_CHANNEL(client->ioc),
+ (char *) &request, sizeof(request), &local_err);
+ if (r <= 0) {
+ break;
+ }
+
+ if (!is_msr_allowed(request[0])) {
+ error_report("Requested unallowed msr: %d", request[0]);
+ break;
+ }
+
+ vmsr = vmsr_read_msr(request[0], request[1]);
+
+ if (!is_tid_present(peer_pid, request[2])) {
+ error_report("Requested TID not in peer PID: %d %d",
+ peer_pid, request[2]);
+ vmsr = 0;
+ }
+
+ r = qio_channel_write_all(QIO_CHANNEL(client->ioc),
+ (char *) &vmsr,
+ sizeof(vmsr),
+ &local_err);
+ if (r < 0) {
+ break;
+ }
+ }
+
+out:
+ if (local_err) {
+ if (!verbose) {
+ error_free(local_err);
+ } else {
+ error_report_err(local_err);
+ }
+ }
+
+ object_unref(OBJECT(client->ioc));
+ g_free(client);
+}
+
+static gboolean accept_client(QIOChannel *ioc,
+ GIOCondition cond,
+ gpointer opaque)
+{
+ QIOChannelSocket *cioc;
+ VMSRHelperClient *vmsrh;
+
+ cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
+ NULL);
+ if (!cioc) {
+ return TRUE;
+ }
+
+ vmsrh = g_new(VMSRHelperClient, 1);
+ vmsrh->ioc = cioc;
+ vmsrh->co = qemu_coroutine_create(vh_co_entry, vmsrh);
+ qemu_coroutine_enter(vmsrh->co);
+
+ return TRUE;
+}
+
+static void termsig_handler(int signum)
+{
+ qatomic_cmpxchg(&state, RUNNING, TERMINATE);
+ qemu_notify_event();
+}
+
+static void close_server_socket(void)
+{
+ assert(server_ioc);
+
+ g_source_remove(server_watch);
+ server_watch = -1;
+ object_unref(OBJECT(server_ioc));
+ num_active_sockets--;
+}
+
+#ifdef CONFIG_LIBCAP_NG
+static int drop_privileges(void)
+{
+ /* clear all capabilities */
+ capng_clear(CAPNG_SELECT_BOTH);
+
+ if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
+ CAP_SYS_RAWIO) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
+int main(int argc, char **argv)
+{
+ const char *sopt = "hVk:f:dT:u:g:vq";
+ struct option lopt[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { "socket", required_argument, NULL, 'k' },
+ { "pidfile", required_argument, NULL, 'f' },
+ { "daemon", no_argument, NULL, 'd' },
+ { "trace", required_argument, NULL, 'T' },
+ { "verbose", no_argument, NULL, 'v' },
+ { NULL, 0, NULL, 0 }
+ };
+ int opt_ind = 0;
+ int ch;
+ Error *local_err = NULL;
+ bool daemonize = false;
+ bool pidfile_specified = false;
+ bool socket_path_specified = false;
+ unsigned socket_activation;
+
+ struct sigaction sa_sigterm;
+ memset(&sa_sigterm, 0, sizeof(sa_sigterm));
+ sa_sigterm.sa_handler = termsig_handler;
+ sigaction(SIGTERM, &sa_sigterm, NULL);
+ sigaction(SIGINT, &sa_sigterm, NULL);
+ sigaction(SIGHUP, &sa_sigterm, NULL);
+
+ signal(SIGPIPE, SIG_IGN);
+
+ error_init(argv[0]);
+ module_call_init(MODULE_INIT_TRACE);
+ module_call_init(MODULE_INIT_QOM);
+ qemu_add_opts(&qemu_trace_opts);
+ qemu_init_exec_dir(argv[0]);
+
+ compute_default_paths();
+
+ /*
+ * Sanity check
+ * 1. cpu must be Intel cpu
+ * 2. RAPL must be enabled
+ */
+ if (!is_intel_processor()) {
+ error_report("error: CPU is not INTEL cpu");
+ exit(EXIT_FAILURE);
+ }
+
+ if (!is_rapl_enabled()) {
+ error_report("error: RAPL driver not enable");
+ exit(EXIT_FAILURE);
+ }
+
+ while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
+ switch (ch) {
+ case 'k':
+ g_free(socket_path);
+ socket_path = g_strdup(optarg);
+ socket_path_specified = true;
+ if (socket_path[0] != '/') {
+ error_report("socket path must be absolute");
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 'f':
+ g_free(pidfile);
+ pidfile = g_strdup(optarg);
+ pidfile_specified = true;
+ break;
+#ifdef CONFIG_LIBCAP_NG
+ case 'u': {
+ unsigned long res;
+ struct passwd *userinfo = getpwnam(optarg);
+ if (userinfo) {
+ uid = userinfo->pw_uid;
+ } else if (qemu_strtoul(optarg, NULL, 10, &res) == 0 &&
+ (uid_t)res == res) {
+ uid = res;
+ } else {
+ error_report("invalid user '%s'", optarg);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ }
+ case 'g': {
+ unsigned long res;
+ struct group *groupinfo = getgrnam(optarg);
+ if (groupinfo) {
+ gid = groupinfo->gr_gid;
+ } else if (qemu_strtoul(optarg, NULL, 10, &res) == 0 &&
+ (gid_t)res == res) {
+ gid = res;
+ } else {
+ error_report("invalid group '%s'", optarg);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ }
+#else
+ case 'u':
+ case 'g':
+ error_report("-%c not supported by this %s", ch, argv[0]);
+ exit(1);
+#endif
+ case 'd':
+ daemonize = true;
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case 'T':
+ trace_opt_parse(optarg);
+ break;
+ case 'V':
+ version(argv[0]);
+ exit(EXIT_SUCCESS);
+ break;
+ case 'h':
+ usage(argv[0]);
+ exit(EXIT_SUCCESS);
+ break;
+ case '?':
+ error_report("Try `%s --help' for more information.", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (!trace_init_backends()) {
+ exit(EXIT_FAILURE);
+ }
+ trace_init_file();
+ qemu_set_log(LOG_TRACE, &error_fatal);
+
+ socket_activation = check_socket_activation();
+ if (socket_activation == 0) {
+ SocketAddress saddr;
+ saddr = (SocketAddress){
+ .type = SOCKET_ADDRESS_TYPE_UNIX,
+ .u.q_unix.path = socket_path,
+ };
+ server_ioc = qio_channel_socket_new();
+ if (qio_channel_socket_listen_sync(server_ioc, &saddr,
+ 1, &local_err) < 0) {
+ object_unref(OBJECT(server_ioc));
+ error_report_err(local_err);
+ return 1;
+ }
+ } else {
+ /* Using socket activation - check user didn't use -p etc. */
+ if (socket_path_specified) {
+ error_report("Unix socket can't be set when"
+ "using socket activation");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Can only listen on a single socket. */
+ if (socket_activation > 1) {
+ error_report("%s does not support socket activation"
+ "with LISTEN_FDS > 1",
+ argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ server_ioc = qio_channel_socket_new_fd(FIRST_SOCKET_ACTIVATION_FD,
+ &local_err);
+ if (server_ioc == NULL) {
+ error_reportf_err(local_err,
+ "Failed to use socket activation: ");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ qemu_init_main_loop(&error_fatal);
+
+ server_watch = qio_channel_add_watch(QIO_CHANNEL(server_ioc),
+ G_IO_IN,
+ accept_client,
+ NULL, NULL);
+
+ if (daemonize) {
+ if (daemon(0, 0) < 0) {
+ error_report("Failed to daemonize: %s", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (daemonize || pidfile_specified) {
+ qemu_write_pidfile(pidfile, &error_fatal);
+ }
+
+#ifdef CONFIG_LIBCAP_NG
+ if (drop_privileges() < 0) {
+ error_report("Failed to drop privileges: %s", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+ info_report("Listening on %s", socket_path);
+
+ state = RUNNING;
+ do {
+ main_loop_wait(false);
+ if (state == TERMINATE) {
+ state = TERMINATING;
+ close_server_socket();
+ }
+ } while (num_active_sockets > 0);
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/tools/i386/rapl-msr-index.h b/tools/i386/rapl-msr-index.h
new file mode 100644
index 0000000..9a71186
--- /dev/null
+++ b/tools/i386/rapl-msr-index.h
@@ -0,0 +1,28 @@
+/*
+ * Allowed list of MSR for Privileged RAPL MSR helper commands for QEMU
+ *
+ * Copyright (C) 2023 Red Hat, Inc. <aharivel@redhat.com>
+ *
+ * Author: Anthony Harivel <aharivel@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; under version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Should stay in sync with the RAPL MSR
+ * in target/i386/cpu.h
+ */
+#define MSR_RAPL_POWER_UNIT 0x00000606
+#define MSR_PKG_POWER_LIMIT 0x00000610
+#define MSR_PKG_ENERGY_STATUS 0x00000611
+#define MSR_PKG_POWER_INFO 0x00000614
diff --git a/ui/clipboard.c b/ui/clipboard.c
index 4264884..132086e 100644
--- a/ui/clipboard.c
+++ b/ui/clipboard.c
@@ -155,6 +155,8 @@ void qemu_clipboard_reset_serial(void)
QemuClipboardNotify notify = { .type = QEMU_CLIPBOARD_RESET_SERIAL };
int i;
+ trace_clipboard_reset_serial();
+
for (i = 0; i < QEMU_CLIPBOARD_SELECTION__COUNT; i++) {
QemuClipboardInfo *info = qemu_clipboard_info(i);
if (info) {
diff --git a/ui/console-vc.c b/ui/console-vc.c
index 899fa11..53fcee8 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -287,7 +287,7 @@ static void kbd_send_chars(QemuTextConsole *s)
const uint8_t *buf;
uint32_t size;
- buf = fifo8_pop_buf(&s->out_fifo, MIN(len, avail), &size);
+ buf = fifo8_pop_bufptr(&s->out_fifo, MIN(len, avail), &size);
qemu_chr_be_write(s->chr, buf, size);
len = qemu_chr_be_can_write(s->chr);
avail -= size;
@@ -648,7 +648,7 @@ static void vc_putchar(VCChardev *vc, int ch)
QemuTextConsole *s = vc->console;
int i;
int x, y;
- char response[40];
+ g_autofree char *response = NULL;
switch(vc->state) {
case TTY_STATE_NORM:
@@ -821,7 +821,7 @@ static void vc_putchar(VCChardev *vc, int ch)
break;
case 6:
/* report cursor position */
- sprintf(response, "\033[%d;%dR",
+ response = g_strdup_printf("\033[%d;%dR",
(s->y_base + s->y) % s->total_height + 1,
s->x + 1);
vc_respond_str(vc, response);
diff --git a/ui/console.c b/ui/console.c
index e8f0083..5165f17 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -37,6 +37,7 @@
#include "trace.h"
#include "exec/memory.h"
#include "qom/object.h"
+#include "qemu/memfd.h"
#include "console-priv.h"
@@ -452,60 +453,26 @@ qemu_graphic_console_init(Object *obj)
{
}
-#ifdef WIN32
-void qemu_displaysurface_win32_set_handle(DisplaySurface *surface,
- HANDLE h, uint32_t offset)
+void qemu_displaysurface_set_share_handle(DisplaySurface *surface,
+ qemu_pixman_shareable handle,
+ uint32_t offset)
{
- assert(!surface->handle);
+ assert(surface->share_handle == SHAREABLE_NONE);
- surface->handle = h;
- surface->handle_offset = offset;
-}
-
-static void
-win32_pixman_image_destroy(pixman_image_t *image, void *data)
-{
- DisplaySurface *surface = data;
-
- if (!surface->handle) {
- return;
- }
-
- assert(surface->handle_offset == 0);
+ surface->share_handle = handle;
+ surface->share_handle_offset = offset;
- qemu_win32_map_free(
- pixman_image_get_data(surface->image),
- surface->handle,
- &error_warn
- );
}
-#endif
DisplaySurface *qemu_create_displaysurface(int width, int height)
{
- DisplaySurface *surface;
- void *bits = NULL;
-#ifdef WIN32
- HANDLE handle = NULL;
-#endif
-
trace_displaysurface_create(width, height);
-#ifdef WIN32
- bits = qemu_win32_map_alloc(width * height * 4, &handle, &error_abort);
-#endif
-
- surface = qemu_create_displaysurface_from(
+ return qemu_create_displaysurface_from(
width, height,
PIXMAN_x8r8g8b8,
- width * 4, bits
+ width * 4, NULL
);
- surface->flags = QEMU_ALLOCATED_FLAG;
-
-#ifdef WIN32
- qemu_displaysurface_win32_set_handle(surface, handle, 0);
-#endif
- return surface;
}
DisplaySurface *qemu_create_displaysurface_from(int width, int height,
@@ -515,15 +482,25 @@ DisplaySurface *qemu_create_displaysurface_from(int width, int height,
DisplaySurface *surface = g_new0(DisplaySurface, 1);
trace_displaysurface_create_from(surface, width, height, format);
- surface->image = pixman_image_create_bits(format,
- width, height,
- (void *)data, linesize);
- assert(surface->image != NULL);
-#ifdef WIN32
- pixman_image_set_destroy_function(surface->image,
- win32_pixman_image_destroy, surface);
-#endif
+ surface->share_handle = SHAREABLE_NONE;
+
+ if (data) {
+ surface->image = pixman_image_create_bits(format,
+ width, height,
+ (void *)data, linesize);
+ } else {
+ qemu_pixman_image_new_shareable(&surface->image,
+ &surface->share_handle,
+ "displaysurface",
+ format,
+ width,
+ height,
+ linesize,
+ &error_abort);
+ surface->flags = QEMU_ALLOCATED_FLAG;
+ }
+ assert(surface->image != NULL);
return surface;
}
@@ -532,6 +509,7 @@ DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image)
DisplaySurface *surface = g_new0(DisplaySurface, 1);
trace_displaysurface_create_pixman(surface);
+ surface->share_handle = SHAREABLE_NONE;
surface->image = pixman_image_ref(image);
return surface;
@@ -1632,4 +1610,9 @@ void qemu_display_help(void)
printf("%s\n", DisplayType_str(dpys[idx]->type));
}
}
+ printf("\n"
+ "Some display backends support suboptions, which can be set with\n"
+ " -display backend,option=value,option=value...\n"
+ "For a short list of the suboptions for each display, see the "
+ "top-level -help output; more detail is in the documentation.\n");
}
diff --git a/ui/curses.c b/ui/curses.c
index ec61615..4d0be9b 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -38,7 +38,7 @@
#include "ui/input.h"
#include "sysemu/sysemu.h"
-#if defined(__APPLE__) || defined(__OpenBSD__)
+#ifdef __APPLE__
#define _XOPEN_SOURCE_EXTENDED 1
#endif
diff --git a/ui/cursor.c b/ui/cursor.c
index 29717b3..6e23244 100644
--- a/ui/cursor.c
+++ b/ui/cursor.c
@@ -197,30 +197,6 @@ void cursor_set_mono(QEMUCursor *c,
}
}
-void cursor_get_mono_image(QEMUCursor *c, int foreground, uint8_t *image)
-{
- uint32_t *data = c->data;
- uint8_t bit;
- int x,y,bpl;
-
- bpl = cursor_get_mono_bpl(c);
- memset(image, 0, bpl * c->height);
- for (y = 0; y < c->height; y++) {
- bit = 0x80;
- for (x = 0; x < c->width; x++, data++) {
- if (((*data & 0xff000000) == 0xff000000) &&
- ((*data & 0x00ffffff) == foreground)) {
- image[x/8] |= bit;
- }
- bit >>= 1;
- if (bit == 0) {
- bit = 0x80;
- }
- }
- image += bpl;
- }
-}
-
void cursor_get_mono_mask(QEMUCursor *c, int transparent, uint8_t *mask)
{
uint32_t *data = c->data;
@@ -232,7 +208,7 @@ void cursor_get_mono_mask(QEMUCursor *c, int transparent, uint8_t *mask)
for (y = 0; y < c->height; y++) {
bit = 0x80;
for (x = 0; x < c->width; x++, data++) {
- if ((*data & 0xff000000) != 0xff000000) {
+ if ((*data & 0x80000000) == 0x0) { /* Alpha < 0x80 (128) */
if (transparent != 0) {
mask[x/8] |= bit;
}
diff --git a/ui/dbus-clipboard.c b/ui/dbus-clipboard.c
index fe7fcde..fbb043a 100644
--- a/ui/dbus-clipboard.c
+++ b/ui/dbus-clipboard.c
@@ -141,6 +141,8 @@ dbus_clipboard_qemu_request(QemuClipboardInfo *info,
const char *mimes[] = { MIME_TEXT_PLAIN_UTF8, NULL };
size_t n;
+ trace_dbus_clipboard_qemu_request(type);
+
if (type != QEMU_CLIPBOARD_TYPE_TEXT) {
/* unsupported atm */
return;
@@ -305,6 +307,8 @@ dbus_clipboard_grab(
return DBUS_METHOD_INVOCATION_HANDLED;
}
+ trace_dbus_clipboard_grab(arg_selection, arg_serial);
+
if (s >= QEMU_CLIPBOARD_SELECTION__COUNT) {
g_dbus_method_invocation_return_error(
invocation,
diff --git a/ui/dbus-console.c b/ui/dbus-console.c
index 578b67f..5eb1d40 100644
--- a/ui/dbus-console.c
+++ b/ui/dbus-console.c
@@ -41,7 +41,7 @@ struct _DBusDisplayConsole {
DisplayChangeListener dcl;
DBusDisplay *display;
- GHashTable *listeners;
+ GPtrArray *listeners;
QemuDBusDisplay1Console *iface;
QemuDBusDisplay1Keyboard *iface_kbd;
@@ -142,8 +142,7 @@ dbus_display_console_init(DBusDisplayConsole *object)
{
DBusDisplayConsole *ddc = DBUS_DISPLAY_CONSOLE(object);
- ddc->listeners = g_hash_table_new_full(g_str_hash, g_str_equal,
- NULL, g_object_unref);
+ ddc->listeners = g_ptr_array_new_with_free_func(g_object_unref);
ddc->dcl.ops = &dbus_console_dcl_ops;
}
@@ -157,7 +156,7 @@ dbus_display_console_dispose(GObject *object)
g_clear_object(&ddc->iface_mouse);
g_clear_object(&ddc->iface_kbd);
g_clear_object(&ddc->iface);
- g_clear_pointer(&ddc->listeners, g_hash_table_unref);
+ g_clear_pointer(&ddc->listeners, g_ptr_array_unref);
g_clear_pointer(&ddc->kbd, qkbd_state_free);
G_OBJECT_CLASS(dbus_display_console_parent_class)->dispose(object);
@@ -179,7 +178,7 @@ listener_vanished_cb(DBusDisplayListener *listener)
trace_dbus_listener_vanished(name);
- g_hash_table_remove(ddc->listeners, name);
+ g_ptr_array_remove_fast(ddc->listeners, listener);
qkbd_state_lift_all_keys(ddc->kbd);
}
@@ -267,16 +266,6 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
DBusDisplayListener *listener;
int fd;
- if (sender && g_hash_table_contains(ddc->listeners, sender)) {
- g_dbus_method_invocation_return_error(
- invocation,
- DBUS_DISPLAY_ERROR,
- DBUS_DISPLAY_ERROR_INVALID,
- "`%s` is already registered!",
- sender);
- return DBUS_METHOD_INVOCATION_HANDLED;
- }
-
#ifdef G_OS_WIN32
if (!dbus_win32_import_socket(invocation, arg_listener, &fd)) {
return DBUS_METHOD_INVOCATION_HANDLED;
@@ -331,9 +320,7 @@ dbus_console_register_listener(DBusDisplayConsole *ddc,
return DBUS_METHOD_INVOCATION_HANDLED;
}
- g_hash_table_insert(ddc->listeners,
- (gpointer)dbus_display_listener_get_bus_name(listener),
- listener);
+ g_ptr_array_add(ddc->listeners, listener);
g_object_connect(listener_conn,
"swapped-signal::closed", listener_vanished_cb, listener,
NULL);
diff --git a/ui/dbus-display1.xml b/ui/dbus-display1.xml
index ce35d64..e70f284 100644
--- a/ui/dbus-display1.xml
+++ b/ui/dbus-display1.xml
@@ -470,12 +470,60 @@
</interface>
<!--
+ org.qemu.Display1.Listener.Unix.Map:
+
+ This optional client-side interface can complement
+ org.qemu.Display1.Listener on ``/org/qemu/Display1/Listener`` for
+ Unix-specific shared memory scanouts.
+ -->
+ <?if $(env.HOST_OS) != windows?>
+ <interface name="org.qemu.Display1.Listener.Unix.Map">
+ <!--
+ ScanoutMap:
+ @handle: the shared map FD.
+ @offset: mapping offset, in bytes.
+ @width: display width, in pixels.
+ @height: display height, in pixels.
+ @stride: stride, in bytes.
+ @pixman_format: image format (ex: ``PIXMAN_X8R8G8B8``).
+
+ Resize and update the display content with a shared map.
+ -->
+ <method name="ScanoutMap">
+ <arg type="h" name="handle" direction="in"/>
+ <arg type="u" name="offset" direction="in"/>
+ <arg type="u" name="width" direction="in"/>
+ <arg type="u" name="height" direction="in"/>
+ <arg type="u" name="stride" direction="in"/>
+ <arg type="u" name="pixman_format" direction="in"/>
+ </method>
+
+ <!--
+ UpdateMap:
+ @x: the X update position, in pixels.
+ @y: the Y update position, in pixels.
+ @width: the update width, in pixels.
+ @height: the update height, in pixels.
+
+ Update the display content with the current shared map and the given region.
+ -->
+ <method name="UpdateMap">
+ <arg type="i" name="x" direction="in"/>
+ <arg type="i" name="y" direction="in"/>
+ <arg type="i" name="width" direction="in"/>
+ <arg type="i" name="height" direction="in"/>
+ </method>
+ </interface>
+ <?endif?>
+
+ <!--
org.qemu.Display1.Listener.Win32.Map:
This optional client-side interface can complement
org.qemu.Display1.Listener on ``/org/qemu/Display1/Listener`` for Windows
specific shared memory scanouts.
-->
+ <?if $(env.HOST_OS) == windows?>
<interface name="org.qemu.Display1.Listener.Win32.Map">
<!--
ScanoutMap:
@@ -513,6 +561,7 @@
<arg type="i" name="height" direction="in"/>
</method>
</interface>
+ <?endif?>
<!--
org.qemu.Display1.Listener.Win32.D3d11:
diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c
index a54123a..99738e7 100644
--- a/ui/dbus-listener.c
+++ b/ui/dbus-listener.c
@@ -26,6 +26,7 @@
#include "qapi/error.h"
#include "sysemu/sysemu.h"
#include "dbus.h"
+#include "glib.h"
#ifdef G_OS_UNIX
#include <gio/gunixfdlist.h>
#endif
@@ -82,10 +83,13 @@ struct _DBusDisplayListener {
#ifdef CONFIG_OPENGL
egl_fb fb;
#endif
+#else /* !WIN32 */
+ QemuDBusDisplay1ListenerUnixMap *map_proxy;
#endif
guint dbus_filter;
- guint32 out_serial_to_discard;
+ guint32 display_serial_to_discard;
+ guint32 cursor_serial_to_discard;
};
G_DEFINE_TYPE(DBusDisplayListener, dbus_display_listener, G_TYPE_OBJECT)
@@ -93,10 +97,20 @@ G_DEFINE_TYPE(DBusDisplayListener, dbus_display_listener, G_TYPE_OBJECT)
static void dbus_gfx_update(DisplayChangeListener *dcl,
int x, int y, int w, int h);
-static void ddl_discard_pending_messages(DBusDisplayListener *ddl)
+static void ddl_discard_display_messages(DBusDisplayListener *ddl)
{
- ddl->out_serial_to_discard = g_dbus_connection_get_last_serial(
+ guint32 serial = g_dbus_connection_get_last_serial(
g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl->proxy)));
+
+ g_atomic_int_set(&ddl->display_serial_to_discard, serial);
+}
+
+static void ddl_discard_cursor_messages(DBusDisplayListener *ddl)
+{
+ guint32 serial = g_dbus_connection_get_last_serial(
+ g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl->proxy)));
+
+ g_atomic_int_set(&ddl->cursor_serial_to_discard, serial);
}
#ifdef CONFIG_OPENGL
@@ -104,6 +118,8 @@ static void dbus_scanout_disable(DisplayChangeListener *dcl)
{
DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
+ ddl_discard_display_messages(ddl);
+
qemu_dbus_display1_listener_call_disable(
ddl->proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
}
@@ -290,7 +306,7 @@ static void dbus_scanout_dmabuf(DisplayChangeListener *dcl,
return;
}
- ddl_discard_pending_messages(ddl);
+ ddl_discard_display_messages(ddl);
width = qemu_dmabuf_get_width(dmabuf);
height = qemu_dmabuf_get_height(dmabuf);
@@ -320,13 +336,13 @@ static bool dbus_scanout_map(DBusDisplayListener *ddl)
return true;
}
- if (!ddl->can_share_map || !ddl->ds->handle) {
+ if (!ddl->can_share_map || !ddl->ds->share_handle) {
return false;
}
success = DuplicateHandle(
GetCurrentProcess(),
- ddl->ds->handle,
+ ddl->ds->share_handle,
ddl->peer_process,
&target_handle,
FILE_MAP_READ | SECTION_QUERY,
@@ -338,12 +354,12 @@ static bool dbus_scanout_map(DBusDisplayListener *ddl)
return false;
}
- ddl_discard_pending_messages(ddl);
+ ddl_discard_display_messages(ddl);
if (!qemu_dbus_display1_listener_win32_map_call_scanout_map_sync(
ddl->map_proxy,
GPOINTER_TO_UINT(target_handle),
- ddl->ds->handle_offset,
+ ddl->ds->share_handle_offset,
surface_width(ddl->ds),
surface_height(ddl->ds),
surface_stride(ddl->ds),
@@ -401,7 +417,7 @@ dbus_scanout_share_d3d_texture(
return false;
}
- ddl_discard_pending_messages(ddl);
+ ddl_discard_display_messages(ddl);
qemu_dbus_display1_listener_win32_d3d11_call_scanout_texture2d(
ddl->d3d11_proxy,
@@ -427,6 +443,51 @@ dbus_scanout_share_d3d_texture(
return true;
}
#endif /* CONFIG_OPENGL */
+#else /* !WIN32 */
+static bool dbus_scanout_map(DBusDisplayListener *ddl)
+{
+ g_autoptr(GError) err = NULL;
+ g_autoptr(GUnixFDList) fd_list = NULL;
+
+ if (ddl->ds_share == SHARE_KIND_MAPPED) {
+ return true;
+ }
+
+ if (!ddl->can_share_map || ddl->ds->share_handle == SHAREABLE_NONE) {
+ return false;
+ }
+
+ ddl_discard_display_messages(ddl);
+ fd_list = g_unix_fd_list_new();
+ if (g_unix_fd_list_append(fd_list, ddl->ds->share_handle, &err) != 0) {
+ g_debug("Failed to setup scanout map fdlist: %s", err->message);
+ ddl->can_share_map = false;
+ return false;
+ }
+
+ if (!qemu_dbus_display1_listener_unix_map_call_scanout_map_sync(
+ ddl->map_proxy,
+ g_variant_new_handle(0),
+ ddl->ds->share_handle_offset,
+ surface_width(ddl->ds),
+ surface_height(ddl->ds),
+ surface_stride(ddl->ds),
+ surface_format(ddl->ds),
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_DEFAULT_TIMEOUT,
+ fd_list,
+ NULL,
+ NULL,
+ &err)) {
+ g_debug("Failed to call ScanoutMap: %s", err->message);
+ ddl->can_share_map = false;
+ return false;
+ }
+
+ ddl->ds_share = SHARE_KIND_MAPPED;
+
+ return true;
+}
#endif /* WIN32 */
#ifdef CONFIG_OPENGL
@@ -497,6 +558,8 @@ static void dbus_cursor_dmabuf(DisplayChangeListener *dcl,
return;
}
+ ddl_discard_cursor_messages(ddl);
+
egl_dmabuf_import_texture(dmabuf);
texture = qemu_dmabuf_get_texture(dmabuf);
if (!texture) {
@@ -659,7 +722,7 @@ static void ddl_scanout(DBusDisplayListener *ddl)
surface_stride(ddl->ds) * surface_height(ddl->ds), TRUE,
(GDestroyNotify)pixman_image_unref, pixman_image_ref(ddl->ds->image));
- ddl_discard_pending_messages(ddl);
+ ddl_discard_display_messages(ddl);
qemu_dbus_display1_listener_call_scanout(
ddl->proxy, surface_width(ddl->ds), surface_height(ddl->ds),
@@ -677,16 +740,22 @@ static void dbus_gfx_update(DisplayChangeListener *dcl,
trace_dbus_update(x, y, w, h);
-#ifdef WIN32
if (dbus_scanout_map(ddl)) {
+#ifdef WIN32
qemu_dbus_display1_listener_win32_map_call_update_map(
ddl->map_proxy,
x, y, w, h,
G_DBUS_CALL_FLAGS_NONE,
DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL);
+#else
+ qemu_dbus_display1_listener_unix_map_call_update_map(
+ ddl->map_proxy,
+ x, y, w, h,
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL);
+#endif
return;
}
-#endif
if (x == 0 && y == 0 && w == surface_width(ddl->ds) && h == surface_height(ddl->ds)) {
return ddl_scanout(ddl);
@@ -740,6 +809,8 @@ static void dbus_cursor_define(DisplayChangeListener *dcl,
DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
GVariant *v_data = NULL;
+ ddl_discard_cursor_messages(ddl);
+
v_data = g_variant_new_from_data(
G_VARIANT_TYPE("ay"),
c->data,
@@ -861,7 +932,6 @@ dbus_display_listener_get_console(DBusDisplayListener *ddl)
return ddl->console;
}
-#ifdef WIN32
static bool
dbus_display_listener_implements(DBusDisplayListener *ddl, const char *iface)
{
@@ -876,6 +946,7 @@ dbus_display_listener_implements(DBusDisplayListener *ddl, const char *iface)
return implements;
}
+#ifdef WIN32
static bool
dbus_display_listener_setup_peer_process(DBusDisplayListener *ddl)
{
@@ -958,10 +1029,11 @@ dbus_display_listener_setup_d3d11(DBusDisplayListener *ddl)
static void
dbus_display_listener_setup_shared_map(DBusDisplayListener *ddl)
{
-#ifdef WIN32
g_autoptr(GError) err = NULL;
- if (!dbus_display_listener_implements(ddl, "org.qemu.Display1.Listener.Win32.Map")) {
+#ifdef WIN32
+ if (!dbus_display_listener_implements(
+ ddl, "org.qemu.Display1.Listener.Win32.Map")) {
return;
}
@@ -982,6 +1054,20 @@ dbus_display_listener_setup_shared_map(DBusDisplayListener *ddl)
}
ddl->can_share_map = true;
+#else /* !WIN32 */
+ if (!dbus_display_listener_implements(
+ ddl, "org.qemu.Display1.Listener.Unix.Map")) {
+ return;
+ }
+ ddl->map_proxy = qemu_dbus_display1_listener_unix_map_proxy_new_sync(
+ ddl->conn, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL,
+ "/org/qemu/Display1/Listener", NULL, &err);
+ if (!ddl->map_proxy) {
+ g_debug("Failed to setup Unix map proxy: %s", err->message);
+ return;
+ }
+
+ ddl->can_share_map = true;
#endif
}
@@ -992,16 +1078,50 @@ dbus_filter(GDBusConnection *connection,
gpointer user_data)
{
DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(user_data);
- guint32 serial;
+ guint32 serial, discard_serial;
if (incoming) {
return message;
}
serial = g_dbus_message_get_serial(message);
- if (serial <= ddl->out_serial_to_discard) {
- trace_dbus_filter(serial, ddl->out_serial_to_discard);
- return NULL;
+
+ discard_serial = g_atomic_int_get(&ddl->display_serial_to_discard);
+ if (serial <= discard_serial) {
+ const char *member = g_dbus_message_get_member(message);
+ static const char *const display_messages[] = {
+ "Scanout",
+ "Update",
+#ifdef CONFIG_GBM
+ "ScanoutDMABUF",
+ "UpdateDMABUF",
+#endif
+ "ScanoutMap",
+ "UpdateMap",
+ "Disable",
+ NULL,
+ };
+
+ if (g_strv_contains(display_messages, member)) {
+ trace_dbus_filter(serial, discard_serial);
+ g_object_unref(message);
+ return NULL;
+ }
+ }
+
+ discard_serial = g_atomic_int_get(&ddl->cursor_serial_to_discard);
+ if (serial <= discard_serial) {
+ const gchar *member = g_dbus_message_get_member(message);
+ static const char *const cursor_messages[] = {
+ "CursorDefine",
+ NULL
+ };
+
+ if (g_strv_contains(cursor_messages, member)) {
+ trace_dbus_filter(serial, discard_serial);
+ g_object_unref(message);
+ return NULL;
+ }
}
return message;
@@ -1037,6 +1157,7 @@ dbus_display_listener_new(const char *bus_name,
ddl->console = console;
dbus_display_listener_setup_shared_map(ddl);
+ trace_dbus_can_share_map(ddl->can_share_map);
dbus_display_listener_setup_d3d11(ddl);
con = qemu_console_lookup_by_index(dbus_display_console_get_index(console));
diff --git a/ui/dbus.c b/ui/dbus.c
index e08b5de..7ecd39e 100644
--- a/ui/dbus.c
+++ b/ui/dbus.c
@@ -176,7 +176,7 @@ dbus_display_add_console(DBusDisplay *dd, int idx, Error **errp)
assert(con);
if (qemu_console_is_graphic(con) &&
- dd->gl_mode != DISPLAYGL_MODE_OFF) {
+ dd->gl_mode != DISPLAY_GL_MODE_OFF) {
qemu_console_set_display_gl_ctx(con, &dd->glctx);
}
@@ -466,9 +466,9 @@ static const TypeInfo dbus_vc_type_info = {
static void
early_dbus_init(DisplayOptions *opts)
{
- DisplayGLMode mode = opts->has_gl ? opts->gl : DISPLAYGL_MODE_OFF;
+ DisplayGLMode mode = opts->has_gl ? opts->gl : DISPLAY_GL_MODE_OFF;
- if (mode != DISPLAYGL_MODE_OFF) {
+ if (mode != DISPLAY_GL_MODE_OFF) {
#ifdef CONFIG_OPENGL
egl_init(opts->u.dbus.rendernode, mode, &error_fatal);
#else
@@ -482,7 +482,7 @@ early_dbus_init(DisplayOptions *opts)
static void
dbus_init(DisplayState *ds, DisplayOptions *opts)
{
- DisplayGLMode mode = opts->has_gl ? opts->gl : DISPLAYGL_MODE_OFF;
+ DisplayGLMode mode = opts->has_gl ? opts->gl : DISPLAY_GL_MODE_OFF;
if (opts->u.dbus.addr && opts->u.dbus.p2p) {
error_report("dbus: can't accept both addr=X and p2p=yes options");
diff --git a/ui/egl-context.c b/ui/egl-context.c
index 9e0df46..aed3e3b 100644
--- a/ui/egl-context.c
+++ b/ui/egl-context.c
@@ -17,7 +17,7 @@ QEMUGLContext qemu_egl_create_context(DisplayGLCtx *dgc,
EGL_CONTEXT_MINOR_VERSION_KHR, params->minor_ver,
EGL_NONE
};
- bool gles = (qemu_egl_mode == DISPLAYGL_MODE_ES);
+ bool gles = (qemu_egl_mode == DISPLAY_GL_MODE_ES);
ctx = eglCreateContext(qemu_egl_display, qemu_egl_config,
eglGetCurrentContext(),
diff --git a/ui/egl-headless.c b/ui/egl-headless.c
index 6187249..1f6b845 100644
--- a/ui/egl-headless.c
+++ b/ui/egl-headless.c
@@ -207,7 +207,7 @@ static const DisplayGLCtxOps eglctx_ops = {
static void early_egl_headless_init(DisplayOptions *opts)
{
- DisplayGLMode mode = DISPLAYGL_MODE_ON;
+ DisplayGLMode mode = DISPLAY_GL_MODE_ON;
if (opts->has_gl) {
mode = opts->gl;
diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c
index 99b2ebbe..81a57fa 100644
--- a/ui/egl-helpers.c
+++ b/ui/egl-helpers.c
@@ -503,7 +503,7 @@ static int qemu_egl_init_dpy(EGLNativeDisplayType dpy,
EGLint major, minor;
EGLBoolean b;
EGLint n;
- bool gles = (mode == DISPLAYGL_MODE_ES);
+ bool gles = (mode == DISPLAY_GL_MODE_ES);
qemu_egl_display = qemu_egl_get_display(dpy, platform);
if (qemu_egl_display == EGL_NO_DISPLAY) {
@@ -533,7 +533,7 @@ static int qemu_egl_init_dpy(EGLNativeDisplayType dpy,
return -1;
}
- qemu_egl_mode = gles ? DISPLAYGL_MODE_ES : DISPLAYGL_MODE_CORE;
+ qemu_egl_mode = gles ? DISPLAY_GL_MODE_ES : DISPLAY_GL_MODE_CORE;
return 0;
}
@@ -564,8 +564,8 @@ int qemu_egl_init_dpy_mesa(EGLNativeDisplayType dpy, DisplayGLMode mode)
int qemu_egl_init_dpy_win32(EGLNativeDisplayType dpy, DisplayGLMode mode)
{
/* prefer GL ES, as that's what ANGLE supports */
- if (mode == DISPLAYGL_MODE_ON) {
- mode = DISPLAYGL_MODE_ES;
+ if (mode == DISPLAY_GL_MODE_ON) {
+ mode = DISPLAY_GL_MODE_ES;
}
if (qemu_egl_init_dpy(dpy, 0, mode) < 0) {
@@ -618,7 +618,7 @@ EGLContext qemu_egl_init_ctx(void)
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
- bool gles = (qemu_egl_mode == DISPLAYGL_MODE_ES);
+ bool gles = (qemu_egl_mode == DISPLAY_GL_MODE_ES);
EGLContext ectx;
EGLBoolean b;
@@ -642,7 +642,7 @@ bool egl_init(const char *rendernode, DisplayGLMode mode, Error **errp)
{
ERRP_GUARD();
- if (mode == DISPLAYGL_MODE_OFF) {
+ if (mode == DISPLAY_GL_MODE_OFF) {
error_setg(errp, "egl: turning off GL doesn't make sense");
return false;
}
diff --git a/ui/gtk.c b/ui/gtk.c
index bc29f7a..bf9d3dd 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -1820,7 +1820,7 @@ static void gd_vc_send_chars(VirtualConsole *vc)
const uint8_t *buf;
uint32_t size;
- buf = fifo8_pop_buf(&vc->vte.out_fifo, MIN(len, avail), &size);
+ buf = fifo8_pop_bufptr(&vc->vte.out_fifo, MIN(len, avail), &size);
qemu_chr_be_write(vc->vte.chr, buf, size);
len = qemu_chr_be_can_write(vc->vte.chr);
avail -= size;
@@ -2514,7 +2514,7 @@ static void early_gtk_display_init(DisplayOptions *opts)
}
assert(opts->type == DISPLAY_TYPE_GTK);
- if (opts->has_gl && opts->gl != DISPLAYGL_MODE_OFF) {
+ if (opts->has_gl && opts->gl != DISPLAY_GL_MODE_OFF) {
#if defined(CONFIG_OPENGL)
#if defined(GDK_WINDOWING_WAYLAND)
if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default())) {
@@ -2530,7 +2530,7 @@ static void early_gtk_display_init(DisplayOptions *opts)
#endif
{
#ifdef CONFIG_X11
- DisplayGLMode mode = opts->has_gl ? opts->gl : DISPLAYGL_MODE_ON;
+ DisplayGLMode mode = opts->has_gl ? opts->gl : DISPLAY_GL_MODE_ON;
gtk_egl_init(mode);
#endif
}
diff --git a/ui/input.c b/ui/input.c
index dc74586..7ddefebc 100644
--- a/ui/input.c
+++ b/ui/input.c
@@ -174,37 +174,6 @@ void qmp_input_send_event(const char *device,
qemu_input_event_sync();
}
-static int qemu_input_transform_invert_abs_value(int value)
-{
- return (int64_t)INPUT_EVENT_ABS_MAX - value + INPUT_EVENT_ABS_MIN;
-}
-
-static void qemu_input_transform_abs_rotate(InputEvent *evt)
-{
- InputMoveEvent *move = evt->u.abs.data;
- switch (graphic_rotate) {
- case 90:
- if (move->axis == INPUT_AXIS_X) {
- move->axis = INPUT_AXIS_Y;
- } else if (move->axis == INPUT_AXIS_Y) {
- move->axis = INPUT_AXIS_X;
- move->value = qemu_input_transform_invert_abs_value(move->value);
- }
- break;
- case 180:
- move->value = qemu_input_transform_invert_abs_value(move->value);
- break;
- case 270:
- if (move->axis == INPUT_AXIS_X) {
- move->axis = INPUT_AXIS_Y;
- move->value = qemu_input_transform_invert_abs_value(move->value);
- } else if (move->axis == INPUT_AXIS_Y) {
- move->axis = INPUT_AXIS_X;
- }
- break;
- }
-}
-
static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
{
const char *name;
@@ -340,11 +309,6 @@ void qemu_input_event_send_impl(QemuConsole *src, InputEvent *evt)
qemu_input_event_trace(src, evt);
- /* pre processing */
- if (graphic_rotate && (evt->type == INPUT_EVENT_KIND_ABS)) {
- qemu_input_transform_abs_rotate(evt);
- }
-
/* send event */
s = qemu_input_find_handler(1 << evt->type, src);
if (!s) {
diff --git a/ui/qemu-pixman.c b/ui/qemu-pixman.c
index 5ca55dd..6ef4376 100644
--- a/ui/qemu-pixman.c
+++ b/ui/qemu-pixman.c
@@ -4,7 +4,9 @@
*/
#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "ui/console.h"
+#include "qemu/memfd.h"
#include "standard-headers/drm/drm_fourcc.h"
#include "trace.h"
@@ -49,7 +51,6 @@ PixelFormat qemu_pixelformat_from_pixman(pixman_format_code_t format)
break;
default:
g_assert_not_reached();
- break;
}
pf.amax = (1 << pf.abits) - 1;
@@ -268,3 +269,72 @@ void qemu_pixman_glyph_render(pixman_image_t *glyph,
pixman_image_unref(ibg);
}
#endif /* CONFIG_PIXMAN */
+
+static void *
+qemu_pixman_shareable_alloc(const char *name, size_t size,
+ qemu_pixman_shareable *handle,
+ Error **errp)
+{
+#ifdef WIN32
+ return qemu_win32_map_alloc(size, handle, errp);
+#else
+ return qemu_memfd_alloc(name, size, 0, handle, errp);
+#endif
+}
+
+static void
+qemu_pixman_shareable_free(qemu_pixman_shareable handle,
+ void *ptr, size_t size)
+{
+#ifdef WIN32
+ qemu_win32_map_free(ptr, handle, &error_warn);
+#else
+ qemu_memfd_free(ptr, size, handle);
+#endif
+}
+
+static void
+qemu_pixman_shared_image_destroy(pixman_image_t *image, void *data)
+{
+ qemu_pixman_shareable handle = PTR_TO_SHAREABLE(data);
+ void *ptr = pixman_image_get_data(image);
+ size_t size = pixman_image_get_height(image) * pixman_image_get_stride(image);
+
+ qemu_pixman_shareable_free(handle, ptr, size);
+}
+
+bool
+qemu_pixman_image_new_shareable(pixman_image_t **image,
+ qemu_pixman_shareable *handle,
+ const char *name,
+ pixman_format_code_t format,
+ int width,
+ int height,
+ int rowstride_bytes,
+ Error **errp)
+{
+ ERRP_GUARD();
+ size_t size = height * rowstride_bytes;
+ void *bits = NULL;
+
+ g_return_val_if_fail(image != NULL, false);
+ g_return_val_if_fail(handle != NULL, false);
+
+ bits = qemu_pixman_shareable_alloc(name, size, handle, errp);
+ if (!bits) {
+ return false;
+ }
+
+ *image = pixman_image_create_bits(format, width, height, bits, rowstride_bytes);
+ if (!*image) {
+ error_setg(errp, "Failed to allocate image");
+ qemu_pixman_shareable_free(*handle, bits, size);
+ return false;
+ }
+
+ pixman_image_set_destroy_function(*image,
+ qemu_pixman_shared_image_destroy,
+ SHAREABLE_TO_PTR(*handle));
+
+ return true;
+}
diff --git a/ui/sdl2-gl.c b/ui/sdl2-gl.c
index 91b7ee2..e01d9ab 100644
--- a/ui/sdl2-gl.c
+++ b/ui/sdl2-gl.c
@@ -147,11 +147,11 @@ QEMUGLContext sdl2_gl_create_context(DisplayGLCtx *dgc,
SDL_GL_MakeCurrent(scon->real_window, scon->winctx);
SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
- if (scon->opts->gl == DISPLAYGL_MODE_ON ||
- scon->opts->gl == DISPLAYGL_MODE_CORE) {
+ if (scon->opts->gl == DISPLAY_GL_MODE_ON ||
+ scon->opts->gl == DISPLAY_GL_MODE_CORE) {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
SDL_GL_CONTEXT_PROFILE_CORE);
- } else if (scon->opts->gl == DISPLAYGL_MODE_ES) {
+ } else if (scon->opts->gl == DISPLAY_GL_MODE_ES) {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
SDL_GL_CONTEXT_PROFILE_ES);
}
@@ -163,7 +163,7 @@ QEMUGLContext sdl2_gl_create_context(DisplayGLCtx *dgc,
/* If SDL fail to create a GL context and we use the "on" flag,
* then try to fallback to GLES.
*/
- if (!ctx && scon->opts->gl == DISPLAYGL_MODE_ON) {
+ if (!ctx && scon->opts->gl == DISPLAY_GL_MODE_ON) {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
SDL_GL_CONTEXT_PROFILE_ES);
ctx = SDL_GL_CreateContext(scon->real_window);
diff --git a/ui/sdl2-input.c b/ui/sdl2-input.c
index b02a89e..2286df4 100644
--- a/ui/sdl2-input.c
+++ b/ui/sdl2-input.c
@@ -58,3 +58,8 @@ void sdl2_process_key(struct sdl2_console *scon,
}
}
}
+
+void sdl2_release_modifiers(struct sdl2_console *scon)
+{
+ qkbd_state_lift_all_keys(scon->kbd);
+}
diff --git a/ui/sdl2.c b/ui/sdl2.c
index 98ed974..bd4f5a9 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -107,7 +107,7 @@ void sdl2_window_create(struct sdl2_console *scon)
if (scon->opengl) {
const char *driver = "opengl";
- if (scon->opts->gl == DISPLAYGL_MODE_ES) {
+ if (scon->opts->gl == DISPLAY_GL_MODE_ES) {
driver = "opengles2";
}
@@ -115,6 +115,7 @@ void sdl2_window_create(struct sdl2_console *scon)
SDL_SetHint(SDL_HINT_RENDER_BATCHING, "1");
scon->winctx = SDL_GL_CreateContext(scon->real_window);
+ SDL_GL_SetSwapInterval(0);
} else {
/* The SDL renderer is only used by sdl2-2D, when OpenGL is disabled */
scon->real_renderer = SDL_CreateRenderer(scon->real_window, -1, 0);
@@ -388,12 +389,13 @@ static void handle_keydown(SDL_Event *ev)
int win;
struct sdl2_console *scon = get_scon_from_window(ev->key.windowID);
int gui_key_modifier_pressed = get_mod_state();
- int gui_keysym = 0;
if (!scon) {
return;
}
+ scon->gui_keysym = false;
+
if (!scon->ignore_hotkeys && gui_key_modifier_pressed && !ev->key.repeat) {
switch (ev->key.keysym.scancode) {
case SDL_SCANCODE_2:
@@ -418,15 +420,16 @@ static void handle_keydown(SDL_Event *ev)
SDL_ShowWindow(sdl2_console[win].real_window);
}
}
- gui_keysym = 1;
+ sdl2_release_modifiers(scon);
+ scon->gui_keysym = true;
}
break;
case SDL_SCANCODE_F:
toggle_full_screen(scon);
- gui_keysym = 1;
+ scon->gui_keysym = true;
break;
case SDL_SCANCODE_G:
- gui_keysym = 1;
+ scon->gui_keysym = true;
if (!gui_grab) {
sdl_grab_start(scon);
} else if (!gui_fullscreen) {
@@ -439,7 +442,7 @@ static void handle_keydown(SDL_Event *ev)
/* re-create scon->texture */
sdl2_2d_switch(&scon->dcl, scon->surface);
}
- gui_keysym = 1;
+ scon->gui_keysym = true;
break;
#if 0
case SDL_SCANCODE_KP_PLUS:
@@ -458,14 +461,14 @@ static void handle_keydown(SDL_Event *ev)
__func__, width, height);
sdl_scale(scon, width, height);
sdl2_redraw(scon);
- gui_keysym = 1;
+ scon->gui_keysym = true;
}
#endif
default:
break;
}
}
- if (!gui_keysym) {
+ if (!scon->gui_keysym) {
sdl2_process_key(scon, &ev->key);
}
}
@@ -491,7 +494,7 @@ static void handle_textinput(SDL_Event *ev)
return;
}
- if (QEMU_IS_TEXT_CONSOLE(con)) {
+ if (!scon->gui_keysym && QEMU_IS_TEXT_CONSOLE(con)) {
qemu_text_console_put_string(QEMU_TEXT_CONSOLE(con), ev->text.text, strlen(ev->text.text));
}
}
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 15be640..bd9dbe0 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -840,7 +840,7 @@ static void qemu_spice_init(void)
"incompatible with -spice port/tls-port");
exit(1);
}
- egl_init(qemu_opt_get(opts, "rendernode"), DISPLAYGL_MODE_ON, &error_fatal);
+ egl_init(qemu_opt_get(opts, "rendernode"), DISPLAY_GL_MODE_ON, &error_fatal);
spice_opengl = 1;
}
#endif
diff --git a/ui/trace-events b/ui/trace-events
index 69ff229..3da0d5e 100644
--- a/ui/trace-events
+++ b/ui/trace-events
@@ -130,9 +130,10 @@ xkeymap_keymap(const char *name) "keymap '%s'"
# clipboard.c
clipboard_check_serial(int cur, int recv, bool ok) "cur:%d recv:%d %d"
+clipboard_reset_serial(void) ""
# vdagent.c
-vdagent_open(void) ""
+vdagent_fe_open(bool fe_open) "fe_open=%d"
vdagent_close(void) ""
vdagent_disconnect(void) ""
vdagent_send(const char *name) "msg %s"
@@ -157,12 +158,15 @@ dbus_mouse_rel_motion(int dx, int dy) "dx=%d, dy=%d"
dbus_touch_send_event(unsigned int kind, uint32_t num_slot, uint32_t x, uint32_t y) "kind=%u, num_slot=%u, x=%d, y=%d"
dbus_update(int x, int y, int w, int h) "x=%d, y=%d, w=%d, h=%d"
dbus_update_gl(int x, int y, int w, int h) "x=%d, y=%d, w=%d, h=%d"
+dbus_clipboard_grab(int selection, unsigned int serial) "selection=%d serial=%u"
dbus_clipboard_grab_failed(void) ""
+dbus_clipboard_qemu_request(int type) "type=%d"
dbus_clipboard_register(const char *bus_name) "peer %s"
dbus_clipboard_unregister(const char *bus_name) "peer %s"
dbus_scanout_texture(uint32_t tex_id, bool backing_y_0_top, uint32_t backing_width, uint32_t backing_height, uint32_t x, uint32_t y, uint32_t w, uint32_t h) "tex_id:%u y0top:%d back:%ux%u %u+%u-%ux%u"
dbus_gl_gfx_switch(void *p) "surf: %p"
dbus_filter(unsigned int serial, unsigned int filter) "serial=%u (<= %u)"
+dbus_can_share_map(bool share) "can_share_map: %d"
# egl-helpers.c
egl_init_d3d11_device(void *p) "d3d device: %p"
diff --git a/ui/vdagent.c b/ui/vdagent.c
index 64d7ab2..724eff9 100644
--- a/ui/vdagent.c
+++ b/ui/vdagent.c
@@ -185,7 +185,7 @@ static void vdagent_send_msg(VDAgentChardev *vd, VDAgentMessage *msg)
vdagent_send_buf(vd);
}
-static void vdagent_send_caps(VDAgentChardev *vd)
+static void vdagent_send_caps(VDAgentChardev *vd, bool request)
{
g_autofree VDAgentMessage *msg = g_malloc0(sizeof(VDAgentMessage) +
sizeof(VDAgentAnnounceCapabilities) +
@@ -205,6 +205,7 @@ static void vdagent_send_caps(VDAgentChardev *vd)
#endif
}
+ caps->request = request;
vdagent_send_msg(vd, msg);
}
@@ -711,7 +712,7 @@ static void vdagent_chr_recv_caps(VDAgentChardev *vd, VDAgentMessage *msg)
vd->caps = caps->caps[0];
if (caps->request) {
- vdagent_send_caps(vd);
+ vdagent_send_caps(vd, false);
}
if (have_mouse(vd) && vd->mouse_hs) {
qemu_input_handler_activate(vd->mouse_hs);
@@ -720,6 +721,8 @@ static void vdagent_chr_recv_caps(VDAgentChardev *vd, VDAgentMessage *msg)
memset(vd->last_serial, 0, sizeof(vd->last_serial));
if (have_clipboard(vd) && vd->cbpeer.notifier.notify == NULL) {
+ qemu_clipboard_reset_serial();
+
vd->cbpeer.name = "vdagent";
vd->cbpeer.notifier.notify = vdagent_clipboard_notify;
vd->cbpeer.request = vdagent_clipboard_request;
@@ -872,6 +875,8 @@ static void vdagent_chr_set_fe_open(struct Chardev *chr, int fe_open)
{
VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(chr);
+ trace_vdagent_fe_open(fe_open);
+
if (!fe_open) {
trace_vdagent_close();
vdagent_disconnect(vd);
@@ -881,7 +886,7 @@ static void vdagent_chr_set_fe_open(struct Chardev *chr, int fe_open)
return;
}
- trace_vdagent_open();
+ vdagent_send_caps(vd, true);
}
static void vdagent_chr_parse(QemuOpts *opts, ChardevBackend *backend,
diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c
index 47fdae5..3f4cfc4 100644
--- a/ui/vnc-auth-sasl.c
+++ b/ui/vnc-auth-sasl.c
@@ -263,8 +263,14 @@ static int protocol_client_auth_sasl_step(VncState *vs, uint8_t *data, size_t le
/* NB, distinction of NULL vs "" is *critical* in SASL */
if (datalen) {
clientdata = (char*)data;
- clientdata[datalen-1] = '\0'; /* Wire includes '\0', but make sure */
- datalen--; /* Don't count NULL byte when passing to _start() */
+ if (clientdata[datalen - 1] != '\0') {
+ trace_vnc_auth_fail(vs, vs->auth, "Malformed SASL client data",
+ "Missing SASL NUL padding byte");
+ sasl_dispose(&vs->sasl.conn);
+ vs->sasl.conn = NULL;
+ goto authabort;
+ }
+ datalen--; /* Discard the extra NUL padding byte */
}
err = sasl_server_step(vs->sasl.conn,
@@ -289,9 +295,10 @@ static int protocol_client_auth_sasl_step(VncState *vs, uint8_t *data, size_t le
goto authabort;
}
- if (serveroutlen) {
+ if (serverout) {
vnc_write_u32(vs, serveroutlen + 1);
- vnc_write(vs, serverout, serveroutlen + 1);
+ vnc_write(vs, serverout, serveroutlen);
+ vnc_write_u8(vs, '\0');
} else {
vnc_write_u32(vs, 0);
}
@@ -384,8 +391,14 @@ static int protocol_client_auth_sasl_start(VncState *vs, uint8_t *data, size_t l
/* NB, distinction of NULL vs "" is *critical* in SASL */
if (datalen) {
clientdata = (char*)data;
- clientdata[datalen-1] = '\0'; /* Should be on wire, but make sure */
- datalen--; /* Don't count NULL byte when passing to _start() */
+ if (clientdata[datalen - 1] != '\0') {
+ trace_vnc_auth_fail(vs, vs->auth, "Malformed SASL client data",
+ "Missing SASL NUL padding byte");
+ sasl_dispose(&vs->sasl.conn);
+ vs->sasl.conn = NULL;
+ goto authabort;
+ }
+ datalen--; /* Discard the extra NUL padding byte */
}
err = sasl_server_start(vs->sasl.conn,
@@ -410,9 +423,10 @@ static int protocol_client_auth_sasl_start(VncState *vs, uint8_t *data, size_t l
goto authabort;
}
- if (serveroutlen) {
+ if (serverout) {
vnc_write_u32(vs, serveroutlen + 1);
- vnc_write(vs, serverout, serveroutlen + 1);
+ vnc_write(vs, serverout, serveroutlen);
+ vnc_write_u8(vs, '\0');
} else {
vnc_write_u32(vs, 0);
}
@@ -524,13 +538,13 @@ static int protocol_client_auth_sasl_mechname_len(VncState *vs, uint8_t *data, s
return 0;
}
-static char *
+static int
vnc_socket_ip_addr_string(QIOChannelSocket *ioc,
bool local,
+ char **addrstr,
Error **errp)
{
SocketAddress *addr;
- char *ret;
if (local) {
addr = qio_channel_socket_get_local_address(ioc, errp);
@@ -538,17 +552,24 @@ vnc_socket_ip_addr_string(QIOChannelSocket *ioc,
addr = qio_channel_socket_get_remote_address(ioc, errp);
}
if (!addr) {
- return NULL;
+ return -1;
}
if (addr->type != SOCKET_ADDRESS_TYPE_INET) {
- error_setg(errp, "Not an inet socket type");
+ *addrstr = NULL;
qapi_free_SocketAddress(addr);
- return NULL;
+ return 0;
}
- ret = g_strdup_printf("%s;%s", addr->u.inet.host, addr->u.inet.port);
+ *addrstr = g_strdup_printf("%s;%s", addr->u.inet.host, addr->u.inet.port);
qapi_free_SocketAddress(addr);
- return ret;
+ return 0;
+}
+
+static bool
+vnc_socket_is_unix(QIOChannelSocket *ioc)
+{
+ SocketAddress *addr = qio_channel_socket_get_local_address(ioc, NULL);
+ return addr && addr->type == SOCKET_ADDRESS_TYPE_UNIX;
}
void start_auth_sasl(VncState *vs)
@@ -561,15 +582,15 @@ void start_auth_sasl(VncState *vs)
int mechlistlen;
/* Get local & remote client addresses in form IPADDR;PORT */
- localAddr = vnc_socket_ip_addr_string(vs->sioc, true, &local_err);
- if (!localAddr) {
+ if (vnc_socket_ip_addr_string(vs->sioc, true,
+ &localAddr, &local_err) < 0) {
trace_vnc_auth_fail(vs, vs->auth, "Cannot format local IP",
error_get_pretty(local_err));
goto authabort;
}
- remoteAddr = vnc_socket_ip_addr_string(vs->sioc, false, &local_err);
- if (!remoteAddr) {
+ if (vnc_socket_ip_addr_string(vs->sioc, false,
+ &remoteAddr, &local_err) < 0) {
trace_vnc_auth_fail(vs, vs->auth, "Cannot format remote IP",
error_get_pretty(local_err));
g_free(localAddr);
@@ -621,16 +642,17 @@ void start_auth_sasl(VncState *vs)
goto authabort;
}
} else {
- vs->sasl.wantSSF = 1;
+ vs->sasl.wantSSF = !vnc_socket_is_unix(vs->sioc);
}
memset (&secprops, 0, sizeof secprops);
/* Inform SASL that we've got an external SSF layer from TLS.
*
- * Disable SSF, if using TLS+x509+SASL only. TLS without x509
- * is not sufficiently strong
+ * Disable SSF, if using TLS+x509+SASL only, or UNIX sockets.
+ * TLS without x509 is not sufficiently strong, nor is plain
+ * TCP
*/
- if (vs->vd->is_unix ||
+ if (vnc_socket_is_unix(vs->sioc) ||
(vs->auth == VNC_AUTH_VENCRYPT &&
vs->subauth == VNC_AUTH_VENCRYPT_X509SASL)) {
/* If we've got TLS or UNIX domain sock, we don't care about SSF */
@@ -674,6 +696,13 @@ void start_auth_sasl(VncState *vs)
}
trace_vnc_auth_sasl_mech_list(vs, mechlist);
+ if (g_str_equal(mechlist, "")) {
+ trace_vnc_auth_fail(vs, vs->auth, "no available SASL mechanisms", "");
+ sasl_dispose(&vs->sasl.conn);
+ vs->sasl.conn = NULL;
+ goto authabort;
+ }
+
vs->sasl.mechlist = g_strdup(mechlist);
mechlistlen = strlen(mechlist);
vnc_write_u32(vs, mechlistlen);
diff --git a/ui/vnc.c b/ui/vnc.c
index dae5d51..5fcb35b 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -1935,7 +1935,7 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
}
qkbd_state_key_event(vs->vd->kbd, qcode, down);
- if (!qemu_console_is_graphic(vs->vd->dcl.con)) {
+ if (QEMU_IS_TEXT_CONSOLE(vs->vd->dcl.con)) {
QemuTextConsole *con = QEMU_TEXT_CONSOLE(vs->vd->dcl.con);
bool numlock = qkbd_state_modifier_get(vs->vd->kbd, QKBD_MOD_NUMLOCK);
bool control = qkbd_state_modifier_get(vs->vd->kbd, QKBD_MOD_CTRL);
@@ -2783,7 +2783,7 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
vnc_munge_des_rfb_key(key, sizeof(key));
cipher = qcrypto_cipher_new(
- QCRYPTO_CIPHER_ALG_DES,
+ QCRYPTO_CIPHER_ALGO_DES,
QCRYPTO_CIPHER_MODE_ECB,
key, G_N_ELEMENTS(key),
&err);
@@ -3430,7 +3430,6 @@ static void vnc_display_close(VncDisplay *vd)
if (!vd) {
return;
}
- vd->is_unix = false;
if (vd->listener) {
qio_net_listener_disconnect(vd->listener);
@@ -3852,7 +3851,7 @@ static int vnc_display_get_addresses(QemuOpts *opts,
return 0;
}
if (qemu_opt_get(opts, "websocket") &&
- !qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA1)) {
+ !qcrypto_hash_supports(QCRYPTO_HASH_ALGO_SHA1)) {
error_setg(errp,
"SHA1 hash support is required for websockets");
return -1;
@@ -3932,8 +3931,6 @@ static int vnc_display_connect(VncDisplay *vd,
error_setg(errp, "Expected a single address in reverse mode");
return -1;
}
- /* TODO SOCKET_ADDRESS_TYPE_FD when fd has AF_UNIX */
- vd->is_unix = saddr_list->value->type == SOCKET_ADDRESS_TYPE_UNIX;
sioc = qio_channel_socket_new();
qio_channel_set_name(QIO_CHANNEL(sioc), "vnc-reverse");
if (qio_channel_socket_connect_sync(sioc, saddr_list->value, errp) < 0) {
@@ -4064,7 +4061,7 @@ void vnc_display_open(const char *id, Error **errp)
}
if (password) {
if (!qcrypto_cipher_supports(
- QCRYPTO_CIPHER_ALG_DES, QCRYPTO_CIPHER_MODE_ECB)) {
+ QCRYPTO_CIPHER_ALGO_DES, QCRYPTO_CIPHER_MODE_ECB)) {
error_setg(errp,
"Cipher backend does not support DES algorithm");
goto fail;
diff --git a/ui/vnc.h b/ui/vnc.h
index 4521dc8..acc53a2 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -81,8 +81,8 @@ typedef void VncSendHextileTile(VncState *vs,
/* VNC_MAX_WIDTH must be a multiple of VNC_DIRTY_PIXELS_PER_BIT. */
-#define VNC_MAX_WIDTH ROUND_UP(2560, VNC_DIRTY_PIXELS_PER_BIT)
-#define VNC_MAX_HEIGHT 2048
+#define VNC_MAX_WIDTH ROUND_UP(5120, VNC_DIRTY_PIXELS_PER_BIT)
+#define VNC_MAX_HEIGHT 2160
/* VNC_DIRTY_BITS is the number of bits in the dirty bitmap. */
#define VNC_DIRTY_BITS (VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT)
@@ -168,7 +168,6 @@ struct VncDisplay
const char *id;
QTAILQ_ENTRY(VncDisplay) next;
- bool is_unix;
char *password;
time_t expires;
int auth;
diff --git a/util/aio-posix.c b/util/aio-posix.c
index 266c9dd..06bf9f4 100644
--- a/util/aio-posix.c
+++ b/util/aio-posix.c
@@ -17,6 +17,7 @@
#include "block/block.h"
#include "block/thread-pool.h"
#include "qemu/main-loop.h"
+#include "qemu/lockcnt.h"
#include "qemu/rcu.h"
#include "qemu/rcu_queue.h"
#include "qemu/sockets.h"
diff --git a/util/aio-win32.c b/util/aio-win32.c
index d144f93..6583d5c 100644
--- a/util/aio-win32.c
+++ b/util/aio-win32.c
@@ -18,6 +18,7 @@
#include "qemu/osdep.h"
#include "block/block.h"
#include "qemu/main-loop.h"
+#include "qemu/lockcnt.h"
#include "qemu/queue.h"
#include "qemu/sockets.h"
#include "qapi/error.h"
diff --git a/util/async.c b/util/async.c
index 0467890..99db283 100644
--- a/util/async.c
+++ b/util/async.c
@@ -30,6 +30,7 @@
#include "block/graph-lock.h"
#include "qemu/main-loop.h"
#include "qemu/atomic.h"
+#include "qemu/lockcnt.h"
#include "qemu/rcu_queue.h"
#include "block/raw-aio.h"
#include "qemu/coroutine_int.h"
@@ -746,7 +747,7 @@ void aio_context_set_thread_pool_params(AioContext *ctx, int64_t min,
int64_t max, Error **errp)
{
- if (min > max || !max || min > INT_MAX || max > INT_MAX) {
+ if (min > max || max <= 0 || min < 0 || min > INT_MAX || max > INT_MAX) {
error_setg(errp, "bad thread-pool-min/thread-pool-max values");
return;
}
diff --git a/util/block-helpers.c b/util/block-helpers.c
index c485143..052b4e1 100644
--- a/util/block-helpers.c
+++ b/util/block-helpers.c
@@ -10,12 +10,10 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "qapi/qmp/qerror.h"
#include "block-helpers.h"
/**
* check_block_size:
- * @id: The unique ID of the object
* @name: The name of the property being validated
* @value: The block size in bytes
* @errp: A pointer to an area to store an error
@@ -24,23 +22,23 @@
* 1. At least MIN_BLOCK_SIZE
* 2. No larger than MAX_BLOCK_SIZE
* 3. A power of 2
+ *
+ * Returns: true on success, false on failure
*/
-void check_block_size(const char *id, const char *name, int64_t value,
- Error **errp)
+bool check_block_size(const char *name, int64_t value, Error **errp)
{
- /* value of 0 means "unset" */
- if (value && (value < MIN_BLOCK_SIZE || value > MAX_BLOCK_SIZE)) {
- error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
- id, name, value, MIN_BLOCK_SIZE, MAX_BLOCK_SIZE);
- return;
+ if (!value) {
+ /* unset */
+ return true;
}
- /* We rely on power-of-2 blocksizes for bitmasks */
- if ((value & (value - 1)) != 0) {
+ if (value < MIN_BLOCK_SIZE || value > MAX_BLOCK_SIZE
+ || (value & (value - 1))) {
error_setg(errp,
- "Property %s.%s doesn't take value '%" PRId64
- "', it's not a power of 2",
- id, name, value);
- return;
+ "parameter %s must be a power of 2 between %" PRId64
+ " and %" PRId64,
+ name, MIN_BLOCK_SIZE, MAX_BLOCK_SIZE);
+ return false;
}
+ return true;
}
diff --git a/util/block-helpers.h b/util/block-helpers.h
index b53295a..838b082 100644
--- a/util/block-helpers.h
+++ b/util/block-helpers.h
@@ -13,7 +13,6 @@
#define MAX_BLOCK_SIZE (2 * MiB)
#define MAX_BLOCK_SIZE_STR "2 MiB"
-void check_block_size(const char *id, const char *name, int64_t value,
- Error **errp);
+bool check_block_size(const char *name, int64_t value, Error **errp);
#endif /* BLOCK_HELPERS_H */
diff --git a/util/cpuinfo-aarch64.c b/util/cpuinfo-aarch64.c
index 8ca775a..5746889 100644
--- a/util/cpuinfo-aarch64.c
+++ b/util/cpuinfo-aarch64.c
@@ -17,10 +17,13 @@
# define HWCAP2_BTI 0 /* added in glibc 2.32 */
# endif
#endif
+#ifdef CONFIG_ELF_AUX_INFO
+#include <sys/auxv.h>
+#endif
#ifdef CONFIG_DARWIN
# include <sys/sysctl.h>
#endif
-#ifdef __OpenBSD__
+#if defined(__OpenBSD__) && !defined(CONFIG_ELF_AUX_INFO)
# include <machine/armreg.h>
# include <machine/cpu.h>
# include <sys/types.h>
@@ -61,7 +64,7 @@ unsigned __attribute__((constructor)) cpuinfo_init(void)
info = CPUINFO_ALWAYS;
-#ifdef CONFIG_LINUX
+#if defined(CONFIG_LINUX) || defined(CONFIG_ELF_AUX_INFO)
unsigned long hwcap = qemu_getauxval(AT_HWCAP);
info |= (hwcap & HWCAP_ATOMICS ? CPUINFO_LSE : 0);
info |= (hwcap & HWCAP_USCAT ? CPUINFO_LSE2 : 0);
@@ -78,7 +81,7 @@ unsigned __attribute__((constructor)) cpuinfo_init(void)
info |= sysctl_for_bool("hw.optional.arm.FEAT_PMULL") * CPUINFO_PMULL;
info |= sysctl_for_bool("hw.optional.arm.FEAT_BTI") * CPUINFO_BTI;
#endif
-#ifdef __OpenBSD__
+#if defined(__OpenBSD__) && !defined(CONFIG_ELF_AUX_INFO)
int mib[2];
uint64_t isar0;
uint64_t pfr1;
diff --git a/util/cpuinfo-ppc.c b/util/cpuinfo-ppc.c
index 1304f9a..4d3d3aa 100644
--- a/util/cpuinfo-ppc.c
+++ b/util/cpuinfo-ppc.c
@@ -14,7 +14,8 @@
# include "elf.h"
# endif
#endif
-#ifdef __FreeBSD__
+#if defined(CONFIG_ELF_AUX_INFO)
+# include <sys/auxv.h>
# include <machine/cpu.h>
# ifndef PPC_FEATURE2_ARCH_3_1
# define PPC_FEATURE2_ARCH_3_1 0
@@ -35,7 +36,7 @@ unsigned __attribute__((constructor)) cpuinfo_init(void)
info = CPUINFO_ALWAYS;
-#if defined(CONFIG_LINUX) || defined(__FreeBSD__)
+#if defined(CONFIG_LINUX) || defined(CONFIG_ELF_AUX_INFO)
unsigned long hwcap = qemu_getauxval(AT_HWCAP);
unsigned long hwcap2 = qemu_getauxval(AT_HWCAP2);
diff --git a/util/cpuinfo-riscv.c b/util/cpuinfo-riscv.c
index 497ce12..971c924 100644
--- a/util/cpuinfo-riscv.c
+++ b/util/cpuinfo-riscv.c
@@ -4,14 +4,17 @@
*/
#include "qemu/osdep.h"
+#include "qemu/host-utils.h"
#include "host/cpuinfo.h"
#ifdef CONFIG_ASM_HWPROBE_H
#include <asm/hwprobe.h>
#include <sys/syscall.h>
+#include <asm/unistd.h>
#endif
unsigned cpuinfo;
+unsigned riscv_lg2_vlenb;
static volatile sig_atomic_t got_sigill;
static void sigill_handler(int signo, siginfo_t *si, void *data)
@@ -33,7 +36,7 @@ static void sigill_handler(int signo, siginfo_t *si, void *data)
/* Called both as constructor and (possibly) via other constructors. */
unsigned __attribute__((constructor)) cpuinfo_init(void)
{
- unsigned left = CPUINFO_ZBA | CPUINFO_ZBB | CPUINFO_ZICOND;
+ unsigned left = CPUINFO_ZBA | CPUINFO_ZBB | CPUINFO_ZICOND | CPUINFO_ZVE64X;
unsigned info = cpuinfo;
if (info) {
@@ -50,6 +53,10 @@ unsigned __attribute__((constructor)) cpuinfo_init(void)
#if defined(__riscv_arch_test) && defined(__riscv_zicond)
info |= CPUINFO_ZICOND;
#endif
+#if defined(__riscv_arch_test) && \
+ (defined(__riscv_vector) || defined(__riscv_zve64x))
+ info |= CPUINFO_ZVE64X;
+#endif
left &= ~info;
#ifdef CONFIG_ASM_HWPROBE_H
@@ -69,10 +76,21 @@ unsigned __attribute__((constructor)) cpuinfo_init(void)
info |= pair.value & RISCV_HWPROBE_EXT_ZICOND ? CPUINFO_ZICOND : 0;
left &= ~CPUINFO_ZICOND;
#endif
+ /* For rv64, V is Zve64d, a superset of Zve64x. */
+ info |= pair.value & RISCV_HWPROBE_IMA_V ? CPUINFO_ZVE64X : 0;
+#ifdef RISCV_HWPROBE_EXT_ZVE64X
+ info |= pair.value & RISCV_HWPROBE_EXT_ZVE64X ? CPUINFO_ZVE64X : 0;
+#endif
}
}
#endif /* CONFIG_ASM_HWPROBE_H */
+ /*
+ * We only detect support for vectors with hwprobe. All kernels with
+ * support for vectors in userspace also support the hwprobe syscall.
+ */
+ left &= ~CPUINFO_ZVE64X;
+
if (left) {
struct sigaction sa_old, sa_new;
@@ -112,6 +130,21 @@ unsigned __attribute__((constructor)) cpuinfo_init(void)
assert(left == 0);
}
+ if (info & CPUINFO_ZVE64X) {
+ /*
+ * We are guaranteed by RVV-1.0 that VLEN is a power of 2.
+ * We are guaranteed by Zve64x that VLEN >= 64, and that
+ * EEW of {8,16,32,64} are supported.
+ */
+ unsigned long vlenb;
+ /* csrr %0, vlenb */
+ asm volatile(".insn i 0x73, 0x2, %0, zero, -990" : "=r"(vlenb));
+ assert(vlenb >= 8);
+ assert(is_power_of_2(vlenb));
+ /* Cache VLEN in a convenient form. */
+ riscv_lg2_vlenb = ctz32(vlenb);
+ }
+
info |= CPUINFO_ALWAYS;
cpuinfo = info;
return info;
diff --git a/util/cutils.c b/util/cutils.c
index 4236403..9803f11 100644
--- a/util/cutils.c
+++ b/util/cutils.c
@@ -1144,11 +1144,6 @@ void qemu_init_exec_dir(const char *argv0)
#endif
}
-const char *qemu_get_exec_dir(void)
-{
- return exec_dir;
-}
-
char *get_relocated_path(const char *dir)
{
size_t prefix_len = strlen(CONFIG_PREFIX);
diff --git a/util/envlist.c b/util/envlist.c
index db937c0..15fdbb1 100644
--- a/util/envlist.c
+++ b/util/envlist.c
@@ -12,9 +12,6 @@ struct envlist {
size_t el_count; /* number of entries */
};
-static int envlist_parse(envlist_t *envlist,
- const char *env, int (*)(envlist_t *, const char *));
-
/*
* Allocates new envlist and returns pointer to it.
*/
@@ -52,72 +49,6 @@ envlist_free(envlist_t *envlist)
}
/*
- * Parses comma separated list of set/modify environment
- * variable entries and updates given enlist accordingly.
- *
- * For example:
- * envlist_parse(el, "HOME=foo,SHELL=/bin/sh");
- *
- * inserts/sets environment variables HOME and SHELL.
- *
- * Returns 0 on success, errno otherwise.
- */
-int
-envlist_parse_set(envlist_t *envlist, const char *env)
-{
- return (envlist_parse(envlist, env, &envlist_setenv));
-}
-
-/*
- * Parses comma separated list of unset environment variable
- * entries and removes given variables from given envlist.
- *
- * Returns 0 on success, errno otherwise.
- */
-int
-envlist_parse_unset(envlist_t *envlist, const char *env)
-{
- return (envlist_parse(envlist, env, &envlist_unsetenv));
-}
-
-/*
- * Parses comma separated list of set, modify or unset entries
- * and calls given callback for each entry.
- *
- * Returns 0 in case of success, errno otherwise.
- */
-static int
-envlist_parse(envlist_t *envlist, const char *env,
- int (*callback)(envlist_t *, const char *))
-{
- char *tmpenv, *envvar;
- char *envsave = NULL;
- int ret = 0;
- assert(callback != NULL);
-
- if ((envlist == NULL) || (env == NULL))
- return (EINVAL);
-
- tmpenv = g_strdup(env);
- envsave = tmpenv;
-
- do {
- envvar = strchr(tmpenv, ',');
- if (envvar != NULL) {
- *envvar = '\0';
- }
- if ((*callback)(envlist, tmpenv) != 0) {
- ret = errno;
- break;
- }
- tmpenv = envvar + 1;
- } while (envvar != NULL);
-
- g_free(envsave);
- return ret;
-}
-
-/*
* Sets environment value to envlist in similar manner
* than putenv(3).
*
diff --git a/util/fdmon-epoll.c b/util/fdmon-epoll.c
index c6413cb..9fb8800 100644
--- a/util/fdmon-epoll.c
+++ b/util/fdmon-epoll.c
@@ -5,6 +5,7 @@
#include "qemu/osdep.h"
#include <sys/epoll.h>
+#include "qemu/lockcnt.h"
#include "qemu/rcu_queue.h"
#include "aio-posix.h"
diff --git a/util/fifo8.c b/util/fifo8.c
index 4e01b53..a26da66 100644
--- a/util/fifo8.c
+++ b/util/fifo8.c
@@ -16,12 +16,17 @@
#include "migration/vmstate.h"
#include "qemu/fifo8.h"
+void fifo8_reset(Fifo8 *fifo)
+{
+ fifo->num = 0;
+ fifo->head = 0;
+}
+
void fifo8_create(Fifo8 *fifo, uint32_t capacity)
{
fifo->data = g_new(uint8_t, capacity);
fifo->capacity = capacity;
- fifo->head = 0;
- fifo->num = 0;
+ fifo8_reset(fifo);
}
void fifo8_destroy(Fifo8 *fifo)
@@ -66,18 +71,27 @@ uint8_t fifo8_pop(Fifo8 *fifo)
return ret;
}
-static const uint8_t *fifo8_peekpop_buf(Fifo8 *fifo, uint32_t max,
- uint32_t *numptr, bool do_pop)
+uint8_t fifo8_peek(Fifo8 *fifo)
+{
+ assert(fifo->num > 0);
+ return fifo->data[fifo->head];
+}
+
+static const uint8_t *fifo8_peekpop_bufptr(Fifo8 *fifo, uint32_t max,
+ uint32_t skip, uint32_t *numptr,
+ bool do_pop)
{
uint8_t *ret;
- uint32_t num;
+ uint32_t num, head;
assert(max > 0 && max <= fifo->num);
- num = MIN(fifo->capacity - fifo->head, max);
- ret = &fifo->data[fifo->head];
+ assert(skip <= fifo->num);
+ head = (fifo->head + skip) % fifo->capacity;
+ num = MIN(fifo->capacity - head, max);
+ ret = &fifo->data[head];
if (do_pop) {
- fifo->head += num;
+ fifo->head = head + num;
fifo->head %= fifo->capacity;
fifo->num -= num;
}
@@ -87,20 +101,60 @@ static const uint8_t *fifo8_peekpop_buf(Fifo8 *fifo, uint32_t max,
return ret;
}
-const uint8_t *fifo8_peek_buf(Fifo8 *fifo, uint32_t max, uint32_t *numptr)
+const uint8_t *fifo8_peek_bufptr(Fifo8 *fifo, uint32_t max, uint32_t *numptr)
{
- return fifo8_peekpop_buf(fifo, max, numptr, false);
+ return fifo8_peekpop_bufptr(fifo, max, 0, numptr, false);
}
-const uint8_t *fifo8_pop_buf(Fifo8 *fifo, uint32_t max, uint32_t *numptr)
+const uint8_t *fifo8_pop_bufptr(Fifo8 *fifo, uint32_t max, uint32_t *numptr)
{
- return fifo8_peekpop_buf(fifo, max, numptr, true);
+ return fifo8_peekpop_bufptr(fifo, max, 0, numptr, true);
}
-void fifo8_reset(Fifo8 *fifo)
+static uint32_t fifo8_peekpop_buf(Fifo8 *fifo, uint8_t *dest, uint32_t destlen,
+ bool do_pop)
{
- fifo->num = 0;
- fifo->head = 0;
+ const uint8_t *buf;
+ uint32_t n1, n2 = 0;
+ uint32_t len;
+
+ if (destlen == 0) {
+ return 0;
+ }
+
+ len = destlen;
+ buf = fifo8_peekpop_bufptr(fifo, len, 0, &n1, do_pop);
+ if (dest) {
+ memcpy(dest, buf, n1);
+ }
+
+ /* Add FIFO wraparound if needed */
+ len -= n1;
+ len = MIN(len, fifo8_num_used(fifo));
+ if (len) {
+ buf = fifo8_peekpop_bufptr(fifo, len, do_pop ? 0 : n1, &n2, do_pop);
+ if (dest) {
+ memcpy(&dest[n1], buf, n2);
+ }
+ }
+
+ return n1 + n2;
+}
+
+uint32_t fifo8_pop_buf(Fifo8 *fifo, uint8_t *dest, uint32_t destlen)
+{
+ return fifo8_peekpop_buf(fifo, dest, destlen, true);
+}
+
+uint32_t fifo8_peek_buf(Fifo8 *fifo, uint8_t *dest, uint32_t destlen)
+{
+ return fifo8_peekpop_buf(fifo, dest, destlen, false);
+}
+
+void fifo8_drop(Fifo8 *fifo, uint32_t len)
+{
+ len -= fifo8_pop_buf(fifo, NULL, len);
+ assert(len == 0);
}
bool fifo8_is_empty(Fifo8 *fifo)
diff --git a/util/getauxval.c b/util/getauxval.c
index b124107..0735cd8 100644
--- a/util/getauxval.c
+++ b/util/getauxval.c
@@ -95,16 +95,20 @@ unsigned long qemu_getauxval(unsigned long type)
}
}
+ errno = ENOENT;
return 0;
}
-#elif defined(__FreeBSD__)
+#elif defined(CONFIG_ELF_AUX_INFO)
#include <sys/auxv.h>
unsigned long qemu_getauxval(unsigned long type)
{
unsigned long aux = 0;
- elf_aux_info(type, &aux, sizeof(aux));
+ int ret = elf_aux_info(type, &aux, sizeof(aux));
+ if (ret != 0) {
+ errno = ret;
+ }
return aux;
}
@@ -112,6 +116,7 @@ unsigned long qemu_getauxval(unsigned long type)
unsigned long qemu_getauxval(unsigned long type)
{
+ errno = ENOSYS;
return 0;
}
diff --git a/util/hbitmap.c b/util/hbitmap.c
index 6d6e1b5..d9a1dab 100644
--- a/util/hbitmap.c
+++ b/util/hbitmap.c
@@ -949,7 +949,7 @@ char *hbitmap_sha256(const HBitmap *bitmap, Error **errp)
size_t size = bitmap->sizes[HBITMAP_LEVELS - 1] * sizeof(unsigned long);
char *data = (char *)bitmap->levels[HBITMAP_LEVELS - 1];
char *hash = NULL;
- qcrypto_hash_digest(QCRYPTO_HASH_ALG_SHA256, data, size, &hash, errp);
+ qcrypto_hash_digest(QCRYPTO_HASH_ALGO_SHA256, data, size, &hash, errp);
return hash;
}
diff --git a/util/iov.c b/util/iov.c
index 7e73948..7777116 100644
--- a/util/iov.c
+++ b/util/iov.c
@@ -3,6 +3,7 @@
*
* Copyright IBM, Corp. 2007, 2008
* Copyright (C) 2010 Red Hat, Inc.
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
*
* Author(s):
* Anthony Liguori <aliguori@us.ibm.com>
@@ -92,7 +93,8 @@ size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt)
/* helper function for iov_send_recv() */
static ssize_t
-do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send)
+do_send_recv(int sockfd, int flags, struct iovec *iov, unsigned iov_cnt,
+ bool do_send)
{
#ifdef CONFIG_POSIX
ssize_t ret;
@@ -102,8 +104,8 @@ do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send)
msg.msg_iovlen = iov_cnt;
do {
ret = do_send
- ? sendmsg(sockfd, &msg, 0)
- : recvmsg(sockfd, &msg, 0);
+ ? sendmsg(sockfd, &msg, flags)
+ : recvmsg(sockfd, &msg, flags);
} while (ret < 0 && errno == EINTR);
return ret;
#else
@@ -114,8 +116,8 @@ do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send)
ssize_t off = 0;
while (i < iov_cnt) {
ssize_t r = do_send
- ? send(sockfd, iov[i].iov_base + off, iov[i].iov_len - off, 0)
- : recv(sockfd, iov[i].iov_base + off, iov[i].iov_len - off, 0);
+ ? send(sockfd, iov[i].iov_base + off, iov[i].iov_len - off, flags)
+ : recv(sockfd, iov[i].iov_base + off, iov[i].iov_len - off, flags);
if (r > 0) {
ret += r;
off += r;
@@ -145,6 +147,15 @@ ssize_t iov_send_recv(int sockfd, const struct iovec *_iov, unsigned iov_cnt,
size_t offset, size_t bytes,
bool do_send)
{
+ return iov_send_recv_with_flags(sockfd, 0, _iov, iov_cnt, offset, bytes,
+ do_send);
+}
+
+ssize_t iov_send_recv_with_flags(int sockfd, int sockflags,
+ const struct iovec *_iov,
+ unsigned iov_cnt, size_t offset,
+ size_t bytes, bool do_send)
+{
ssize_t total = 0;
ssize_t ret;
size_t orig_len, tail;
@@ -192,11 +203,11 @@ ssize_t iov_send_recv(int sockfd, const struct iovec *_iov, unsigned iov_cnt,
assert(iov[niov].iov_len > tail);
orig_len = iov[niov].iov_len;
iov[niov++].iov_len = tail;
- ret = do_send_recv(sockfd, iov, niov, do_send);
+ ret = do_send_recv(sockfd, sockflags, iov, niov, do_send);
/* Undo the changes above before checking for errors */
iov[niov-1].iov_len = orig_len;
} else {
- ret = do_send_recv(sockfd, iov, niov, do_send);
+ ret = do_send_recv(sockfd, sockflags, iov, niov, do_send);
}
if (offset) {
iov[0].iov_base -= offset;
diff --git a/util/iova-tree.c b/util/iova-tree.c
index 5367897..06295e2 100644
--- a/util/iova-tree.c
+++ b/util/iova-tree.c
@@ -115,13 +115,6 @@ const DMAMap *iova_tree_find_iova(const IOVATree *tree, const DMAMap *map)
return args.result;
}
-const DMAMap *iova_tree_find_address(const IOVATree *tree, hwaddr iova)
-{
- const DMAMap map = { .iova = iova, .size = 0 };
-
- return iova_tree_find(tree, &map);
-}
-
static inline void iova_tree_insert_internal(GTree *gtree, DMAMap *range)
{
/* Key and value are sharing the same range data */
@@ -148,22 +141,6 @@ int iova_tree_insert(IOVATree *tree, const DMAMap *map)
return IOVA_OK;
}
-static gboolean iova_tree_traverse(gpointer key, gpointer value,
- gpointer data)
-{
- iova_tree_iterator iterator = data;
- DMAMap *map = key;
-
- g_assert(key == value);
-
- return iterator(map);
-}
-
-void iova_tree_foreach(IOVATree *tree, iova_tree_iterator iterator)
-{
- g_tree_foreach(tree->tree, iova_tree_traverse, iterator);
-}
-
void iova_tree_remove(IOVATree *tree, DMAMap map)
{
const DMAMap *overlap;
diff --git a/util/lockcnt.c b/util/lockcnt.c
index 5da3694..d07c6cc 100644
--- a/util/lockcnt.c
+++ b/util/lockcnt.c
@@ -7,6 +7,7 @@
* Paolo Bonzini <pbonzini@redhat.com>
*/
#include "qemu/osdep.h"
+#include "qemu/lockcnt.h"
#include "qemu/thread.h"
#include "qemu/atomic.h"
#include "trace.h"
diff --git a/util/memfd.c b/util/memfd.c
index 4a3c07e..8a2e906 100644
--- a/util/memfd.c
+++ b/util/memfd.c
@@ -28,6 +28,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
+#include "qemu/error-report.h"
#include "qemu/memfd.h"
#include "qemu/host-utils.h"
@@ -149,11 +150,15 @@ err:
void qemu_memfd_free(void *ptr, size_t size, int fd)
{
if (ptr) {
- munmap(ptr, size);
+ if (munmap(ptr, size) != 0) {
+ error_report("memfd munmap() failed: %s", strerror(errno));
+ }
}
if (fd != -1) {
- close(fd);
+ if (close(fd) != 0) {
+ error_report("memfd close() failed: %s", strerror(errno));
+ }
}
}
diff --git a/util/module.c b/util/module.c
index 32e2631..3eb0f06 100644
--- a/util/module.c
+++ b/util/module.c
@@ -354,13 +354,13 @@ int module_load_qom(const char *type, Error **errp)
void module_load_qom_all(void)
{
const QemuModinfo *modinfo;
- Error *local_err = NULL;
if (module_loaded_qom_all) {
return;
}
for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
+ Error *local_err = NULL;
if (!modinfo->objs) {
continue;
}
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
index b090fe0..11b35e4 100644
--- a/util/oslib-posix.c
+++ b/util/oslib-posix.c
@@ -807,3 +807,127 @@ int qemu_msync(void *addr, size_t length, int fd)
return msync(addr, length, MS_SYNC);
}
+
+static bool qemu_close_all_open_fd_proc(const int *skip, unsigned int nskip)
+{
+ struct dirent *de;
+ int fd, dfd;
+ DIR *dir;
+ unsigned int skip_start = 0, skip_end = nskip;
+
+ dir = opendir("/proc/self/fd");
+ if (!dir) {
+ /* If /proc is not mounted, there is nothing that can be done. */
+ return false;
+ }
+ /* Avoid closing the directory. */
+ dfd = dirfd(dir);
+
+ for (de = readdir(dir); de; de = readdir(dir)) {
+ bool close_fd = true;
+
+ if (de->d_name[0] == '.') {
+ continue;
+ }
+ fd = atoi(de->d_name);
+ if (fd == dfd) {
+ continue;
+ }
+
+ for (unsigned int i = skip_start; i < skip_end; i++) {
+ if (fd < skip[i]) {
+ /* We are below the next skipped fd, break */
+ break;
+ } else if (fd == skip[i]) {
+ close_fd = false;
+ /* Restrict the range as we found fds matching start/end */
+ if (i == skip_start) {
+ skip_start++;
+ } else if (i == skip_end) {
+ skip_end--;
+ }
+ break;
+ }
+ }
+
+ if (close_fd) {
+ close(fd);
+ }
+ }
+ closedir(dir);
+
+ return true;
+}
+
+static bool qemu_close_all_open_fd_close_range(const int *skip,
+ unsigned int nskip,
+ int open_max)
+{
+#ifdef CONFIG_CLOSE_RANGE
+ int max_fd = open_max - 1;
+ int first = 0, last;
+ unsigned int cur_skip = 0;
+ int ret;
+
+ do {
+ /* Find the start boundary of the range to close */
+ while (cur_skip < nskip && first == skip[cur_skip]) {
+ cur_skip++;
+ first++;
+ }
+
+ /* Find the upper boundary of the range to close */
+ last = max_fd;
+ if (cur_skip < nskip) {
+ last = skip[cur_skip] - 1;
+ last = MIN(last, max_fd);
+ }
+
+ /* With the adjustments to the range, we might be done. */
+ if (first > last) {
+ break;
+ }
+
+ ret = close_range(first, last, 0);
+ if (ret < 0) {
+ return false;
+ }
+
+ first = last + 1;
+ } while (last < max_fd);
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+static void qemu_close_all_open_fd_fallback(const int *skip, unsigned int nskip,
+ int open_max)
+{
+ unsigned int cur_skip = 0;
+
+ /* Fallback */
+ for (int i = 0; i < open_max; i++) {
+ if (cur_skip < nskip && i == skip[cur_skip]) {
+ cur_skip++;
+ continue;
+ }
+ close(i);
+ }
+}
+
+/*
+ * Close all open file descriptors.
+ */
+void qemu_close_all_open_fd(const int *skip, unsigned int nskip)
+{
+ int open_max = sysconf(_SC_OPEN_MAX);
+
+ assert(skip != NULL || nskip == 0);
+
+ if (!qemu_close_all_open_fd_close_range(skip, nskip, open_max) &&
+ !qemu_close_all_open_fd_proc(skip, nskip)) {
+ qemu_close_all_open_fd_fallback(skip, nskip, open_max);
+ }
+}
diff --git a/util/qemu-co-shared-resource.c b/util/qemu-co-shared-resource.c
index a66cc07..752eb5a 100644
--- a/util/qemu-co-shared-resource.c
+++ b/util/qemu-co-shared-resource.c
@@ -66,12 +66,6 @@ static bool co_try_get_from_shres_locked(SharedResource *s, uint64_t n)
return false;
}
-bool co_try_get_from_shres(SharedResource *s, uint64_t n)
-{
- QEMU_LOCK_GUARD(&s->lock);
- return co_try_get_from_shres_locked(s, n);
-}
-
void coroutine_fn co_get_from_shres(SharedResource *s, uint64_t n)
{
assert(n <= s->total);
diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c
index eb4eebe..64d6264 100644
--- a/util/qemu-coroutine.c
+++ b/util/qemu-coroutine.c
@@ -136,7 +136,7 @@ static Coroutine *coroutine_pool_get_local(void)
static void coroutine_pool_refill_local(void)
{
CoroutinePool *local_pool = get_ptr_local_pool();
- CoroutinePoolBatch *batch;
+ CoroutinePoolBatch *batch = NULL;
WITH_QEMU_LOCK_GUARD(&global_pool_lock) {
batch = QSLIST_FIRST(&global_pool);
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 60c44b2..77477c1 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -367,7 +367,6 @@ static int inet_connect_addr(const InetSocketAddress *saddr,
addr->ai_family);
return -1;
}
- socket_set_fast_reuse(sock);
/* connect to peer */
do {
@@ -707,26 +706,6 @@ int inet_parse(InetSocketAddress *addr, const char *str, Error **errp)
}
-/**
- * Create a blocking socket and connect it to an address.
- *
- * @str: address string
- * @errp: set in case of an error
- *
- * Returns -1 in case of error, file descriptor on success
- **/
-int inet_connect(const char *str, Error **errp)
-{
- int sock = -1;
- InetSocketAddress *addr = g_new(InetSocketAddress, 1);
-
- if (!inet_parse(addr, str, errp)) {
- sock = inet_connect_saddr(addr, errp);
- }
- qapi_free_InetSocketAddress(addr);
- return sock;
-}
-
#ifdef CONFIG_AF_VSOCK
static bool vsock_parse_vaddr_to_sockaddr(const VsockSocketAddress *vaddr,
struct sockaddr_vm *svm,
@@ -1421,21 +1400,6 @@ SocketAddress *socket_local_address(int fd, Error **errp)
}
-SocketAddress *socket_remote_address(int fd, Error **errp)
-{
- struct sockaddr_storage ss;
- socklen_t sslen = sizeof(ss);
-
- if (getpeername(fd, (struct sockaddr *)&ss, &sslen) < 0) {
- error_setg_errno(errp, errno, "%s",
- "Unable to query remote socket address");
- return NULL;
- }
-
- return socket_sockaddr_to_address(&ss, sslen, errp);
-}
-
-
SocketAddress *socket_address_flatten(SocketAddressLegacy *addr_legacy)
{
SocketAddress *addr;
diff --git a/util/qemu-timer.c b/util/qemu-timer.c
index 213114b..ffe9a3c 100644
--- a/util/qemu-timer.c
+++ b/util/qemu-timer.c
@@ -182,7 +182,7 @@ bool qemu_clock_has_timers(QEMUClockType type)
bool timerlist_expired(QEMUTimerList *timer_list)
{
- int64_t expire_time;
+ int64_t expire_time = 0;
if (!qatomic_read(&timer_list->active_timers)) {
return false;
@@ -212,7 +212,7 @@ bool qemu_clock_expired(QEMUClockType type)
int64_t timerlist_deadline_ns(QEMUTimerList *timer_list)
{
int64_t delta;
- int64_t expire_time;
+ int64_t expire_time = 0;
if (!qatomic_read(&timer_list->active_timers)) {
return -1;
@@ -286,16 +286,6 @@ int64_t qemu_clock_deadline_ns_all(QEMUClockType type, int attr_mask)
return deadline;
}
-QEMUClockType timerlist_get_clock(QEMUTimerList *timer_list)
-{
- return timer_list->clock->type;
-}
-
-QEMUTimerList *qemu_clock_get_main_loop_timerlist(QEMUClockType type)
-{
- return main_loop_tlg.tl[type];
-}
-
void timerlist_notify(QEMUTimerList *timer_list)
{
if (timer_list->notify_cb) {
@@ -461,7 +451,7 @@ void timer_mod_ns(QEMUTimer *ts, int64_t expire_time)
void timer_mod_anticipate_ns(QEMUTimer *ts, int64_t expire_time)
{
QEMUTimerList *timer_list = ts->timer_list;
- bool rearm;
+ bool rearm = false;
WITH_QEMU_LOCK_GUARD(&timer_list->active_timers_lock) {
if (ts->expire_time == -1 || ts->expire_time > expire_time) {
@@ -685,10 +675,17 @@ int64_t qemu_clock_advance_virtual_time(int64_t dest)
{
int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
AioContext *aio_context;
+ int64_t deadline;
+
aio_context = qemu_get_aio_context();
- while (clock < dest) {
- int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL,
+
+ deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL,
QEMU_TIMER_ATTR_ALL);
+ /*
+ * A deadline of < 0 indicates this timer is not enabled, so we
+ * won't get far trying to run it forward.
+ */
+ while (deadline >= 0 && clock < dest) {
int64_t warp = qemu_soonest_timeout(dest - clock, deadline);
qemu_virtual_clock_set_ns(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + warp);
@@ -696,6 +693,9 @@ int64_t qemu_clock_advance_virtual_time(int64_t dest)
qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL);
timerlist_run_timers(aio_context->tlg.tl[QEMU_CLOCK_VIRTUAL]);
clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+ deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL,
+ QEMU_TIMER_ATTR_ALL);
}
qemu_clock_notify(QEMU_CLOCK_VIRTUAL);
diff --git a/util/timed-average.c b/util/timed-average.c
index 2b49d53..5b5c22a 100644
--- a/util/timed-average.c
+++ b/util/timed-average.c
@@ -8,10 +8,12 @@
* BenoƮt Canet <benoit.canet@nodalink.com>
* Alberto Garcia <berto@igalia.com>
*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
* 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) version 3 or any later version.
+ * (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
diff --git a/util/userfaultfd.c b/util/userfaultfd.c
index 1b2fa94..2396104 100644
--- a/util/userfaultfd.c
+++ b/util/userfaultfd.c
@@ -240,7 +240,7 @@ int uffd_change_protection(int uffd_fd, void *addr, uint64_t length,
* Copy range of source pages to the destination to resolve
* missing page fault somewhere in the destination range.
*
- * Returns 0 on success, negative value in case of an error
+ * Returns 0 on success, -errno in case of an error
*
* @uffd_fd: UFFD file descriptor
* @dst_addr: destination base address
@@ -259,10 +259,11 @@ int uffd_copy_page(int uffd_fd, void *dst_addr, void *src_addr,
uffd_copy.mode = dont_wake ? UFFDIO_COPY_MODE_DONTWAKE : 0;
if (ioctl(uffd_fd, UFFDIO_COPY, &uffd_copy)) {
+ int e = errno;
error_report("uffd_copy_page() failed: dst_addr=%p src_addr=%p length=%" PRIu64
" mode=%" PRIx64 " errno=%i", dst_addr, src_addr,
- length, (uint64_t) uffd_copy.mode, errno);
- return -1;
+ length, (uint64_t) uffd_copy.mode, e);
+ return -e;
}
return 0;
@@ -273,7 +274,7 @@ int uffd_copy_page(int uffd_fd, void *dst_addr, void *src_addr,
*
* Fill range pages with zeroes to resolve missing page fault within the range.
*
- * Returns 0 on success, negative value in case of an error
+ * Returns 0 on success, -errno in case of an error
*
* @uffd_fd: UFFD file descriptor
* @addr: base address
@@ -289,10 +290,11 @@ int uffd_zero_page(int uffd_fd, void *addr, uint64_t length, bool dont_wake)
uffd_zeropage.mode = dont_wake ? UFFDIO_ZEROPAGE_MODE_DONTWAKE : 0;
if (ioctl(uffd_fd, UFFDIO_ZEROPAGE, &uffd_zeropage)) {
+ int e = errno;
error_report("uffd_zero_page() failed: addr=%p length=%" PRIu64
" mode=%" PRIx64 " errno=%i", addr, length,
- (uint64_t) uffd_zeropage.mode, errno);
- return -1;
+ (uint64_t) uffd_zeropage.mode, e);
+ return -e;
}
return 0;
@@ -306,7 +308,7 @@ int uffd_zero_page(int uffd_fd, void *addr, uint64_t length, bool dont_wake)
* via UFFD-IO IOCTLs with MODE_DONTWAKE flag set, then after that all waits
* for the whole memory range are satisfied in a single call to uffd_wakeup().
*
- * Returns 0 on success, negative value in case of an error
+ * Returns 0 on success, -errno in case of an error
*
* @uffd_fd: UFFD file descriptor
* @addr: base address
@@ -320,9 +322,10 @@ int uffd_wakeup(int uffd_fd, void *addr, uint64_t length)
uffd_range.len = length;
if (ioctl(uffd_fd, UFFDIO_WAKE, &uffd_range)) {
+ int e = errno;
error_report("uffd_wakeup() failed: addr=%p length=%" PRIu64 " errno=%i",
- addr, length, errno);
- return -1;
+ addr, length, e);
+ return -e;
}
return 0;
@@ -355,31 +358,3 @@ int uffd_read_events(int uffd_fd, struct uffd_msg *msgs, int count)
return (int) (res / sizeof(struct uffd_msg));
}
-
-/**
- * uffd_poll_events: poll UFFD file descriptor for read
- *
- * Returns true if events are available for read, false otherwise
- *
- * @uffd_fd: UFFD file descriptor
- * @tmo: timeout value
- */
-bool uffd_poll_events(int uffd_fd, int tmo)
-{
- int res;
- struct pollfd poll_fd = { .fd = uffd_fd, .events = POLLIN, .revents = 0 };
-
- do {
- res = poll(&poll_fd, 1, tmo);
- } while (res < 0 && errno == EINTR);
-
- if (res == 0) {
- return false;
- }
- if (res < 0) {
- error_report("uffd_poll_events() failed: errno=%i", errno);
- return false;
- }
-
- return (poll_fd.revents & POLLIN) != 0;
-}